summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClark Williams <williams@redhat.com>2007-07-13 13:55:05 -0500
committerClark Williams <williams@redhat.com>2007-07-13 13:55:05 -0500
commit84b2104792afe5559bc3bb9d696ca88352736e68 (patch)
treeaf31ee048e1d655e6c958631a5f6b1de7223d6f9
parentf30345b7189548ca6ed9c88fdc2447cf00b5aa54 (diff)
downloadmock-84b2104792afe5559bc3bb9d696ca88352736e68.tar.gz
mock-84b2104792afe5559bc3bb9d696ca88352736e68.tar.xz
mock-84b2104792afe5559bc3bb9d696ca88352736e68.zip
-rw-r--r--mock.py5
-rw-r--r--mock.spec2
-rw-r--r--src/mock-helper.c139
3 files changed, 145 insertions, 1 deletions
diff --git a/mock.py b/mock.py
index 68ddf62..6eb6ff0 100644
--- a/mock.py
+++ b/mock.py
@@ -866,6 +866,7 @@ def setup_default_config_opts(config_opts):
config_opts['basedir'] = '/var/lib/mock/' # root name is automatically added to this
config_opts['chroot'] = '/usr/sbin/mock-helper chroot'
config_opts['mount'] = '/usr/sbin/mock-helper mount'
+ config_opts['orphanskill'] = '/usr/sbin/mock-helper orphanskill'
config_opts['umount'] = '/usr/sbin/mock-helper umount'
config_opts['rm'] = '/usr/sbin/mock-helper rm'
config_opts['mknod'] = '/usr/sbin/mock-helper mknod'
@@ -960,6 +961,10 @@ def do_run_cmd(config_opts, cmd, env='', raw_chroot=0):
os.umask(0002) # set umask so mock group can all share.
my.debug("executing: %s" % cmd)
my._mount()
+ # Orphans killing must be included it to the same command as otherwise
+ # self.do() would get stuck.
+ # orphanskill output is visible only with the --debug option.
+ cmd += '; %s %s' % (config_opts['orphanskill'], my.rootdir)
if raw_chroot:
cmd = '%s %s %s %s' % (env, config_opts['chroot'], my.rootdir, cmd)
os.system(cmd)
diff --git a/mock.spec b/mock.spec
index 6c0c34f..57acf3e 100644
--- a/mock.spec
+++ b/mock.spec
@@ -1,6 +1,6 @@
Summary: Builds packages inside chroots
Name: mock
-Version: 0.7.3
+Version: 0.7.4
Release: 1%{?dist}
License: GPL
Group: Development/Tools
diff --git a/src/mock-helper.c b/src/mock-helper.c
index 93c29b3..2c44277 100644
--- a/src/mock-helper.c
+++ b/src/mock-helper.c
@@ -16,6 +16,11 @@
#include <string.h>
#include <grp.h>
#include <libgen.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <signal.h>
+#include <dirent.h>
#ifdef USE_SELINUX
#include <selinux/selinux.h>
@@ -57,6 +62,19 @@ error (const char *format, ...)
exit (1);
}
+/* print formatted string to stderr, print newline and continue */
+void
+warning (const char *format, ...)
+{
+ va_list ap;
+
+ va_start (ap, format);
+ fprintf (stderr, "mock-helper: warning: ");
+ vfprintf (stderr, format, ap);
+ va_end (ap);
+ fprintf (stderr, "\n");
+}
+
/*
* perform checks on the given dir
* - is the given dir under the allowed hierarchy ?
@@ -484,6 +502,125 @@ do_chmod (int argc, char *argv[])
do_command("/bin/chmod", &(argv[1]), 1);
}
+const char *read_cmdline (pid_t pid)
+{
+ char cmdline_fname[32];
+ static char cmdline[LINE_MAX];
+ int fd;
+ ssize_t got;
+ char *s;
+
+ if (snprintf (cmdline_fname, sizeof (cmdline_fname), "/proc/%d/cmdline",
+ (int) pid) < 0)
+ return NULL;
+ fd = open (cmdline_fname, O_RDONLY);
+ if (fd == -1) {
+ warning ("open (\"%s\"): %s", cmdline_fname, strerror (errno));
+ return NULL;
+ }
+ got = read (fd, cmdline, sizeof (cmdline) - 1);
+ if (got == -1)
+ warning ("read (\"%s\"): %s", cmdline_fname, strerror (errno));
+ if (close (fd))
+ warning ("close (\"%s\"): %s", cmdline_fname, strerror (errno));
+ if (got < 0)
+ return NULL;
+ /* Convert '\0' argument delimiters to spaces. */
+ for (s = cmdline; s < cmdline + got; s++)
+ if (*s == 0)
+ *s = ' ';
+ /* Trim the trailing spaces (typically single '\0'->' '). */
+ while (s > cmdline && isspace (s[-1]) != 0)
+ s--;
+ *s = 0;
+ return cmdline;
+}
+
+void orphanskill_pid (pid_t pid)
+{
+ const char *cmdline;
+
+ /* Should not happen. */
+ if (pid == getpid())
+ error ("We as PID %d should not be chrooted", (int) pid);
+
+ cmdline = read_cmdline (pid);
+ if (cmdline == 0)
+ cmdline = "<error>";
+ warning ("Killed -9 orphan PID %d: %s", (int) pid, cmdline);
+ if (kill (pid, SIGKILL))
+ {
+ /* It may just be a race. */
+ warning ("kill (%d, SIGKILL): %s", (int) pid, strerror (errno));
+ return;
+ }
+ /* Do not waitpid(2) as it cannot be our direct descendant and it gets
+ cleaned up by init(8). */
+}
+
+void
+do_orphanskill (int argc, char *argv[])
+{
+ DIR *dir;
+ struct dirent *dirent;
+ const char *chrootdir;
+ size_t chrootdir_len;
+ char *link_buf;
+
+ if (argc < 3)
+ error ("No directory given for chroot !");
+ //printf ("DEBUG: rootsdir: %s\n", rootsdir);
+
+ chrootdir = argv[2];
+ /* do we allow this dir ? */
+ check_dir_allowed (rootsdir, chrootdir);
+ chrootdir_len = strlen (chrootdir) + 1;
+ link_buf = malloc (chrootdir_len);
+ if (link_buf == 0)
+ error ("malloc (%lu): %s", (unsigned long) chrootdir_len,
+ strerror (errno));
+
+ dir = opendir ("/proc");
+ if (dir == 0)
+ error ("opendir (\"/proc\"): %s", strerror (errno));
+ while ((errno = 0, dirent = readdir (dir)))
+ {
+ const char *cs;
+ char proc_root[64];
+ int proc_root_got;
+ int pid;
+ ssize_t link_buf_got;
+
+ /* FIXME: POSIX portability. */
+ if (dirent->d_type != DT_DIR)
+ continue;
+ /* Check /^\d+$/: */
+ for (cs = dirent->d_name; *cs; cs++)
+ if (isdigit (*cs) == 0)
+ break;
+ if (cs == dirent->d_name || *cs != 0)
+ continue;
+ pid = atoi (dirent->d_name);
+
+ proc_root_got = snprintf (proc_root, sizeof (proc_root), "/proc/%d/root",
+ pid);
+ if (proc_root_got <= 0 || proc_root_got >= sizeof (proc_root))
+ error ("/proc/%d/root: %s", pid, strerror (errno));
+
+ link_buf_got = readlink (proc_root, link_buf, chrootdir_len);
+ /* Errors may occur due to races. */
+ if (link_buf_got != chrootdir_len - 1
+ || memcmp (link_buf, chrootdir, chrootdir_len - 1) != 0)
+ continue;
+
+ orphanskill_pid (pid);
+ }
+ if (errno != 0)
+ error ("readdir (\"/proc\"): %s", strerror (errno));
+ if (closedir (dir) != 0)
+ error ("closedir (\"/proc\"): %s", strerror (errno));
+}
+
int
main (int argc, char *argv[])
{
@@ -514,6 +651,8 @@ main (int argc, char *argv[])
do_chown(argc, argv);
else if (strncmp ("chmod", argv[1], 5) == 0)
do_chmod(argc, argv);
+ else if (strncmp ("orphanskill", argv[1], 11) == 0)
+ do_orphanskill (argc, argv);
else
{
error ("Command %s not recognized !\n", argv[1]);