chiark / gitweb /
clients: unify how we invoke getopt_long()
[elogind.git] / src / tmpfiles / tmpfiles.c
index fb25b77b2bd2602b73ba9b6636b1e61b88807248..b7f6a2e058bcdcf539c5aaa7e06c7cf69b60b710 100644 (file)
@@ -52,6 +52,7 @@
 #include "conf-files.h"
 #include "capability.h"
 #include "specifier.h"
+#include "build.h"
 
 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
  * them in the file system. This is intended to be used to create
@@ -69,6 +70,7 @@ typedef enum ItemType {
         CREATE_SYMLINK = 'L',
         CREATE_CHAR_DEVICE = 'c',
         CREATE_BLOCK_DEVICE = 'b',
+        ADJUST_MODE = 'm',
 
         /* These ones take globs */
         IGNORE_PATH = 'x',
@@ -257,8 +259,8 @@ static int dir_cleanup(
                 dev_t rootdev,
                 bool mountpoint,
                 int maxdepth,
-                bool keep_this_level)
-{
+                bool keep_this_level) {
+
         struct dirent *dent;
         struct timespec times[2];
         bool deleted = false;
@@ -274,12 +276,15 @@ static int dir_cleanup(
                         continue;
 
                 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
+                        if (errno == ENOENT)
+                                continue;
 
-                        if (errno != ENOENT) {
+                        /* FUSE, NFS mounts, SELinux might return EACCES */
+                        if (errno == EACCES)
+                                log_debug("stat(%s/%s) failed: %m", p, dent->d_name);
+                        else
                                 log_error("stat(%s/%s) failed: %m", p, dent->d_name);
-                                r = -errno;
-                        }
-
+                        r = -errno;
                         continue;
                 }
 
@@ -429,12 +434,16 @@ finish:
         return r;
 }
 
-static int item_set_perms(Item *i, const char *path) {
+static int item_set_perms_full(Item *i, const char *path, bool ignore_enoent) {
+        int r;
+
         /* not using i->path directly because it may be a glob */
         if (i->mode_set)
                 if (chmod(path, i->mode) < 0) {
-                        log_error("chmod(%s) failed: %m", path);
-                        return -errno;
+                        if (errno != ENOENT || !ignore_enoent) {
+                                log_error("chmod(%s) failed: %m", path);
+                                return -errno;
+                        }
                 }
 
         if (i->uid_set || i->gid_set)
@@ -442,16 +451,25 @@ static int item_set_perms(Item *i, const char *path) {
                           i->uid_set ? i->uid : (uid_t) -1,
                           i->gid_set ? i->gid : (gid_t) -1) < 0) {
 
-                        log_error("chown(%s) failed: %m", path);
-                        return -errno;
+                        if (errno != ENOENT || !ignore_enoent) {
+                                log_error("chown(%s) failed: %m", path);
+                                return -errno;
+                        }
                 }
 
-        return label_fix(path, false, false);
+        r = label_fix(path, false, false);
+        return r == -ENOENT && ignore_enoent ? 0 : r;
+}
+
+static int item_set_perms(Item *i, const char *path) {
+        return item_set_perms_full(i, path, false);
 }
 
 static int write_one_file(Item *i, const char *path) {
-        int r, e, fd, flags;
+        int e, flags;
+        int fd = -1;
         struct stat st;
+        int r = 0;
 
         flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
                 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
@@ -623,8 +641,9 @@ static int glob_item(Item *i, int (*action)(Item *, const char *)) {
 }
 
 static int create_item(Item *i) {
-        int r, e;
+        int e;
         struct stat st;
+        int r = 0;
 
         assert(i);
 
@@ -642,6 +661,7 @@ static int create_item(Item *i) {
                 if (r < 0)
                         return r;
                 break;
+
         case WRITE_FILE:
                 r = glob_item(i, write_one_file);
                 if (r < 0)
@@ -649,6 +669,13 @@ static int create_item(Item *i) {
 
                 break;
 
+        case ADJUST_MODE:
+                r = item_set_perms_full(i, i->path, true);
+                if (r < 0)
+                        return r;
+
+                break;
+
         case TRUNCATE_DIRECTORY:
         case CREATE_DIRECTORY:
 
@@ -819,6 +846,7 @@ static int remove_item_instance(Item *i, const char *instance) {
         case RELABEL_PATH:
         case RECURSIVE_RELABEL_PATH:
         case WRITE_FILE:
+        case ADJUST_MODE:
                 break;
 
         case REMOVE_PATH:
@@ -864,6 +892,7 @@ static int remove_item(Item *i) {
         case RELABEL_PATH:
         case RECURSIVE_RELABEL_PATH:
         case WRITE_FILE:
+        case ADJUST_MODE:
                 break;
 
         case REMOVE_PATH:
@@ -973,10 +1002,7 @@ static void item_free(Item *i) {
         free(i);
 }
 
-static inline void item_freep(Item **i) {
-        if (*i)
-                item_free(*i);
-}
+DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
 #define _cleanup_item_free_ _cleanup_(item_freep)
 
 static bool item_equal(Item *a, Item *b) {
@@ -1106,6 +1132,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         case RECURSIVE_REMOVE_PATH:
         case RELABEL_PATH:
         case RECURSIVE_RELABEL_PATH:
+        case ADJUST_MODE:
                 break;
 
         case CREATE_SYMLINK:
@@ -1240,6 +1267,7 @@ static int help(void) {
         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
                "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
                "  -h --help                 Show this help\n"
+               "     --version              Show package version\n"
                "     --create               Create marked files/directories\n"
                "     --clean                Clean up marked directories\n"
                "     --remove               Remove marked files/directories\n"
@@ -1253,6 +1281,7 @@ static int help(void) {
 static int parse_argv(int argc, char *argv[]) {
 
         enum {
+                ARG_VERSION = 0x100,
                 ARG_CREATE,
                 ARG_CLEAN,
                 ARG_REMOVE,
@@ -1262,12 +1291,13 @@ static int parse_argv(int argc, char *argv[]) {
 
         static const struct option options[] = {
                 { "help",           no_argument,         NULL, 'h'                },
+                { "version",        no_argument,         NULL, ARG_VERSION        },
                 { "create",         no_argument,         NULL, ARG_CREATE         },
                 { "clean",          no_argument,         NULL, ARG_CLEAN          },
                 { "remove",         no_argument,         NULL, ARG_REMOVE         },
                 { "prefix",         required_argument,   NULL, ARG_PREFIX         },
                 { "exclude-prefix", required_argument,   NULL, ARG_EXCLUDE_PREFIX },
-                { NULL,             0,                   NULL, 0                  }
+                {}
         };
 
         int c;
@@ -1280,7 +1310,11 @@ static int parse_argv(int argc, char *argv[]) {
                 switch (c) {
 
                 case 'h':
-                        help();
+                        return help();
+
+                case ARG_VERSION:
+                        puts(PACKAGE_STRING);
+                        puts(SYSTEMD_FEATURES);
                         return 0;
 
                 case ARG_CREATE:
@@ -1309,8 +1343,7 @@ static int parse_argv(int argc, char *argv[]) {
                         return -EINVAL;
 
                 default:
-                        log_error("Unknown option code %c", c);
-                        return -EINVAL;
+                        assert_not_reached("Unhandled option");
                 }
         }