bool gid_set:1;
bool mode_set:1;
bool age_set:1;
+ bool mask_perms:1;
bool keep_first_level:1;
+ bool force:1;
+
bool done:1;
} Item;
return r;
}
-static int item_set_perms_full(Item *i, const char *path, bool ignore_enoent) {
+static int item_set_perms(Item *i, const char *path) {
assert(i);
assert(path);
/* not using i->path directly because it may be a glob */
- if (i->mode_set)
- if (chmod(path, i->mode) < 0) {
- if (errno != ENOENT || !ignore_enoent) {
- log_error("chmod(%s) failed: %m", path);
- return -errno;
+ 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 (chmod(path, m) < 0) {
+ log_error("chmod(%s) failed: %m", path);
+ return -errno;
+ }
+ }
+
if (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) {
- if (errno != ENOENT || !ignore_enoent) {
- log_error("chown(%s) failed: %m", path);
- return -errno;
- }
+ log_error("chown(%s) failed: %m", path);
+ return -errno;
}
- return label_fix(path, ignore_enoent, false);
-}
-
-static int item_set_perms(Item *i, const char *path) {
- return item_set_perms_full(i, path, false);
+ return label_fix(path, false, false);
}
static int write_one_file(Item *i, const char *path) {
case CREATE_FIFO:
+ label_context_set(i->path, S_IFIFO);
RUN_WITH_UMASK(0000) {
r = mkfifo(i->path, i->mode);
}
+ label_context_clear();
if (r < 0 && errno != EEXIST) {
log_error("Failed to create fifo %s: %m", i->path);
break;
- case CREATE_SYMLINK: {
- _cleanup_free_ char *x = NULL;
+ case CREATE_SYMLINK:
label_context_set(i->path, S_IFLNK);
r = symlink(i->argument, i->path);
label_context_clear();
- if (r < 0 && errno != EEXIST) {
- log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
- return -errno;
- }
-
- r = readlink_malloc(i->path, &x);
if (r < 0) {
- log_error("readlink(%s) failed: %s", i->path, strerror(-r));
- return -errno;
- }
+ _cleanup_free_ char *x = NULL;
- if (!streq(i->argument, x)) {
- log_error("%s is not the right symlink.", i->path);
- return -EEXIST;
+ if (errno != EEXIST) {
+ log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
+ return -errno;
+ }
+
+ r = readlink_malloc(i->path, &x);
+ if (r < 0 || !streq(i->argument, x)) {
+
+ if (i->force) {
+ label_context_set(i->path, S_IFLNK);
+ r = symlink_atomic(i->argument, i->path);
+ label_context_clear();
+
+ if (r < 0) {
+ log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
+ return -errno;
+ }
+ } else
+ log_debug("%s is not a symlink or does not point to the correct path.", i->path);
+ }
}
break;
- }
case CREATE_BLOCK_DEVICE:
case CREATE_CHAR_DEVICE: {
label_context_clear();
}
- if (r < 0 && errno != EEXIST) {
- log_error("Failed to create device node %s: %m", i->path);
- return -errno;
+ if (r < 0) {
+ if (errno == EPERM) {
+ log_debug("We lack permissions, possibly because of cgroup configuration; "
+ "skipping creation of device node %s.", i->path);
+ return 0;
+ }
+
+ if (errno != EEXIST) {
+ log_error("Failed to create device node %s: %m", i->path);
+ return -errno;
+ }
}
if (stat(i->path, &st) < 0) {
}
static void item_free(Item *i) {
- assert(i);
+
+ if (!i)
+ return;
free(i->path);
free(i->argument);
static bool should_include_path(const char *path) {
char **prefix;
- STRV_FOREACH(prefix, arg_exclude_prefixes) {
+ STRV_FOREACH(prefix, arg_exclude_prefixes)
if (path_startswith(path, *prefix))
return false;
- }
- STRV_FOREACH(prefix, arg_include_prefixes) {
+ STRV_FOREACH(prefix, arg_include_prefixes)
if (path_startswith(path, *prefix))
return true;
- }
/* no matches, so we should include this path only if we
* have no whitelist at all */
return -EIO;
}
- if (strlen(action) > 2 || (strlen(action) > 1 && action[1] != '!')) {
- log_error("[%s:%u] Unknown modifier '%s'", fname, line, action);
+ if (isempty(action)) {
+ log_error("[%s:%u] Command too short '%s'.", fname, line, action);
return -EINVAL;
- } else if (strlen(action) > 1 && !arg_boot)
+ }
+
+ if (strlen(action) > 1 && !in_charset(action+1, "!+")) {
+ log_error("[%s:%u] Unknown modifiers in command '%s'", fname, line, action);
+ return -EINVAL;
+ }
+
+ if (strchr(action+1, '!') && !arg_boot)
return 0;
type = action[0];
if (!i)
return log_oom();
+ i->force = !!strchr(action+1, '+');
+
r = specifier_printf(path, specifier_table, NULL, &i->path);
if (r < 0) {
log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
}
}
- switch(type) {
+ switch (type) {
case CREATE_FILE:
case TRUNCATE_FILE:
}
default:
- log_error("[%s:%u] Unknown file type '%c'.", fname, line, type);
+ log_error("[%s:%u] Unknown command type '%c'.", fname, line, type);
return -EBADMSG;
}
}
if (mode && !streq(mode, "-")) {
+ const char *mm = mode;
unsigned m;
- if (sscanf(mode, "%o", &m) != 1) {
+ if (*mm == '~') {
+ i->mask_perms = true;
+ mm++;
+ }
+
+ if (sscanf(mm, "%o", &m) != 1) {
log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
return -ENOENT;
}
break;
case ARG_ROOT:
+ free(arg_root);
arg_root = path_make_absolute_cwd(optarg);
if (!arg_root)
return log_oom();
+
path_kill_slashes(arg_root);
break;
r = parse_argv(argc, argv);
if (r <= 0)
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+ goto finish;
log_set_target(LOG_TARGET_AUTO);
log_parse_environment();