chiark / gitweb /
udevd: clarify worker exit status
[elogind.git] / libudev / libudev-util-private.c
index fb64c13229cfdb384c84ff8d51e4bdbd3bff2c0f..2d7f8dc758f5bd595e304db9198b2800858ad2ba 100644 (file)
 #include <ctype.h>
 #include <pwd.h>
 #include <grp.h>
-#include <sys/wait.h>
 #include <sys/param.h>
 
 #include "libudev.h"
 #include "libudev-private.h"
 
-int util_create_path(struct udev *udev, const char *path)
+static int create_path(struct udev *udev, const char *path, bool selinux)
 {
        char p[UTIL_PATH_SIZE];
        char *pos;
@@ -43,27 +42,50 @@ int util_create_path(struct udev *udev, const char *path)
        pos[0] = '\0';
 
        dbg(udev, "stat '%s'\n", p);
-       if (stat(p, &stats) == 0 && (stats.st_mode & S_IFMT) == S_IFDIR)
-               return 0;
+       if (stat(p, &stats) == 0) {
+               if ((stats.st_mode & S_IFMT) == S_IFDIR)
+                       return 0;
+               else
+                       return -ENOTDIR;
+       }
 
-       if (util_create_path(udev, p) != 0)
-               return -1;
+       err = util_create_path(udev, p);
+       if (err != 0)
+               return err;
 
        dbg(udev, "mkdir '%s'\n", p);
-       udev_selinux_setfscreatecon(udev, p, S_IFDIR|0755);
+       if (selinux)
+               udev_selinux_setfscreatecon(udev, p, S_IFDIR|0755);
        err = mkdir(p, 0755);
-       if (err != 0 && errno == EEXIST)
-               if (stat(p, &stats) == 0 && (stats.st_mode & S_IFMT) == S_IFDIR)
-                       err = 0;
-       udev_selinux_resetfscreatecon(udev);
+       if (err != 0) {
+               err = -errno;
+               if (err == -EEXIST && stat(p, &stats) == 0) {
+                       if ((stats.st_mode & S_IFMT) == S_IFDIR)
+                               err = 0;
+                       else
+                               err = -ENOTDIR;
+               }
+       }
+       if (selinux)
+               udev_selinux_resetfscreatecon(udev);
        return err;
 }
 
+int util_create_path(struct udev *udev, const char *path)
+{
+       return create_path(udev, path, false);
+}
+
+int util_create_path_selinux(struct udev *udev, const char *path)
+{
+       return create_path(udev, path, true);
+}
+
 int util_delete_path(struct udev *udev, const char *path)
 {
        char p[UTIL_PATH_SIZE];
        char *pos;
-       int retval;
+       int err = 0;
 
        if (path[0] == '/')
                while(path[1] == '/')
@@ -73,7 +95,7 @@ int util_delete_path(struct udev *udev, const char *path)
        if (pos == p || pos == NULL)
                return 0;
 
-       while (1) {
+       for (;;) {
                *pos = '\0';
                pos = strrchr(p, '/');
 
@@ -81,19 +103,14 @@ int util_delete_path(struct udev *udev, const char *path)
                if ((pos == p) || (pos == NULL))
                        break;
 
-               /* remove if empty */
-               retval = rmdir(p);
-               if (errno == ENOENT)
-                       retval = 0;
-               if (retval) {
-                       if (errno == ENOTEMPTY)
-                               return 0;
-                       err(udev, "rmdir(%s) failed: %m\n", p);
+               err = rmdir(p);
+               if (err < 0) {
+                       if (errno == ENOENT)
+                               err = 0;
                        break;
                }
-               dbg(udev, "removed '%s'\n", p);
        }
-       return 0;
+       return err;
 }
 
 /* Reset permissions on the device node, before unlinking it to make sure,
@@ -103,8 +120,8 @@ int util_unlink_secure(struct udev *udev, const char *filename)
 {
        int err;
 
-       chmod(filename, 0000);
        chown(filename, 0, 0);
+       chmod(filename, 0000);
        err = unlink(filename);
        if (errno == ENOENT)
                err = 0;
@@ -116,7 +133,7 @@ int util_unlink_secure(struct udev *udev, const char *filename)
 uid_t util_lookup_user(struct udev *udev, const char *user)
 {
        char *endptr;
-       int buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
+       size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
        char buf[buflen];
        struct passwd pwbuf;
        struct passwd *pw;
@@ -141,7 +158,7 @@ uid_t util_lookup_user(struct udev *udev, const char *user)
 gid_t util_lookup_group(struct udev *udev, const char *group)
 {
        char *endptr;
-       int buflen = sysconf(_SC_GETGR_R_SIZE_MAX);
+       size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX);
        char *buf;
        struct group grbuf;
        struct group *gr;
@@ -240,224 +257,3 @@ int util_resolve_subsys_kernel(struct udev *udev, const char *string,
        udev_device_unref(dev);
        return 0;
 }
-
-int util_run_program(struct udev *udev, const char *command, char **envp,
-                    char *result, size_t ressize, size_t *reslen,
-                    const sigset_t *sigmask)
-{
-       int status;
-       int outpipe[2] = {-1, -1};
-       int errpipe[2] = {-1, -1};
-       pid_t pid;
-       char arg[UTIL_PATH_SIZE];
-       char program[UTIL_PATH_SIZE];
-       char *argv[(sizeof(arg) / 2) + 1];
-       int devnull;
-       int i;
-       int err = 0;
-
-       info(udev, "'%s' started\n", command);
-
-       /* build argv from command */
-       util_strscpy(arg, sizeof(arg), command);
-       i = 0;
-       if (strchr(arg, ' ') != NULL) {
-               char *pos = arg;
-
-               while (pos != NULL && pos[0] != '\0') {
-                       if (pos[0] == '\'') {
-                               /* do not separate quotes */
-                               pos++;
-                               argv[i] = strsep(&pos, "\'");
-                               if (pos != NULL)
-                                       while (pos[0] == ' ')
-                                               pos++;
-                       } else {
-                               argv[i] = strsep(&pos, " ");
-                               if (pos != NULL)
-                                       while (pos[0] == ' ')
-                                               pos++;
-                       }
-                       dbg(udev, "arg[%i] '%s'\n", i, argv[i]);
-                       i++;
-               }
-               argv[i] = NULL;
-       } else {
-               argv[0] = arg;
-               argv[1] = NULL;
-       }
-
-       /* prepare pipes from child to parent */
-       if (result != NULL || udev_get_log_priority(udev) >= LOG_INFO) {
-               if (pipe(outpipe) != 0) {
-                       err(udev, "pipe failed: %m\n");
-                       return -1;
-               }
-       }
-       if (udev_get_log_priority(udev) >= LOG_INFO) {
-               if (pipe(errpipe) != 0) {
-                       err(udev, "pipe failed: %m\n");
-                       return -1;
-               }
-       }
-
-       /* allow programs in /lib/udev/ to be called without the path */
-       if (argv[0][0] != '/') {
-               util_strscpyl(program, sizeof(program), LIBEXECDIR "/", argv[0], NULL);
-               argv[0] = program;
-       }
-
-       pid = fork();
-       switch(pid) {
-       case 0:
-               /* child closes parent ends of pipes */
-               if (outpipe[READ_END] > 0)
-                       close(outpipe[READ_END]);
-               if (errpipe[READ_END] > 0)
-                       close(errpipe[READ_END]);
-
-               /* discard child output or connect to pipe */
-               devnull = open("/dev/null", O_RDWR);
-               if (devnull > 0) {
-                       dup2(devnull, STDIN_FILENO);
-                       if (outpipe[WRITE_END] < 0)
-                               dup2(devnull, STDOUT_FILENO);
-                       if (errpipe[WRITE_END] < 0)
-                               dup2(devnull, STDERR_FILENO);
-                       close(devnull);
-               } else
-                       err(udev, "open /dev/null failed: %m\n");
-               if (outpipe[WRITE_END] > 0) {
-                       dup2(outpipe[WRITE_END], STDOUT_FILENO);
-                       close(outpipe[WRITE_END]);
-               }
-               if (errpipe[WRITE_END] > 0) {
-                       dup2(errpipe[WRITE_END], STDERR_FILENO);
-                       close(errpipe[WRITE_END]);
-               }
-
-               if (sigmask)
-                       sigprocmask(SIG_BLOCK, sigmask, NULL);
-
-               execve(argv[0], argv, envp);
-               if (errno == ENOENT || errno == ENOTDIR) {
-                       /* may be on a filesystem which is not mounted right now */
-                       info(udev, "program '%s' not found\n", argv[0]);
-               } else {
-                       /* other problems */
-                       err(udev, "exec of program '%s' failed\n", argv[0]);
-               }
-               _exit(1);
-       case -1:
-               err(udev, "fork of '%s' failed: %m\n", argv[0]);
-               return -1;
-       default:
-               /* read from child if requested */
-               if (outpipe[READ_END] > 0 || errpipe[READ_END] > 0) {
-                       ssize_t count;
-                       size_t respos = 0;
-
-                       /* parent closes child ends of pipes */
-                       if (outpipe[WRITE_END] > 0)
-                               close(outpipe[WRITE_END]);
-                       if (errpipe[WRITE_END] > 0)
-                               close(errpipe[WRITE_END]);
-
-                       /* read child output */
-                       while (outpipe[READ_END] > 0 || errpipe[READ_END] > 0) {
-                               int fdcount;
-                               fd_set readfds;
-
-                               FD_ZERO(&readfds);
-                               if (outpipe[READ_END] > 0)
-                                       FD_SET(outpipe[READ_END], &readfds);
-                               if (errpipe[READ_END] > 0)
-                                       FD_SET(errpipe[READ_END], &readfds);
-                               fdcount = select(MAX(outpipe[READ_END], errpipe[READ_END])+1, &readfds, NULL, NULL, NULL);
-                               if (fdcount < 0) {
-                                       if (errno == EINTR)
-                                               continue;
-                                       err = -1;
-                                       break;
-                               }
-
-                               /* get stdout */
-                               if (outpipe[READ_END] > 0 && FD_ISSET(outpipe[READ_END], &readfds)) {
-                                       char inbuf[1024];
-                                       char *pos;
-                                       char *line;
-
-                                       count = read(outpipe[READ_END], inbuf, sizeof(inbuf)-1);
-                                       if (count <= 0) {
-                                               close(outpipe[READ_END]);
-                                               outpipe[READ_END] = -1;
-                                               if (count < 0) {
-                                                       err(udev, "stdin read failed: %m\n");
-                                                       err = -1;
-                                               }
-                                               continue;
-                                       }
-                                       inbuf[count] = '\0';
-
-                                       /* store result for rule processing */
-                                       if (result) {
-                                               if (respos + count < ressize) {
-                                                       memcpy(&result[respos], inbuf, count);
-                                                       respos += count;
-                                               } else {
-                                                       err(udev, "ressize %ld too short\n", (long)ressize);
-                                                       err = -1;
-                                               }
-                                       }
-                                       pos = inbuf;
-                                       while ((line = strsep(&pos, "\n")))
-                                               if (pos || line[0] != '\0')
-                                                       info(udev, "'%s' (stdout) '%s'\n", argv[0], line);
-                               }
-
-                               /* get stderr */
-                               if (errpipe[READ_END] > 0 && FD_ISSET(errpipe[READ_END], &readfds)) {
-                                       char errbuf[1024];
-                                       char *pos;
-                                       char *line;
-
-                                       count = read(errpipe[READ_END], errbuf, sizeof(errbuf)-1);
-                                       if (count <= 0) {
-                                               close(errpipe[READ_END]);
-                                               errpipe[READ_END] = -1;
-                                               if (count < 0)
-                                                       err(udev, "stderr read failed: %m\n");
-                                               continue;
-                                       }
-                                       errbuf[count] = '\0';
-                                       pos = errbuf;
-                                       while ((line = strsep(&pos, "\n")))
-                                               if (pos || line[0] != '\0')
-                                                       info(udev, "'%s' (stderr) '%s'\n", argv[0], line);
-                               }
-                       }
-                       if (outpipe[READ_END] > 0)
-                               close(outpipe[READ_END]);
-                       if (errpipe[READ_END] > 0)
-                               close(errpipe[READ_END]);
-
-                       /* return the childs stdout string */
-                       if (result) {
-                               result[respos] = '\0';
-                               dbg(udev, "result='%s'\n", result);
-                               if (reslen)
-                                       *reslen = respos;
-                       }
-               }
-               waitpid(pid, &status, 0);
-               if (WIFEXITED(status)) {
-                       info(udev, "'%s' returned with exitcode %i\n", command, WEXITSTATUS(status));
-                       if (WEXITSTATUS(status) != 0)
-                               err = -1;
-               } else {
-                       err(udev, "'%s' unexpected exit with status 0x%04x\n", command, status);
-                       err = -1;
-               }
-       }
-       return err;
-}