return true;
}
-char *file_in_same_dir(const char *path, const char *filename) {
- char *e, *ret;
- size_t k;
+int file_in_same_dir(const char *path, const char *filename, char **ret) {
+ _cleanup_free_ char *b = NULL;
+ int r;
assert(path);
assert(filename);
+ assert(ret);
- /* This removes the last component of path and appends
- * filename, unless the latter is absolute anyway or the
- * former isn't */
+ /* This removes the last component of path and appends filename, unless the latter is absolute anyway
+ * or the former isn't */
if (path_is_absolute(filename))
- return strdup(filename);
-
- e = strrchr(path, '/');
- if (!e)
- return strdup(filename);
+ b = strdup(filename);
+ else {
+ _cleanup_free_ char *dn = NULL;
- k = strlen(filename);
- ret = new(char, (e + 1 - path) + k + 1);
- if (!ret)
- return NULL;
+ r = path_extract_directory(path, &dn);
+ if (r == -EDESTADDRREQ) /* no path prefix */
+ b = strdup(filename);
+ else if (r < 0)
+ return r;
+ else
+ b = path_join(dn, filename);
+ }
+ if (!b)
+ return -ENOMEM;
- memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1);
- return ret;
+ *ret = TAKE_PTR(b);
+ return 0;
}
bool hidden_or_backup_file(const char *filename) {
* actual image we shall boot. */
if (arg_image) {
- p = file_in_same_dir(arg_image, arg_settings_filename);
- if (!p)
- return log_oom();
- } else if (arg_directory && !path_equal(arg_directory, "/")) {
- p = file_in_same_dir(arg_directory, arg_settings_filename);
- if (!p)
- return log_oom();
+ r = file_in_same_dir(arg_image, arg_settings_filename, &p);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate settings path from image path: %m");
+ } else if (arg_directory) {
+ r = file_in_same_dir(arg_directory, arg_settings_filename, &p);
+ if (r < 0 && r != -EADDRNOTAVAIL) /* if directory is root fs, don't complain */
+ return log_error_errno(r, "Failed to generate settings path from directory path: %m");
}
if (p) {
static char **image_settings_path(Image *image) {
_cleanup_strv_free_ char **l = NULL;
- const char *fn;
- unsigned i = 0;
+ _cleanup_free_ char *fn = NULL;
+ size_t i = 0;
+ int r;
assert(image);
if (!l)
return NULL;
- fn = strjoina(image->name, ".nspawn");
+ fn = strjoin(image->name, ".nspawn");
+ if (!fn)
+ return NULL;
FOREACH_STRING(s, "/etc/systemd/nspawn", "/run/systemd/nspawn") {
l[i] = path_join(s, fn);
i++;
}
- l[i] = file_in_same_dir(image->path, fn);
- if (!l[i])
+ r = file_in_same_dir(image->path, fn, l + i);
+ if (r == -ENOMEM)
return NULL;
+ if (r < 0)
+ log_debug_errno(r, "Failed to generate .nspawn settings path from image path, ignoring: %m");
+
+ strv_uniq(l);
return TAKE_PTR(l);
}
-static char *image_roothash_path(Image *image) {
- const char *fn;
+static int image_roothash_path(Image *image, char **ret) {
+ _cleanup_free_ char *fn = NULL;
assert(image);
- fn = strjoina(image->name, ".roothash");
+ fn = strjoin(image->name, ".roothash");
+ if (!fn)
+ return -ENOMEM;
- return file_in_same_dir(image->path, fn);
+ return file_in_same_dir(image->path, fn, ret);
}
static int image_new(
if (!settings)
return -ENOMEM;
- roothash = image_roothash_path(i);
- if (!roothash)
- return -ENOMEM;
+ r = image_roothash_path(i, &roothash);
+ if (r < 0)
+ return r;
/* Make sure we don't interfere with a running nspawn */
r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
}
static int rename_auxiliary_file(const char *path, const char *new_name, const char *suffix) {
- _cleanup_free_ char *rs = NULL;
- const char *fn;
-
- fn = strjoina(new_name, suffix);
+ _cleanup_free_ char *fn = NULL, *rs = NULL;
+ int r;
- rs = file_in_same_dir(path, fn);
- if (!rs)
+ fn = strjoin(new_name, suffix);
+ if (!fn)
return -ENOMEM;
+ r = file_in_same_dir(path, fn, &rs);
+ if (r < 0)
+ return r;
+
return rename_noreplace(AT_FDCWD, path, AT_FDCWD, rs);
}
if (!settings)
return -ENOMEM;
- roothash = image_roothash_path(i);
- if (!roothash)
- return -ENOMEM;
+ r = image_roothash_path(i, &roothash);
+ if (r < 0)
+ return r;
/* Make sure we don't interfere with a running nspawn */
r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
_fallthrough_;
case IMAGE_SUBVOLUME:
- new_path = file_in_same_dir(i->path, new_name);
+ r = file_in_same_dir(i->path, new_name, &new_path);
break;
case IMAGE_BLOCK:
if (path_startswith(i->path, "/dev"))
return -EROFS;
- new_path = file_in_same_dir(i->path, new_name);
+ r = file_in_same_dir(i->path, new_name, &new_path);
break;
case IMAGE_RAW: {
const char *fn;
fn = strjoina(new_name, ".raw");
- new_path = file_in_same_dir(i->path, fn);
+
+ r = file_in_same_dir(i->path, fn, &new_path);
break;
}
default:
return -EOPNOTSUPP;
}
-
- if (!new_path)
- return -ENOMEM;
+ if (r < 0)
+ return r;
nn = strdup(new_name);
if (!nn)
}
static int clone_auxiliary_file(const char *path, const char *new_name, const char *suffix) {
- _cleanup_free_ char *rs = NULL;
- const char *fn;
-
- fn = strjoina(new_name, suffix);
+ _cleanup_free_ char *fn = NULL, *rs = NULL;
+ int r;
- rs = file_in_same_dir(path, fn);
- if (!rs)
+ fn = strjoin(new_name, suffix);
+ if (!fn)
return -ENOMEM;
+ r = file_in_same_dir(path, fn, &rs);
+ if (r < 0)
+ return r;
+
return copy_file_atomic(path, rs, 0664, 0, 0, COPY_REFLINK);
}
if (!settings)
return -ENOMEM;
- roothash = image_roothash_path(i);
- if (!roothash)
- return -ENOMEM;
+ r = image_roothash_path(i, &roothash);
+ if (r < 0)
+ return r;
/* Make sure nobody takes the new name, between the time we
* checked it is currently unused in all search paths, and the
TEST(file_in_same_dir) {
char *t;
- t = file_in_same_dir("/", "a");
- assert_se(streq(t, "/a"));
- free(t);
+ assert_se(file_in_same_dir("/", "a", &t) == -EADDRNOTAVAIL);
- t = file_in_same_dir("/", "/a");
+ assert_se(file_in_same_dir("/", "/a", &t) >= 0);
assert_se(streq(t, "/a"));
free(t);
- t = file_in_same_dir("", "a");
- assert_se(streq(t, "a"));
- free(t);
+ assert_se(file_in_same_dir("", "a", &t) == -EINVAL);
- t = file_in_same_dir("a/", "a");
- assert_se(streq(t, "a/a"));
+ assert_se(file_in_same_dir("a/", "x", &t) >= 0);
+ assert_se(streq(t, "x"));
free(t);
- t = file_in_same_dir("bar/foo", "bar");
+ assert_se(file_in_same_dir("bar/foo", "bar", &t) >= 0);
assert_se(streq(t, "bar/bar"));
free(t);
}