[pacman-dev] [PATCH] redirect scriptlet stderr through alpm
Xavier Chantry
chantry.xavier at gmail.com
Fri May 21 03:30:28 EDT 2010
This looks mostly good to me, I like this patch as a first smaller
step, thanks !
Just have a few comments below, and I didn't test it yet.
On Fri, May 21, 2010 at 5:22 AM, Jonathan Conder <j at skurvy.no-ip.org> wrote:
> Sorry, I forgot to rebase against master. Here's the real patch:
>
Comments like this should be put below (look below :))
> Fixes FS#18770, and hopefully an occasional deadlock in my frontend as well.
> For simplicity it redirects all scriptlet output through SCRIPTLET_INFO, and
> all callbacks in the child process have been replaced for thread-safety.
>
> Signed-off-by: Jonathan Conder <j at skurvy.no-ip.org>
> ---
> lib/libalpm/util.c | 86 +++++++++++++++++++++++++++++----------------------
> 1 files changed, 49 insertions(+), 37 deletions(-)
>
Here between --- and diff, you can put any comments that don't belong
to commit log / git history.
> diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c
> index 32eaa44..62851c1 100644
> --- a/lib/libalpm/util.c
> +++ b/lib/libalpm/util.c
> @@ -448,6 +448,7 @@ int _alpm_run_chroot(const char *root, const char *cmd)
> {
> char cwd[PATH_MAX];
> pid_t pid;
> + int pipefd[2];
> int restore_cwd = 0;
> int retval = 0;
>
> @@ -471,6 +472,12 @@ int _alpm_run_chroot(const char *root, const char *cmd)
> /* Flush open fds before fork() to avoid cloning buffers */
> fflush(NULL);
>
> + if(pipe(pipefd) == -1) {
> + _alpm_log(PM_LOG_ERROR, _("could not create pipe (%s)\n"), strerror(errno));
> + retval = 1;
> + goto cleanup;
> + }
> +
> /* fork- parent and child each have seperate code blocks below */
> pid = fork();
> if(pid == -1) {
> @@ -480,55 +487,60 @@ int _alpm_run_chroot(const char *root, const char *cmd)
> }
>
> if(pid == 0) {
> - FILE *pipe;
> /* this code runs for the child only (the actual chroot/exec) */
> - _alpm_log(PM_LOG_DEBUG, "chrooting in %s\n", root);
> + close(1);
> + close(2);
> + close(pipefd[0]);
> + while(dup2(pipefd[1], 1) == -1 && errno == EINTR);
> + while(dup2(pipefd[1], 2) == -1 && errno == EINTR);
> + close(pipefd[1]);
> +
> if(chroot(root) != 0) {
> - _alpm_log(PM_LOG_ERROR, _("could not change the root directory (%s)\n"),
> - strerror(errno));
> + printf(_("could not change the root directory (%s)\n"), strerror(errno));
> exit(1);
> }
So we want to avoid callback here and cannot use alpm_log in the child ?
A printf in libalpm does not seem very useful for a frontend. But well
maybe we would keep it for easier debugging of pacman.
And at least frontend will see the return value.
IMO it's worth a comment explaining we use printf instead of alpm_log
to avoid callback in child because it can cause problems.
To be honest, I never looked into thread safety problems so I don't
know anything about this.
> if(chdir("/") != 0) {
> - _alpm_log(PM_LOG_ERROR, _("could not change directory to / (%s)\n"),
> - strerror(errno));
> + printf(_("could not change directory to / (%s)\n"), strerror(errno));
> exit(1);
> }
> umask(0022);
> - pipe = popen(cmd, "r");
> - if(!pipe) {
> - _alpm_log(PM_LOG_ERROR, _("call to popen failed (%s)\n"),
> - strerror(errno));
> - exit(1);
> - }
> - while(!feof(pipe)) {
> - char line[PATH_MAX];
> - if(fgets(line, PATH_MAX, pipe) == NULL)
> - break;
> - alpm_logaction("%s", line);
> - EVENT(handle->trans, PM_TRANS_EVT_SCRIPTLET_INFO, line, NULL);
> - }
> - retval = pclose(pipe);
> - exit(WEXITSTATUS(retval));
> + execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
> + printf(_("call to execl failed (%s)\n"), strerror(errno));
> + exit(1);
> } else {
> /* this code runs for the parent only (wait on the child) */
> - pid_t retpid;
> int status;
> - do {
> - retpid = waitpid(pid, &status, 0);
> - } while(retpid == -1 && errno == EINTR);
> - if(retpid == -1) {
> - _alpm_log(PM_LOG_ERROR, _("call to waitpid failed (%s)\n"),
> - strerror(errno));
> - retval = 1;
> - goto cleanup;
> + FILE *pipe;
> +
> + close(pipefd[1]);
> + pipe = fdopen(pipefd[0], "r");
> + if(pipe == NULL) {
> + close(pipefd[0]);
This is not a failure, we reach that for a scriptlet with no output ?
If so, can you put a quick comment for that case ?
> } else {
> - /* check the return status, make sure it is 0 (success) */
> - if(WIFEXITED(status)) {
> - _alpm_log(PM_LOG_DEBUG, "call to waitpid succeeded\n");
> - if(WEXITSTATUS(status) != 0) {
> - _alpm_log(PM_LOG_ERROR, _("command failed to execute correctly\n"));
> - retval = 1;
> - }
> + while(!feof(pipe)) {
> + char line[PATH_MAX];
> + if(fgets(line, PATH_MAX, pipe) == NULL)
> + break;
> + alpm_logaction("%s", line);
> + EVENT(handle->trans, PM_TRANS_EVT_SCRIPTLET_INFO, line, NULL);
> + }
> + fclose(pipe);
Do we need close(pipefd[0]); there too or is that done anyway ?
> + }
> +
> + while(waitpid(pid, &status, 0) == -1) {
> + if(errno != EINTR) {
> + _alpm_log(PM_LOG_ERROR, _("call to waitpid failed (%s)\n"), strerror(errno));
> + retval = 1;
> + goto cleanup;
> + }
> + }
> +
> + /* check the return status, make sure it is 0 (success) */
> + if(WIFEXITED(status)) {
> + _alpm_log(PM_LOG_DEBUG, "call to waitpid succeeded\n");
> + if(WEXITSTATUS(status) != 0) {
> + _alpm_log(PM_LOG_ERROR, _("command failed to execute correctly\n"));
> + retval = 1;
> }
> }
> }
> --
> 1.7.1
>
>
>
>
More information about the pacman-dev
mailing list