X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Ftmpfiles%2Ftmpfiles.c;h=f9830c431d2b905aa46fae305640930a5a93fd55;hb=e7eb49db071f9aab2a9bad0660962f2aa4d0c7d1;hp=c6c8ce8fee321ba96be65bf2d3dadce33ddd6cc3;hpb=19f3934057d20c63f4c95791312038a41b4666d0;p=elogind.git diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index c6c8ce8fe..f9830c431 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -165,7 +165,7 @@ static void load_unix_sockets(void) { /* We maintain a cache of the sockets we found in * /proc/net/unix to speed things up a little. */ - unix_sockets = set_new(string_hash_func, string_compare_func); + unix_sockets = set_new(&string_hash_ops); if (!unix_sockets) return; @@ -453,35 +453,39 @@ finish: } static int item_set_perms(Item *i, const char *path) { + struct stat st; + bool st_valid; + assert(i); assert(path); + st_valid = stat(path, &st) == 0; + /* not using i->path directly because it may be a glob */ if (i->mode_set) { mode_t m = i->mode; - if (i->mask_perms) { - struct stat st; - - if (stat(path, &st) >= 0) { - if (!(st.st_mode & 0111)) - m &= ~0111; - if (!(st.st_mode & 0222)) - m &= ~0222; - if (!(st.st_mode & 0444)) - m &= ~0444; - if (!S_ISDIR(st.st_mode)) - m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */ - } + if (i->mask_perms && st_valid) { + if (!(st.st_mode & 0111)) + m &= ~0111; + if (!(st.st_mode & 0222)) + m &= ~0222; + if (!(st.st_mode & 0444)) + m &= ~0444; + if (!S_ISDIR(st.st_mode)) + m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */ } - if (chmod(path, m) < 0) { - log_error("chmod(%s) failed: %m", path); - return -errno; + if (!st_valid || m != (st.st_mode & 07777)) { + if (chmod(path, m) < 0) { + log_error("chmod(%s) failed: %m", path); + return -errno; + } } } - if (i->uid_set || i->gid_set) + if ((!st_valid || (i->uid != st.st_uid || i->gid != st.st_gid)) && + (i->uid_set || i->gid_set)) if (chown(path, i->uid_set ? i->uid : (uid_t) -1, i->gid_set ? i->gid : (gid_t) -1) < 0) { @@ -667,10 +671,29 @@ static int create_item(Item *i) { break; case COPY_FILES: - r = copy_tree(i->argument, i->path); + r = copy_tree(i->argument, i->path, false); if (r < 0) { - log_error("Failed to copy files to %s: %s", i->path, strerror(-r)); - return r; + struct stat a, b; + + if (r != -EEXIST) { + log_error("Failed to copy files to %s: %s", i->path, strerror(-r)); + return -r; + } + + if (stat(i->argument, &a) < 0) { + log_error("stat(%s) failed: %m", i->argument); + return -errno; + } + + if (stat(i->path, &b) < 0) { + log_error("stat(%s) failed: %m", i->path); + return -errno; + } + + if ((a.st_mode ^ b.st_mode) & S_IFMT) { + log_debug("Can't copy to %s, file exists already and is of different type", i->path); + return 0; + } } r = item_set_perms(i, i->path); @@ -694,19 +717,21 @@ static int create_item(Item *i) { r = mkdir_label(i->path, i->mode); } - if (r < 0 && r != -EEXIST) { - log_error("Failed to create directory %s: %s", i->path, strerror(-r)); - return r; - } + if (r < 0) { + if (r != -EEXIST) { + log_error("Failed to create directory %s: %s", i->path, strerror(-r)); + return r; + } - if (stat(i->path, &st) < 0) { - log_error("stat(%s) failed: %m", i->path); - return -errno; - } + if (stat(i->path, &st) < 0) { + log_error("stat(%s) failed: %m", i->path); + return -errno; + } - if (!S_ISDIR(st.st_mode)) { - log_error("%s is not a directory.", i->path); - return -EEXIST; + if (!S_ISDIR(st.st_mode)) { + log_debug("%s already exists and is not a directory.", i->path); + return 0; + } } r = item_set_perms(i, i->path); @@ -1228,10 +1253,10 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { case CREATE_SYMLINK: if (!i->argument) { - log_error("[%s:%u] Symlink file requires argument.", fname, line); - return -EBADMSG; + i->argument = strappend("/usr/share/factory", i->path); + if (!i->argument) + return log_oom(); } - break; case WRITE_FILE: @@ -1243,8 +1268,9 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { case COPY_FILES: if (!i->argument) { - log_error("[%s:%u] Copy files requires argument.", fname, line); - return -EBADMSG; + i->argument = strappend("/usr/share/factory", i->path); + if (!i->argument) + return log_oom(); } if (!path_is_absolute(i->argument)) { @@ -1385,8 +1411,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { return 0; } -static int help(void) { - +static void 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" @@ -1399,8 +1424,6 @@ static int help(void) { " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n" " --root=PATH Operate on an alternate filesystem root\n", program_invocation_short_name); - - return 0; } static int parse_argv(int argc, char *argv[]) { @@ -1434,12 +1457,13 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) switch (c) { case 'h': - return help(); + help(); + return 0; case ARG_VERSION: puts(PACKAGE_STRING); @@ -1487,7 +1511,6 @@ static int parse_argv(int argc, char *argv[]) { default: assert_not_reached("Unhandled option"); } - } if (!arg_clean && !arg_create && !arg_remove) { log_error("You need to specify at least one of --clean, --create or --remove."); @@ -1585,8 +1608,8 @@ int main(int argc, char *argv[]) { label_init(NULL); - items = hashmap_new(string_hash_func, string_compare_func); - globs = hashmap_new(string_hash_func, string_compare_func); + items = hashmap_new(&string_hash_ops); + globs = hashmap_new(&string_hash_ops); if (!items || !globs) { r = log_oom();