Merge branch 'morganamilo/exec' into 'master'

libalpm: say what we tried to exec on error

See merge request pacman/pacman!102
This commit is contained in:
Morgan Adamiec 2024-03-26 02:15:07 +00:00
commit 506be7b8ac
11 changed files with 124 additions and 51 deletions

View file

@ -469,7 +469,7 @@ static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg,
!(trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) {
const char *scriptlet_name = is_upgrade ? "pre_upgrade" : "pre_install";
_alpm_runscriptlet(handle, pkgfile, scriptlet_name,
_alpm_runscriptlet(handle, newpkg->name, pkgfile, scriptlet_name,
newpkg->version, oldpkg ? oldpkg->version : NULL, 1);
}
@ -641,7 +641,7 @@ static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg,
char *scriptlet = _alpm_local_db_pkgpath(db, newpkg, "install");
const char *scriptlet_name = is_upgrade ? "post_upgrade" : "post_install";
_alpm_runscriptlet(handle, scriptlet, scriptlet_name,
_alpm_runscriptlet(handle, newpkg->name, scriptlet, scriptlet_name,
newpkg->version, oldpkg ? oldpkg->version : NULL, 0);
free(scriptlet);
}

View file

@ -750,6 +750,10 @@ typedef enum _alpm_event_type_t {
ALPM_EVENT_LOAD_START,
/** Target package is finished loading. */
ALPM_EVENT_LOAD_DONE,
/** An install file is about to be ran */
ALPM_EVENT_INSTALL_RUN_START,
/** An install file has finished running */
ALPM_EVENT_INSTALL_RUN_DONE,
/** Scriptlet has printed information; See alpm_event_scriptlet_info_t for
* arguments. */
ALPM_EVENT_SCRIPTLET_INFO,
@ -840,10 +844,32 @@ typedef struct _alpm_event_optdep_removal_t {
alpm_depend_t *optdep;
} alpm_event_optdep_removal_t;
/** Enum of the kinds of scriptlets */
typedef enum _alpm_scriptlet_kind_t {
/** We are running an install file */
ALPM_SCRIPTLET_KIND_INSTALL_FILE,
/** We are running a hook */
ALPM_SCRIPTLET_KIND_HOOK,
/** We are running a command */
ALPM_SCRIPTLET_KIND_COMMAND,
} alpm_scriptlet_kind_t;
/** We are running an install file. */
typedef struct _alpm_event_install_run_t {
/** Type of event */
alpm_event_type_t type;
/** The name of the package */
const char *pkgname;
} alpm_event_install_run_t;
/** A scriptlet was ran. */
typedef struct _alpm_event_scriptlet_info_t {
/** Type of event */
alpm_event_type_t type;
/** The kind of scriptlet being ran */
alpm_scriptlet_kind_t kind;
/** The name of the scriptlet **/
const char *name;
/** Line of scriptlet output */
const char *line;
} alpm_event_scriptlet_info_t;
@ -946,6 +972,8 @@ typedef union _alpm_event_t {
alpm_event_package_operation_t package_operation;
/** An optdept was remove */
alpm_event_optdep_removal_t optdep_removal;
/** An install file is about to be run */
alpm_event_install_run_t install_run;
/** A scriptlet was ran */
alpm_event_scriptlet_info_t scriptlet_info;
/** A database is missing */

View file

@ -522,10 +522,10 @@ static int _alpm_hook_run_hook(alpm_handle_t *handle, struct _alpm_hook_t *hook)
alpm_list_count(hook->matches), (alpm_list_fn_cmp)strcmp);
/* hooks with multiple triggers could have duplicate matches */
ctx = hook->matches = _alpm_strlist_dedup(hook->matches);
return _alpm_run_chroot(handle, hook->cmd[0], hook->cmd,
return _alpm_run_chroot(handle, hook->name, ALPM_SCRIPTLET_KIND_HOOK, hook->cmd[0], hook->cmd,
(_alpm_cb_io) _alpm_hook_feed_targets, &ctx);
} else {
return _alpm_run_chroot(handle, hook->cmd[0], hook->cmd, NULL, NULL);
return _alpm_run_chroot(handle, hook->name, ALPM_SCRIPTLET_KIND_HOOK, hook->cmd[0], hook->cmd, NULL, NULL);
}
}

View file

@ -694,7 +694,7 @@ int _alpm_remove_single_package(alpm_handle_t *handle,
!(handle->trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) {
char *scriptlet = _alpm_local_db_pkgpath(handle->db_local,
oldpkg, "install");
_alpm_runscriptlet(handle, scriptlet, "pre_remove", pkgver, NULL, 0);
_alpm_runscriptlet(handle, oldpkg->name, scriptlet, "pre_remove", pkgver, NULL, 0);
free(scriptlet);
}
}
@ -714,7 +714,7 @@ int _alpm_remove_single_package(alpm_handle_t *handle,
!(handle->trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) {
char *scriptlet = _alpm_local_db_pkgpath(handle->db_local,
oldpkg, "install");
_alpm_runscriptlet(handle, scriptlet, "post_remove", pkgver, NULL, 0);
_alpm_runscriptlet(handle, oldpkg->name, scriptlet, "post_remove", pkgver, NULL, 0);
free(scriptlet);
}

View file

@ -334,7 +334,7 @@ static int grep(const char *fn, const char *needle)
return 0;
}
int _alpm_runscriptlet(alpm_handle_t *handle, const char *filepath,
int _alpm_runscriptlet(alpm_handle_t *handle, const char *pkgname, const char *filepath,
const char *script, const char *ver, const char *oldver, int is_archive)
{
char arg0[64], arg1[3], cmdline[PATH_MAX];
@ -407,7 +407,16 @@ int _alpm_runscriptlet(alpm_handle_t *handle, const char *filepath,
_alpm_log(handle, ALPM_LOG_DEBUG, "executing \"%s\"\n", cmdline);
retval = _alpm_run_chroot(handle, SCRIPTLET_SHELL, argv, NULL, NULL);
alpm_event_install_run_t event = {
.type = ALPM_EVENT_INSTALL_RUN_START,
.pkgname = pkgname,
};
EVENT(handle, &event);
retval = _alpm_run_chroot(handle, pkgname, ALPM_SCRIPTLET_KIND_INSTALL_FILE, SCRIPTLET_SHELL, argv, NULL, NULL);
event.type = ALPM_EVENT_INSTALL_RUN_DONE;
EVENT(handle, &event);
cleanup:
if(scriptfn && unlink(scriptfn)) {

View file

@ -49,7 +49,7 @@ typedef struct _alpm_trans_t {
void _alpm_trans_free(alpm_trans_t *trans);
/* flags is a bitfield of alpm_transflag_t flags */
int _alpm_trans_init(alpm_trans_t *trans, int flags);
int _alpm_runscriptlet(alpm_handle_t *handle, const char *filepath,
int _alpm_runscriptlet(alpm_handle_t *handle, const char *name, const char *filepath,
const char *script, const char *ver, const char *oldver, int is_archive);
#endif /* ALPM_TRANS_H */

View file

@ -497,18 +497,21 @@ static int _alpm_chroot_write_to_child(alpm_handle_t *handle, int fd,
return 0;
}
static void _alpm_chroot_process_output(alpm_handle_t *handle, const char *line)
static void _alpm_chroot_process_output(alpm_handle_t *handle, const char *name,
alpm_scriptlet_kind_t kind, const char *line)
{
alpm_event_scriptlet_info_t event = {
.type = ALPM_EVENT_SCRIPTLET_INFO,
.kind = kind,
.name = name,
.line = line
};
alpm_logaction(handle, "ALPM-SCRIPTLET", "%s", line);
EVENT(handle, &event);
}
static int _alpm_chroot_read_from_child(alpm_handle_t *handle, int fd,
char *buf, ssize_t *buf_size, ssize_t buf_limit)
static int _alpm_chroot_read_from_child(alpm_handle_t *handle, int fd, const char *name,
alpm_scriptlet_kind_t kind, char *buf, ssize_t *buf_size, ssize_t buf_limit)
{
ssize_t space = buf_limit - *buf_size - 2; /* reserve 2 for "\n\0" */
ssize_t nread = read(fd, buf + *buf_size, space);
@ -520,7 +523,7 @@ static int _alpm_chroot_read_from_child(alpm_handle_t *handle, int fd,
size_t linelen = newline - buf + 1;
char old = buf[linelen];
buf[linelen] = '\0';
_alpm_chroot_process_output(handle, buf);
_alpm_chroot_process_output(handle, name, kind, buf);
buf[linelen] = old;
*buf_size -= linelen;
@ -530,14 +533,14 @@ static int _alpm_chroot_read_from_child(alpm_handle_t *handle, int fd,
} else if(nread == space) {
/* we didn't read a full line, but we're out of space */
strcpy(buf + *buf_size, "\n");
_alpm_chroot_process_output(handle, buf);
_alpm_chroot_process_output(handle, name, kind, buf);
*buf_size = 0;
}
} else if(nread == 0) {
/* end-of-file */
if(*buf_size) {
strcpy(buf + *buf_size, "\n");
_alpm_chroot_process_output(handle, buf);
_alpm_chroot_process_output(handle, name, kind, buf);
}
return -1;
} else if(should_retry(errno)) {
@ -546,7 +549,7 @@ static int _alpm_chroot_read_from_child(alpm_handle_t *handle, int fd,
/* read error */
if(*buf_size) {
strcpy(buf + *buf_size, "\n");
_alpm_chroot_process_output(handle, buf);
_alpm_chroot_process_output(handle, name, kind, buf);
}
_alpm_log(handle, ALPM_LOG_ERROR,
_("unable to read from pipe (%s)\n"), strerror(errno));
@ -582,14 +585,16 @@ static void _alpm_reset_signals(void)
/** Execute a command with arguments in a chroot.
* @param handle the context handle
* @param name a human readable name to describe the command
* @param kind what kind of scriptlet is running
* @param cmd command to execute
* @param argv arguments to pass to cmd
* @param stdin_cb callback to provide input to the chroot on stdin
* @param stdin_ctx context to be passed to @a stdin_cb
* @return 0 on success, 1 on error
*/
int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[],
_alpm_cb_io stdin_cb, void *stdin_ctx)
int _alpm_run_chroot(alpm_handle_t *handle, const char *name, alpm_scriptlet_kind_t kind,
const char *cmd, char *const argv[], _alpm_cb_io stdin_cb, void *stdin_ctx)
{
pid_t pid;
int child2parent_pipefd[2], parent2child_pipefd[2];
@ -650,6 +655,7 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[],
close(parent2child_pipefd[HEAD]);
close(child2parent_pipefd[TAIL]);
close(child2parent_pipefd[HEAD]);
if(cwdfd >= 0) {
close(cwdfd);
}
@ -678,24 +684,38 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[],
_alpm_handle_free(handle);
execv(cmd, argv);
/* execv only returns if there was an error */
fprintf(stderr, _("call to execv failed (%s)\n"), strerror(errno));
fprintf(stderr, _("%s: failed to execv '%s' (%s)\n"), name, cmd, strerror(errno));
exit(1);
} else {
/* this code runs for the parent only (wait on the child) */
int status;
char obuf[PIPE_BUF]; /* writes <= PIPE_BUF are guaranteed atomic */
char ibuf[LINE_MAX];
char sciptlet_name[32];
ssize_t olen = 0, ilen = 0;
nfds_t nfds = 2;
struct pollfd fds[2], *child2parent = &(fds[0]), *parent2child = &(fds[1]);
int poll_ret;
switch(kind) {
case ALPM_SCRIPTLET_KIND_HOOK:
snprintf(sciptlet_name, 32, "hook '%s'", name);
break;
case ALPM_SCRIPTLET_KIND_INSTALL_FILE:
snprintf(sciptlet_name, 32, "'%s.install'", name);
break;
case ALPM_SCRIPTLET_KIND_COMMAND:
strncpy(sciptlet_name, "ldconfig", 32);
break;
}
child2parent->fd = child2parent_pipefd[TAIL];
child2parent->events = POLLIN;
fcntl(child2parent->fd, F_SETFL, O_NONBLOCK);
close(child2parent_pipefd[HEAD]);
close(parent2child_pipefd[TAIL]);
if(stdin_cb) {
parent2child->fd = parent2child_pipefd[HEAD];
parent2child->events = POLLOUT;
@ -718,7 +738,7 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[],
}
}
if(child2parent->revents & POLLIN) {
if(_alpm_chroot_read_from_child(handle, child2parent->fd,
if(_alpm_chroot_read_from_child(handle, child2parent->fd, name, kind,
ibuf, &ilen, sizeof(ibuf)) != 0) {
/* we encountered end-of-file or an error */
STOP_POLLING(child2parent);
@ -741,7 +761,7 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[],
if(ilen) {
/* buffer would have already been flushed if it had a newline */
strcpy(ibuf + ilen, "\n");
_alpm_chroot_process_output(handle, ibuf);
_alpm_chroot_process_output(handle, name, kind, ibuf);
}
#undef STOP_POLLING
@ -757,7 +777,7 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[],
while(waitpid(pid, &status, 0) == -1) {
if(errno != EINTR) {
_alpm_log(handle, ALPM_LOG_ERROR, _("call to waitpid failed (%s)\n"), strerror(errno));
_alpm_log(handle, ALPM_LOG_ERROR, _("failed to run %s: call to waitpid failed (%s)\n"), sciptlet_name, strerror(errno));
retval = 1;
goto cleanup;
}
@ -767,7 +787,8 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[],
if(WIFEXITED(status)) {
_alpm_log(handle, ALPM_LOG_DEBUG, "call to waitpid succeeded\n");
if(WEXITSTATUS(status) != 0) {
_alpm_log(handle, ALPM_LOG_ERROR, _("command failed to execute correctly\n"));
_alpm_log(handle, ALPM_LOG_ERROR, _("%s did not complete sucessfully (%s exited %d)\n"),
sciptlet_name, cmd, WEXITSTATUS(status));
retval = 1;
}
} else if(WIFSIGNALED(status) != 0) {
@ -776,8 +797,8 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[],
if(signal_description == NULL) {
signal_description = _("Unknown signal");
}
_alpm_log(handle, ALPM_LOG_ERROR, _("command terminated by signal %d: %s\n"),
WTERMSIG(status), signal_description);
_alpm_log(handle, ALPM_LOG_ERROR, _("%s terminated by signal %d: %s\n"),
sciptlet_name, WTERMSIG(status), signal_description);
retval = 1;
}
}
@ -808,10 +829,9 @@ int _alpm_ldconfig(alpm_handle_t *handle)
if(access(line, F_OK) == 0) {
snprintf(line, PATH_MAX, "%s%s", handle->root, LDCONFIG);
if(access(line, X_OK) == 0) {
char arg0[32];
char *arg0 = strdup(LDCONFIG);
char *argv[] = { arg0, NULL };
strcpy(arg0, "ldconfig");
return _alpm_run_chroot(handle, LDCONFIG, argv, NULL, NULL);
return _alpm_run_chroot(handle, "ldconfig", ALPM_SCRIPTLET_KIND_COMMAND, LDCONFIG, argv, NULL, NULL);
}
}

View file

@ -129,8 +129,8 @@ ssize_t _alpm_files_in_directory(alpm_handle_t *handle, const char *path, int fu
typedef ssize_t (*_alpm_cb_io)(void *buf, ssize_t len, void *ctx);
int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[],
_alpm_cb_io in_cb, void *in_ctx);
int _alpm_run_chroot(alpm_handle_t *handle, const char *name, alpm_scriptlet_kind_t kind,
const char *cmd, char *const argv[], _alpm_cb_io in_cb, void *in_ctx);
int _alpm_ldconfig(alpm_handle_t *handle);
int _alpm_str_cmp(const void *s1, const void *s2);
char *_alpm_filecache_find(alpm_handle_t *handle, const char *filename);

View file

@ -217,7 +217,10 @@ static int number_length(size_t n)
/* callback to handle messages/notifications from libalpm transactions */
void cb_event(void *ctx, alpm_event_t *event)
{
static int install_line_count = 0;
const colstr_t *colstr = &config->colstr;
(void)ctx;
if(config->print) {
console_cursor_move_end();
return;
@ -313,8 +316,16 @@ void cb_event(void *ctx, alpm_event_t *event)
printf(_("loading package files...\n"));
}
break;
case ALPM_EVENT_INSTALL_RUN_START:
install_line_count = 0;
break;
case ALPM_EVENT_SCRIPTLET_INFO:
fputs(event->scriptlet_info.line, stdout);
/* onlt say we're running the install file if it outputs */
if(install_line_count == 0 && event->scriptlet_info.kind == ALPM_SCRIPTLET_KIND_INSTALL_FILE) {
printf("Running %s.install...\n", event->scriptlet_info.name);
}
install_line_count++;
printf(" %s%s%s", colstr->scriptlet, event->scriptlet_info.line, colstr->nocolor);
break;
case ALPM_EVENT_DB_RETRIEVE_START:
on_progress = 1;
@ -413,6 +424,7 @@ void cb_event(void *ctx, alpm_event_t *event)
case ALPM_EVENT_DISKSPACE_DONE:
case ALPM_EVENT_HOOK_DONE:
case ALPM_EVENT_HOOK_RUN_DONE:
case ALPM_EVENT_INSTALL_RUN_DONE:
/* nothing */
break;
}

View file

@ -63,6 +63,7 @@ config_t *config = NULL;
#define BOLDMAGENTA "\033[1;35m"
#define BOLDCYAN "\033[1;36m"
#define BOLDWHITE "\033[1;37m"
#define BLUE117 "\033[38;5;117m"
#define GREY46 "\033[38;5;243m"
void enable_colors(int colors)
@ -78,6 +79,7 @@ void enable_colors(int colors)
colstr->meta = BOLDCYAN;
colstr->warn = BOLDYELLOW;
colstr->err = BOLDRED;
colstr->scriptlet = BLUE117;
colstr->faint = GREY46;
colstr->nocolor = NOCOLOR;
} else {
@ -89,6 +91,7 @@ void enable_colors(int colors)
colstr->meta = "";
colstr->warn = "";
colstr->err = "";
colstr->scriptlet = "";
colstr->faint = "";
colstr->nocolor = "";
}

View file

@ -32,6 +32,7 @@ typedef struct __colstr_t {
const char *warn;
const char *err;
const char *faint;
const char *scriptlet;
const char *nocolor;
} colstr_t;