Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
morganamilo
47ee7e9442
Rework scriptlet printing and callbacks
This adds more info to the scriptlet callbacks and adds callbacks for
when and install file is about to run/finished running.

Indent and colour the scriptlet output so the user can see it clearly.
2023-12-04 18:38:32 +00:00
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

@ -692,7 +692,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);
}
}
@ -712,7 +712,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);
}
@ -677,24 +683,38 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[],
_alpm_reset_signals();
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;
@ -717,7 +737,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);
@ -740,7 +760,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
@ -756,7 +776,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;
}
@ -766,7 +786,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) {
@ -775,8 +796,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;
}
}
@ -807,10 +828,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)
@ -70,27 +71,29 @@ void enable_colors(int colors)
colstr_t *colstr = &config->colstr;
if(colors == PM_COLOR_ON) {
colstr->colon = BOLDBLUE "::" BOLD " ";
colstr->title = BOLD;
colstr->repo = BOLDMAGENTA;
colstr->version = BOLDGREEN;
colstr->groups = BOLDBLUE;
colstr->meta = BOLDCYAN;
colstr->warn = BOLDYELLOW;
colstr->err = BOLDRED;
colstr->faint = GREY46;
colstr->nocolor = NOCOLOR;
colstr->colon = BOLDBLUE "::" BOLD " ";
colstr->title = BOLD;
colstr->repo = BOLDMAGENTA;
colstr->version = BOLDGREEN;
colstr->groups = BOLDBLUE;
colstr->meta = BOLDCYAN;
colstr->warn = BOLDYELLOW;
colstr->err = BOLDRED;
colstr->scriptlet = BLUE117;
colstr->faint = GREY46;
colstr->nocolor = NOCOLOR;
} else {
colstr->colon = ":: ";
colstr->title = "";
colstr->repo = "";
colstr->version = "";
colstr->groups = "";
colstr->meta = "";
colstr->warn = "";
colstr->err = "";
colstr->faint = "";
colstr->nocolor = "";
colstr->colon = ":: ";
colstr->title = "";
colstr->repo = "";
colstr->version = "";
colstr->groups = "";
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;