[systemd-commits] 19 commits - TODO src/import src/login src/machine src/shared src/test
Lennart Poettering
lennart at kemper.freedesktop.org
Fri Dec 26 11:13:10 PST 2014
TODO | 4
src/import/import-dkr.c | 43 +++++--
src/import/import-dkr.h | 2
src/import/import-gpt.c | 278 ++++++++++++++++++++++++++++++++++++++++-------
src/import/import-gpt.h | 2
src/import/import.c | 86 ++++++++------
src/login/loginctl.c | 32 ++---
src/machine/image.c | 109 +++++++++++++-----
src/machine/machinectl.c | 192 ++++++++++++++++++++++++++++++--
src/shared/copy.c | 103 +++++++++++++++++
src/shared/copy.h | 2
src/shared/util.c | 2
src/test/test-btrfs.c | 14 +-
13 files changed, 716 insertions(+), 153 deletions(-)
New commits:
commit 01c51934cbca705d854c3986870ca424df0cae46
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Dec 26 20:10:01 2014 +0100
loginctl: reindent --help text
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index 8e5239c..cc27544 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -1040,18 +1040,18 @@ static int terminate_seat(sd_bus *bus, char **args, unsigned n) {
static void help(void) {
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
"Send control commands to or query the login manager.\n\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
- " --no-pager Do not pipe output into a pager\n"
- " --no-legend Do not show the headers and footers\n"
- " --no-ask-password Don't prompt for password\n"
- " -H --host=[USER@]HOST Operate on remote host\n"
- " -M --machine=CONTAINER Operate on local container\n"
- " -p --property=NAME Show only properties by this name\n"
- " -a --all Show all properties, including empty ones\n"
- " -l --full Do not ellipsize output\n"
- " --kill-who=WHO Who to send signal to\n"
- " -s --signal=SIGNAL Which signal to send\n\n"
+ " -h --help Show this help\n"
+ " --version Show package version\n"
+ " --no-pager Do not pipe output into a pager\n"
+ " --no-legend Do not show the headers and footers\n"
+ " --no-ask-password Don't prompt for password\n"
+ " -H --host=[USER@]HOST Operate on remote host\n"
+ " -M --machine=CONTAINER Operate on local container\n"
+ " -p --property=NAME Show only properties by this name\n"
+ " -a --all Show all properties, including empty ones\n"
+ " -l --full Do not ellipsize output\n"
+ " --kill-who=WHO Who to send signal to\n"
+ " -s --signal=SIGNAL Which signal to send\n\n"
"Session Commands:\n"
" list-sessions List sessions\n"
" session-status ID... Show session status\n"
commit 2520f939bae6c26425d6737fd2e285c28b9f49c8
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Dec 26 20:09:21 2014 +0100
loginctl: add more --help sections
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index 03abb75..8e5239c 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -1052,7 +1052,7 @@ static void help(void) {
" -l --full Do not ellipsize output\n"
" --kill-who=WHO Who to send signal to\n"
" -s --signal=SIGNAL Which signal to send\n\n"
- "Commands:\n"
+ "Session Commands:\n"
" list-sessions List sessions\n"
" session-status ID... Show session status\n"
" show-session [ID...] Show properties of sessions or the manager\n"
@@ -1062,14 +1062,16 @@ static void help(void) {
" lock-sessions Screen lock all current sessions\n"
" unlock-sessions Screen unlock all current sessions\n"
" terminate-session ID... Terminate one or more sessions\n"
- " kill-session ID... Send signal to processes of a session\n"
+ " kill-session ID... Send signal to processes of a session\n\n"
+ "User Commands:\n"
" list-users List users\n"
" user-status USER... Show user status\n"
" show-user [USER...] Show properties of users or the manager\n"
" enable-linger USER... Enable linger state of one or more users\n"
" disable-linger USER... Disable linger state of one or more users\n"
" terminate-user USER... Terminate all sessions of one or more users\n"
- " kill-user USER... Send signal to processes of a user\n"
+ " kill-user USER... Send signal to processes of a user\n\n"
+ "Seat Commands:\n"
" list-seats List seats\n"
" seat-status NAME... Show seat status\n"
" show-seat NAME... Show properties of one or more seats\n"
commit fefdc04b38725457a91651218feb7000f6ccc1f4
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Dec 26 20:09:04 2014 +0100
machinectl: add status commands
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index 04e6cb9..0f69734 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -525,7 +525,7 @@ static int map_netif(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_
return 0;
}
-static int show_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
+static int show_machine_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
static const struct bus_properties_map map[] = {
{ "Name", "s", NULL, offsetof(MachineStatusInfo, name) },
@@ -572,7 +572,7 @@ static int show_info(const char *verb, sd_bus *bus, const char *path, bool *new_
return r;
}
-static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
+static int show_machine_properties(sd_bus *bus, const char *path, bool *new_line) {
int r;
assert(bus);
@@ -591,7 +591,7 @@ static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
return r;
}
-static int show(int argc, char *argv[], void *userdata) {
+static int show_machine(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
@@ -609,7 +609,7 @@ static int show(int argc, char *argv[], void *userdata) {
/* If no argument is specified, inspect the manager
* itself */
- r = show_properties(bus, "/org/freedesktop/machine1", &new_line);
+ r = show_machine_properties(bus, "/org/freedesktop/machine1", &new_line);
if (r < 0)
return r;
}
@@ -636,9 +636,169 @@ static int show(int argc, char *argv[], void *userdata) {
return bus_log_parse_error(r);
if (properties)
- r = show_properties(bus, path, &new_line);
+ r = show_machine_properties(bus, path, &new_line);
else
- r = show_info(argv[0], bus, path, &new_line);
+ r = show_machine_info(argv[0], bus, path, &new_line);
+ }
+
+ return r;
+}
+
+typedef struct ImageStatusInfo {
+ char *name;
+ char *path;
+ char *type;
+ int read_only;
+ usec_t crtime;
+ usec_t mtime;
+} ImageStatusInfo;
+
+static void print_image_status_info(sd_bus *bus, ImageStatusInfo *i) {
+ char ts_relative[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
+ char ts_absolute[FORMAT_TIMESTAMP_MAX], *s2;
+
+ assert(bus);
+ assert(i);
+
+ if (i->name) {
+ fputs(i->name, stdout);
+ putchar('\n');
+ }
+
+ if (i->path)
+ printf("\t Type: %s\n", i->type);
+
+ if (i->path)
+ printf("\t Path: %s\n", i->path);
+
+ printf("\t RO: %s%s%s\n",
+ i->read_only ? ansi_highlight_red() : "",
+ i->read_only ? "read-only" : "writable",
+ i->read_only ? ansi_highlight_off() : "");
+
+ s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->crtime);
+ s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->crtime);
+ if (s1)
+ printf("\t Created: %s; %s\n", s2, s1);
+ else if (s2)
+ printf("\t Created: %s\n", s2);
+
+ s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->mtime);
+ s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->mtime);
+ if (s1)
+ printf("\tModified: %s; %s\n", s2, s1);
+ else if (s2)
+ printf("\tModified: %s\n", s2);
+}
+
+static int show_image_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
+
+ static const struct bus_properties_map map[] = {
+ { "Name", "s", NULL, offsetof(ImageStatusInfo, name) },
+ { "Path", "s", NULL, offsetof(ImageStatusInfo, path) },
+ { "Type", "s", NULL, offsetof(ImageStatusInfo, type) },
+ { "ReadOnly", "b", NULL, offsetof(ImageStatusInfo, read_only) },
+ { "CreationTimestamp", "t", NULL, offsetof(ImageStatusInfo, crtime) },
+ { "ModificationTimestamp", "t", NULL, offsetof(ImageStatusInfo, mtime) },
+ {}
+ };
+
+ ImageStatusInfo info = {};
+ int r;
+
+ assert(verb);
+ assert(bus);
+ assert(path);
+ assert(new_line);
+
+ r = bus_map_all_properties(bus,
+ "org.freedesktop.machine1",
+ path,
+ map,
+ &info);
+ if (r < 0)
+ return log_error_errno(r, "Could not get properties: %m");
+
+ if (*new_line)
+ printf("\n");
+ *new_line = true;
+
+ print_image_status_info(bus, &info);
+
+ free(info.name);
+ free(info.path);
+ free(info.type);
+
+ return r;
+}
+
+static int show_image_properties(sd_bus *bus, const char *path, bool *new_line) {
+ int r;
+
+ assert(bus);
+ assert(path);
+ assert(new_line);
+
+ if (*new_line)
+ printf("\n");
+
+ *new_line = true;
+
+ r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
+ if (r < 0)
+ log_error_errno(r, "Could not get properties: %m");
+
+ return r;
+}
+
+static int show_image(int argc, char *argv[], void *userdata) {
+
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ bool properties, new_line = false;
+ sd_bus *bus = userdata;
+ int r = 0, i;
+
+ assert(bus);
+
+ properties = !strstr(argv[0], "status");
+
+ pager_open_if_enabled();
+
+ if (properties && argc <= 1) {
+
+ /* If no argument is specified, inspect the manager
+ * itself */
+ r = show_image_properties(bus, "/org/freedesktop/machine1", &new_line);
+ if (r < 0)
+ return r;
+ }
+
+ for (i = 1; i < argc; i++) {
+ const char *path = NULL;
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ "GetImage",
+ &error,
+ &reply,
+ "s", argv[i]);
+ if (r < 0) {
+ log_error("Could not get path to image: %s", bus_error_message(&error, -r));
+ return r;
+ }
+
+ r = sd_bus_message_read(reply, "o", &path);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ if (properties)
+ r = show_image_properties(bus, path, &new_line);
+ else
+ r = show_image_info(argv[0], bus, path, &new_line);
}
return r;
@@ -1143,7 +1303,7 @@ static int help(int argc, char *argv[], void *userdata) {
" --mkdir Create directory before bind mounting, if missing\n\n"
"Machine Commands:\n"
" list List running VMs and containers\n"
- " status NAME... Show VM/container status\n"
+ " status NAME... Show VM/container details\n"
" show NAME... Show properties of one or more VMs/containers\n"
" login NAME Get a login prompt on a container\n"
" poweroff NAME... Power off one or more containers\n"
@@ -1153,8 +1313,10 @@ static int help(int argc, char *argv[], void *userdata) {
" bind NAME PATH [PATH] Bind mount a path from the host into a container\n"
" copy-to NAME PATH [PATH] Copy files from the host to a container\n"
" copy-from NAME PATH [PATH] Copy files from a container to the host\n\n"
- "Image commands:\n"
- " list-images Show available images\n",
+ "Image Commands:\n"
+ " list-images Show available images\n"
+ " image-status NAME... Show image details\n"
+ " show-image NAME... Show properties of image\n",
program_invocation_short_name);
return 0;
@@ -1278,8 +1440,10 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
{ "help", VERB_ANY, VERB_ANY, 0, help },
{ "list", VERB_ANY, 1, VERB_DEFAULT, list_machines },
{ "list-images", VERB_ANY, 1, 0, list_images },
- { "status", 2, VERB_ANY, 0, show },
- { "show", VERB_ANY, VERB_ANY, 0, show },
+ { "status", 2, VERB_ANY, 0, show_machine },
+ { "image-status",2, VERB_ANY, 0, show_image },
+ { "show", VERB_ANY, VERB_ANY, 0, show_machine },
+ { "show-image", VERB_ANY, VERB_ANY, 0, show_image },
{ "terminate", 2, VERB_ANY, 0, terminate_machine },
{ "reboot", 2, VERB_ANY, 0, reboot_machine },
{ "poweroff", 2, VERB_ANY, 0, poweroff_machine },
commit 27c88c4e23f1f062ae69d54485033f88a7d7fbb3
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Dec 26 20:05:11 2014 +0100
machined: fix search patch magic for '.host' image
diff --git a/src/machine/image.c b/src/machine/image.c
index 8a119e5..46a216b 100644
--- a/src/machine/image.c
+++ b/src/machine/image.c
@@ -243,7 +243,7 @@ int image_find(const char *name, Image **ret) {
}
if (streq(name, ".host"))
- return image_make(NULL, AT_FDCWD, NULL, "/", ret);
+ return image_make(".host", AT_FDCWD, NULL, "/", ret);
return 0;
};
commit 08ff5529dfd4fd2588d6fc9e194cc732795a85e6
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Dec 26 19:36:25 2014 +0100
machined: make image read-only check indepenednt on own privs
diff --git a/src/machine/image.c b/src/machine/image.c
index 1574adf..8a119e5 100644
--- a/src/machine/image.c
+++ b/src/machine/image.c
@@ -112,7 +112,7 @@ static int image_make(
read_only =
(path && path_startswith(path, "/usr")) ||
- faccessat(dfd, filename, W_OK, AT_EACCESS) < 0;
+ (faccessat(dfd, filename, W_OK, AT_EACCESS) < 0 && errno == EROFS);
if (S_ISDIR(st.st_mode)) {
commit 8937e7b68940d0fa0d0aab90eb7425fa7dccebc9
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Dec 26 19:32:55 2014 +0100
machinectl: mark read-only images when listing in red
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index 64caf7c..04e6cb9 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -231,10 +231,10 @@ static int list_images(int argc, char *argv[], void *userdata) {
for (j = 0; j < n_images; j++) {
char crtime_buf[FORMAT_TIMESTAMP_MAX], mtime_buf[FORMAT_TIMESTAMP_MAX];
- printf("%-*s %-*s %-3s %-*s %-*s\n",
+ printf("%-*s %-*s %s%-3s%s %-*s %-*s\n",
(int) max_name, images[j].name,
(int) max_type, images[j].type,
- yes_no(images[j].read_only),
+ images[j].read_only ? ansi_highlight_red() : "", yes_no(images[j].read_only), images[j].read_only ? ansi_highlight_off() : "",
(int) max_crtime, images[j].crtime != 0 ? format_timestamp(crtime_buf, sizeof(crtime_buf), images[j].crtime) : "-",
(int) max_mtime, images[j].mtime != 0 ? format_timestamp(mtime_buf, sizeof(mtime_buf), images[j].mtime) : "-");
}
commit 679829e4aa1461a2db7537aae4c68c6780362c06
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Dec 26 17:11:03 2014 +0100
update TODO
diff --git a/TODO b/TODO
index d5b7ff2..ea9933d 100644
--- a/TODO
+++ b/TODO
@@ -31,7 +31,7 @@ External:
Features:
-* teach fd_get_crtime_at() the btrfs crtime
+* change default container location from /var/lib/container to /var/lib/machines
* import pull-gpt: create writable snapshot of downloaded image, by the right name
@@ -51,6 +51,8 @@ Features:
* "machinectl diff"
+* "machinectl read-only"
+
* show btrfs quota in machinectl
* "machinectl commit" that takes a writable snapshot of a tree, invokes a shell in it, and marks it read-only after use
commit 087682d103e08670963686d9b1bc1d35c412a63f
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Dec 26 19:21:09 2014 +0100
import: make image root directory configurable, instead of hardcoding /var/lib/container
diff --git a/src/import/import-dkr.c b/src/import/import-dkr.c
index fbd6412..a3f390c 100644
--- a/src/import/import-dkr.c
+++ b/src/import/import-dkr.c
@@ -94,6 +94,7 @@ struct DkrImport {
CurlGlue *glue;
char *index_url;
+ char *image_root;
Hashmap *names;
Hashmap *jobs;
@@ -406,8 +407,8 @@ static void dkr_import_name_maybe_finish(DkrImportName *name) {
assert(name->id);
- p = strappenda("/var/lib/container/", name->local);
- q = strappenda("/var/lib/container/.dkr-", name->id);
+ p = strappenda(name->import->image_root, "/", name->local);
+ q = strappenda(name->import->image_root, "/.dkr-", name->id);
if (name->force_local) {
(void) btrfs_subvol_remove(p);
@@ -534,7 +535,7 @@ static int dkr_import_name_pull_layer(DkrImportName *name) {
return 0;
}
- path = strjoin("/var/lib/container/.dkr-", layer, NULL);
+ path = strjoin(name->import->image_root, "/.dkr-", layer, NULL);
if (!path)
return log_oom();
@@ -575,7 +576,7 @@ static int dkr_import_name_pull_layer(DkrImportName *name) {
if (base) {
const char *base_path;
- base_path = strappend("/var/lib/container/.dkr-", base);
+ base_path = strappenda(name->import->image_root, "/.dkr-", base);
r = btrfs_subvol_snapshot(base_path, temp, false, true);
} else
r = btrfs_subvol_make(temp);
@@ -1021,13 +1022,21 @@ static int dkr_import_name_begin(DkrImportName *name) {
return dkr_import_name_add_job(name, DKR_IMPORT_JOB_IMAGES, url, &name->job_images);
}
-int dkr_import_new(DkrImport **import, sd_event *event, const char *index_url, dkr_import_on_finished on_finished, void *userdata) {
+int dkr_import_new(
+ DkrImport **import,
+ sd_event *event,
+ const char *index_url,
+ const char *image_root,
+ dkr_import_on_finished on_finished,
+ void *userdata) {
+
_cleanup_(dkr_import_unrefp) DkrImport *i = NULL;
char *e;
int r;
assert(import);
assert(dkr_url_is_valid(index_url));
+ assert(image_root);
i = new0(DkrImport, 1);
if (!i)
@@ -1040,6 +1049,10 @@ int dkr_import_new(DkrImport **import, sd_event *event, const char *index_url, d
if (!i->index_url)
return -ENOMEM;
+ i->image_root = strdup(image_root);
+ if (!i->image_root)
+ return -ENOMEM;
+
e = endswith(i->index_url, "/");
if (e)
*e = 0;
@@ -1084,7 +1097,7 @@ DkrImport* dkr_import_unref(DkrImport *import) {
sd_event_unref(import->event);
free(import->index_url);
-
+ free(import->image_root);
free(import);
return NULL;
diff --git a/src/import/import-dkr.h b/src/import/import-dkr.h
index 8e6a462..5f88876 100644
--- a/src/import/import-dkr.h
+++ b/src/import/import-dkr.h
@@ -26,7 +26,7 @@ typedef struct DkrImport DkrImport;
typedef void (*dkr_import_on_finished)(DkrImport *import, int error, void *userdata);
-int dkr_import_new(DkrImport **import, sd_event *event, const char *index_url, dkr_import_on_finished on_finished, void *userdata);
+int dkr_import_new(DkrImport **import, sd_event *event, const char *index_url, const char *image_root, dkr_import_on_finished on_finished, void *userdata);
DkrImport* dkr_import_unref(DkrImport *import);
DEFINE_TRIVIAL_CLEANUP_FUNC(DkrImport*, dkr_import_unref);
diff --git a/src/import/import-gpt.c b/src/import/import-gpt.c
index e1c493b..a85ceee 100644
--- a/src/import/import-gpt.c
+++ b/src/import/import-gpt.c
@@ -60,6 +60,7 @@ struct GptImport {
sd_event *event;
CurlGlue *glue;
+ char *image_root;
Hashmap *files;
gpt_import_on_finished on_finished;
@@ -129,9 +130,9 @@ static int gpt_import_file_make_final_path(GptImportFile *f) {
if (!escaped_etag)
return -ENOMEM;
- f->final_path = strjoin("/var/lib/container/.gpt-", escaped_url, ".", escaped_etag, ".gpt", NULL);
+ f->final_path = strjoin(f->import->image_root, "/.gpt-", escaped_url, ".", escaped_etag, ".gpt", NULL);
} else
- f->final_path = strjoin("/var/lib/container/.gpt-", escaped_url, ".gpt", NULL);
+ f->final_path = strjoin(f->import->image_root, "/.gpt-", escaped_url, ".gpt", NULL);
if (!f->final_path)
return -ENOMEM;
@@ -169,7 +170,7 @@ static void gpt_import_file_success(GptImportFile *f) {
}
}
- p = strappenda("/var/lib/container/", f->local, ".gpt");
+ p = strappenda(f->import->image_root, "/", f->local, ".gpt");
if (f->force_local)
(void) rm_rf_dangerous(p, false, true, false);
@@ -469,7 +470,7 @@ static int gpt_import_file_find_old_etags(GptImportFile *f) {
if (!escaped_url)
return -ENOMEM;
- d = opendir("/var/lib/container/");
+ d = opendir(f->import->image_root);
if (!d) {
if (errno == ENOENT)
return 0;
@@ -575,11 +576,12 @@ static int gpt_import_file_begin(GptImportFile *f) {
return 0;
}
-int gpt_import_new(GptImport **import, sd_event *event, gpt_import_on_finished on_finished, void *userdata) {
+int gpt_import_new(GptImport **import, sd_event *event, const char *image_root, gpt_import_on_finished on_finished, void *userdata) {
_cleanup_(gpt_import_unrefp) GptImport *i = NULL;
int r;
assert(import);
+ assert(image_root);
i = new0(GptImport, 1);
if (!i)
@@ -588,6 +590,10 @@ int gpt_import_new(GptImport **import, sd_event *event, gpt_import_on_finished o
i->on_finished = on_finished;
i->userdata = userdata;
+ i->image_root = strdup(image_root);
+ if (!i->image_root)
+ return -ENOMEM;
+
if (event)
i->event = sd_event_ref(event);
else {
@@ -622,6 +628,7 @@ GptImport* gpt_import_unref(GptImport *import) {
curl_glue_unref(import->glue);
sd_event_unref(import->event);
+ free(import->image_root);
free(import);
return NULL;
diff --git a/src/import/import-gpt.h b/src/import/import-gpt.h
index e4c534c..e9003db 100644
--- a/src/import/import-gpt.h
+++ b/src/import/import-gpt.h
@@ -26,7 +26,7 @@ typedef struct GptImport GptImport;
typedef void (*gpt_import_on_finished)(GptImport *import, int error, void *userdata);
-int gpt_import_new(GptImport **import, sd_event *event, gpt_import_on_finished on_finished, void *userdata);
+int gpt_import_new(GptImport **import, sd_event *event, const char *image_root, gpt_import_on_finished on_finished, void *userdata);
GptImport* gpt_import_unref(GptImport *import);
DEFINE_TRIVIAL_CLEANUP_FUNC(GptImport*, gpt_import_unref);
diff --git a/src/import/import.c b/src/import/import.c
index 79dd203..c28ff8f 100644
--- a/src/import/import.c
+++ b/src/import/import.c
@@ -29,6 +29,7 @@
#include "import-dkr.h"
static bool arg_force = false;
+static const char *arg_image_root = "/var/lib/container";
static const char* arg_dkr_index_url = DEFAULT_DKR_INDEX_URL;
@@ -87,7 +88,7 @@ static int pull_gpt(int argc, char *argv[], void *userdata) {
return -EINVAL;
}
- p = strappenda("/var/lib/container/", local, ".gpt");
+ p = strappenda(arg_image_root, "/", local, ".gpt");
if (laccess(p, F_OK) >= 0) {
if (!arg_force) {
log_info("Image '%s' already exists.", local);
@@ -108,7 +109,7 @@ static int pull_gpt(int argc, char *argv[], void *userdata) {
sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
- r = gpt_import_new(&import, event, on_gpt_finished, event);
+ r = gpt_import_new(&import, event, arg_image_root, on_gpt_finished, event);
if (r < 0)
return log_error_errno(r, "Failed to allocate importer: %m");
@@ -188,7 +189,7 @@ static int pull_dkr(int argc, char *argv[], void *userdata) {
return -EINVAL;
}
- p = strappenda("/var/lib/container/", local);
+ p = strappenda(arg_image_root, "/", local);
if (laccess(p, F_OK) >= 0) {
if (!arg_force) {
log_info("Image '%s' already exists.", local);
@@ -209,7 +210,7 @@ static int pull_dkr(int argc, char *argv[], void *userdata) {
sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
- r = dkr_import_new(&import, event, arg_dkr_index_url, on_dkr_finished, event);
+ r = dkr_import_new(&import, event, arg_dkr_index_url, arg_image_root, on_dkr_finished, event);
if (r < 0)
return log_error_errno(r, "Failed to allocate importer: %m");
@@ -233,6 +234,7 @@ static int help(int argc, char *argv[], void *userdata) {
" -h --help Show this help\n"
" --version Show package version\n"
" --force Force creation of image\n"
+ " --image-root= Image root directory\n"
" --dkr-index-url=URL Specify index URL to use for downloads\n\n"
"Commands:\n"
" pull-dkr REMOTE [NAME] Download a DKR image\n"
@@ -248,6 +250,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_VERSION = 0x100,
ARG_FORCE,
ARG_DKR_INDEX_URL,
+ ARG_IMAGE_ROOT,
};
static const struct option options[] = {
@@ -255,6 +258,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "version", no_argument, NULL, ARG_VERSION },
{ "force", no_argument, NULL, ARG_FORCE },
{ "dkr-index-url", required_argument, NULL, ARG_DKR_INDEX_URL },
+ { "image-root", required_argument, NULL, ARG_IMAGE_ROOT },
{}
};
@@ -288,6 +292,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_dkr_index_url = optarg;
break;
+ case ARG_IMAGE_ROOT:
+ arg_image_root = optarg;
+ break;
+
case '?':
return -EINVAL;
commit 5fc7f358420883c73dd662769b1670c0694111a0
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Dec 26 18:59:26 2014 +0100
machined: when discovering images, implicitly add ".host" as pseudo image referring to the host's own directory tree
diff --git a/src/machine/image.c b/src/machine/image.c
index 4f59c57..1574adf 100644
--- a/src/machine/image.c
+++ b/src/machine/image.c
@@ -45,8 +45,9 @@ Image *image_unref(Image *i) {
static int image_new(
ImageType t,
- const char *name,
+ const char *pretty,
const char *path,
+ const char *filename,
bool read_only,
usec_t crtime,
usec_t mtime,
@@ -56,7 +57,8 @@ static int image_new(
assert(t >= 0);
assert(t < _IMAGE_TYPE_MAX);
- assert(name);
+ assert(pretty);
+ assert(filename);
assert(ret);
i = new0(Image, 1);
@@ -68,17 +70,19 @@ static int image_new(
i->crtime = crtime;
i->mtime = mtime;
- i->name = strdup(name);
+ i->name = strdup(pretty);
if (!i->name)
return -ENOMEM;
- if (path) {
- i->path = strjoin(path, "/", name, NULL);
- if (!i->path)
- return -ENOMEM;
+ if (path)
+ i->path = strjoin(path, "/", filename, NULL);
+ else
+ i->path = strdup(filename);
- path_kill_slashes(i->path);
- }
+ if (!i->path)
+ return -ENOMEM;
+
+ path_kill_slashes(i->path);
*ret = i;
i = NULL;
@@ -86,34 +90,44 @@ static int image_new(
return 0;
}
-static int image_make(int dfd, const char *name, const char *path, Image **ret) {
+static int image_make(
+ const char *pretty,
+ int dfd,
+ const char *path,
+ const char *filename,
+ Image **ret) {
+
struct stat st;
- bool writable;
+ bool read_only;
int r;
- assert(dfd >= 0);
- assert(name);
+ assert(filename);
/* We explicitly *do* follow symlinks here, since we want to
* allow symlinking trees into /var/lib/container/, and treat
* them normally. */
- if (fstatat(dfd, name, &st, 0) < 0)
+ if (fstatat(dfd, filename, &st, 0) < 0)
return -errno;
- writable = faccessat(dfd, name, W_OK, AT_EACCESS) >= 0;
+ read_only =
+ (path && path_startswith(path, "/usr")) ||
+ faccessat(dfd, filename, W_OK, AT_EACCESS) < 0;
if (S_ISDIR(st.st_mode)) {
if (!ret)
return 1;
+ if (!pretty)
+ pretty = filename;
+
/* btrfs subvolumes have inode 256 */
if (st.st_ino == 256) {
_cleanup_close_ int fd = -1;
struct statfs sfs;
- fd = openat(dfd, name, O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
+ fd = openat(dfd, filename, O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
if (fd < 0)
return -errno;
@@ -130,9 +144,10 @@ static int image_make(int dfd, const char *name, const char *path, Image **ret)
return r;
r = image_new(IMAGE_SUBVOLUME,
- name,
+ pretty,
path,
- info.read_only || !writable,
+ filename,
+ info.read_only || read_only,
info.otime,
0,
ret);
@@ -146,9 +161,10 @@ static int image_make(int dfd, const char *name, const char *path, Image **ret)
/* It's just a normal directory. */
r = image_new(IMAGE_DIRECTORY,
- name,
+ pretty,
path,
- !writable,
+ filename,
+ read_only,
0,
0,
ret);
@@ -157,8 +173,7 @@ static int image_make(int dfd, const char *name, const char *path, Image **ret)
return 1;
- } else if (S_ISREG(st.st_mode) && endswith(name, ".gpt")) {
- const char *truncated;
+ } else if (S_ISREG(st.st_mode) && endswith(filename, ".gpt")) {
usec_t crtime = 0;
/* It's a GPT block device */
@@ -166,14 +181,16 @@ static int image_make(int dfd, const char *name, const char *path, Image **ret)
if (!ret)
return 1;
- fd_getcrtime_at(dfd, name, &crtime, 0);
+ fd_getcrtime_at(dfd, filename, &crtime, 0);
- truncated = strndupa(name, strlen(name) - 4);
+ if (!pretty)
+ pretty = strndupa(filename, strlen(filename) - 4);
r = image_new(IMAGE_GPT,
- truncated,
+ pretty,
path,
- !(st.st_mode & 0222) || !writable,
+ filename,
+ !(st.st_mode & 0222) || read_only,
crtime,
timespec_load(&st.st_mtim),
ret);
@@ -207,15 +224,27 @@ int image_find(const char *name, Image **ret) {
return -errno;
}
- r = image_make(dirfd(d), name, path, ret);
- if (r == 0 || r == -ENOENT)
- continue;
+ r = image_make(NULL, dirfd(d), path, name, ret);
+ if (r == 0 || r == -ENOENT) {
+ _cleanup_free_ char *gpt = NULL;
+
+ gpt = strappend(name, ".gpt");
+ if (!gpt)
+ return -ENOMEM;
+
+ r = image_make(NULL, dirfd(d), path, gpt, ret);
+ if (r == 0 || r == -ENOENT)
+ continue;
+ }
if (r < 0)
return r;
return 1;
}
+ if (streq(name, ".host"))
+ return image_make(NULL, AT_FDCWD, NULL, "/", ret);
+
return 0;
};
@@ -246,7 +275,7 @@ int image_discover(Hashmap *h) {
if (hashmap_contains(h, de->d_name))
continue;
- r = image_make(dirfd(d), de->d_name, path, &image);
+ r = image_make(NULL, dirfd(d), path, de->d_name, &image);
if (r == 0 || r == -ENOENT)
continue;
if (r < 0)
@@ -260,6 +289,21 @@ int image_discover(Hashmap *h) {
}
}
+ if (!hashmap_contains(h, ".host")) {
+ _cleanup_(image_unrefp) Image *image = NULL;
+
+ r = image_make(".host", AT_FDCWD, NULL, "/", &image);
+ if (r < 0)
+ return r;
+
+ r = hashmap_put(h, image->name, image);
+ if (r < 0)
+ return r;
+
+ image = NULL;
+
+ }
+
return 0;
}
commit a67a4c8cb728db1d803ebd43dcc39c7de50f2725
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Dec 26 18:19:47 2014 +0100
machined: fix image search path iteration
diff --git a/src/machine/image.c b/src/machine/image.c
index c4645a1..4f59c57 100644
--- a/src/machine/image.c
+++ b/src/machine/image.c
@@ -232,7 +232,7 @@ int image_discover(Hashmap *h) {
d = opendir(path);
if (!d) {
if (errno == ENOENT)
- return 0;
+ continue;
return -errno;
}
commit 42c6f2c9b2e5c2f013ce0af20bb11f63e9ec13c9
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Dec 26 18:19:22 2014 +0100
machined: let's also check machine directories in /usr and /usr/local
diff --git a/src/machine/image.c b/src/machine/image.c
index f72a5c3..c4645a1 100644
--- a/src/machine/image.c
+++ b/src/machine/image.c
@@ -28,8 +28,10 @@
#include "image.h"
static const char image_search_path[] =
+ "/var/lib/machines\0"
"/var/lib/container\0"
- "/var/lib/machine\0";
+ "/usr/local/lib/machines\0"
+ "/usr/lib/machines\0";
Image *image_unref(Image *i) {
if (!i)
commit f0be89eee9bf887bac87b59702bf688f691c2340
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Dec 26 18:18:47 2014 +0100
import: properly remove pre-existing images if --force is used
diff --git a/src/import/import-dkr.c b/src/import/import-dkr.c
index 1658053..fbd6412 100644
--- a/src/import/import-dkr.c
+++ b/src/import/import-dkr.c
@@ -411,12 +411,12 @@ static void dkr_import_name_maybe_finish(DkrImportName *name) {
if (name->force_local) {
(void) btrfs_subvol_remove(p);
- (void) rm_rf(p, false, true, false);
+ (void) rm_rf_dangerous(p, false, true, false);
}
r = btrfs_subvol_snapshot(q, p, false, false);
if (r < 0) {
- log_error_errno(r, "Failed to snapshot final image: %m");
+ log_error_errno(r, "Failed to snapshot local image: %m");
dkr_import_finish(name->import, r);
return;
}
commit 8620a9a32391fd74d70ddc07c9b79729ad4ec067
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Dec 26 17:10:31 2014 +0100
import: beef up gpt importer to optionally make writable copy of read-only vendor image
diff --git a/src/import/import-gpt.c b/src/import/import-gpt.c
index a81efa2..e1c493b 100644
--- a/src/import/import-gpt.c
+++ b/src/import/import-gpt.c
@@ -26,6 +26,8 @@
#include "utf8.h"
#include "curl-util.h"
#include "import-gpt.h"
+#include "strv.h"
+#include "copy.h"
typedef struct GptImportFile GptImportFile;
@@ -41,7 +43,7 @@ struct GptImportFile {
char *temp_path;
char *final_path;
char *etag;
- char *old_etag;
+ char **old_etags;
uint64_t content_length;
uint64_t written;
@@ -66,6 +68,8 @@ struct GptImport {
bool finished;
};
+#define FILENAME_ESCAPE "/.#\"\'"
+
static GptImportFile *gpt_import_file_unref(GptImportFile *f) {
if (!f)
return NULL;
@@ -86,7 +90,7 @@ static GptImportFile *gpt_import_file_unref(GptImportFile *f) {
free(f->url);
free(f->local);
free(f->etag);
- free(f->old_etag);
+ strv_free(f->old_etags);
free(f);
return NULL;
@@ -108,6 +112,108 @@ static void gpt_import_finish(GptImport *import, int error) {
sd_event_exit(import->event, error);
}
+static int gpt_import_file_make_final_path(GptImportFile *f) {
+ _cleanup_free_ char *escaped_url = NULL, *escaped_etag = NULL;
+
+ assert(f);
+
+ if (f->final_path)
+ return 0;
+
+ escaped_url = xescape(f->url, FILENAME_ESCAPE);
+ if (!escaped_url)
+ return -ENOMEM;
+
+ if (f->etag) {
+ escaped_etag = xescape(f->etag, FILENAME_ESCAPE);
+ if (!escaped_etag)
+ return -ENOMEM;
+
+ f->final_path = strjoin("/var/lib/container/.gpt-", escaped_url, ".", escaped_etag, ".gpt", NULL);
+ } else
+ f->final_path = strjoin("/var/lib/container/.gpt-", escaped_url, ".gpt", NULL);
+ if (!f->final_path)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void gpt_import_file_success(GptImportFile *f) {
+ int r;
+
+ assert(f);
+
+ f->done = true;
+
+ if (f->local) {
+ _cleanup_free_ char *tp = NULL;
+ _cleanup_close_ int dfd = -1;
+ const char *p;
+
+ if (f->disk_fd >= 0) {
+ if (lseek(f->disk_fd, SEEK_SET, 0) == (off_t) -1) {
+ r = log_error_errno(errno, "Failed to seek to beginning of vendor image: %m");
+ goto finish;
+ }
+ } else {
+ r = gpt_import_file_make_final_path(f);
+ if (r < 0) {
+ log_oom();
+ goto finish;
+ }
+
+ f->disk_fd = open(f->final_path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+ if (f->disk_fd < 0) {
+ r = log_error_errno(errno, "Failed top open vendor image: %m");
+ goto finish;
+ }
+ }
+
+ p = strappenda("/var/lib/container/", f->local, ".gpt");
+ if (f->force_local)
+ (void) rm_rf_dangerous(p, false, true, false);
+
+ r = tempfn_random(p, &tp);
+ if (r < 0) {
+ log_oom();
+ goto finish;
+ }
+
+ dfd = open(tp, O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
+ if (dfd < 0) {
+ r = log_error_errno(errno, "Failed to create writable copy of image: %m");
+ goto finish;
+ }
+
+ r = copy_bytes(f->disk_fd, dfd, (off_t) -1, true);
+ if (r < 0) {
+ log_error_errno(r, "Failed to make writable copy of image: %m");
+ unlink(tp);
+ goto finish;
+ }
+
+ (void) copy_times(f->disk_fd, dfd);
+ (void) copy_xattr(f->disk_fd, dfd);
+
+ dfd = safe_close(dfd);
+
+ r = rename(tp, p);
+ if (r < 0) {
+ r = log_error_errno(errno, "Failed to move writable image into place: %m");
+ unlink(tp);
+ goto finish;
+ }
+
+ log_info("Created new local image %s.", p);
+ }
+
+ f->disk_fd = safe_close(f->disk_fd);
+ r = 0;
+
+finish:
+ gpt_import_finish(f->import, r);
+}
+
static void gpt_import_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
GptImportFile *f = NULL;
struct stat st;
@@ -118,7 +224,7 @@ static void gpt_import_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result
if (curl_easy_getinfo(curl, CURLINFO_PRIVATE, &f) != CURLE_OK)
return;
- if (!f)
+ if (!f || f->done)
return;
f->done = true;
@@ -135,9 +241,9 @@ static void gpt_import_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result
r = -EIO;
goto fail;
} else if (status == 304) {
- log_info("File unmodified.");
- r = 0;
- goto fail;
+ log_info("Image already downloaded. Skipping download.");
+ gpt_import_file_success(f);
+ return;
} else if (status >= 300) {
log_error("HTTP request to %s failed with code %li.", f->url, status);
r = -EIO;
@@ -162,14 +268,15 @@ static void gpt_import_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result
}
if (f->etag)
- (void) fsetxattr(f->disk_fd, "user.etag", f->etag, strlen(f->etag), XATTR_CREATE);
+ (void) fsetxattr(f->disk_fd, "user.source_etag", f->etag, strlen(f->etag), 0);
+ if (f->url)
+ (void) fsetxattr(f->disk_fd, "user.source_url", f->url, strlen(f->url), 0);
if (f->mtime != 0) {
struct timespec ut[2];
timespec_store(&ut[0], f->mtime);
ut[1] = ut[0];
-
(void) futimens(f->disk_fd, ut);
fd_setcrtime(f->disk_fd, f->mtime);
@@ -183,8 +290,6 @@ static void gpt_import_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result
/* Mark read-only */
(void) fchmod(f->disk_fd, st.st_mode & 07444);
- f->disk_fd = safe_close(f->disk_fd);
-
assert(f->temp_path);
assert(f->final_path);
@@ -194,13 +299,19 @@ static void gpt_import_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result
goto fail;
}
- r = 0;
+ free(f->temp_path);
+ f->temp_path = NULL;
+
+ log_info("Completed writing vendor image %s.", f->final_path);
+
+ gpt_import_file_success(f);
+ return;
fail:
gpt_import_finish(f->import, r);
}
-static int gpt_import_file_open_disk(GptImportFile *f) {
+static int gpt_import_file_open_disk_for_write(GptImportFile *f) {
int r;
assert(f);
@@ -208,7 +319,9 @@ static int gpt_import_file_open_disk(GptImportFile *f) {
if (f->disk_fd >= 0)
return 0;
- assert(f->final_path);
+ r = gpt_import_file_make_final_path(f);
+ if (r < 0)
+ return log_oom();
if (!f->temp_path) {
r = tempfn_random(f->final_path, &f->temp_path);
@@ -216,7 +329,7 @@ static int gpt_import_file_open_disk(GptImportFile *f) {
return log_oom();
}
- f->disk_fd = open(f->temp_path, O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC|O_WRONLY, 0644);
+ f->disk_fd = open(f->temp_path, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0644);
if (f->disk_fd < 0)
return log_error_errno(errno, "Failed to create %s: %m", f->temp_path);
@@ -232,7 +345,12 @@ static size_t gpt_import_file_write_callback(void *contents, size_t size, size_t
assert(contents);
assert(f);
- r = gpt_import_file_open_disk(f);
+ if (f->done) {
+ r = -ESTALE;
+ goto fail;
+ }
+
+ r = gpt_import_file_open_disk_for_write(f);
if (r < 0)
goto fail;
@@ -280,6 +398,11 @@ static size_t gpt_import_file_header_callback(void *contents, size_t size, size_
assert(contents);
assert(f);
+ if (f->done) {
+ r = -ESTALE;
+ goto fail;
+ }
+
r = curl_header_strdup(contents, sz, "ETag:", &etag);
if (r < 0) {
log_oom();
@@ -289,9 +412,9 @@ static size_t gpt_import_file_header_callback(void *contents, size_t size, size_
free(f->etag);
f->etag = etag;
- if (streq_ptr(f->old_etag, f->etag)) {
- log_info("Image already up to date. Finishing.");
- gpt_import_finish(f->import, 0);
+ if (strv_contains(f->old_etags, f->etag)) {
+ log_info("Image already downloaded. Skipping download.");
+ gpt_import_file_success(f);
return sz;
}
@@ -325,6 +448,79 @@ fail:
return 0;
}
+static bool etag_is_valid(const char *etag) {
+
+ if (!endswith(etag, "\""))
+ return false;
+
+ if (!startswith(etag, "\"") && !startswith(etag, "W/\""))
+ return false;
+
+ return true;
+}
+
+static int gpt_import_file_find_old_etags(GptImportFile *f) {
+ _cleanup_free_ char *escaped_url = NULL;
+ _cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
+ int r;
+
+ escaped_url = xescape(f->url, FILENAME_ESCAPE);
+ if (!escaped_url)
+ return -ENOMEM;
+
+ d = opendir("/var/lib/container/");
+ if (!d) {
+ if (errno == ENOENT)
+ return 0;
+
+ return -errno;
+ }
+
+ FOREACH_DIRENT_ALL(de, d, return -errno) {
+ const char *a, *b;
+ char *u;
+
+ if (de->d_type != DT_UNKNOWN &&
+ de->d_type != DT_REG)
+ continue;
+
+ a = startswith(de->d_name, ".gpt-");
+ if (!a)
+ continue;
+
+ a = startswith(a, escaped_url);
+ if (!a)
+ continue;
+
+ a = startswith(a, ".");
+ if (!a)
+ continue;
+
+ b = endswith(de->d_name, ".gpt");
+ if (!b)
+ continue;
+
+ if (a >= b)
+ continue;
+
+ u = cunescape_length(a, b - a);
+ if (!u)
+ return -ENOMEM;
+
+ if (!etag_is_valid(u)) {
+ free(u);
+ continue;
+ }
+
+ r = strv_consume(&f->old_etags, u);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
static int gpt_import_file_begin(GptImportFile *f) {
int r;
@@ -333,14 +529,24 @@ static int gpt_import_file_begin(GptImportFile *f) {
log_info("Getting %s.", f->url);
+ r = gpt_import_file_find_old_etags(f);
+ if (r < 0)
+ return r;
+
r = curl_glue_make(&f->curl, f->url, f);
if (r < 0)
return r;
- if (f->old_etag) {
- const char *hdr;
+ if (!strv_isempty(f->old_etags)) {
+ _cleanup_free_ char *cc = NULL, *hdr = NULL;
- hdr = strappenda("If-None-Match: ", f->old_etag);
+ cc = strv_join(f->old_etags, ", ");
+ if (!cc)
+ return -ENOMEM;
+
+ hdr = strappend("If-None-Match: ", cc);
+ if (!hdr)
+ return -ENOMEM;
f->request_header = curl_slist_new(hdr, NULL);
if (!f->request_header)
@@ -437,13 +643,11 @@ int gpt_import_cancel(GptImport *import, const char *url) {
int gpt_import_pull(GptImport *import, const char *url, const char *local, bool force_local) {
_cleanup_(gpt_import_file_unrefp) GptImportFile *f = NULL;
- char etag[LINE_MAX];
- ssize_t n;
int r;
assert(import);
assert(gpt_url_is_valid(url));
- assert(machine_name_is_valid(local));
+ assert(!local || machine_name_is_valid(local));
if (hashmap_get(import->files, url))
return -EEXIST;
@@ -464,19 +668,12 @@ int gpt_import_pull(GptImport *import, const char *url, const char *local, bool
if (!f->url)
return -ENOMEM;
- f->local = strdup(local);
- if (!f->local)
- return -ENOMEM;
-
- f->final_path = strjoin("/var/lib/container/", local, ".gpt", NULL);
- if (!f->final_path)
- return -ENOMEM;
-
- n = getxattr(f->final_path, "user.etag", etag, sizeof(etag));
- if (n > 0) {
- f->old_etag = strndup(etag, n);
- if (!f->old_etag)
+ if (local) {
+ f->local = strdup(local);
+ if (!f->local)
return -ENOMEM;
+
+ f->force_local = force_local;
}
r = hashmap_put(import->files, f->url, f);
diff --git a/src/import/import.c b/src/import/import.c
index a81200c..79dd203 100644
--- a/src/import/import.c
+++ b/src/import/import.c
@@ -47,22 +47,18 @@ static void on_gpt_finished(GptImport *import, int error, void *userdata) {
static int pull_gpt(int argc, char *argv[], void *userdata) {
_cleanup_(gpt_import_unrefp) GptImport *import = NULL;
_cleanup_event_unref_ sd_event *event = NULL;
- _cleanup_free_ char *local_truncated = NULL, *local_generated = NULL;
const char *url, *local, *suffix;
int r;
url = argv[1];
- local = argv[2];
-
if (!gpt_url_is_valid(url)) {
log_error("URL '%s' is not valid.", url);
return -EINVAL;
}
- if (isempty(local) || streq(local, "-"))
- local = NULL;
-
- if (!local) {
+ if (argc >= 3)
+ local = argv[2];
+ else {
const char *e, *p;
e = url + strlen(url);
@@ -73,28 +69,36 @@ static int pull_gpt(int argc, char *argv[], void *userdata) {
while (p > url && p[-1] != '/')
p--;
- local_generated = strndup(p, e - p);
- if (!local_generated)
- return log_oom();
-
- local = local_generated;
+ local = strndupa(p, e - p);
}
- suffix = endswith(local, ".gpt");
- if (suffix) {
- local_truncated = strndup(local, suffix - local);
- if (!local_truncated)
- return log_oom();
+ if (isempty(local) || streq(local, "-"))
+ local = NULL;
- local = local_truncated;
- }
+ if (local) {
+ const char *p;
- if (!machine_name_is_valid(local)) {
- log_error("Local image name '%s' is not valid.", local);
- return -EINVAL;
- }
+ suffix = endswith(local, ".gpt");
+ if (suffix)
+ local = strndupa(local, suffix - local);
- log_info("Pulling '%s' as '%s'", url, local);
+ if (!machine_name_is_valid(local)) {
+ log_error("Local image name '%s' is not valid.", local);
+ return -EINVAL;
+ }
+
+ p = strappenda("/var/lib/container/", local, ".gpt");
+ if (laccess(p, F_OK) >= 0) {
+ if (!arg_force) {
+ log_info("Image '%s' already exists.", local);
+ return 0;
+ }
+ } else if (errno != ENOENT)
+ return log_error_errno(errno, "Can't check if image '%s' already exists: %m", local);
+
+ log_info("Pulling '%s', saving as '%s'.", url, local);
+ } else
+ log_info("Pulling '%s'.", url);
r = sd_event_default(&event);
if (r < 0)
@@ -153,6 +157,16 @@ static int pull_dkr(int argc, char *argv[], void *userdata) {
tag = "latest";
}
+ if (!dkr_name_is_valid(name)) {
+ log_error("Remote name '%s' is not valid.", name);
+ return -EINVAL;
+ }
+
+ if (!dkr_tag_is_valid(tag)) {
+ log_error("Tag name '%s' is not valid.", tag);
+ return -EINVAL;
+ }
+
if (argc >= 3)
local = argv[2];
else {
@@ -166,16 +180,6 @@ static int pull_dkr(int argc, char *argv[], void *userdata) {
if (isempty(local) || streq(local, "-"))
local = NULL;
- if (!dkr_name_is_valid(name)) {
- log_error("Remote name '%s' is not valid.", name);
- return -EINVAL;
- }
-
- if (!dkr_tag_is_valid(tag)) {
- log_error("Tag name '%s' is not valid.", tag);
- return -EINVAL;
- }
-
if (local) {
const char *p;
commit e9d7333468ff02fd45a8aeb957e758f641026278
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Dec 26 17:10:05 2014 +0100
import: minor improvements to dkr importer
diff --git a/src/import/import-dkr.c b/src/import/import-dkr.c
index b290619..1658053 100644
--- a/src/import/import-dkr.c
+++ b/src/import/import-dkr.c
@@ -421,7 +421,7 @@ static void dkr_import_name_maybe_finish(DkrImportName *name) {
return;
}
- log_info("Created new image %s.", p);
+ log_info("Created new local image %s.", p);
}
dkr_import_finish(name->import, 0);
@@ -718,7 +718,7 @@ static void dkr_import_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result
if (curl_easy_getinfo(curl, CURLINFO_PRIVATE, &job) != CURLE_OK)
return;
- if (!job)
+ if (!job || job->done)
return;
job->done = true;
@@ -817,6 +817,11 @@ static size_t dkr_import_job_write_callback(void *contents, size_t size, size_t
assert(contents);
assert(j);
+ if (j->done) {
+ r = -ESTALE;
+ goto fail;
+ }
+
if (j->tar_stream) {
size_t l;
@@ -866,6 +871,11 @@ static size_t dkr_import_job_header_callback(void *contents, size_t size, size_t
assert(contents);
assert(j);
+ if (j->done) {
+ r = -ESTALE;
+ goto fail;
+ }
+
r = curl_header_strdup(contents, sz, HEADER_TOKEN, &token);
if (r < 0) {
log_oom();
commit 2c39ea529b35383022946a07eeecd6711bcd2684
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Dec 26 17:03:01 2014 +0100
util: always override crtime xattr
diff --git a/src/shared/util.c b/src/shared/util.c
index 52e5df4..d04d738 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -7645,7 +7645,7 @@ int fd_setcrtime(int fd, usec_t usec) {
assert(fd >= 0);
le = htole64((uint64_t) usec);
- if (fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), XATTR_CREATE) < 0)
+ if (fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), 0) < 0)
return -errno;
return 0;
commit 6389e747d5b09b18e00d85b9b13c1be2ff884015
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Dec 26 17:01:00 2014 +0100
machinectl: left-align times
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index 1cc5dfc..64caf7c 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -221,7 +221,7 @@ static int list_images(int argc, char *argv[], void *userdata) {
qsort_safe(images, n_images, sizeof(ImageInfo), compare_image_info);
if (arg_legend)
- printf("%-*s %-*s %-3s %*s %*s\n",
+ printf("%-*s %-*s %-3s %-*s %-*s\n",
(int) max_name, "NAME",
(int) max_type, "TYPE",
"RO",
@@ -231,7 +231,7 @@ static int list_images(int argc, char *argv[], void *userdata) {
for (j = 0; j < n_images; j++) {
char crtime_buf[FORMAT_TIMESTAMP_MAX], mtime_buf[FORMAT_TIMESTAMP_MAX];
- printf("%-*s %-*s %-3s %*s %*s\n",
+ printf("%-*s %-*s %-3s %-*s %-*s\n",
(int) max_name, images[j].name,
(int) max_type, images[j].type,
yes_no(images[j].read_only),
commit e6bd041c973c1f4074c3268b23c380ede0d64f19
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Dec 26 17:00:39 2014 +0100
copy: try top copy atime/time/xattrs when copying files
diff --git a/src/shared/copy.c b/src/shared/copy.c
index 0c2cdc8..92f6e1e 100644
--- a/src/shared/copy.c
+++ b/src/shared/copy.c
@@ -20,6 +20,7 @@
***/
#include <sys/sendfile.h>
+#include <sys/xattr.h>
#include "util.h"
#include "btrfs-util.h"
@@ -145,6 +146,9 @@ static int fd_copy_regular(int df, const char *from, const struct stat *st, int
if (fchmod(fdt, st->st_mode & 07777) < 0)
r = -errno;
+ (void) copy_times(fdf, fdt);
+ (void) copy_xattr(fdf, fdt);
+
q = close(fdt);
fdt = -1;
@@ -244,6 +248,9 @@ static int fd_copy_directory(
if (fchmod(fdt, st->st_mode & 07777) < 0)
r = -errno;
+
+ (void) copy_times(fdf, fdt);
+ (void) copy_xattr(fdf, fdt);
}
FOREACH_DIRENT(de, d, return -errno) {
@@ -326,6 +333,7 @@ int copy_directory_fd(int dirfd, const char *to, bool merge) {
int copy_file_fd(const char *from, int fdt, bool try_reflink) {
_cleanup_close_ int fdf = -1;
+ int r;
assert(from);
assert(fdt >= 0);
@@ -334,7 +342,12 @@ int copy_file_fd(const char *from, int fdt, bool try_reflink) {
if (fdf < 0)
return -errno;
- return copy_bytes(fdf, fdt, (off_t) -1, try_reflink);
+ r = copy_bytes(fdf, fdt, (off_t) -1, try_reflink);
+
+ (void) copy_times(fdf, fdt);
+ (void) copy_xattr(fdf, fdt);
+
+ return r;
}
int copy_file(const char *from, const char *to, int flags, mode_t mode) {
@@ -361,3 +374,91 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode) {
return 0;
}
+
+int copy_times(int fdf, int fdt) {
+ struct timespec ut[2];
+ struct stat st;
+ usec_t crtime;
+
+ assert(fdf >= 0);
+ assert(fdt >= 0);
+
+ if (fstat(fdf, &st) < 0)
+ return -errno;
+
+ ut[0] = st.st_atim;
+ ut[1] = st.st_mtim;
+
+ if (futimens(fdt, ut) < 0)
+ return -errno;
+
+ if (fd_getcrtime(fdf, &crtime) >= 0)
+ (void) fd_setcrtime(fdt, crtime);
+
+ return 0;
+}
+
+int copy_xattr(int fdf, int fdt) {
+ _cleanup_free_ char *bufa = NULL, *bufb = NULL;
+ size_t sza = 100, szb = 100;
+ ssize_t n;
+ int ret = 0;
+ const char *p;
+
+ for (;;) {
+ bufa = malloc(sza);
+ if (!bufa)
+ return -ENOMEM;
+
+ n = flistxattr(fdf, bufa, sza);
+ if (n == 0)
+ return 0;
+ if (n > 0)
+ break;
+ if (errno != ERANGE)
+ return -errno;
+
+ sza *= 2;
+
+ free(bufa);
+ bufa = NULL;
+ }
+
+ p = bufa;
+ while (n > 0) {
+ size_t l;
+
+ l = strlen(p);
+ assert(l < (size_t) n);
+
+ if (startswith(p, "user.")) {
+ ssize_t m;
+
+ if (!bufb) {
+ bufb = malloc(szb);
+ if (!bufb)
+ return -ENOMEM;
+ }
+
+ m = fgetxattr(fdf, p, bufb, szb);
+ if (m < 0) {
+ if (errno == ERANGE) {
+ szb *= 2;
+ free(bufb);
+ bufb = NULL;
+ continue;
+ }
+
+ return -errno;
+ }
+
+ if (fsetxattr(fdt, p, bufb, m, 0) < 0)
+ ret = -errno;
+ }
+
+ p += l + 1;
+ n -= l + 1;
+ }
+
+ return ret;
+}
diff --git a/src/shared/copy.h b/src/shared/copy.h
index 714addf..6d725ef 100644
--- a/src/shared/copy.h
+++ b/src/shared/copy.h
@@ -30,3 +30,5 @@ int copy_tree(const char *from, const char *to, bool merge);
int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge);
int copy_directory_fd(int dirfd, const char *to, bool merge);
int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink);
+int copy_times(int fdf, int fdt);
+int copy_xattr(int fdf, int fdt);
commit c75f27ea2b483f91d437ebaf8494457dc76f3fd6
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Dec 26 16:59:53 2014 +0100
test: improve btrfs test case
diff --git a/src/test/test-btrfs.c b/src/test/test-btrfs.c
index 4a08c72..43b445d 100644
--- a/src/test/test-btrfs.c
+++ b/src/test/test-btrfs.c
@@ -29,26 +29,30 @@
int main(int argc, char *argv[]) {
int r;
- BtrfsSubvolInfo info;
- char ts[FORMAT_TIMESTAMP_MAX];
int fd;
fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
if (fd < 0)
log_error_errno(errno, "Failed to open root directory: %m");
else {
+ BtrfsSubvolInfo info;
+ char ts[FORMAT_TIMESTAMP_MAX];
+
r = btrfs_subvol_get_info_fd(fd, &info);
if (r < 0)
log_error_errno(r, "Failed to get subvolume info: %m");
else {
log_info("otime: %s", format_timestamp(ts, sizeof(ts), info.otime));
- log_info("read-only: %s", yes_no(info.read_only));
+ log_info("read-only (search): %s", yes_no(info.read_only));
}
r = btrfs_subvol_get_read_only_fd(fd);
- assert_se(r >= 0);
+ if (r < 0)
+ log_error_errno(r, "Failed to get read only flag: %m");
+ else
+ log_info("read-only (ioctl): %s", yes_no(r));
- log_info("read-only: %s", yes_no(r));
+ safe_close(fd);
}
r = btrfs_subvol_make("/xxxtest");
commit 86e339c8846cdf614a41653384c0b4e84b233696
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Dec 26 16:44:15 2014 +0100
machined: be more thorough when checking whether an image is writable or not
diff --git a/src/machine/image.c b/src/machine/image.c
index 9f88b05..f72a5c3 100644
--- a/src/machine/image.c
+++ b/src/machine/image.c
@@ -86,6 +86,7 @@ static int image_new(
static int image_make(int dfd, const char *name, const char *path, Image **ret) {
struct stat st;
+ bool writable;
int r;
assert(dfd >= 0);
@@ -98,6 +99,8 @@ static int image_make(int dfd, const char *name, const char *path, Image **ret)
if (fstatat(dfd, name, &st, 0) < 0)
return -errno;
+ writable = faccessat(dfd, name, W_OK, AT_EACCESS) >= 0;
+
if (S_ISDIR(st.st_mode)) {
if (!ret)
@@ -127,7 +130,7 @@ static int image_make(int dfd, const char *name, const char *path, Image **ret)
r = image_new(IMAGE_SUBVOLUME,
name,
path,
- info.read_only,
+ info.read_only || !writable,
info.otime,
0,
ret);
@@ -143,7 +146,7 @@ static int image_make(int dfd, const char *name, const char *path, Image **ret)
r = image_new(IMAGE_DIRECTORY,
name,
path,
- false,
+ !writable,
0,
0,
ret);
@@ -168,7 +171,7 @@ static int image_make(int dfd, const char *name, const char *path, Image **ret)
r = image_new(IMAGE_GPT,
truncated,
path,
- !(st.st_mode & 0222),
+ !(st.st_mode & 0222) || !writable,
crtime,
timespec_load(&st.st_mtim),
ret);
More information about the systemd-commits
mailing list