/* 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;
}
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) {
}
static int write_one_file(Item *i, const char *path) {
- int flags;
- int fd = -1;
+ _cleanup_close_ int fd = -1;
+ int flags, r = 0;
struct stat st;
- int r = 0;
assert(i);
assert(path);
- flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
- i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
+ flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
+ i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
- RUN_WITH_UMASK(0) {
+ RUN_WITH_UMASK(0000) {
label_context_set(path, S_IFREG);
- fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
+ fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
label_context_clear();
}
size_t l;
unescaped = cunescape(i->argument);
- if (unescaped == NULL) {
- safe_close(fd);
+ if (!unescaped)
return log_oom();
- }
l = strlen(unescaped);
n = write(fd, unescaped, l);
if (n < 0 || (size_t) n < l) {
log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
- safe_close(fd);
return n < 0 ? n : -EIO;
}
}
- safe_close(fd);
+ fd = safe_close(fd);
if (stat(path, &st) < 0) {
log_error("stat(%s) failed: %m", path);
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: %s", 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);
RUN_WITH_UMASK(0000) {
mkdir_parents_label(i->path, 0755);
- r = mkdir(i->path, i->mode);
+ r = mkdir_label(i->path, i->mode);
}
- if (r < 0 && errno != EEXIST) {
- log_error("Failed to create directory %s: %m", i->path);
- return -errno;
- }
+ 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);
case CREATE_FIFO:
- label_context_set(i->path, S_IFIFO);
RUN_WITH_UMASK(0000) {
+ label_context_set(i->path, S_IFIFO);
r = mkfifo(i->path, i->mode);
+ label_context_clear();
}
- label_context_clear();
- if (r < 0 && errno != EEXIST) {
- log_error("Failed to create fifo %s: %m", i->path);
- return -errno;
- }
+ if (r < 0) {
+ if (errno != EEXIST) {
+ log_error("Failed to create fifo %s: %m", i->path);
+ return -errno;
+ }
- 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_ISFIFO(st.st_mode)) {
+
+ if (i->force) {
- if (!S_ISFIFO(st.st_mode)) {
- log_error("%s is not a fifo.", i->path);
- return -EEXIST;
+ RUN_WITH_UMASK(0000) {
+ label_context_set(i->path, S_IFIFO);
+ r = mkfifo_atomic(i->path, i->mode);
+ label_context_clear();
+ }
+
+ if (r < 0) {
+ log_error("Failed to create fifo %s: %s", i->path, strerror(-r));
+ return r;
+ }
+ } else {
+ log_debug("%s is not a fifo.", i->path);
+ return 0;
+ }
+ }
}
r = item_set_perms(i, i->path);
label_context_clear();
if (r < 0) {
- log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
- return -errno;
+ log_error("symlink(%s, %s) failed: %s", i->argument, i->path, strerror(-r));
+ return r;
}
- } else
+ } else {
log_debug("%s is not a symlink or does not point to the correct path.", i->path);
+ return 0;
+ }
}
}
return 0;
}
- file_type = (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
+ file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
RUN_WITH_UMASK(0000) {
label_context_set(i->path, file_type);
log_error("Failed to create device node %s: %m", i->path);
return -errno;
}
- }
- 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 ((st.st_mode & S_IFMT) != file_type) {
+
+ if (i->force) {
- if ((st.st_mode & S_IFMT) != file_type) {
- log_error("%s is not a device node.", i->path);
- return -EEXIST;
+ RUN_WITH_UMASK(0000) {
+ label_context_set(i->path, file_type);
+ r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
+ label_context_clear();
+ }
+
+ if (r < 0) {
+ log_error("Failed to create device node %s: %s", i->path, strerror(-r));
+ return r;
+ }
+ } else {
+ log_debug("%s is not a device node.", i->path);
+ return 0;
+ }
+ }
}
r = item_set_perms(i, i->path);
static int process_item(Item *i) {
int r, q, p;
- char prefix[PATH_MAX];
+ _cleanup_free_ char *prefix = NULL;
assert(i);
i->done = true;
+ prefix = malloc(strlen(i->path) + 1);
+ if (!prefix)
+ return log_oom();
+
PATH_FOREACH_PREFIX(prefix, i->path) {
Item *j;
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:
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)) {
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"
" --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[]) {
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);
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.");
candidate_item = j;
}
- if (candidate_item) {
+ if (candidate_item && candidate_item->age_set) {
i->age = candidate_item->age;
i->age_set = true;
}
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();