LCOV - code coverage report
Current view: top level - libpkg - scripts.c (source / functions) Hit Total Coverage
Test: cov.info Lines: 52 93 55.9 %
Date: 2015-08-15 Functions: 1 1 100.0 %

          Line data    Source code
       1             : /*-
       2             :  * Copyright (c) 2011-2012 Baptiste Daroussin <bapt@FreeBSD.org>
       3             :  * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
       4             :  * Copyright (c) 2011 Philippe Pepiot <phil@philpep.org>
       5             :  * All rights reserved.
       6             :  * 
       7             :  * Redistribution and use in source and binary forms, with or without
       8             :  * modification, are permitted provided that the following conditions
       9             :  * are met:
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer
      12             :  *    in this position and unchanged.
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  * 
      17             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
      18             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      19             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      20             :  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
      21             :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      22             :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      23             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      24             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      25             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      26             :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      27             :  */
      28             : 
      29             : #include "pkg_config.h"
      30             : 
      31             : #include <sys/wait.h>
      32             : #ifdef HAVE_SYS_PROCCTL_H
      33             : #include <sys/procctl.h>
      34             : #endif
      35             : 
      36             : #include <assert.h>
      37             : #include <errno.h>
      38             : #include <paths.h>
      39             : #include <spawn.h>
      40             : #include <stdlib.h>
      41             : #include <limits.h>
      42             : #include <string.h>
      43             : 
      44             : #include "pkg.h"
      45             : #include "private/pkg.h"
      46             : #include "private/event.h"
      47             : 
      48             : extern char **environ;
      49             : 
      50             : int
      51          74 : pkg_script_run(struct pkg * const pkg, pkg_script type)
      52             : {
      53          74 :         struct sbuf * const script_cmd = sbuf_new_auto();
      54             :         size_t i, j;
      55             :         int error, pstat;
      56             :         pid_t pid;
      57             :         const char *script_cmd_p;
      58             :         const char *argv[4];
      59             :         char **ep;
      60          74 :         int ret = EPKG_OK;
      61          74 :         int stdin_pipe[2] = {-1, -1};
      62             :         posix_spawn_file_actions_t action;
      63          74 :         bool use_pipe = 0;
      64          74 :         bool debug = false;
      65             :         ssize_t bytes_written;
      66             :         size_t script_cmd_len;
      67             :         long argmax;
      68             : #ifdef PROC_REAP_KILL
      69             :         bool do_reap;
      70             :         struct procctl_reaper_status info;
      71             :         struct procctl_reaper_kill killemall;
      72             : #endif
      73             : 
      74             :         struct {
      75             :                 const char * const arg;
      76             :                 const pkg_script b;
      77             :                 const pkg_script a;
      78          74 :         } const map[] = {
      79             :                 /* a implies b with argument arg */
      80             :                 {"PRE-INSTALL",    PKG_SCRIPT_INSTALL,   PKG_SCRIPT_PRE_INSTALL},
      81             :                 {"POST-INSTALL",   PKG_SCRIPT_INSTALL,   PKG_SCRIPT_POST_INSTALL},
      82             :                 {"PRE-UPGRADE",    PKG_SCRIPT_UPGRADE,   PKG_SCRIPT_PRE_UPGRADE},
      83             :                 {"POST-UPGRADE",   PKG_SCRIPT_UPGRADE,   PKG_SCRIPT_POST_UPGRADE},
      84             :                 {"DEINSTALL",      PKG_SCRIPT_DEINSTALL, PKG_SCRIPT_PRE_DEINSTALL},
      85             :                 {"POST-DEINSTALL", PKG_SCRIPT_DEINSTALL, PKG_SCRIPT_POST_DEINSTALL},
      86             :         };
      87             : 
      88          74 :         if (!pkg_object_bool(pkg_config_get("RUN_SCRIPTS")))
      89           0 :                 return (EPKG_OK);
      90             : 
      91         159 :         for (i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
      92         159 :                 if (map[i].a == type)
      93          74 :                         break;
      94             :         }
      95             : 
      96          74 :         assert(i < sizeof(map) / sizeof(map[0]));
      97             : 
      98             : #ifdef PROC_REAP_KILL
      99          74 :         do_reap = procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL) == 0;
     100             : #endif
     101         740 :         for (j = 0; j < PKG_NUM_SCRIPTS; j++) {
     102         666 :                 if (pkg_script_get(pkg, j) == NULL)
     103         642 :                         continue;
     104          24 :                 if (j == map[i].a || j == map[i].b) {
     105          12 :                         sbuf_reset(script_cmd);
     106          12 :                         setenv("PKG_PREFIX", pkg->prefix, 1);
     107          12 :                         if (pkg_rootdir != NULL)
     108           0 :                                 setenv("PKG_ROOTDIR", pkg_rootdir, 1);
     109          12 :                         debug = pkg_object_bool(pkg_config_get("DEBUG_SCRIPTS"));
     110          12 :                         if (debug)
     111           0 :                                 sbuf_printf(script_cmd, "set -x\n");
     112          12 :                         pkg_sbuf_printf(script_cmd, "set -- %n-%v", pkg, pkg);
     113             : 
     114          12 :                         if (j == map[i].b) {
     115             :                                 /* add arg **/
     116           0 :                                 sbuf_cat(script_cmd, " ");
     117           0 :                                 sbuf_cat(script_cmd, map[i].arg);
     118             :                         }
     119             : 
     120          12 :                         sbuf_cat(script_cmd, "\n");
     121          12 :                         sbuf_cat(script_cmd, pkg_script_get(pkg, j));
     122          12 :                         sbuf_finish(script_cmd);
     123             : 
     124             :                         /* Determine the maximum argument length for the given
     125             :                            script to determine if /bin/sh -c can be used, or
     126             :                            if a pipe is required to /bin/sh -s. Similar to
     127             :                            find(1) determination */
     128          12 :                         if ((argmax = sysconf(_SC_ARG_MAX)) == -1)
     129           0 :                                 argmax = _POSIX_ARG_MAX;
     130          12 :                         argmax -= 1024;
     131        1032 :                         for (ep = environ; *ep != NULL; ep++)
     132        1020 :                                 argmax -= strlen(*ep) + 1 + sizeof(*ep);
     133          12 :                         argmax -= 1 + sizeof(*ep);
     134             : 
     135          12 :                         pkg_debug(3, "Scripts: executing\n--- BEGIN ---\n%s\nScripts: --- END ---", sbuf_data(script_cmd));
     136          12 :                         if (sbuf_len(script_cmd) > argmax) {
     137           0 :                                 if (pipe(stdin_pipe) < 0) {
     138           0 :                                         ret = EPKG_FATAL;
     139           0 :                                         goto cleanup;
     140             :                                 }
     141             : 
     142           0 :                                 posix_spawn_file_actions_init(&action);
     143           0 :                                 posix_spawn_file_actions_adddup2(&action, stdin_pipe[0],
     144             :                                     STDIN_FILENO);
     145           0 :                                 posix_spawn_file_actions_addclose(&action, stdin_pipe[1]);
     146             : 
     147           0 :                                 argv[0] = _PATH_BSHELL;
     148           0 :                                 argv[1] = "-s";
     149           0 :                                 argv[2] = NULL;
     150             : 
     151           0 :                                 use_pipe = 1;
     152             :                         } else {
     153          12 :                                 argv[0] = _PATH_BSHELL;
     154          12 :                                 argv[1] = "-c";
     155          12 :                                 argv[2] = sbuf_data(script_cmd);
     156          12 :                                 argv[3] = NULL;
     157             : 
     158          12 :                                 use_pipe = 0;
     159             :                         }
     160             : 
     161          12 :                         if ((error = posix_spawn(&pid, _PATH_BSHELL,
     162             :                             use_pipe ? &action : NULL,
     163             :                             NULL, __DECONST(char **, argv),
     164             :                             environ)) != 0) {
     165           0 :                                 errno = error;
     166           0 :                                 pkg_emit_errno("Cannot run script",
     167             :                                     map[i].arg);
     168           0 :                                 goto cleanup;
     169             :                         }
     170             : 
     171          12 :                         if (use_pipe) {
     172           0 :                                 script_cmd_p = sbuf_data(script_cmd);
     173           0 :                                 script_cmd_len = sbuf_len(script_cmd);
     174           0 :                                 while (script_cmd_len > 0) {
     175           0 :                                         if ((bytes_written = write(stdin_pipe[1], script_cmd_p,
     176             :                                             script_cmd_len)) == -1) {
     177           0 :                                                 if (errno == EINTR)
     178           0 :                                                         continue;
     179           0 :                                                 ret = EPKG_FATAL;
     180           0 :                                                 goto cleanup;
     181             :                                         }
     182           0 :                                         script_cmd_p += bytes_written;
     183           0 :                                         script_cmd_len -= bytes_written;
     184             :                                 }
     185           0 :                                 close(stdin_pipe[1]);
     186             :                         }
     187             : 
     188          12 :                         unsetenv("PKG_PREFIX");
     189             : 
     190          12 :                         while (waitpid(pid, &pstat, 0) == -1) {
     191           0 :                                 if (errno != EINTR)
     192           0 :                                         goto cleanup;
     193             :                         }
     194             : 
     195          12 :                         if (WEXITSTATUS(pstat) != 0) {
     196           0 :                                 pkg_emit_error("%s script failed", map[i].arg);
     197           0 :                                 goto cleanup;
     198             :                         }
     199             :                 }
     200             :         }
     201             : 
     202             : cleanup:
     203             : 
     204          74 :         sbuf_delete(script_cmd);
     205          74 :         if (stdin_pipe[0] != -1)
     206           0 :                 close(stdin_pipe[0]);
     207          74 :         if (stdin_pipe[1] != -1)
     208           0 :                 close(stdin_pipe[1]);
     209             : 
     210             : #ifdef PROC_REAP_KILL
     211             :         /*
     212             :          * If the prior PROCCTL_REAP_ACQUIRE call failed, the kernel
     213             :          * probably doesn't support this, so don't try.
     214             :          */
     215          74 :         if (!do_reap)
     216           0 :                 return (ret);
     217             : 
     218          74 :         procctl(P_PID, getpid(), PROC_REAP_STATUS, &info);
     219          74 :         if (info.rs_children != 0) {
     220           0 :                 killemall.rk_sig = SIGKILL;
     221           0 :                 killemall.rk_flags = 0;
     222           0 :                 if (procctl(P_PID, getpid(), PROC_REAP_KILL, &killemall) != 0)
     223           0 :                         pkg_emit_errno("procctl", "PROC_REAP_KILL");
     224             :         }
     225          74 :         procctl(P_PID, getpid(), PROC_REAP_RELEASE, NULL);
     226             : #endif
     227             : 
     228          74 :         return (ret);
     229             : }
     230             : 

Generated by: LCOV version 1.10