2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2013-07-02 03:47:23 +02:00
|
|
|
/***
|
|
|
|
This file is part of systemd.
|
|
|
|
|
|
|
|
Copyright 2013 Lennart Poettering
|
|
|
|
|
|
|
|
systemd is free software; you can redistribute it and/or modify it
|
|
|
|
under the terms of the GNU Lesser General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
systemd is distributed in the hope that it will be useful, but
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
|
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
***/
|
|
|
|
|
2015-09-23 03:01:06 +02:00
|
|
|
#include <arpa/inet.h>
|
2013-07-02 03:47:23 +02:00
|
|
|
#include <errno.h>
|
2015-09-23 03:01:06 +02:00
|
|
|
#include <fcntl.h>
|
2013-07-02 03:47:23 +02:00
|
|
|
#include <getopt.h>
|
|
|
|
#include <locale.h>
|
2014-07-10 23:12:32 +02:00
|
|
|
#include <net/if.h>
|
2015-09-23 03:01:06 +02:00
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <string.h>
|
2014-12-17 21:51:45 +01:00
|
|
|
#include <sys/mount.h>
|
2015-09-23 03:01:06 +02:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <unistd.h>
|
2015-02-11 18:50:38 +01:00
|
|
|
|
2013-08-12 14:19:22 +02:00
|
|
|
#include "sd-bus.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2016-06-26 17:41:33 +02:00
|
|
|
#include "bus-common-errors.h"
|
2013-08-12 14:19:22 +02:00
|
|
|
#include "bus-error.h"
|
2016-04-20 15:51:33 +02:00
|
|
|
#include "bus-unit-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "bus-util.h"
|
2013-07-02 03:47:23 +02:00
|
|
|
#include "cgroup-show.h"
|
2013-07-11 19:14:38 +02:00
|
|
|
#include "cgroup-util.h"
|
2014-12-18 01:35:58 +01:00
|
|
|
#include "copy.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "env-util.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "fd-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "hostname-util.h"
|
2015-01-22 03:57:15 +01:00
|
|
|
#include "import-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "log.h"
|
|
|
|
#include "logs-show.h"
|
|
|
|
#include "macro.h"
|
|
|
|
#include "mkdir.h"
|
|
|
|
#include "pager.h"
|
2015-10-26 16:18:16 +01:00
|
|
|
#include "parse-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "path-util.h"
|
2015-04-10 19:10:00 +02:00
|
|
|
#include "process-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "ptyfwd.h"
|
2017-11-10 21:04:08 +01:00
|
|
|
#include "sigbus.h"
|
2015-05-29 20:14:11 +02:00
|
|
|
#include "signal-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "spawn-polkit-agent.h"
|
2017-11-10 21:04:08 +01:00
|
|
|
#include "stdio-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "strv.h"
|
|
|
|
#include "terminal-util.h"
|
|
|
|
#include "unit-name.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "verbs.h"
|
2015-10-27 00:41:29 +01:00
|
|
|
#include "web-util.h"
|
2016-08-31 20:06:57 +02:00
|
|
|
|
|
|
|
#define ALL_IP_ADDRESSES -1
|
2013-07-02 03:47:23 +02:00
|
|
|
|
|
|
|
static char **arg_property = NULL;
|
|
|
|
static bool arg_all = false;
|
2016-04-06 04:44:42 +02:00
|
|
|
static bool arg_value = false;
|
2013-07-02 03:47:23 +02:00
|
|
|
static bool arg_full = false;
|
|
|
|
static bool arg_no_pager = false;
|
2014-02-18 21:09:05 +01:00
|
|
|
static bool arg_legend = true;
|
2013-07-02 03:47:23 +02:00
|
|
|
static const char *arg_kill_who = NULL;
|
|
|
|
static int arg_signal = SIGTERM;
|
2013-10-30 16:44:55 +01:00
|
|
|
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
|
2013-07-02 03:47:23 +02:00
|
|
|
static char *arg_host = NULL;
|
2014-12-17 21:51:45 +01:00
|
|
|
static bool arg_read_only = false;
|
|
|
|
static bool arg_mkdir = false;
|
2014-12-29 14:05:17 +01:00
|
|
|
static bool arg_quiet = false;
|
2015-01-08 15:23:54 +01:00
|
|
|
static bool arg_ask_password = true;
|
2015-01-08 15:09:12 +01:00
|
|
|
static unsigned arg_lines = 10;
|
|
|
|
static OutputMode arg_output = OUTPUT_SHORT;
|
2015-01-22 03:57:15 +01:00
|
|
|
static bool arg_force = false;
|
2015-01-22 17:30:40 +01:00
|
|
|
static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE;
|
2015-03-09 17:55:07 +01:00
|
|
|
static const char* arg_format = NULL;
|
2015-08-23 13:24:10 +02:00
|
|
|
static const char *arg_uid = NULL;
|
|
|
|
static char **arg_setenv = NULL;
|
2016-08-31 20:06:57 +02:00
|
|
|
static int arg_addrs = 1;
|
|
|
|
|
|
|
|
static int print_addresses(sd_bus *bus, const char *name, int, const char *pr1, const char *pr2, int n_addr);
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2015-01-08 15:09:12 +01:00
|
|
|
static OutputFlags get_output_flags(void) {
|
|
|
|
return
|
|
|
|
arg_all * OUTPUT_SHOW_ALL |
|
2017-11-10 21:40:47 +01:00
|
|
|
(arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
|
2016-01-19 10:17:19 +01:00
|
|
|
colors_enabled() * OUTPUT_COLOR |
|
2015-01-08 15:09:12 +01:00
|
|
|
!arg_quiet * OUTPUT_WARN_CUTOFF;
|
|
|
|
}
|
|
|
|
|
2015-01-07 19:13:48 +01:00
|
|
|
typedef struct MachineInfo {
|
|
|
|
const char *name;
|
|
|
|
const char *class;
|
|
|
|
const char *service;
|
2016-08-21 05:39:07 +02:00
|
|
|
char *os;
|
2016-08-31 20:06:57 +02:00
|
|
|
char *version_id;
|
2015-01-07 19:13:48 +01:00
|
|
|
} MachineInfo;
|
|
|
|
|
|
|
|
static int compare_machine_info(const void *a, const void *b) {
|
|
|
|
const MachineInfo *x = a, *y = b;
|
|
|
|
|
|
|
|
return strcmp(x->name, y->name);
|
|
|
|
}
|
|
|
|
|
2016-08-21 05:39:07 +02:00
|
|
|
static void clean_machine_info(MachineInfo *machines, size_t n_machines) {
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (!machines || n_machines == 0)
|
|
|
|
return;
|
|
|
|
|
2016-08-31 20:06:57 +02:00
|
|
|
for (i = 0; i < n_machines; i++) {
|
2016-08-21 05:39:07 +02:00
|
|
|
free(machines[i].os);
|
2016-08-31 20:06:57 +02:00
|
|
|
free(machines[i].version_id);
|
|
|
|
}
|
2016-08-21 05:39:07 +02:00
|
|
|
free(machines);
|
|
|
|
}
|
|
|
|
|
2016-12-01 23:24:20 +01:00
|
|
|
static int call_get_os_release(sd_bus *bus, const char *method, const char *name, const char *query, ...) {
|
2016-08-21 05:39:07 +02:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
2016-08-31 20:06:57 +02:00
|
|
|
const char *k, *v, *iter, **query_res = NULL;
|
|
|
|
size_t count = 0, awaited_args = 0;
|
|
|
|
va_list ap;
|
2016-08-21 05:39:07 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
assert(name);
|
2016-08-31 20:06:57 +02:00
|
|
|
assert(query);
|
|
|
|
|
|
|
|
NULSTR_FOREACH(iter, query)
|
|
|
|
awaited_args++;
|
|
|
|
query_res = newa0(const char *, awaited_args);
|
2016-08-21 05:39:07 +02:00
|
|
|
|
2016-12-01 23:24:20 +01:00
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
|
|
|
method,
|
|
|
|
NULL, &reply, "s", name);
|
2016-08-21 05:39:07 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_bus_message_enter_container(reply, 'a', "{ss}");
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
|
|
while ((r = sd_bus_message_read(reply, "{ss}", &k, &v)) > 0) {
|
2016-08-31 20:06:57 +02:00
|
|
|
count = 0;
|
|
|
|
NULSTR_FOREACH(iter, query) {
|
|
|
|
if (streq(k, iter)) {
|
|
|
|
query_res[count] = v;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
count++;
|
|
|
|
}
|
2016-08-21 05:39:07 +02:00
|
|
|
}
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_exit_container(reply);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
2016-08-31 20:06:57 +02:00
|
|
|
va_start(ap, query);
|
|
|
|
for (count = 0; count < awaited_args; count++) {
|
|
|
|
char *val, **out;
|
|
|
|
|
|
|
|
out = va_arg(ap, char **);
|
|
|
|
assert(out);
|
|
|
|
if (query_res[count]) {
|
|
|
|
val = strdup(query_res[count]);
|
|
|
|
if (!val) {
|
|
|
|
va_end(ap);
|
2016-12-01 23:24:20 +01:00
|
|
|
return -ENOMEM;
|
2016-08-31 20:06:57 +02:00
|
|
|
}
|
|
|
|
*out = val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
va_end(ap);
|
2016-08-21 05:39:07 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
static int list_machines(int argc, char *argv[], void *userdata) {
|
|
|
|
|
2017-12-14 19:02:29 +01:00
|
|
|
size_t max_name = STRLEN("MACHINE"), max_class = STRLEN("CLASS"),
|
|
|
|
max_service = STRLEN("SERVICE"), max_os = STRLEN("OS"), max_version_id = STRLEN("VERSION");
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
2016-08-31 20:06:57 +02:00
|
|
|
_cleanup_free_ char *prefix = NULL;
|
2016-08-21 05:39:07 +02:00
|
|
|
MachineInfo *machines = NULL;
|
2013-08-12 14:19:22 +02:00
|
|
|
const char *name, *class, *service, *object;
|
2015-01-07 19:13:48 +01:00
|
|
|
size_t n_machines = 0, n_allocated = 0, j;
|
2014-12-19 19:19:05 +01:00
|
|
|
sd_bus *bus = userdata;
|
2013-07-02 03:47:23 +02:00
|
|
|
int r;
|
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
assert(bus);
|
|
|
|
|
2018-03-14 09:48:29 +01:00
|
|
|
(void) pager_open(arg_no_pager, false);
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2016-04-06 05:03:46 +02:00
|
|
|
r = sd_bus_call_method(bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
|
|
|
"ListMachines",
|
|
|
|
&error,
|
|
|
|
&reply,
|
|
|
|
NULL);
|
2013-08-12 14:19:22 +02:00
|
|
|
if (r < 0) {
|
|
|
|
log_error("Could not get machines: %s", bus_error_message(&error, -r));
|
2013-07-02 03:47:23 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2015-01-22 03:57:15 +01:00
|
|
|
r = sd_bus_message_enter_container(reply, 'a', "(ssso)");
|
2013-08-12 14:19:22 +02:00
|
|
|
if (r < 0)
|
2013-11-07 21:26:31 +01:00
|
|
|
return bus_log_parse_error(r);
|
2013-08-12 14:19:22 +02:00
|
|
|
while ((r = sd_bus_message_read(reply, "(ssso)", &name, &class, &service, &object)) > 0) {
|
2015-01-07 19:13:48 +01:00
|
|
|
size_t l;
|
|
|
|
|
2015-08-24 21:08:04 +02:00
|
|
|
if (name[0] == '.' && !arg_all)
|
|
|
|
continue;
|
|
|
|
|
2016-12-29 12:09:54 +01:00
|
|
|
if (!GREEDY_REALLOC0(machines, n_allocated, n_machines + 1)) {
|
2016-08-21 05:39:07 +02:00
|
|
|
r = log_oom();
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2016-12-29 12:09:54 +01:00
|
|
|
machines[n_machines].name = name;
|
|
|
|
machines[n_machines].class = class;
|
|
|
|
machines[n_machines].service = service;
|
|
|
|
|
|
|
|
(void) call_get_os_release(
|
2016-12-01 23:24:20 +01:00
|
|
|
bus,
|
|
|
|
"GetMachineOSRelease",
|
|
|
|
name,
|
|
|
|
"ID\0"
|
|
|
|
"VERSION_ID\0",
|
2016-08-31 20:06:57 +02:00
|
|
|
&machines[n_machines].os,
|
|
|
|
&machines[n_machines].version_id);
|
2015-01-07 19:13:48 +01:00
|
|
|
|
|
|
|
l = strlen(name);
|
|
|
|
if (l > max_name)
|
|
|
|
max_name = l;
|
|
|
|
|
|
|
|
l = strlen(class);
|
|
|
|
if (l > max_class)
|
|
|
|
max_class = l;
|
|
|
|
|
|
|
|
l = strlen(service);
|
|
|
|
if (l > max_service)
|
|
|
|
max_service = l;
|
|
|
|
|
2016-08-31 20:06:57 +02:00
|
|
|
l = machines[n_machines].os ? strlen(machines[n_machines].os) : 1;
|
2016-08-21 05:39:07 +02:00
|
|
|
if (l > max_os)
|
|
|
|
max_os = l;
|
|
|
|
|
2016-08-31 20:06:57 +02:00
|
|
|
l = machines[n_machines].version_id ? strlen(machines[n_machines].version_id) : 1;
|
|
|
|
if (l > max_version_id)
|
|
|
|
max_version_id = l;
|
|
|
|
|
2016-02-23 05:32:04 +01:00
|
|
|
n_machines++;
|
2013-07-02 03:47:23 +02:00
|
|
|
}
|
2016-08-21 05:39:07 +02:00
|
|
|
if (r < 0) {
|
|
|
|
r = bus_log_parse_error(r);
|
|
|
|
goto out;
|
|
|
|
}
|
2013-08-12 14:19:22 +02:00
|
|
|
|
|
|
|
r = sd_bus_message_exit_container(reply);
|
2016-08-21 05:39:07 +02:00
|
|
|
if (r < 0) {
|
|
|
|
r = bus_log_parse_error(r);
|
|
|
|
goto out;
|
|
|
|
}
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2015-01-07 19:13:48 +01:00
|
|
|
qsort_safe(machines, n_machines, sizeof(MachineInfo), compare_machine_info);
|
|
|
|
|
2017-12-14 19:02:29 +01:00
|
|
|
/* Allocate for prefix max characters for all fields + spaces between them + STRLEN(",\n") */
|
2016-08-31 20:06:57 +02:00
|
|
|
r = asprintf(&prefix, "%-*s",
|
|
|
|
(int) (max_name +
|
|
|
|
max_class +
|
|
|
|
max_service +
|
|
|
|
max_os +
|
2017-12-14 19:02:29 +01:00
|
|
|
max_version_id + 5 + STRLEN(",\n")),
|
2016-08-31 20:06:57 +02:00
|
|
|
",\n");
|
|
|
|
if (r < 0) {
|
|
|
|
r = log_oom();
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2016-08-01 17:39:27 +02:00
|
|
|
if (arg_legend && n_machines > 0)
|
2016-08-31 20:06:57 +02:00
|
|
|
printf("%-*s %-*s %-*s %-*s %-*s %s\n",
|
2015-01-07 19:13:48 +01:00
|
|
|
(int) max_name, "MACHINE",
|
|
|
|
(int) max_class, "CLASS",
|
2016-08-21 05:39:07 +02:00
|
|
|
(int) max_service, "SERVICE",
|
2016-08-31 20:06:57 +02:00
|
|
|
(int) max_os, "OS",
|
|
|
|
(int) max_version_id, "VERSION",
|
|
|
|
"ADDRESSES");
|
2015-01-07 19:13:48 +01:00
|
|
|
|
2016-08-31 20:06:57 +02:00
|
|
|
for (j = 0; j < n_machines; j++) {
|
|
|
|
printf("%-*s %-*s %-*s %-*s %-*s ",
|
2015-01-07 19:13:48 +01:00
|
|
|
(int) max_name, machines[j].name,
|
|
|
|
(int) max_class, machines[j].class,
|
2016-08-31 20:06:57 +02:00
|
|
|
(int) max_service, strdash_if_empty(machines[j].service),
|
|
|
|
(int) max_os, strdash_if_empty(machines[j].os),
|
|
|
|
(int) max_version_id, strdash_if_empty(machines[j].version_id));
|
|
|
|
|
|
|
|
r = print_addresses(bus, machines[j].name, 0, "", prefix, arg_addrs);
|
2017-02-13 17:23:58 +01:00
|
|
|
if (r <= 0) /* error or no addresses defined? */
|
|
|
|
fputs("-\n", stdout);
|
|
|
|
else
|
|
|
|
fputc('\n', stdout);
|
2016-08-31 20:06:57 +02:00
|
|
|
}
|
2015-01-07 19:13:48 +01:00
|
|
|
|
2016-11-06 15:19:57 +01:00
|
|
|
if (arg_legend) {
|
|
|
|
if (n_machines > 0)
|
|
|
|
printf("\n%zu machines listed.\n", n_machines);
|
|
|
|
else
|
|
|
|
printf("No machines.\n");
|
|
|
|
}
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2017-03-14 22:38:19 +01:00
|
|
|
r = 0;
|
2016-08-21 05:39:07 +02:00
|
|
|
out:
|
|
|
|
clean_machine_info(machines, n_machines);
|
|
|
|
return r;
|
2013-07-02 03:47:23 +02:00
|
|
|
}
|
|
|
|
|
2014-12-19 18:42:50 +01:00
|
|
|
typedef struct ImageInfo {
|
|
|
|
const char *name;
|
|
|
|
const char *type;
|
|
|
|
bool read_only;
|
2014-12-25 03:19:19 +01:00
|
|
|
usec_t crtime;
|
|
|
|
usec_t mtime;
|
2014-12-28 02:05:28 +01:00
|
|
|
uint64_t size;
|
2014-12-19 18:42:50 +01:00
|
|
|
} ImageInfo;
|
|
|
|
|
|
|
|
static int compare_image_info(const void *a, const void *b) {
|
|
|
|
const ImageInfo *x = a, *y = b;
|
|
|
|
|
|
|
|
return strcmp(x->name, y->name);
|
|
|
|
}
|
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
static int list_images(int argc, char *argv[], void *userdata) {
|
2014-12-19 18:42:50 +01:00
|
|
|
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2017-12-14 19:02:29 +01:00
|
|
|
size_t max_name = STRLEN("NAME"), max_type = STRLEN("TYPE"), max_size = STRLEN("USAGE"), max_crtime = STRLEN("CREATED"), max_mtime = STRLEN("MODIFIED");
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
2014-12-19 18:42:50 +01:00
|
|
|
_cleanup_free_ ImageInfo *images = NULL;
|
|
|
|
size_t n_images = 0, n_allocated = 0, j;
|
|
|
|
const char *name, *type, *object;
|
2014-12-19 19:19:05 +01:00
|
|
|
sd_bus *bus = userdata;
|
2014-12-28 02:05:28 +01:00
|
|
|
uint64_t crtime, mtime, size;
|
2014-12-25 03:19:19 +01:00
|
|
|
int read_only, r;
|
2014-12-19 18:42:50 +01:00
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
assert(bus);
|
|
|
|
|
2018-03-14 09:48:29 +01:00
|
|
|
(void) pager_open(arg_no_pager, false);
|
2014-12-19 18:42:50 +01:00
|
|
|
|
2016-04-06 05:03:46 +02:00
|
|
|
r = sd_bus_call_method(bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
|
|
|
"ListImages",
|
|
|
|
&error,
|
|
|
|
&reply,
|
|
|
|
"");
|
2014-12-19 18:42:50 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_error("Could not get images: %s", bus_error_message(&error, -r));
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-12-28 02:05:28 +01:00
|
|
|
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssbttto)");
|
2014-12-19 18:42:50 +01:00
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
2014-12-28 02:05:28 +01:00
|
|
|
while ((r = sd_bus_message_read(reply, "(ssbttto)", &name, &type, &read_only, &crtime, &mtime, &size, &object)) > 0) {
|
|
|
|
char buf[MAX(FORMAT_TIMESTAMP_MAX, FORMAT_BYTES_MAX)];
|
2014-12-25 03:19:19 +01:00
|
|
|
size_t l;
|
2014-12-19 18:42:50 +01:00
|
|
|
|
|
|
|
if (name[0] == '.' && !arg_all)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!GREEDY_REALLOC(images, n_allocated, n_images + 1))
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
images[n_images].name = name;
|
|
|
|
images[n_images].type = type;
|
|
|
|
images[n_images].read_only = read_only;
|
2014-12-25 03:19:19 +01:00
|
|
|
images[n_images].crtime = crtime;
|
|
|
|
images[n_images].mtime = mtime;
|
2014-12-28 02:05:28 +01:00
|
|
|
images[n_images].size = size;
|
2014-12-25 03:19:19 +01:00
|
|
|
|
|
|
|
l = strlen(name);
|
|
|
|
if (l > max_name)
|
|
|
|
max_name = l;
|
2014-12-19 18:42:50 +01:00
|
|
|
|
2014-12-25 03:19:19 +01:00
|
|
|
l = strlen(type);
|
|
|
|
if (l > max_type)
|
|
|
|
max_type = l;
|
2014-12-19 18:42:50 +01:00
|
|
|
|
2014-12-25 03:19:19 +01:00
|
|
|
if (crtime != 0) {
|
2014-12-28 02:05:28 +01:00
|
|
|
l = strlen(strna(format_timestamp(buf, sizeof(buf), crtime)));
|
2014-12-25 03:19:19 +01:00
|
|
|
if (l > max_crtime)
|
|
|
|
max_crtime = l;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mtime != 0) {
|
2014-12-28 02:05:28 +01:00
|
|
|
l = strlen(strna(format_timestamp(buf, sizeof(buf), mtime)));
|
2014-12-25 03:19:19 +01:00
|
|
|
if (l > max_mtime)
|
|
|
|
max_mtime = l;
|
|
|
|
}
|
2014-12-19 18:42:50 +01:00
|
|
|
|
2014-12-28 02:05:28 +01:00
|
|
|
if (size != (uint64_t) -1) {
|
|
|
|
l = strlen(strna(format_bytes(buf, sizeof(buf), size)));
|
|
|
|
if (l > max_size)
|
|
|
|
max_size = l;
|
|
|
|
}
|
|
|
|
|
2014-12-19 18:42:50 +01:00
|
|
|
n_images++;
|
|
|
|
}
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_exit_container(reply);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
|
|
qsort_safe(images, n_images, sizeof(ImageInfo), compare_image_info);
|
|
|
|
|
2016-08-01 17:39:27 +02:00
|
|
|
if (arg_legend && n_images > 0)
|
2014-12-28 02:05:28 +01:00
|
|
|
printf("%-*s %-*s %-3s %-*s %-*s %-*s\n",
|
2014-12-25 03:19:19 +01:00
|
|
|
(int) max_name, "NAME",
|
|
|
|
(int) max_type, "TYPE",
|
|
|
|
"RO",
|
2015-01-19 17:01:15 +01:00
|
|
|
(int) max_size, "USAGE",
|
2014-12-25 03:19:19 +01:00
|
|
|
(int) max_crtime, "CREATED",
|
|
|
|
(int) max_mtime, "MODIFIED");
|
2014-12-19 18:42:50 +01:00
|
|
|
|
|
|
|
for (j = 0; j < n_images; j++) {
|
2014-12-28 02:05:28 +01:00
|
|
|
char crtime_buf[FORMAT_TIMESTAMP_MAX], mtime_buf[FORMAT_TIMESTAMP_MAX], size_buf[FORMAT_BYTES_MAX];
|
2014-12-25 03:19:19 +01:00
|
|
|
|
2014-12-28 02:05:28 +01:00
|
|
|
printf("%-*s %-*s %s%-3s%s %-*s %-*s %-*s\n",
|
2014-12-19 18:42:50 +01:00
|
|
|
(int) max_name, images[j].name,
|
|
|
|
(int) max_type, images[j].type,
|
2015-09-19 00:45:05 +02:00
|
|
|
images[j].read_only ? ansi_highlight_red() : "", yes_no(images[j].read_only), images[j].read_only ? ansi_normal() : "",
|
2014-12-28 02:05:28 +01:00
|
|
|
(int) max_size, strna(format_bytes(size_buf, sizeof(size_buf), images[j].size)),
|
|
|
|
(int) max_crtime, strna(format_timestamp(crtime_buf, sizeof(crtime_buf), images[j].crtime)),
|
|
|
|
(int) max_mtime, strna(format_timestamp(mtime_buf, sizeof(mtime_buf), images[j].mtime)));
|
2014-12-19 18:42:50 +01:00
|
|
|
}
|
|
|
|
|
2016-11-06 15:19:57 +01:00
|
|
|
if (arg_legend) {
|
|
|
|
if (n_images > 0)
|
|
|
|
printf("\n%zu images listed.\n", n_images);
|
|
|
|
else
|
|
|
|
printf("No images.\n");
|
|
|
|
}
|
2014-12-19 18:42:50 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-02-11 17:15:38 +01:00
|
|
|
static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
|
2017-02-01 20:30:57 +01:00
|
|
|
_cleanup_free_ char *cgroup = NULL;
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2015-01-08 15:09:12 +01:00
|
|
|
int r;
|
2013-07-11 00:27:54 +02:00
|
|
|
unsigned c;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
assert(unit);
|
|
|
|
|
2017-02-01 20:30:57 +01:00
|
|
|
r = show_cgroup_get_unit_path_and_warn(bus, unit, &cgroup);
|
2016-04-20 15:51:33 +02:00
|
|
|
if (r < 0)
|
2017-02-01 20:30:57 +01:00
|
|
|
return r;
|
2013-07-11 00:27:54 +02:00
|
|
|
|
2016-04-20 15:51:33 +02:00
|
|
|
if (isempty(cgroup))
|
2013-07-11 19:14:38 +02:00
|
|
|
return 0;
|
|
|
|
|
2013-07-11 00:27:54 +02:00
|
|
|
c = columns();
|
|
|
|
if (c > 18)
|
|
|
|
c -= 18;
|
|
|
|
else
|
|
|
|
c = 0;
|
|
|
|
|
2016-04-20 15:51:33 +02:00
|
|
|
r = unit_show_processes(bus, unit, cgroup, "\t\t ", c, get_output_flags(), &error);
|
|
|
|
if (r == -EBADR) {
|
|
|
|
|
|
|
|
if (arg_transport == BUS_TRANSPORT_REMOTE)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
|
|
|
|
|
|
|
|
if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
|
|
|
|
return 0;
|
|
|
|
|
2016-04-20 16:06:58 +02:00
|
|
|
show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, &leader, leader > 0, get_output_flags());
|
2016-04-20 15:51:33 +02:00
|
|
|
} else if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to dump process list: %s", bus_error_message(&error, r));
|
|
|
|
|
2013-07-11 00:27:54 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-08-31 20:06:57 +02:00
|
|
|
static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *prefix, const char *prefix2, int n_addr) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
2016-08-31 20:06:57 +02:00
|
|
|
_cleanup_free_ char *addresses = NULL;
|
|
|
|
bool truncate = false;
|
2017-02-13 17:23:58 +01:00
|
|
|
unsigned n = 0;
|
2014-05-18 13:48:53 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
assert(name);
|
|
|
|
assert(prefix);
|
|
|
|
assert(prefix2);
|
|
|
|
|
|
|
|
r = sd_bus_call_method(bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
|
|
|
"GetMachineAddresses",
|
|
|
|
NULL,
|
|
|
|
&reply,
|
|
|
|
"s", name);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-08-31 20:06:57 +02:00
|
|
|
addresses = strdup(prefix);
|
|
|
|
if (!addresses)
|
|
|
|
return log_oom();
|
|
|
|
prefix = "";
|
|
|
|
|
2014-07-18 16:09:30 +02:00
|
|
|
r = sd_bus_message_enter_container(reply, 'a', "(iay)");
|
2014-05-18 13:48:53 +02:00
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
2014-07-18 16:09:30 +02:00
|
|
|
while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
|
|
|
|
int family;
|
2014-05-18 13:48:53 +02:00
|
|
|
const void *a;
|
|
|
|
size_t sz;
|
2016-08-31 20:06:57 +02:00
|
|
|
char buf_ifi[DECIMAL_STR_MAX(int) + 2], buffer[MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)];
|
2014-05-18 13:48:53 +02:00
|
|
|
|
2014-07-18 16:09:30 +02:00
|
|
|
r = sd_bus_message_read(reply, "i", &family);
|
2014-05-18 13:48:53 +02:00
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_read_array(reply, 'y', &a, &sz);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
2016-08-31 20:06:57 +02:00
|
|
|
if (n_addr != 0) {
|
|
|
|
if (family == AF_INET6 && ifi > 0)
|
|
|
|
xsprintf(buf_ifi, "%%%i", ifi);
|
|
|
|
else
|
|
|
|
strcpy(buf_ifi, "");
|
|
|
|
|
2017-02-13 17:23:58 +01:00
|
|
|
if (!strextend(&addresses, prefix, inet_ntop(family, a, buffer, sizeof(buffer)), buf_ifi, NULL))
|
2016-08-31 20:06:57 +02:00
|
|
|
return log_oom();
|
|
|
|
} else
|
|
|
|
truncate = true;
|
2014-05-18 13:48:53 +02:00
|
|
|
|
|
|
|
r = sd_bus_message_exit_container(reply);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
|
|
if (prefix != prefix2)
|
|
|
|
prefix = prefix2;
|
2016-08-31 20:06:57 +02:00
|
|
|
|
|
|
|
if (n_addr > 0)
|
|
|
|
n_addr -= 1;
|
2017-02-13 17:23:58 +01:00
|
|
|
|
|
|
|
n++;
|
2014-05-18 13:48:53 +02:00
|
|
|
}
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_exit_container(reply);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
2017-02-13 17:23:58 +01:00
|
|
|
if (n > 0)
|
|
|
|
fprintf(stdout, "%s%s", addresses, truncate ? "..." : "");
|
|
|
|
|
|
|
|
return (int) n;
|
2014-05-18 13:48:53 +02:00
|
|
|
}
|
|
|
|
|
2016-12-01 23:24:20 +01:00
|
|
|
static int print_os_release(sd_bus *bus, const char *method, const char *name, const char *prefix) {
|
2016-08-21 05:39:07 +02:00
|
|
|
_cleanup_free_ char *pretty = NULL;
|
2014-07-03 17:50:55 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
assert(name);
|
|
|
|
assert(prefix);
|
|
|
|
|
2016-12-01 23:24:20 +01:00
|
|
|
r = call_get_os_release(bus, method, name, "PRETTY_NAME\0", &pretty, NULL);
|
2014-07-03 17:50:55 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (pretty)
|
|
|
|
printf("%s%s\n", prefix, pretty);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-02-10 19:44:09 +01:00
|
|
|
static int print_uid_shift(sd_bus *bus, const char *name) {
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
|
|
|
uint32_t shift;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
assert(name);
|
|
|
|
|
|
|
|
r = sd_bus_call_method(bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
|
|
|
"GetMachineUIDShift",
|
|
|
|
&error,
|
|
|
|
&reply,
|
|
|
|
"s", name);
|
|
|
|
if (r < 0)
|
|
|
|
return log_debug_errno(r, "Failed to query UID/GID shift: %s", bus_error_message(&error, r));
|
|
|
|
|
|
|
|
r = sd_bus_message_read(reply, "u", &shift);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (shift == 0) /* Don't show trivial mappings */
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
printf(" UID Shift: %" PRIu32 "\n", shift);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-02 03:47:23 +02:00
|
|
|
typedef struct MachineStatusInfo {
|
2018-03-19 15:46:29 +01:00
|
|
|
const char *name;
|
2013-07-02 03:47:23 +02:00
|
|
|
sd_id128_t id;
|
2018-03-19 15:46:29 +01:00
|
|
|
const char *class;
|
|
|
|
const char *service;
|
|
|
|
const char *unit;
|
|
|
|
const char *root_directory;
|
2013-07-02 03:47:23 +02:00
|
|
|
pid_t leader;
|
2015-01-08 15:09:12 +01:00
|
|
|
struct dual_timestamp timestamp;
|
2014-07-10 23:12:32 +02:00
|
|
|
int *netif;
|
|
|
|
unsigned n_netif;
|
2013-07-02 03:47:23 +02:00
|
|
|
} MachineStatusInfo;
|
|
|
|
|
2015-06-14 15:08:52 +02:00
|
|
|
static void machine_status_info_clear(MachineStatusInfo *info) {
|
|
|
|
if (info) {
|
|
|
|
free(info->netif);
|
|
|
|
zero(*info);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-12 14:19:22 +02:00
|
|
|
static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
|
2013-07-02 03:47:23 +02:00
|
|
|
char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
|
|
|
|
char since2[FORMAT_TIMESTAMP_MAX], *s2;
|
2014-07-10 23:12:32 +02:00
|
|
|
int ifi = -1;
|
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
assert(bus);
|
2013-07-02 03:47:23 +02:00
|
|
|
assert(i);
|
|
|
|
|
|
|
|
fputs(strna(i->name), stdout);
|
|
|
|
|
2016-07-21 16:06:31 +02:00
|
|
|
if (!sd_id128_is_null(i->id))
|
2013-07-02 03:47:23 +02:00
|
|
|
printf("(" SD_ID128_FORMAT_STR ")\n", SD_ID128_FORMAT_VAL(i->id));
|
|
|
|
else
|
|
|
|
putchar('\n');
|
|
|
|
|
2015-01-08 15:09:12 +01:00
|
|
|
s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp.realtime);
|
|
|
|
s2 = format_timestamp(since2, sizeof(since2), i->timestamp.realtime);
|
2013-07-02 03:47:23 +02:00
|
|
|
|
|
|
|
if (s1)
|
|
|
|
printf("\t Since: %s; %s\n", s2, s1);
|
|
|
|
else if (s2)
|
|
|
|
printf("\t Since: %s\n", s2);
|
|
|
|
|
|
|
|
if (i->leader > 0) {
|
|
|
|
_cleanup_free_ char *t = NULL;
|
|
|
|
|
|
|
|
printf("\t Leader: %u", (unsigned) i->leader);
|
|
|
|
|
|
|
|
get_process_comm(i->leader, &t);
|
|
|
|
if (t)
|
|
|
|
printf(" (%s)", t);
|
|
|
|
|
|
|
|
putchar('\n');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i->service) {
|
|
|
|
printf("\t Service: %s", i->service);
|
|
|
|
|
|
|
|
if (i->class)
|
|
|
|
printf("; class %s", i->class);
|
|
|
|
|
|
|
|
putchar('\n');
|
|
|
|
} else if (i->class)
|
|
|
|
printf("\t Class: %s\n", i->class);
|
|
|
|
|
|
|
|
if (i->root_directory)
|
|
|
|
printf("\t Root: %s\n", i->root_directory);
|
|
|
|
|
2014-07-10 23:12:32 +02:00
|
|
|
if (i->n_netif > 0) {
|
|
|
|
unsigned c;
|
|
|
|
|
|
|
|
fputs("\t Iface:", stdout);
|
|
|
|
|
|
|
|
for (c = 0; c < i->n_netif; c++) {
|
|
|
|
char name[IF_NAMESIZE+1] = "";
|
|
|
|
|
|
|
|
if (if_indextoname(i->netif[c], name)) {
|
|
|
|
fputc(' ', stdout);
|
|
|
|
fputs(name, stdout);
|
|
|
|
|
|
|
|
if (ifi < 0)
|
|
|
|
ifi = i->netif[c];
|
|
|
|
else
|
|
|
|
ifi = 0;
|
|
|
|
} else
|
|
|
|
printf(" %i", i->netif[c]);
|
|
|
|
}
|
|
|
|
|
|
|
|
fputc('\n', stdout);
|
|
|
|
}
|
|
|
|
|
2017-02-13 17:23:58 +01:00
|
|
|
if (print_addresses(bus, i->name, ifi,
|
|
|
|
"\t Address: ",
|
|
|
|
"\n\t ",
|
|
|
|
ALL_IP_ADDRESSES) > 0)
|
|
|
|
fputc('\n', stdout);
|
2014-05-18 13:48:53 +02:00
|
|
|
|
2016-12-01 23:24:20 +01:00
|
|
|
print_os_release(bus, "GetMachineOSRelease", i->name, "\t OS: ");
|
2014-07-03 17:50:55 +02:00
|
|
|
|
2017-02-10 19:44:09 +01:00
|
|
|
print_uid_shift(bus, i->name);
|
|
|
|
|
2014-02-11 17:15:38 +01:00
|
|
|
if (i->unit) {
|
|
|
|
printf("\t Unit: %s\n", i->unit);
|
|
|
|
show_unit_cgroup(bus, i->unit, i->leader);
|
2015-01-08 15:09:12 +01:00
|
|
|
|
2015-09-08 23:03:38 +02:00
|
|
|
if (arg_transport == BUS_TRANSPORT_LOCAL)
|
2015-01-08 15:09:12 +01:00
|
|
|
|
|
|
|
show_journal_by_unit(
|
|
|
|
stdout,
|
|
|
|
i->unit,
|
|
|
|
arg_output,
|
|
|
|
0,
|
|
|
|
i->timestamp.monotonic,
|
|
|
|
arg_lines,
|
|
|
|
0,
|
|
|
|
get_output_flags() | OUTPUT_BEGIN_NEWLINE,
|
|
|
|
SD_JOURNAL_LOCAL_ONLY,
|
|
|
|
true,
|
|
|
|
NULL);
|
2013-07-02 03:47:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-10 23:12:32 +02:00
|
|
|
static int map_netif(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
|
|
|
MachineStatusInfo *i = userdata;
|
|
|
|
size_t l;
|
|
|
|
const void *v;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_cc(sizeof(int32_t) == sizeof(int));
|
|
|
|
r = sd_bus_message_read_array(m, SD_BUS_TYPE_INT32, &v, &l);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-07-19 03:44:58 +02:00
|
|
|
if (r == 0)
|
|
|
|
return -EBADMSG;
|
2014-07-10 23:12:32 +02:00
|
|
|
|
|
|
|
i->n_netif = l / sizeof(int32_t);
|
|
|
|
i->netif = memdup(v, l);
|
|
|
|
if (!i->netif)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-26 20:09:04 +01:00
|
|
|
static int show_machine_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
|
2013-11-08 00:49:44 +01:00
|
|
|
|
2013-11-05 02:57:49 +01:00
|
|
|
static const struct bus_properties_map map[] = {
|
2015-01-08 15:09:12 +01:00
|
|
|
{ "Name", "s", NULL, offsetof(MachineStatusInfo, name) },
|
|
|
|
{ "Class", "s", NULL, offsetof(MachineStatusInfo, class) },
|
|
|
|
{ "Service", "s", NULL, offsetof(MachineStatusInfo, service) },
|
|
|
|
{ "Unit", "s", NULL, offsetof(MachineStatusInfo, unit) },
|
|
|
|
{ "RootDirectory", "s", NULL, offsetof(MachineStatusInfo, root_directory) },
|
|
|
|
{ "Leader", "u", NULL, offsetof(MachineStatusInfo, leader) },
|
|
|
|
{ "Timestamp", "t", NULL, offsetof(MachineStatusInfo, timestamp.realtime) },
|
|
|
|
{ "TimestampMonotonic", "t", NULL, offsetof(MachineStatusInfo, timestamp.monotonic) },
|
|
|
|
{ "Id", "ay", bus_map_id128, offsetof(MachineStatusInfo, id) },
|
|
|
|
{ "NetworkInterfaces", "ai", map_netif, 0 },
|
2013-11-05 02:57:49 +01:00
|
|
|
{}
|
|
|
|
};
|
2013-11-08 00:49:44 +01:00
|
|
|
|
2017-02-08 17:59:58 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2018-03-19 15:46:29 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
2015-06-14 15:08:52 +02:00
|
|
|
_cleanup_(machine_status_info_clear) MachineStatusInfo info = {};
|
2013-08-12 14:19:22 +02:00
|
|
|
int r;
|
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
assert(verb);
|
|
|
|
assert(bus);
|
2013-07-02 03:47:23 +02:00
|
|
|
assert(path);
|
|
|
|
assert(new_line);
|
|
|
|
|
2013-11-05 02:57:49 +01:00
|
|
|
r = bus_map_all_properties(bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
path,
|
|
|
|
map,
|
2017-02-08 17:59:58 +01:00
|
|
|
&error,
|
2018-03-19 15:46:29 +01:00
|
|
|
&m,
|
2013-11-05 02:57:49 +01:00
|
|
|
&info);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2017-02-08 17:59:58 +01:00
|
|
|
return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
|
2013-07-02 03:47:23 +02:00
|
|
|
|
|
|
|
if (*new_line)
|
|
|
|
printf("\n");
|
|
|
|
*new_line = true;
|
|
|
|
|
2013-11-05 02:57:49 +01:00
|
|
|
print_machine_status_info(bus, &info);
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2013-11-05 02:57:49 +01:00
|
|
|
return r;
|
|
|
|
}
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2014-12-26 20:09:04 +01:00
|
|
|
static int show_machine_properties(sd_bus *bus, const char *path, bool *new_line) {
|
2013-11-05 02:57:49 +01:00
|
|
|
int r;
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
assert(bus);
|
|
|
|
assert(path);
|
|
|
|
assert(new_line);
|
|
|
|
|
2013-11-05 02:57:49 +01:00
|
|
|
if (*new_line)
|
|
|
|
printf("\n");
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2013-11-05 02:57:49 +01:00
|
|
|
*new_line = true;
|
2013-08-12 14:19:22 +02:00
|
|
|
|
2016-04-06 04:44:42 +02:00
|
|
|
r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_value, arg_all);
|
2013-08-12 14:19:22 +02:00
|
|
|
if (r < 0)
|
2014-11-28 13:19:16 +01:00
|
|
|
log_error_errno(r, "Could not get properties: %m");
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2013-10-30 15:34:50 +01:00
|
|
|
return r;
|
2013-07-02 03:47:23 +02:00
|
|
|
}
|
|
|
|
|
2014-12-26 20:09:04 +01:00
|
|
|
static int show_machine(int argc, char *argv[], void *userdata) {
|
2014-12-19 19:19:05 +01:00
|
|
|
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
2013-11-05 02:57:49 +01:00
|
|
|
bool properties, new_line = false;
|
2014-12-19 19:19:05 +01:00
|
|
|
sd_bus *bus = userdata;
|
|
|
|
int r = 0, i;
|
2013-07-02 03:47:23 +02:00
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
properties = !strstr(argv[0], "status");
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2018-03-14 09:48:29 +01:00
|
|
|
(void) pager_open(arg_no_pager, false);
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
if (properties && argc <= 1) {
|
2013-08-12 14:19:22 +02:00
|
|
|
|
2013-11-05 02:57:49 +01:00
|
|
|
/* If no argument is specified, inspect the manager
|
2013-07-02 03:47:23 +02:00
|
|
|
* itself */
|
2014-12-26 20:09:04 +01:00
|
|
|
r = show_machine_properties(bus, "/org/freedesktop/machine1", &new_line);
|
2013-12-17 23:40:15 +01:00
|
|
|
if (r < 0)
|
2013-11-05 02:57:49 +01:00
|
|
|
return r;
|
2013-07-02 03:47:23 +02:00
|
|
|
}
|
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
for (i = 1; i < argc; i++) {
|
2013-07-02 03:47:23 +02:00
|
|
|
const char *path = NULL;
|
|
|
|
|
2016-04-06 05:03:46 +02:00
|
|
|
r = sd_bus_call_method(bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
|
|
|
"GetMachine",
|
|
|
|
&error,
|
|
|
|
&reply,
|
|
|
|
"s", argv[i]);
|
2013-08-12 14:19:22 +02:00
|
|
|
if (r < 0) {
|
|
|
|
log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_bus_message_read(reply, "o", &path);
|
2013-11-07 21:26:31 +01:00
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2013-11-05 02:57:49 +01:00
|
|
|
if (properties)
|
2014-12-26 20:09:04 +01:00
|
|
|
r = show_machine_properties(bus, path, &new_line);
|
2013-11-05 02:57:49 +01:00
|
|
|
else
|
2014-12-26 20:09:04 +01:00
|
|
|
r = show_machine_info(argv[0], bus, path, &new_line);
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2017-11-14 23:28:57 +01:00
|
|
|
static int print_image_hostname(sd_bus *bus, const char *name) {
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
|
|
|
const char *hn;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
|
|
|
"GetImageHostname",
|
|
|
|
NULL, &reply, "s", name);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_bus_message_read(reply, "s", &hn);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (!isempty(hn))
|
|
|
|
printf("\tHostname: %s\n", hn);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int print_image_machine_id(sd_bus *bus, const char *name) {
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
|
|
|
sd_id128_t id = SD_ID128_NULL;
|
|
|
|
const void *p;
|
|
|
|
size_t size;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
|
|
|
"GetImageMachineID",
|
|
|
|
NULL, &reply, "s", name);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_bus_message_read_array(reply, 'y', &p, &size);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (size == sizeof(sd_id128_t))
|
|
|
|
memcpy(&id, p, size);
|
|
|
|
|
|
|
|
if (!sd_id128_is_null(id))
|
|
|
|
printf(" Machine ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(id));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int print_image_machine_info(sd_bus *bus, const char *name) {
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
|
|
|
"GetImageMachineInfo",
|
|
|
|
NULL, &reply, "s", name);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_bus_message_enter_container(reply, 'a', "{ss}");
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
const char *p, *q;
|
|
|
|
|
|
|
|
r = sd_bus_message_read(reply, "{ss}", &p, &q);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (streq(p, "DEPLOYMENT"))
|
|
|
|
printf(" Deployment: %s\n", q);
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_bus_message_exit_container(reply);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-26 20:09:04 +01:00
|
|
|
typedef struct ImageStatusInfo {
|
2018-03-19 15:46:29 +01:00
|
|
|
const char *name;
|
|
|
|
const char *path;
|
|
|
|
const char *type;
|
|
|
|
bool read_only;
|
2014-12-26 20:09:04 +01:00
|
|
|
usec_t crtime;
|
|
|
|
usec_t mtime;
|
2015-01-19 17:01:15 +01:00
|
|
|
uint64_t usage;
|
2014-12-28 02:05:28 +01:00
|
|
|
uint64_t limit;
|
2015-01-19 17:01:15 +01:00
|
|
|
uint64_t usage_exclusive;
|
2014-12-28 02:05:28 +01:00
|
|
|
uint64_t limit_exclusive;
|
2014-12-26 20:09:04 +01:00
|
|
|
} 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;
|
2014-12-28 02:05:28 +01:00
|
|
|
char bs[FORMAT_BYTES_MAX], *s3;
|
|
|
|
char bs_exclusive[FORMAT_BYTES_MAX], *s4;
|
2014-12-26 20:09:04 +01:00
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
assert(i);
|
|
|
|
|
|
|
|
if (i->name) {
|
|
|
|
fputs(i->name, stdout);
|
|
|
|
putchar('\n');
|
|
|
|
}
|
|
|
|
|
2015-01-02 20:29:04 +01:00
|
|
|
if (i->type)
|
2014-12-26 20:09:04 +01:00
|
|
|
printf("\t Type: %s\n", i->type);
|
|
|
|
|
|
|
|
if (i->path)
|
|
|
|
printf("\t Path: %s\n", i->path);
|
|
|
|
|
2017-11-14 23:28:57 +01:00
|
|
|
(void) print_image_hostname(bus, i->name);
|
|
|
|
(void) print_image_machine_id(bus, i->name);
|
|
|
|
(void) print_image_machine_info(bus, i->name);
|
|
|
|
|
2016-12-01 23:24:20 +01:00
|
|
|
print_os_release(bus, "GetImageOSRelease", i->name, "\t OS: ");
|
|
|
|
|
2014-12-26 20:09:04 +01:00
|
|
|
printf("\t RO: %s%s%s\n",
|
|
|
|
i->read_only ? ansi_highlight_red() : "",
|
|
|
|
i->read_only ? "read-only" : "writable",
|
2015-09-19 00:45:05 +02:00
|
|
|
i->read_only ? ansi_normal() : "");
|
2014-12-26 20:09:04 +01:00
|
|
|
|
|
|
|
s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->crtime);
|
|
|
|
s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->crtime);
|
2014-12-28 02:05:28 +01:00
|
|
|
if (s1 && s2)
|
2014-12-26 20:09:04 +01:00
|
|
|
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);
|
2014-12-28 02:05:28 +01:00
|
|
|
if (s1 && s2)
|
2014-12-26 20:09:04 +01:00
|
|
|
printf("\tModified: %s; %s\n", s2, s1);
|
|
|
|
else if (s2)
|
|
|
|
printf("\tModified: %s\n", s2);
|
2014-12-28 02:05:28 +01:00
|
|
|
|
2015-01-19 17:01:15 +01:00
|
|
|
s3 = format_bytes(bs, sizeof(bs), i->usage);
|
|
|
|
s4 = i->usage_exclusive != i->usage ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->usage_exclusive) : NULL;
|
2014-12-28 02:05:28 +01:00
|
|
|
if (s3 && s4)
|
2015-01-19 17:01:15 +01:00
|
|
|
printf("\t Usage: %s (exclusive: %s)\n", s3, s4);
|
2014-12-28 02:05:28 +01:00
|
|
|
else if (s3)
|
2015-01-19 17:01:15 +01:00
|
|
|
printf("\t Usage: %s\n", s3);
|
2014-12-28 02:05:28 +01:00
|
|
|
|
|
|
|
s3 = format_bytes(bs, sizeof(bs), i->limit);
|
|
|
|
s4 = i->limit_exclusive != i->limit ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->limit_exclusive) : NULL;
|
|
|
|
if (s3 && s4)
|
|
|
|
printf("\t Limit: %s (exclusive: %s)\n", s3, s4);
|
|
|
|
else if (s3)
|
|
|
|
printf("\t Limit: %s\n", s3);
|
2014-12-26 20:09:04 +01:00
|
|
|
}
|
|
|
|
|
2015-02-24 18:23:40 +01:00
|
|
|
static int show_image_info(sd_bus *bus, const char *path, bool *new_line) {
|
2014-12-26 20:09:04 +01:00
|
|
|
|
|
|
|
static const struct bus_properties_map map[] = {
|
2014-12-28 02:05:28 +01:00
|
|
|
{ "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) },
|
2015-01-19 17:01:15 +01:00
|
|
|
{ "Usage", "t", NULL, offsetof(ImageStatusInfo, usage) },
|
2014-12-28 02:05:28 +01:00
|
|
|
{ "Limit", "t", NULL, offsetof(ImageStatusInfo, limit) },
|
2015-01-19 17:01:15 +01:00
|
|
|
{ "UsageExclusive", "t", NULL, offsetof(ImageStatusInfo, usage_exclusive) },
|
2014-12-28 02:05:28 +01:00
|
|
|
{ "LimitExclusive", "t", NULL, offsetof(ImageStatusInfo, limit_exclusive) },
|
2014-12-26 20:09:04 +01:00
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2017-02-08 17:59:58 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2018-03-19 15:46:29 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
|
|
|
ImageStatusInfo info = {};
|
2014-12-26 20:09:04 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
assert(path);
|
|
|
|
assert(new_line);
|
|
|
|
|
|
|
|
r = bus_map_all_properties(bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
path,
|
|
|
|
map,
|
2017-02-08 17:59:58 +01:00
|
|
|
&error,
|
2018-03-19 15:46:29 +01:00
|
|
|
&m,
|
2014-12-26 20:09:04 +01:00
|
|
|
&info);
|
|
|
|
if (r < 0)
|
2017-02-08 17:59:58 +01:00
|
|
|
return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
|
2014-12-26 20:09:04 +01:00
|
|
|
|
|
|
|
if (*new_line)
|
|
|
|
printf("\n");
|
|
|
|
*new_line = true;
|
|
|
|
|
|
|
|
print_image_status_info(bus, &info);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2015-02-24 18:23:40 +01:00
|
|
|
typedef struct PoolStatusInfo {
|
2018-03-19 15:46:29 +01:00
|
|
|
const char *path;
|
2015-02-24 18:23:40 +01:00
|
|
|
uint64_t usage;
|
|
|
|
uint64_t limit;
|
|
|
|
} PoolStatusInfo;
|
|
|
|
|
|
|
|
static void print_pool_status_info(sd_bus *bus, PoolStatusInfo *i) {
|
|
|
|
char bs[FORMAT_BYTES_MAX], *s;
|
|
|
|
|
|
|
|
if (i->path)
|
|
|
|
printf("\t Path: %s\n", i->path);
|
|
|
|
|
|
|
|
s = format_bytes(bs, sizeof(bs), i->usage);
|
|
|
|
if (s)
|
|
|
|
printf("\t Usage: %s\n", s);
|
|
|
|
|
|
|
|
s = format_bytes(bs, sizeof(bs), i->limit);
|
|
|
|
if (s)
|
|
|
|
printf("\t Limit: %s\n", s);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int show_pool_info(sd_bus *bus) {
|
|
|
|
|
|
|
|
static const struct bus_properties_map map[] = {
|
|
|
|
{ "PoolPath", "s", NULL, offsetof(PoolStatusInfo, path) },
|
|
|
|
{ "PoolUsage", "t", NULL, offsetof(PoolStatusInfo, usage) },
|
|
|
|
{ "PoolLimit", "t", NULL, offsetof(PoolStatusInfo, limit) },
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2018-03-19 15:46:29 +01:00
|
|
|
PoolStatusInfo info = {
|
2015-02-24 18:23:40 +01:00
|
|
|
.usage = (uint64_t) -1,
|
|
|
|
.limit = (uint64_t) -1,
|
|
|
|
};
|
2017-02-08 17:59:58 +01:00
|
|
|
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2018-03-19 15:46:29 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
2015-02-24 18:23:40 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
|
|
|
r = bus_map_all_properties(bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
map,
|
2017-02-08 17:59:58 +01:00
|
|
|
&error,
|
2018-03-19 15:46:29 +01:00
|
|
|
&m,
|
2015-02-24 18:23:40 +01:00
|
|
|
&info);
|
|
|
|
if (r < 0)
|
2017-02-08 17:59:58 +01:00
|
|
|
return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
|
2015-02-24 18:23:40 +01:00
|
|
|
|
|
|
|
print_pool_status_info(bus, &info);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-26 20:09:04 +01:00
|
|
|
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;
|
|
|
|
|
2016-04-06 04:44:42 +02:00
|
|
|
r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_value, arg_all);
|
2014-12-26 20:09:04 +01:00
|
|
|
if (r < 0)
|
|
|
|
log_error_errno(r, "Could not get properties: %m");
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int show_image(int argc, char *argv[], void *userdata) {
|
|
|
|
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
2014-12-26 20:09:04 +01:00
|
|
|
bool properties, new_line = false;
|
|
|
|
sd_bus *bus = userdata;
|
|
|
|
int r = 0, i;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
|
|
|
properties = !strstr(argv[0], "status");
|
|
|
|
|
2018-03-14 09:48:29 +01:00
|
|
|
(void) pager_open(arg_no_pager, false);
|
2014-12-26 20:09:04 +01:00
|
|
|
|
2015-02-24 18:23:40 +01:00
|
|
|
if (argc <= 1) {
|
2014-12-26 20:09:04 +01:00
|
|
|
|
|
|
|
/* If no argument is specified, inspect the manager
|
|
|
|
* itself */
|
2015-02-24 18:23:40 +01:00
|
|
|
|
|
|
|
if (properties)
|
|
|
|
r = show_image_properties(bus, "/org/freedesktop/machine1", &new_line);
|
|
|
|
else
|
|
|
|
r = show_pool_info(bus);
|
2014-12-26 20:09:04 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
|
|
const char *path = NULL;
|
|
|
|
|
|
|
|
r = sd_bus_call_method(
|
2015-02-17 17:19:57 +01:00
|
|
|
bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
|
|
|
"GetImage",
|
|
|
|
&error,
|
|
|
|
&reply,
|
|
|
|
"s", argv[i]);
|
2014-12-26 20:09:04 +01:00
|
|
|
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
|
2015-02-24 18:23:40 +01:00
|
|
|
r = show_image_info(bus, path, &new_line);
|
2013-07-02 03:47:23 +02:00
|
|
|
}
|
|
|
|
|
2013-11-05 02:57:49 +01:00
|
|
|
return r;
|
2013-07-02 03:47:23 +02:00
|
|
|
}
|
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
static int kill_machine(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2014-12-19 19:19:05 +01:00
|
|
|
sd_bus *bus = userdata;
|
2015-02-17 17:19:57 +01:00
|
|
|
int r, i;
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
assert(bus);
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2017-10-30 09:57:53 +01:00
|
|
|
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
2015-01-08 15:23:54 +01:00
|
|
|
|
2013-07-02 03:47:23 +02:00
|
|
|
if (!arg_kill_who)
|
|
|
|
arg_kill_who = "all";
|
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
for (i = 1; i < argc; i++) {
|
2013-08-12 14:19:22 +02:00
|
|
|
r = sd_bus_call_method(
|
2014-12-19 19:19:05 +01:00
|
|
|
bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
|
|
|
"KillMachine",
|
|
|
|
&error,
|
|
|
|
NULL,
|
|
|
|
"ssi", argv[i], arg_kill_who, arg_signal);
|
2013-08-12 14:19:22 +02:00
|
|
|
if (r < 0) {
|
|
|
|
log_error("Could not kill machine: %s", bus_error_message(&error, -r));
|
2013-07-02 03:47:23 +02:00
|
|
|
return r;
|
2013-08-12 14:19:22 +02:00
|
|
|
}
|
2013-07-02 03:47:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
static int reboot_machine(int argc, char *argv[], void *userdata) {
|
2014-03-18 04:44:39 +01:00
|
|
|
arg_kill_who = "leader";
|
|
|
|
arg_signal = SIGINT; /* sysvinit + systemd */
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
return kill_machine(argc, argv, userdata);
|
2014-03-18 04:44:39 +01:00
|
|
|
}
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
static int poweroff_machine(int argc, char *argv[], void *userdata) {
|
2014-03-18 04:44:39 +01:00
|
|
|
arg_kill_who = "leader";
|
|
|
|
arg_signal = SIGRTMIN+4; /* only systemd */
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
return kill_machine(argc, argv, userdata);
|
2013-07-02 03:47:23 +02:00
|
|
|
}
|
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
static int terminate_machine(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2014-12-19 19:19:05 +01:00
|
|
|
sd_bus *bus = userdata;
|
2015-02-18 11:42:03 +01:00
|
|
|
int r, i;
|
2014-02-12 02:07:57 +01:00
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
assert(bus);
|
2014-02-12 02:07:57 +01:00
|
|
|
|
2017-10-30 09:57:53 +01:00
|
|
|
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
2015-01-08 15:23:54 +01:00
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
for (i = 1; i < argc; i++) {
|
2014-02-12 02:07:57 +01:00
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
2014-03-18 04:44:39 +01:00
|
|
|
"TerminateMachine",
|
2014-02-12 02:07:57 +01:00
|
|
|
&error,
|
2014-03-18 04:44:39 +01:00
|
|
|
NULL,
|
2014-12-19 19:19:05 +01:00
|
|
|
"s", argv[i]);
|
2014-02-12 02:07:57 +01:00
|
|
|
if (r < 0) {
|
2014-03-18 04:44:39 +01:00
|
|
|
log_error("Could not terminate machine: %s", bus_error_message(&error, -r));
|
2014-02-12 02:07:57 +01:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-17 19:22:03 +01:00
|
|
|
static int copy_files(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2016-04-29 20:57:39 +02:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
2015-07-31 17:24:09 +02:00
|
|
|
_cleanup_free_ char *abs_host_path = NULL;
|
|
|
|
char *dest, *host_path, *container_path;
|
2015-02-17 19:22:03 +01:00
|
|
|
sd_bus *bus = userdata;
|
|
|
|
bool copy_from;
|
2014-12-17 21:51:45 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(bus);
|
2015-02-17 19:22:03 +01:00
|
|
|
|
2017-10-30 09:57:53 +01:00
|
|
|
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
2015-02-18 11:42:03 +01:00
|
|
|
|
2015-02-17 19:22:03 +01:00
|
|
|
copy_from = streq(argv[0], "copy-from");
|
2015-07-31 17:24:09 +02:00
|
|
|
dest = argv[3] ?: argv[2];
|
|
|
|
host_path = copy_from ? dest : argv[2];
|
|
|
|
container_path = copy_from ? argv[2] : dest;
|
|
|
|
|
|
|
|
if (!path_is_absolute(host_path)) {
|
2015-10-22 19:28:31 +02:00
|
|
|
r = path_make_absolute_cwd(host_path, &abs_host_path);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to make path absolute: %m");
|
|
|
|
|
2015-07-31 17:24:09 +02:00
|
|
|
host_path = abs_host_path;
|
|
|
|
}
|
2014-12-17 21:51:45 +01:00
|
|
|
|
2016-04-29 20:57:39 +02:00
|
|
|
r = sd_bus_message_new_method_call(
|
2014-12-17 21:51:45 +01:00
|
|
|
bus,
|
2016-04-29 20:57:39 +02:00
|
|
|
&m,
|
2014-12-17 21:51:45 +01:00
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
2016-04-29 20:57:39 +02:00
|
|
|
copy_from ? "CopyFromMachine" : "CopyToMachine");
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_append(
|
|
|
|
m,
|
2015-02-17 19:22:03 +01:00
|
|
|
"sss",
|
|
|
|
argv[1],
|
2015-07-31 17:24:09 +02:00
|
|
|
copy_from ? container_path : host_path,
|
|
|
|
copy_from ? host_path : container_path);
|
2016-04-29 20:57:39 +02:00
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
/* This is a slow operation, hence turn off any method call timeouts */
|
|
|
|
r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL);
|
2015-10-22 19:28:31 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to copy: %s", bus_error_message(&error, r));
|
2014-12-18 01:35:58 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
static int bind_mount(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2014-12-19 19:19:05 +01:00
|
|
|
sd_bus *bus = userdata;
|
2014-12-17 21:51:45 +01:00
|
|
|
int r;
|
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
assert(bus);
|
|
|
|
|
2017-10-30 09:57:53 +01:00
|
|
|
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
2015-02-18 11:42:03 +01:00
|
|
|
|
2015-02-17 17:19:57 +01:00
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
|
|
|
"BindMountMachine",
|
|
|
|
&error,
|
|
|
|
NULL,
|
|
|
|
"sssbb",
|
|
|
|
argv[1],
|
|
|
|
argv[2],
|
|
|
|
argv[3],
|
|
|
|
arg_read_only,
|
|
|
|
arg_mkdir);
|
2014-12-17 21:51:45 +01:00
|
|
|
if (r < 0) {
|
2015-02-17 17:19:57 +01:00
|
|
|
log_error("Failed to bind mount: %s", bus_error_message(&error, -r));
|
|
|
|
return r;
|
2014-12-17 21:51:45 +01:00
|
|
|
}
|
|
|
|
|
2015-02-17 17:19:57 +01:00
|
|
|
return 0;
|
2014-12-17 21:51:45 +01:00
|
|
|
}
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
static int on_machine_removed(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
|
2015-01-07 03:08:00 +01:00
|
|
|
PTYForward ** forward = (PTYForward**) userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(forward);
|
|
|
|
|
|
|
|
if (*forward) {
|
|
|
|
/* If the forwarder is already initialized, tell it to
|
2015-01-07 14:46:45 +01:00
|
|
|
* exit on the next vhangup(), so that we still flush
|
|
|
|
* out what might be queued and exit then. */
|
2015-01-07 03:08:00 +01:00
|
|
|
|
2015-01-07 14:46:45 +01:00
|
|
|
r = pty_forward_set_ignore_vhangup(*forward, false);
|
2015-01-07 03:08:00 +01:00
|
|
|
if (r >= 0)
|
|
|
|
return 0;
|
|
|
|
|
2015-01-07 14:46:45 +01:00
|
|
|
log_error_errno(r, "Failed to set ignore_vhangup flag: %m");
|
2015-01-07 03:08:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* On error, or when the forwarder is not initialized yet, quit immediately */
|
2015-04-29 18:35:10 +02:00
|
|
|
sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), EXIT_FAILURE);
|
2015-01-07 03:08:00 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-07 20:10:48 +02:00
|
|
|
static int process_forward(sd_event *event, PTYForward **forward, int master, PTYForwardFlags flags, const char *name) {
|
2015-08-23 13:24:10 +02:00
|
|
|
char last_char = 0;
|
|
|
|
bool machine_died;
|
|
|
|
int ret = 0, r;
|
|
|
|
|
|
|
|
assert(event);
|
|
|
|
assert(master >= 0);
|
|
|
|
assert(name);
|
|
|
|
|
|
|
|
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGWINCH, SIGTERM, SIGINT, -1) >= 0);
|
|
|
|
|
2016-09-22 21:49:22 +02:00
|
|
|
if (!arg_quiet) {
|
|
|
|
if (streq(name, ".host"))
|
|
|
|
log_info("Connected to the local host. Press ^] three times within 1s to exit session.");
|
|
|
|
else
|
|
|
|
log_info("Connected to machine %s. Press ^] three times within 1s to exit session.", name);
|
|
|
|
}
|
2015-08-23 13:24:10 +02:00
|
|
|
|
|
|
|
sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
|
|
|
|
sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
|
|
|
|
|
2015-10-07 20:10:48 +02:00
|
|
|
r = pty_forward_new(event, master, flags, forward);
|
2015-08-23 13:24:10 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to create PTY forwarder: %m");
|
|
|
|
|
|
|
|
r = sd_event_loop(event);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to run event loop: %m");
|
|
|
|
|
|
|
|
pty_forward_get_last_char(*forward, &last_char);
|
|
|
|
|
|
|
|
machine_died =
|
2015-10-07 20:10:48 +02:00
|
|
|
(flags & PTY_FORWARD_IGNORE_VHANGUP) &&
|
2015-08-23 13:24:10 +02:00
|
|
|
pty_forward_get_ignore_vhangup(*forward) == 0;
|
|
|
|
|
|
|
|
*forward = pty_forward_free(*forward);
|
|
|
|
|
|
|
|
if (last_char != '\n')
|
|
|
|
fputc('\n', stdout);
|
|
|
|
|
2016-09-22 21:49:22 +02:00
|
|
|
if (!arg_quiet) {
|
|
|
|
if (machine_died)
|
|
|
|
log_info("Machine %s terminated.", name);
|
|
|
|
else if (streq(name, ".host"))
|
|
|
|
log_info("Connection to the local host terminated.");
|
|
|
|
else
|
|
|
|
log_info("Connection to machine %s terminated.", name);
|
|
|
|
}
|
2015-08-23 13:24:10 +02:00
|
|
|
|
|
|
|
sd_event_get_exit_code(event, &ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-09-26 17:45:31 +02:00
|
|
|
static int parse_machine_uid(const char *spec, const char **machine, char **uid) {
|
|
|
|
/*
|
|
|
|
* Whatever is specified in the spec takes priority over global arguments.
|
|
|
|
*/
|
|
|
|
char *_uid = NULL;
|
|
|
|
const char *_machine = NULL;
|
|
|
|
|
|
|
|
if (spec) {
|
|
|
|
const char *at;
|
|
|
|
|
|
|
|
at = strchr(spec, '@');
|
|
|
|
if (at) {
|
|
|
|
if (at == spec)
|
|
|
|
/* Do the same as ssh and refuse "@host". */
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
_machine = at + 1;
|
|
|
|
_uid = strndup(spec, at - spec);
|
|
|
|
if (!_uid)
|
|
|
|
return -ENOMEM;
|
|
|
|
} else
|
|
|
|
_machine = spec;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (arg_uid && !_uid) {
|
|
|
|
_uid = strdup(arg_uid);
|
|
|
|
if (!_uid)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
*uid = _uid;
|
|
|
|
*machine = isempty(_machine) ? ".host" : _machine;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
static int login_machine(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2014-10-31 16:54:11 +01:00
|
|
|
_cleanup_(pty_forward_freep) PTYForward *forward = NULL;
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL;
|
|
|
|
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
2015-08-23 13:24:10 +02:00
|
|
|
int master = -1, r;
|
2014-12-19 19:19:05 +01:00
|
|
|
sd_bus *bus = userdata;
|
2015-08-24 22:17:52 +02:00
|
|
|
const char *pty, *match, *machine;
|
2013-10-31 01:25:44 +01:00
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
2015-08-23 13:24:10 +02:00
|
|
|
if (!strv_isempty(arg_setenv) || arg_uid) {
|
|
|
|
log_error("--setenv= and --uid= are not supported for 'login'. Use 'shell' instead.");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2017-10-04 16:01:32 +02:00
|
|
|
if (!IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE)) {
|
2014-02-12 02:07:57 +01:00
|
|
|
log_error("Login only supported on local machines.");
|
2015-03-13 14:08:00 +01:00
|
|
|
return -EOPNOTSUPP;
|
2013-10-31 01:25:44 +01:00
|
|
|
}
|
|
|
|
|
2017-10-30 09:57:53 +01:00
|
|
|
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
2015-01-08 15:23:54 +01:00
|
|
|
|
2014-10-31 16:54:11 +01:00
|
|
|
r = sd_event_default(&event);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get event loop: %m");
|
2014-10-31 16:54:11 +01:00
|
|
|
|
|
|
|
r = sd_bus_attach_event(bus, event, 0);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to attach bus to event loop: %m");
|
2014-10-31 16:54:11 +01:00
|
|
|
|
2015-08-24 22:17:52 +02:00
|
|
|
machine = argc < 2 || isempty(argv[1]) ? ".host" : argv[1];
|
|
|
|
|
2015-02-03 02:05:59 +01:00
|
|
|
match = strjoina("type='signal',"
|
2015-08-23 13:24:10 +02:00
|
|
|
"sender='org.freedesktop.machine1',"
|
|
|
|
"path='/org/freedesktop/machine1',",
|
|
|
|
"interface='org.freedesktop.machine1.Manager',"
|
|
|
|
"member='MachineRemoved',"
|
2015-08-24 22:17:52 +02:00
|
|
|
"arg0='", machine, "'");
|
2015-01-07 03:08:00 +01:00
|
|
|
|
2017-12-19 12:29:04 +01:00
|
|
|
r = sd_bus_add_match_async(bus, &slot, match, on_machine_removed, NULL, &forward);
|
2015-01-07 03:08:00 +01:00
|
|
|
if (r < 0)
|
2017-12-19 12:29:04 +01:00
|
|
|
return log_error_errno(r, "Failed to request machine removal match: %m");
|
2015-01-07 03:08:00 +01:00
|
|
|
|
2015-02-18 11:42:03 +01:00
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
|
|
|
"OpenMachineLogin",
|
|
|
|
&error,
|
|
|
|
&reply,
|
2015-08-24 22:17:52 +02:00
|
|
|
"s", machine);
|
2014-12-22 21:17:29 +01:00
|
|
|
if (r < 0) {
|
2015-08-23 13:24:10 +02:00
|
|
|
log_error("Failed to get login PTY: %s", bus_error_message(&error, -r));
|
2014-12-17 21:51:45 +01:00
|
|
|
return r;
|
2014-12-22 21:17:29 +01:00
|
|
|
}
|
2013-10-31 01:25:44 +01:00
|
|
|
|
2014-12-22 21:17:29 +01:00
|
|
|
r = sd_bus_message_read(reply, "hs", &master, &pty);
|
|
|
|
if (r < 0)
|
2014-12-23 01:58:49 +01:00
|
|
|
return bus_log_parse_error(r);
|
2013-10-31 01:25:44 +01:00
|
|
|
|
2015-10-07 20:10:48 +02:00
|
|
|
return process_forward(event, &forward, master, PTY_FORWARD_IGNORE_VHANGUP, machine);
|
2015-08-23 13:24:10 +02:00
|
|
|
}
|
2013-10-31 01:25:44 +01:00
|
|
|
|
2015-08-23 13:24:10 +02:00
|
|
|
static int shell_machine(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2015-08-23 13:24:10 +02:00
|
|
|
_cleanup_(pty_forward_freep) PTYForward *forward = NULL;
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL;
|
|
|
|
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
2015-08-23 13:24:10 +02:00
|
|
|
int master = -1, r;
|
|
|
|
sd_bus *bus = userdata;
|
2016-09-26 17:45:31 +02:00
|
|
|
const char *pty, *match, *machine, *path;
|
|
|
|
_cleanup_free_ char *uid = NULL;
|
2013-10-31 01:25:44 +01:00
|
|
|
|
2015-08-23 13:24:10 +02:00
|
|
|
assert(bus);
|
|
|
|
|
2017-10-04 16:01:32 +02:00
|
|
|
if (!IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE)) {
|
2015-08-23 13:24:10 +02:00
|
|
|
log_error("Shell only supported on local machines.");
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
2015-08-26 10:07:21 +02:00
|
|
|
/* Pass $TERM to shell session, if not explicitly specified. */
|
|
|
|
if (!strv_find_prefix(arg_setenv, "TERM=")) {
|
|
|
|
const char *t;
|
|
|
|
|
|
|
|
t = strv_find_prefix(environ, "TERM=");
|
|
|
|
if (t) {
|
|
|
|
if (strv_extend(&arg_setenv, t) < 0)
|
|
|
|
return log_oom();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-30 09:57:53 +01:00
|
|
|
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
2014-10-31 16:54:11 +01:00
|
|
|
|
2015-08-23 13:24:10 +02:00
|
|
|
r = sd_event_default(&event);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2015-08-23 13:24:10 +02:00
|
|
|
return log_error_errno(r, "Failed to get event loop: %m");
|
2014-10-31 16:54:11 +01:00
|
|
|
|
2015-08-23 13:24:10 +02:00
|
|
|
r = sd_bus_attach_event(bus, event, 0);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2015-08-23 13:24:10 +02:00
|
|
|
return log_error_errno(r, "Failed to attach bus to event loop: %m");
|
2013-10-31 01:25:44 +01:00
|
|
|
|
2016-09-26 17:45:31 +02:00
|
|
|
r = parse_machine_uid(argc >= 2 ? argv[1] : NULL, &machine, &uid);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to parse machine specification: %m");
|
2015-08-24 22:17:52 +02:00
|
|
|
|
2015-08-23 13:24:10 +02:00
|
|
|
match = strjoina("type='signal',"
|
|
|
|
"sender='org.freedesktop.machine1',"
|
|
|
|
"path='/org/freedesktop/machine1',",
|
|
|
|
"interface='org.freedesktop.machine1.Manager',"
|
|
|
|
"member='MachineRemoved',"
|
2015-08-24 22:17:52 +02:00
|
|
|
"arg0='", machine, "'");
|
2014-12-22 20:33:45 +01:00
|
|
|
|
2017-12-19 12:29:04 +01:00
|
|
|
r = sd_bus_add_match_async(bus, &slot, match, on_machine_removed, NULL, &forward);
|
2015-08-23 13:24:10 +02:00
|
|
|
if (r < 0)
|
2017-12-19 12:29:04 +01:00
|
|
|
return log_error_errno(r, "Failed to request machine removal match: %m");
|
2014-10-31 16:54:11 +01:00
|
|
|
|
2015-08-23 13:24:10 +02:00
|
|
|
r = sd_bus_message_new_method_call(
|
|
|
|
bus,
|
|
|
|
&m,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
|
|
|
"OpenMachineShell");
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
2013-10-31 01:25:44 +01:00
|
|
|
|
2015-08-24 22:17:52 +02:00
|
|
|
path = argc < 3 || isempty(argv[2]) ? NULL : argv[2];
|
|
|
|
|
2015-08-24 22:44:54 +02:00
|
|
|
r = sd_bus_message_append(m, "sss", machine, uid, path);
|
2015-08-23 13:24:10 +02:00
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
2013-10-31 01:25:44 +01:00
|
|
|
|
2015-08-24 22:17:52 +02:00
|
|
|
r = sd_bus_message_append_strv(m, strv_length(argv) <= 3 ? NULL : argv + 2);
|
2015-08-23 13:24:10 +02:00
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_append_strv(m, arg_setenv);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_call(bus, m, 0, &error, &reply);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error("Failed to get shell PTY: %s", bus_error_message(&error, -r));
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_bus_message_read(reply, "hs", &master, &pty);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
2015-10-07 23:38:20 +02:00
|
|
|
return process_forward(event, &forward, master, 0, machine);
|
2013-10-31 01:25:44 +01:00
|
|
|
}
|
|
|
|
|
2014-12-27 02:35:47 +01:00
|
|
|
static int remove_image(int argc, char *argv[], void *userdata) {
|
|
|
|
sd_bus *bus = userdata;
|
2014-12-27 17:44:04 +01:00
|
|
|
int r, i;
|
2014-12-27 02:35:47 +01:00
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
2017-10-30 09:57:53 +01:00
|
|
|
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
2015-01-08 15:23:54 +01:00
|
|
|
|
2014-12-27 02:35:47 +01:00
|
|
|
for (i = 1; i < argc; i++) {
|
2016-04-29 20:57:39 +02:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
|
|
|
|
|
|
|
r = sd_bus_message_new_method_call(
|
2014-12-27 02:35:47 +01:00
|
|
|
bus,
|
2016-04-29 20:57:39 +02:00
|
|
|
&m,
|
2014-12-27 02:35:47 +01:00
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
2016-04-29 20:57:39 +02:00
|
|
|
"RemoveImage");
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_append(m, "s", argv[i]);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
/* This is a slow operation, hence turn off any method call timeouts */
|
|
|
|
r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not remove image: %s", bus_error_message(&error, r));
|
2014-12-27 02:35:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-27 17:44:04 +01:00
|
|
|
static int rename_image(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2014-12-27 17:44:04 +01:00
|
|
|
sd_bus *bus = userdata;
|
|
|
|
int r;
|
|
|
|
|
2018-02-03 04:14:32 +01:00
|
|
|
assert(bus);
|
|
|
|
|
2017-10-30 09:57:53 +01:00
|
|
|
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
2015-01-08 15:23:54 +01:00
|
|
|
|
2014-12-27 17:44:04 +01:00
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
|
|
|
"RenameImage",
|
|
|
|
&error,
|
|
|
|
NULL,
|
|
|
|
"ss", argv[1], argv[2]);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error("Could not rename image: %s", bus_error_message(&error, -r));
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int clone_image(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2016-04-29 20:57:39 +02:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
2014-12-27 17:44:04 +01:00
|
|
|
sd_bus *bus = userdata;
|
|
|
|
int r;
|
|
|
|
|
2018-02-03 04:14:32 +01:00
|
|
|
assert(bus);
|
|
|
|
|
2017-10-30 09:57:53 +01:00
|
|
|
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
2015-01-08 15:23:54 +01:00
|
|
|
|
2016-04-29 20:57:39 +02:00
|
|
|
r = sd_bus_message_new_method_call(
|
2014-12-27 17:44:04 +01:00
|
|
|
bus,
|
2016-04-29 20:57:39 +02:00
|
|
|
&m,
|
2014-12-27 17:44:04 +01:00
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
2016-04-29 20:57:39 +02:00
|
|
|
"CloneImage");
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_append(m, "ssb", argv[1], argv[2], arg_read_only);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
/* This is a slow operation, hence turn off any method call timeouts */
|
|
|
|
r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not clone image: %s", bus_error_message(&error, r));
|
2014-12-27 17:44:04 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int read_only_image(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2014-12-27 17:44:04 +01:00
|
|
|
sd_bus *bus = userdata;
|
|
|
|
int b = true, r;
|
|
|
|
|
2018-02-03 04:14:32 +01:00
|
|
|
assert(bus);
|
|
|
|
|
2014-12-27 17:44:04 +01:00
|
|
|
if (argc > 2) {
|
|
|
|
b = parse_boolean(argv[2]);
|
|
|
|
if (b < 0) {
|
|
|
|
log_error("Failed to parse boolean argument: %s", argv[2]);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-30 09:57:53 +01:00
|
|
|
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
2015-01-08 15:23:54 +01:00
|
|
|
|
2014-12-27 17:44:04 +01:00
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
|
|
|
"MarkImageReadOnly",
|
|
|
|
&error,
|
|
|
|
NULL,
|
|
|
|
"sb", argv[1], b);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error("Could not mark image read-only: %s", bus_error_message(&error, -r));
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-06-26 17:41:33 +02:00
|
|
|
static int image_exists(sd_bus *bus, const char *name) {
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
assert(name);
|
|
|
|
|
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
|
|
|
"GetImage",
|
|
|
|
&error,
|
|
|
|
NULL,
|
|
|
|
"s", name);
|
|
|
|
if (r < 0) {
|
|
|
|
if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_IMAGE))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return log_error_errno(r, "Failed to check whether image %s exists: %s", name, bus_error_message(&error, -r));
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-04-30 20:21:00 +02:00
|
|
|
static int make_service_name(const char *name, char **ret) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(name);
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
if (!machine_name_is_valid(name)) {
|
|
|
|
log_error("Invalid machine name %s.", name);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2016-06-22 17:10:52 +02:00
|
|
|
r = unit_name_build("systemd-nspawn", name, ".service", ret);
|
2015-04-30 20:21:00 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to build unit name: %m");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-29 12:41:26 +01:00
|
|
|
static int start_machine(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2014-12-29 12:41:26 +01:00
|
|
|
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
|
|
|
|
sd_bus *bus = userdata;
|
|
|
|
int r, i;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
2017-10-30 09:57:53 +01:00
|
|
|
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
2015-01-08 15:23:54 +01:00
|
|
|
|
2014-12-29 12:41:26 +01:00
|
|
|
r = bus_wait_for_jobs_new(bus, &w);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
for (i = 1; i < argc; i++) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
2015-04-30 20:21:00 +02:00
|
|
|
_cleanup_free_ char *unit = NULL;
|
2014-12-29 12:41:26 +01:00
|
|
|
const char *object;
|
|
|
|
|
2015-04-30 20:21:00 +02:00
|
|
|
r = make_service_name(argv[i], &unit);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-12-29 12:41:26 +01:00
|
|
|
|
2016-06-26 17:41:33 +02:00
|
|
|
r = image_exists(bus, argv[i]);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0) {
|
|
|
|
log_error("Machine image '%s' does not exist.", argv[1]);
|
|
|
|
return -ENXIO;
|
|
|
|
}
|
|
|
|
|
2015-02-18 11:42:03 +01:00
|
|
|
r = sd_bus_call_method(
|
2014-12-29 12:41:26 +01:00
|
|
|
bus,
|
|
|
|
"org.freedesktop.systemd1",
|
|
|
|
"/org/freedesktop/systemd1",
|
|
|
|
"org.freedesktop.systemd1.Manager",
|
2015-02-18 11:42:03 +01:00
|
|
|
"StartUnit",
|
|
|
|
&error,
|
|
|
|
&reply,
|
|
|
|
"ss", unit, "fail");
|
2014-12-29 12:41:26 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_error("Failed to start unit: %s", bus_error_message(&error, -r));
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_bus_message_read(reply, "o", &object);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
|
|
r = bus_wait_for_jobs_add(w, object);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
}
|
|
|
|
|
2015-12-29 06:15:04 +01:00
|
|
|
r = bus_wait_for_jobs(w, arg_quiet, NULL);
|
2014-12-29 12:41:26 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-29 14:05:17 +01:00
|
|
|
static int enable_machine(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2016-05-26 15:57:37 +02:00
|
|
|
UnitFileChange *changes = NULL;
|
|
|
|
unsigned n_changes = 0;
|
2014-12-29 14:05:17 +01:00
|
|
|
int carries_install_info = 0;
|
|
|
|
const char *method = NULL;
|
|
|
|
sd_bus *bus = userdata;
|
|
|
|
int r, i;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
2017-10-30 09:57:53 +01:00
|
|
|
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
2015-01-08 15:23:54 +01:00
|
|
|
|
2014-12-29 14:05:17 +01:00
|
|
|
method = streq(argv[0], "enable") ? "EnableUnitFiles" : "DisableUnitFiles";
|
|
|
|
|
|
|
|
r = sd_bus_message_new_method_call(
|
|
|
|
bus,
|
|
|
|
&m,
|
|
|
|
"org.freedesktop.systemd1",
|
|
|
|
"/org/freedesktop/systemd1",
|
|
|
|
"org.freedesktop.systemd1.Manager",
|
|
|
|
method);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_open_container(m, 'a', "s");
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
for (i = 1; i < argc; i++) {
|
2015-05-06 18:23:11 +02:00
|
|
|
_cleanup_free_ char *unit = NULL;
|
2014-12-29 14:05:17 +01:00
|
|
|
|
2015-04-30 20:21:00 +02:00
|
|
|
r = make_service_name(argv[i], &unit);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-12-29 14:05:17 +01:00
|
|
|
|
2016-06-26 17:41:33 +02:00
|
|
|
r = image_exists(bus, argv[i]);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0) {
|
|
|
|
log_error("Machine image '%s' does not exist.", argv[1]);
|
|
|
|
return -ENXIO;
|
|
|
|
}
|
|
|
|
|
2014-12-29 14:05:17 +01:00
|
|
|
r = sd_bus_message_append(m, "s", unit);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
if (streq(argv[0], "enable"))
|
|
|
|
r = sd_bus_message_append(m, "bb", false, false);
|
|
|
|
else
|
|
|
|
r = sd_bus_message_append(m, "b", false);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_call(bus, m, 0, &error, &reply);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error("Failed to enable or disable unit: %s", bus_error_message(&error, -r));
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (streq(argv[0], "enable")) {
|
|
|
|
r = sd_bus_message_read(reply, "b", carries_install_info);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
}
|
|
|
|
|
2016-05-26 15:57:37 +02:00
|
|
|
r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
|
2014-12-29 14:05:17 +01:00
|
|
|
if (r < 0)
|
2016-05-26 15:57:37 +02:00
|
|
|
goto finish;
|
2014-12-29 14:05:17 +01:00
|
|
|
|
2015-02-18 11:42:03 +01:00
|
|
|
r = sd_bus_call_method(
|
2014-12-29 14:05:17 +01:00
|
|
|
bus,
|
|
|
|
"org.freedesktop.systemd1",
|
|
|
|
"/org/freedesktop/systemd1",
|
|
|
|
"org.freedesktop.systemd1.Manager",
|
2015-02-18 11:42:03 +01:00
|
|
|
"Reload",
|
|
|
|
&error,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
2014-12-29 14:05:17 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_error("Failed to reload daemon: %s", bus_error_message(&error, -r));
|
2016-05-26 15:57:37 +02:00
|
|
|
goto finish;
|
2014-12-29 14:05:17 +01:00
|
|
|
}
|
|
|
|
|
2016-05-26 15:57:37 +02:00
|
|
|
r = 0;
|
|
|
|
|
|
|
|
finish:
|
|
|
|
unit_file_changes_free(changes, n_changes);
|
|
|
|
|
|
|
|
return r;
|
2014-12-29 14:05:17 +01:00
|
|
|
}
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
static int match_log_message(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
2015-01-22 17:31:59 +01:00
|
|
|
const char **our_path = userdata, *line;
|
2015-01-22 03:57:15 +01:00
|
|
|
unsigned priority;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
2015-01-22 17:31:59 +01:00
|
|
|
assert(our_path);
|
2015-01-22 03:57:15 +01:00
|
|
|
|
|
|
|
r = sd_bus_message_read(m, "us", &priority, &line);
|
|
|
|
if (r < 0) {
|
|
|
|
bus_log_parse_error(r);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-01-22 17:31:59 +01:00
|
|
|
if (!streq_ptr(*our_path, sd_bus_message_get_path(m)))
|
2015-01-22 03:57:15 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (arg_quiet && LOG_PRI(priority) >= LOG_INFO)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
log_full(priority, "%s", line);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
static int match_transfer_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
2015-01-22 17:31:59 +01:00
|
|
|
const char **our_path = userdata, *path, *result;
|
2015-01-22 03:57:15 +01:00
|
|
|
uint32_t id;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
2015-01-22 17:31:59 +01:00
|
|
|
assert(our_path);
|
2015-01-22 03:57:15 +01:00
|
|
|
|
|
|
|
r = sd_bus_message_read(m, "uos", &id, &path, &result);
|
|
|
|
if (r < 0) {
|
|
|
|
bus_log_parse_error(r);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-01-22 17:31:59 +01:00
|
|
|
if (!streq_ptr(*our_path, path))
|
2015-01-22 03:57:15 +01:00
|
|
|
return 0;
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), !streq_ptr(result, "done"));
|
2015-01-22 17:31:59 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int transfer_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
|
|
|
|
assert(s);
|
|
|
|
assert(si);
|
|
|
|
|
|
|
|
if (!arg_quiet)
|
2015-01-26 15:29:14 +01:00
|
|
|
log_info("Continuing download in the background. Use \"machinectl cancel-transfer %" PRIu32 "\" to abort transfer.", PTR_TO_UINT32(userdata));
|
2015-01-22 17:31:59 +01:00
|
|
|
|
|
|
|
sd_event_exit(sd_event_source_get_event(s), EINTR);
|
2015-01-22 03:57:15 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-03-09 17:55:07 +01:00
|
|
|
static int transfer_image_common(sd_bus *bus, sd_bus_message *m) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot_job_removed = NULL, *slot_log_message = NULL;
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
|
|
|
_cleanup_(sd_event_unrefp) sd_event* event = NULL;
|
2015-01-22 17:31:59 +01:00
|
|
|
const char *path = NULL;
|
2015-01-22 03:57:15 +01:00
|
|
|
uint32_t id;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
assert(m);
|
|
|
|
|
2017-10-30 09:57:53 +01:00
|
|
|
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
2015-01-22 03:57:15 +01:00
|
|
|
|
2015-01-22 17:31:59 +01:00
|
|
|
r = sd_event_default(&event);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get event loop: %m");
|
|
|
|
|
|
|
|
r = sd_bus_attach_event(bus, event, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to attach bus to event loop: %m");
|
|
|
|
|
2017-12-19 12:29:04 +01:00
|
|
|
r = sd_bus_match_signal_async(
|
2015-01-22 03:57:15 +01:00
|
|
|
bus,
|
|
|
|
&slot_job_removed,
|
2017-12-19 12:29:04 +01:00
|
|
|
"org.freedesktop.import1",
|
|
|
|
"/org/freedesktop/import1",
|
|
|
|
"org.freedesktop.import1.Manager",
|
|
|
|
"TransferRemoved",
|
|
|
|
match_transfer_removed, NULL, &path);
|
2015-01-22 03:57:15 +01:00
|
|
|
if (r < 0)
|
2017-12-19 12:29:04 +01:00
|
|
|
return log_error_errno(r, "Failed to request match: %m");
|
2015-01-22 03:57:15 +01:00
|
|
|
|
2017-12-19 12:29:04 +01:00
|
|
|
r = sd_bus_match_signal_async(
|
2015-01-22 03:57:15 +01:00
|
|
|
bus,
|
|
|
|
&slot_log_message,
|
2017-12-19 12:29:04 +01:00
|
|
|
"org.freedesktop.import1",
|
|
|
|
NULL,
|
|
|
|
"org.freedesktop.import1.Transfer",
|
|
|
|
"LogMessage",
|
|
|
|
match_log_message, NULL, &path);
|
2015-01-22 03:57:15 +01:00
|
|
|
if (r < 0)
|
2017-12-19 12:29:04 +01:00
|
|
|
return log_error_errno(r, "Failed to request match: %m");
|
2015-01-22 03:57:15 +01:00
|
|
|
|
|
|
|
r = sd_bus_call(bus, m, 0, &error, &reply);
|
|
|
|
if (r < 0) {
|
2016-02-23 14:17:19 +01:00
|
|
|
log_error("Failed to transfer image: %s", bus_error_message(&error, -r));
|
2015-01-22 03:57:15 +01:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2015-01-22 17:31:59 +01:00
|
|
|
r = sd_bus_message_read(reply, "uo", &id, &path);
|
2015-01-22 03:57:15 +01:00
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
2015-06-15 20:13:23 +02:00
|
|
|
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
|
2015-01-22 03:57:15 +01:00
|
|
|
|
2015-01-22 17:31:59 +01:00
|
|
|
if (!arg_quiet)
|
|
|
|
log_info("Enqueued transfer job %u. Press C-c to continue download in background.", id);
|
2015-01-22 03:57:15 +01:00
|
|
|
|
2015-01-22 17:31:59 +01:00
|
|
|
sd_event_add_signal(event, NULL, SIGINT, transfer_signal_handler, UINT32_TO_PTR(id));
|
|
|
|
sd_event_add_signal(event, NULL, SIGTERM, transfer_signal_handler, UINT32_TO_PTR(id));
|
|
|
|
|
|
|
|
r = sd_event_loop(event);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to run event loop: %m");
|
2015-01-22 03:57:15 +01:00
|
|
|
|
2015-01-22 17:31:59 +01:00
|
|
|
return -r;
|
2015-01-22 03:57:15 +01:00
|
|
|
}
|
|
|
|
|
2015-03-05 00:56:08 +01:00
|
|
|
static int import_tar(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
2015-03-05 00:56:08 +01:00
|
|
|
_cleanup_free_ char *ll = NULL;
|
|
|
|
_cleanup_close_ int fd = -1;
|
|
|
|
const char *local = NULL, *path = NULL;
|
|
|
|
sd_bus *bus = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
|
|
|
if (argc >= 2)
|
|
|
|
path = argv[1];
|
|
|
|
if (isempty(path) || streq(path, "-"))
|
|
|
|
path = NULL;
|
|
|
|
|
|
|
|
if (argc >= 3)
|
|
|
|
local = argv[2];
|
|
|
|
else if (path)
|
|
|
|
local = basename(path);
|
|
|
|
if (isempty(local) || streq(local, "-"))
|
|
|
|
local = NULL;
|
|
|
|
|
|
|
|
if (!local) {
|
|
|
|
log_error("Need either path or local name.");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = tar_strip_suffixes(local, &ll);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
local = ll;
|
|
|
|
|
|
|
|
if (!machine_name_is_valid(local)) {
|
|
|
|
log_error("Local name %s is not a suitable machine name.", local);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (path) {
|
|
|
|
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
|
|
|
if (fd < 0)
|
|
|
|
return log_error_errno(errno, "Failed to open %s: %m", path);
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_bus_message_new_method_call(
|
|
|
|
bus,
|
|
|
|
&m,
|
|
|
|
"org.freedesktop.import1",
|
|
|
|
"/org/freedesktop/import1",
|
|
|
|
"org.freedesktop.import1.Manager",
|
|
|
|
"ImportTar");
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_append(
|
|
|
|
m,
|
|
|
|
"hsbb",
|
|
|
|
fd >= 0 ? fd : STDIN_FILENO,
|
|
|
|
local,
|
|
|
|
arg_force,
|
|
|
|
arg_read_only);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
2015-03-09 17:55:07 +01:00
|
|
|
return transfer_image_common(bus, m);
|
2015-03-05 00:56:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int import_raw(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
2015-03-05 00:56:08 +01:00
|
|
|
_cleanup_free_ char *ll = NULL;
|
|
|
|
_cleanup_close_ int fd = -1;
|
|
|
|
const char *local = NULL, *path = NULL;
|
|
|
|
sd_bus *bus = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
|
|
|
if (argc >= 2)
|
|
|
|
path = argv[1];
|
|
|
|
if (isempty(path) || streq(path, "-"))
|
|
|
|
path = NULL;
|
|
|
|
|
|
|
|
if (argc >= 3)
|
|
|
|
local = argv[2];
|
|
|
|
else if (path)
|
|
|
|
local = basename(path);
|
|
|
|
if (isempty(local) || streq(local, "-"))
|
|
|
|
local = NULL;
|
|
|
|
|
|
|
|
if (!local) {
|
|
|
|
log_error("Need either path or local name.");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = raw_strip_suffixes(local, &ll);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
local = ll;
|
|
|
|
|
|
|
|
if (!machine_name_is_valid(local)) {
|
|
|
|
log_error("Local name %s is not a suitable machine name.", local);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (path) {
|
|
|
|
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
|
|
|
if (fd < 0)
|
|
|
|
return log_error_errno(errno, "Failed to open %s: %m", path);
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_bus_message_new_method_call(
|
|
|
|
bus,
|
|
|
|
&m,
|
|
|
|
"org.freedesktop.import1",
|
|
|
|
"/org/freedesktop/import1",
|
|
|
|
"org.freedesktop.import1.Manager",
|
|
|
|
"ImportRaw");
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_append(
|
|
|
|
m,
|
|
|
|
"hsbb",
|
|
|
|
fd >= 0 ? fd : STDIN_FILENO,
|
|
|
|
local,
|
|
|
|
arg_force,
|
|
|
|
arg_read_only);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
2015-03-09 17:55:07 +01:00
|
|
|
return transfer_image_common(bus, m);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void determine_compression_from_filename(const char *p) {
|
|
|
|
if (arg_format)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!p)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (endswith(p, ".xz"))
|
|
|
|
arg_format = "xz";
|
|
|
|
else if (endswith(p, ".gz"))
|
|
|
|
arg_format = "gzip";
|
|
|
|
else if (endswith(p, ".bz2"))
|
|
|
|
arg_format = "bzip2";
|
|
|
|
}
|
|
|
|
|
|
|
|
static int export_tar(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
2015-03-09 17:55:07 +01:00
|
|
|
_cleanup_close_ int fd = -1;
|
|
|
|
const char *local = NULL, *path = NULL;
|
|
|
|
sd_bus *bus = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
|
|
|
local = argv[1];
|
|
|
|
if (!machine_name_is_valid(local)) {
|
|
|
|
log_error("Machine name %s is not valid.", local);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argc >= 3)
|
|
|
|
path = argv[2];
|
|
|
|
if (isempty(path) || streq(path, "-"))
|
|
|
|
path = NULL;
|
|
|
|
|
|
|
|
if (path) {
|
|
|
|
determine_compression_from_filename(path);
|
|
|
|
|
|
|
|
fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666);
|
|
|
|
if (fd < 0)
|
|
|
|
return log_error_errno(errno, "Failed to open %s: %m", path);
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_bus_message_new_method_call(
|
|
|
|
bus,
|
|
|
|
&m,
|
|
|
|
"org.freedesktop.import1",
|
|
|
|
"/org/freedesktop/import1",
|
|
|
|
"org.freedesktop.import1.Manager",
|
|
|
|
"ExportTar");
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_append(
|
|
|
|
m,
|
|
|
|
"shs",
|
|
|
|
local,
|
|
|
|
fd >= 0 ? fd : STDOUT_FILENO,
|
|
|
|
arg_format);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
return transfer_image_common(bus, m);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int export_raw(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
2015-03-09 17:55:07 +01:00
|
|
|
_cleanup_close_ int fd = -1;
|
|
|
|
const char *local = NULL, *path = NULL;
|
|
|
|
sd_bus *bus = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
|
|
|
local = argv[1];
|
|
|
|
if (!machine_name_is_valid(local)) {
|
|
|
|
log_error("Machine name %s is not valid.", local);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argc >= 3)
|
|
|
|
path = argv[2];
|
|
|
|
if (isempty(path) || streq(path, "-"))
|
|
|
|
path = NULL;
|
|
|
|
|
|
|
|
if (path) {
|
|
|
|
determine_compression_from_filename(path);
|
|
|
|
|
|
|
|
fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666);
|
|
|
|
if (fd < 0)
|
|
|
|
return log_error_errno(errno, "Failed to open %s: %m", path);
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_bus_message_new_method_call(
|
|
|
|
bus,
|
|
|
|
&m,
|
|
|
|
"org.freedesktop.import1",
|
|
|
|
"/org/freedesktop/import1",
|
|
|
|
"org.freedesktop.import1.Manager",
|
|
|
|
"ExportRaw");
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_append(
|
|
|
|
m,
|
|
|
|
"shs",
|
|
|
|
local,
|
|
|
|
fd >= 0 ? fd : STDOUT_FILENO,
|
|
|
|
arg_format);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
return transfer_image_common(bus, m);
|
2015-03-05 00:56:08 +01:00
|
|
|
}
|
|
|
|
|
2015-01-22 03:57:15 +01:00
|
|
|
static int pull_tar(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
2015-01-22 03:57:15 +01:00
|
|
|
_cleanup_free_ char *l = NULL, *ll = NULL;
|
|
|
|
const char *local, *remote;
|
|
|
|
sd_bus *bus = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
|
|
|
remote = argv[1];
|
|
|
|
if (!http_url_is_valid(remote)) {
|
|
|
|
log_error("URL '%s' is not valid.", remote);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argc >= 3)
|
|
|
|
local = argv[2];
|
|
|
|
else {
|
|
|
|
r = import_url_last_component(remote, &l);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get final component of URL: %m");
|
|
|
|
|
|
|
|
local = l;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isempty(local) || streq(local, "-"))
|
|
|
|
local = NULL;
|
|
|
|
|
|
|
|
if (local) {
|
|
|
|
r = tar_strip_suffixes(local, &ll);
|
|
|
|
if (r < 0)
|
2015-03-05 00:56:08 +01:00
|
|
|
return log_oom();
|
2015-01-22 03:57:15 +01:00
|
|
|
|
|
|
|
local = ll;
|
|
|
|
|
|
|
|
if (!machine_name_is_valid(local)) {
|
|
|
|
log_error("Local name %s is not a suitable machine name.", local);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_bus_message_new_method_call(
|
|
|
|
bus,
|
|
|
|
&m,
|
|
|
|
"org.freedesktop.import1",
|
|
|
|
"/org/freedesktop/import1",
|
|
|
|
"org.freedesktop.import1.Manager",
|
|
|
|
"PullTar");
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_append(
|
|
|
|
m,
|
|
|
|
"sssb",
|
|
|
|
remote,
|
|
|
|
local,
|
2015-01-22 17:30:40 +01:00
|
|
|
import_verify_to_string(arg_verify),
|
2015-01-22 03:57:15 +01:00
|
|
|
arg_force);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
2015-03-09 17:55:07 +01:00
|
|
|
return transfer_image_common(bus, m);
|
2015-01-22 03:57:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int pull_raw(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
2015-01-22 03:57:15 +01:00
|
|
|
_cleanup_free_ char *l = NULL, *ll = NULL;
|
|
|
|
const char *local, *remote;
|
|
|
|
sd_bus *bus = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
|
|
|
remote = argv[1];
|
|
|
|
if (!http_url_is_valid(remote)) {
|
|
|
|
log_error("URL '%s' is not valid.", remote);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argc >= 3)
|
|
|
|
local = argv[2];
|
|
|
|
else {
|
|
|
|
r = import_url_last_component(remote, &l);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get final component of URL: %m");
|
|
|
|
|
|
|
|
local = l;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isempty(local) || streq(local, "-"))
|
|
|
|
local = NULL;
|
|
|
|
|
|
|
|
if (local) {
|
|
|
|
r = raw_strip_suffixes(local, &ll);
|
|
|
|
if (r < 0)
|
2015-03-05 00:56:08 +01:00
|
|
|
return log_oom();
|
2015-01-22 03:57:15 +01:00
|
|
|
|
|
|
|
local = ll;
|
|
|
|
|
|
|
|
if (!machine_name_is_valid(local)) {
|
|
|
|
log_error("Local name %s is not a suitable machine name.", local);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_bus_message_new_method_call(
|
|
|
|
bus,
|
|
|
|
&m,
|
|
|
|
"org.freedesktop.import1",
|
|
|
|
"/org/freedesktop/import1",
|
|
|
|
"org.freedesktop.import1.Manager",
|
|
|
|
"PullRaw");
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_append(
|
|
|
|
m,
|
|
|
|
"sssb",
|
|
|
|
remote,
|
|
|
|
local,
|
2015-01-22 17:30:40 +01:00
|
|
|
import_verify_to_string(arg_verify),
|
2015-01-22 03:57:15 +01:00
|
|
|
arg_force);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
2015-03-09 17:55:07 +01:00
|
|
|
return transfer_image_common(bus, m);
|
2015-01-22 03:57:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct TransferInfo {
|
|
|
|
uint32_t id;
|
|
|
|
const char *type;
|
|
|
|
const char *remote;
|
|
|
|
const char *local;
|
2015-01-23 01:16:31 +01:00
|
|
|
double progress;
|
2015-01-22 03:57:15 +01:00
|
|
|
} TransferInfo;
|
|
|
|
|
|
|
|
static int compare_transfer_info(const void *a, const void *b) {
|
|
|
|
const TransferInfo *x = a, *y = b;
|
|
|
|
|
|
|
|
return strcmp(x->local, y->local);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int list_transfers(int argc, char *argv[], void *userdata) {
|
2017-12-14 19:02:29 +01:00
|
|
|
size_t max_type = STRLEN("TYPE"), max_local = STRLEN("LOCAL"), max_remote = STRLEN("REMOTE");
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2015-01-22 03:57:15 +01:00
|
|
|
_cleanup_free_ TransferInfo *transfers = NULL;
|
|
|
|
size_t n_transfers = 0, n_allocated = 0, j;
|
|
|
|
const char *type, *remote, *local, *object;
|
|
|
|
sd_bus *bus = userdata;
|
|
|
|
uint32_t id, max_id = 0;
|
2015-01-23 01:16:31 +01:00
|
|
|
double progress;
|
2015-01-22 03:57:15 +01:00
|
|
|
int r;
|
|
|
|
|
2018-03-14 09:48:29 +01:00
|
|
|
(void) pager_open(arg_no_pager, false);
|
2015-01-22 03:57:15 +01:00
|
|
|
|
2016-04-06 05:03:46 +02:00
|
|
|
r = sd_bus_call_method(bus,
|
|
|
|
"org.freedesktop.import1",
|
|
|
|
"/org/freedesktop/import1",
|
|
|
|
"org.freedesktop.import1.Manager",
|
|
|
|
"ListTransfers",
|
|
|
|
&error,
|
|
|
|
&reply,
|
|
|
|
NULL);
|
2015-01-22 03:57:15 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_error("Could not get transfers: %s", bus_error_message(&error, -r));
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2015-01-23 01:16:31 +01:00
|
|
|
r = sd_bus_message_enter_container(reply, 'a', "(usssdo)");
|
2015-01-22 03:57:15 +01:00
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
2015-01-23 01:16:31 +01:00
|
|
|
while ((r = sd_bus_message_read(reply, "(usssdo)", &id, &type, &remote, &local, &progress, &object)) > 0) {
|
2015-01-22 03:57:15 +01:00
|
|
|
size_t l;
|
|
|
|
|
|
|
|
if (!GREEDY_REALLOC(transfers, n_allocated, n_transfers + 1))
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
transfers[n_transfers].id = id;
|
|
|
|
transfers[n_transfers].type = type;
|
|
|
|
transfers[n_transfers].remote = remote;
|
|
|
|
transfers[n_transfers].local = local;
|
2015-01-23 01:16:31 +01:00
|
|
|
transfers[n_transfers].progress = progress;
|
2015-01-22 03:57:15 +01:00
|
|
|
|
|
|
|
l = strlen(type);
|
|
|
|
if (l > max_type)
|
|
|
|
max_type = l;
|
|
|
|
|
|
|
|
l = strlen(remote);
|
|
|
|
if (l > max_remote)
|
|
|
|
max_remote = l;
|
|
|
|
|
|
|
|
l = strlen(local);
|
|
|
|
if (l > max_local)
|
|
|
|
max_local = l;
|
|
|
|
|
|
|
|
if (id > max_id)
|
|
|
|
max_id = id;
|
|
|
|
|
2016-02-23 05:32:04 +01:00
|
|
|
n_transfers++;
|
2015-01-22 03:57:15 +01:00
|
|
|
}
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_exit_container(reply);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
|
|
qsort_safe(transfers, n_transfers, sizeof(TransferInfo), compare_transfer_info);
|
|
|
|
|
2016-08-01 17:39:27 +02:00
|
|
|
if (arg_legend && n_transfers > 0)
|
2015-01-23 01:16:31 +01:00
|
|
|
printf("%-*s %-*s %-*s %-*s %-*s\n",
|
2015-01-22 03:57:15 +01:00
|
|
|
(int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), "ID",
|
2015-01-23 01:16:31 +01:00
|
|
|
(int) 7, "PERCENT",
|
2015-01-22 03:57:15 +01:00
|
|
|
(int) max_type, "TYPE",
|
|
|
|
(int) max_local, "LOCAL",
|
|
|
|
(int) max_remote, "REMOTE");
|
|
|
|
|
|
|
|
for (j = 0; j < n_transfers; j++)
|
2015-01-23 01:16:31 +01:00
|
|
|
printf("%*" PRIu32 " %*u%% %-*s %-*s %-*s\n",
|
2015-01-22 03:57:15 +01:00
|
|
|
(int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), transfers[j].id,
|
2015-01-23 01:16:31 +01:00
|
|
|
(int) 6, (unsigned) (transfers[j].progress * 100),
|
2015-01-22 03:57:15 +01:00
|
|
|
(int) max_type, transfers[j].type,
|
|
|
|
(int) max_local, transfers[j].local,
|
|
|
|
(int) max_remote, transfers[j].remote);
|
|
|
|
|
2016-11-06 15:19:57 +01:00
|
|
|
if (arg_legend) {
|
|
|
|
if (n_transfers > 0)
|
|
|
|
printf("\n%zu transfers listed.\n", n_transfers);
|
|
|
|
else
|
|
|
|
printf("No transfers.\n");
|
|
|
|
}
|
2015-01-22 03:57:15 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cancel_transfer(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2015-01-22 03:57:15 +01:00
|
|
|
sd_bus *bus = userdata;
|
|
|
|
int r, i;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
2017-10-30 09:57:53 +01:00
|
|
|
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
2015-01-22 03:57:15 +01:00
|
|
|
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
|
|
uint32_t id;
|
|
|
|
|
|
|
|
r = safe_atou32(argv[i], &id);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to parse transfer id: %s", argv[i]);
|
|
|
|
|
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.import1",
|
|
|
|
"/org/freedesktop/import1",
|
|
|
|
"org.freedesktop.import1.Manager",
|
|
|
|
"CancelTransfer",
|
|
|
|
&error,
|
|
|
|
NULL,
|
|
|
|
"u", id);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error("Could not cancel transfer: %s", bus_error_message(&error, -r));
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-24 23:50:37 +01:00
|
|
|
static int set_limit(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2015-02-24 23:50:37 +01:00
|
|
|
sd_bus *bus = userdata;
|
|
|
|
uint64_t limit;
|
|
|
|
int r;
|
|
|
|
|
2015-10-21 22:41:31 +02:00
|
|
|
if (STR_IN_SET(argv[argc-1], "-", "none", "infinity"))
|
2015-02-24 23:50:37 +01:00
|
|
|
limit = (uint64_t) -1;
|
|
|
|
else {
|
2015-09-10 18:16:18 +02:00
|
|
|
r = parse_size(argv[argc-1], 1024, &limit);
|
2015-02-24 23:50:37 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error("Failed to parse size: %s", argv[argc-1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argc > 2)
|
|
|
|
/* With two arguments changes the quota limit of the
|
|
|
|
* specified image */
|
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
|
|
|
"SetImageLimit",
|
|
|
|
&error,
|
|
|
|
NULL,
|
|
|
|
"st", argv[1], limit);
|
|
|
|
else
|
|
|
|
/* With one argument changes the pool quota limit */
|
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
|
|
|
"SetPoolLimit",
|
|
|
|
&error,
|
|
|
|
NULL,
|
|
|
|
"t", limit);
|
|
|
|
|
|
|
|
if (r < 0) {
|
|
|
|
log_error("Could not set limit: %s", bus_error_message(&error, -r));
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-11 17:24:08 +02:00
|
|
|
static int clean_images(int argc, char *argv[], void *userdata) {
|
2016-06-24 16:01:14 +02:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
|
2016-04-11 17:24:08 +02:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
uint64_t usage, total = 0;
|
|
|
|
char fb[FORMAT_BYTES_MAX];
|
|
|
|
sd_bus *bus = userdata;
|
|
|
|
const char *name;
|
|
|
|
unsigned c = 0;
|
|
|
|
int r;
|
|
|
|
|
2016-06-24 16:01:14 +02:00
|
|
|
r = sd_bus_message_new_method_call(
|
2016-04-11 17:24:08 +02:00
|
|
|
bus,
|
2016-06-24 16:01:14 +02:00
|
|
|
&m,
|
2016-04-11 17:24:08 +02:00
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
2016-06-24 16:01:14 +02:00
|
|
|
"CleanPool");
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_append(m, "s", arg_all ? "all" : "hidden");
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
/* This is a slow operation, hence permit a longer time for completion. */
|
|
|
|
r = sd_bus_call(bus, m, USEC_INFINITY, &error, &reply);
|
2016-04-11 17:24:08 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not clean pool: %s", bus_error_message(&error, r));
|
|
|
|
|
|
|
|
r = sd_bus_message_enter_container(reply, 'a', "(st)");
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
|
|
while ((r = sd_bus_message_read(reply, "(st)", &name, &usage)) > 0) {
|
|
|
|
log_info("Removed image '%s'. Freed exclusive disk space: %s",
|
|
|
|
name, format_bytes(fb, sizeof(fb), usage));
|
|
|
|
|
|
|
|
total += usage;
|
|
|
|
c++;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_bus_message_exit_container(reply);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
|
|
log_info("Removed %u images in total. Total freed exclusive disk space %s.",
|
|
|
|
c, format_bytes(fb, sizeof(fb), total));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
static int help(int argc, char *argv[], void *userdata) {
|
2018-03-14 09:48:29 +01:00
|
|
|
(void) pager_open(arg_no_pager, false);
|
2014-12-19 19:19:05 +01:00
|
|
|
|
2013-07-02 03:47:23 +02:00
|
|
|
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
|
2014-12-18 01:35:58 +01:00
|
|
|
"Send control commands to or query the virtual machine and container\n"
|
|
|
|
"registration 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"
|
2015-01-08 15:23:54 +01:00
|
|
|
" --no-ask-password Do not ask for system passwords\n"
|
2014-12-18 01:35:58 +01:00
|
|
|
" -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"
|
2014-12-29 14:05:17 +01:00
|
|
|
" -q --quiet Suppress output\n"
|
2014-12-18 01:35:58 +01:00
|
|
|
" -a --all Show all properties, including empty ones\n"
|
2016-04-06 04:44:42 +02:00
|
|
|
" --value When showing properties, only print the value\n"
|
2014-12-18 01:35:58 +01:00
|
|
|
" -l --full Do not ellipsize output\n"
|
|
|
|
" --kill-who=WHO Who to send signal to\n"
|
|
|
|
" -s --signal=SIGNAL Which signal to send\n"
|
2015-08-23 13:24:10 +02:00
|
|
|
" --uid=USER Specify user ID to invoke shell as\n"
|
2016-04-20 14:41:25 +02:00
|
|
|
" -E --setenv=VAR=VALUE Add an environment variable for shell\n"
|
2014-12-18 01:35:58 +01:00
|
|
|
" --read-only Create read-only bind mount\n"
|
2015-01-08 15:09:12 +01:00
|
|
|
" --mkdir Create directory before bind mounting, if missing\n"
|
|
|
|
" -n --lines=INTEGER Number of journal entries to show\n"
|
2016-08-31 20:06:57 +02:00
|
|
|
" --max-addresses=INTEGER Number of internet addresses to show at most\n"
|
2017-05-08 02:23:49 +02:00
|
|
|
" -o --output=STRING Change journal output mode (short, short-precise,\n"
|
|
|
|
" short-iso, short-iso-precise, short-full,\n"
|
|
|
|
" short-monotonic, short-unix, verbose, export,\n"
|
|
|
|
" json, json-pretty, json-sse, cat)\n"
|
2016-12-20 17:50:42 +01:00
|
|
|
" --verify=MODE Verification mode for downloaded images (no,\n"
|
2015-01-22 15:13:53 +01:00
|
|
|
" checksum, signature)\n"
|
2016-12-20 17:50:42 +01:00
|
|
|
" --force Download image even if already exists\n\n"
|
2014-12-19 18:42:50 +01:00
|
|
|
"Machine Commands:\n"
|
2014-12-18 01:35:58 +01:00
|
|
|
" list List running VMs and containers\n"
|
2014-12-26 20:09:04 +01:00
|
|
|
" status NAME... Show VM/container details\n"
|
2015-08-24 22:17:52 +02:00
|
|
|
" show [NAME...] Show properties of one or more VMs/containers\n"
|
2014-12-29 12:41:26 +01:00
|
|
|
" start NAME... Start container as a service\n"
|
2015-08-24 22:17:52 +02:00
|
|
|
" login [NAME] Get a login prompt in a container or on the\n"
|
|
|
|
" local host\n"
|
2015-08-24 22:44:54 +02:00
|
|
|
" shell [[USER@]NAME [COMMAND...]]\n"
|
|
|
|
" Invoke a shell (or other command) in a container\n"
|
|
|
|
" or on the local host\n"
|
2014-12-29 14:05:17 +01:00
|
|
|
" enable NAME... Enable automatic container start at boot\n"
|
|
|
|
" disable NAME... Disable automatic container start at boot\n"
|
2014-12-18 01:35:58 +01:00
|
|
|
" poweroff NAME... Power off one or more containers\n"
|
|
|
|
" reboot NAME... Reboot one or more containers\n"
|
|
|
|
" terminate NAME... Terminate one or more VMs/containers\n"
|
2014-12-27 17:44:04 +01:00
|
|
|
" kill NAME... Send signal to processes of a VM/container\n"
|
2014-12-18 01:35:58 +01:00
|
|
|
" copy-to NAME PATH [PATH] Copy files from the host to a container\n"
|
2014-12-27 17:44:04 +01:00
|
|
|
" copy-from NAME PATH [PATH] Copy files from a container to the host\n"
|
|
|
|
" bind NAME PATH [PATH] Bind mount a path from the host into a container\n\n"
|
2014-12-26 20:09:04 +01:00
|
|
|
"Image Commands:\n"
|
2015-01-25 03:07:27 +01:00
|
|
|
" list-images Show available container and VM images\n"
|
2015-08-24 22:17:52 +02:00
|
|
|
" image-status [NAME...] Show image details\n"
|
|
|
|
" show-image [NAME...] Show properties of image\n"
|
2014-12-27 17:44:04 +01:00
|
|
|
" clone NAME NAME Clone an image\n"
|
|
|
|
" rename NAME NAME Rename an image\n"
|
|
|
|
" read-only NAME [BOOL] Mark or unmark image read-only\n"
|
2015-02-24 23:50:37 +01:00
|
|
|
" remove NAME... Remove an image\n"
|
2016-04-22 17:14:30 +02:00
|
|
|
" set-limit [NAME] BYTES Set image or pool size limit (disk quota)\n"
|
|
|
|
" clean Remove hidden (or all) images\n\n"
|
2015-01-22 15:14:23 +01:00
|
|
|
"Image Transfer Commands:\n"
|
|
|
|
" pull-tar URL [NAME] Download a TAR container image\n"
|
|
|
|
" pull-raw URL [NAME] Download a RAW container or VM image\n"
|
2015-03-09 17:55:07 +01:00
|
|
|
" import-tar FILE [NAME] Import a local TAR container image\n"
|
|
|
|
" import-raw FILE [NAME] Import a local RAW container or VM image\n"
|
2015-03-10 15:47:45 +01:00
|
|
|
" export-tar NAME [FILE] Export a TAR container image locally\n"
|
|
|
|
" export-raw NAME [FILE] Export a RAW container or VM image locally\n"
|
2015-01-22 15:14:23 +01:00
|
|
|
" list-transfers Show list of downloads in progress\n"
|
2015-01-22 03:57:15 +01:00
|
|
|
" cancel-transfer Cancel a download\n"
|
2015-01-08 23:11:35 +01:00
|
|
|
, program_invocation_short_name);
|
2014-12-19 19:19:05 +01:00
|
|
|
|
|
|
|
return 0;
|
2013-07-02 03:47:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int parse_argv(int argc, char *argv[]) {
|
|
|
|
|
|
|
|
enum {
|
|
|
|
ARG_VERSION = 0x100,
|
|
|
|
ARG_NO_PAGER,
|
2014-02-18 21:09:05 +01:00
|
|
|
ARG_NO_LEGEND,
|
2016-04-06 04:44:42 +02:00
|
|
|
ARG_VALUE,
|
2013-07-02 03:47:23 +02:00
|
|
|
ARG_KILL_WHO,
|
2014-12-17 21:51:45 +01:00
|
|
|
ARG_READ_ONLY,
|
|
|
|
ARG_MKDIR,
|
2015-01-08 15:23:54 +01:00
|
|
|
ARG_NO_ASK_PASSWORD,
|
2015-01-22 03:57:15 +01:00
|
|
|
ARG_VERIFY,
|
|
|
|
ARG_FORCE,
|
2015-03-09 17:55:07 +01:00
|
|
|
ARG_FORMAT,
|
2015-08-23 13:24:10 +02:00
|
|
|
ARG_UID,
|
2016-08-31 20:06:57 +02:00
|
|
|
ARG_NUMBER_IPS,
|
2013-07-02 03:47:23 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct option options[] = {
|
|
|
|
{ "help", no_argument, NULL, 'h' },
|
|
|
|
{ "version", no_argument, NULL, ARG_VERSION },
|
|
|
|
{ "property", required_argument, NULL, 'p' },
|
|
|
|
{ "all", no_argument, NULL, 'a' },
|
2016-04-06 04:44:42 +02:00
|
|
|
{ "value", no_argument, NULL, ARG_VALUE },
|
2013-07-02 03:47:23 +02:00
|
|
|
{ "full", no_argument, NULL, 'l' },
|
|
|
|
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
2014-02-18 21:09:05 +01:00
|
|
|
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
|
2013-07-02 03:47:23 +02:00
|
|
|
{ "kill-who", required_argument, NULL, ARG_KILL_WHO },
|
|
|
|
{ "signal", required_argument, NULL, 's' },
|
|
|
|
{ "host", required_argument, NULL, 'H' },
|
2013-10-30 15:34:50 +01:00
|
|
|
{ "machine", required_argument, NULL, 'M' },
|
2014-12-17 21:51:45 +01:00
|
|
|
{ "read-only", no_argument, NULL, ARG_READ_ONLY },
|
|
|
|
{ "mkdir", no_argument, NULL, ARG_MKDIR },
|
2014-12-29 14:05:17 +01:00
|
|
|
{ "quiet", no_argument, NULL, 'q' },
|
2015-01-08 15:09:12 +01:00
|
|
|
{ "lines", required_argument, NULL, 'n' },
|
|
|
|
{ "output", required_argument, NULL, 'o' },
|
2015-01-08 15:23:54 +01:00
|
|
|
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
|
2015-01-22 03:57:15 +01:00
|
|
|
{ "verify", required_argument, NULL, ARG_VERIFY },
|
|
|
|
{ "force", no_argument, NULL, ARG_FORCE },
|
2015-03-09 17:55:07 +01:00
|
|
|
{ "format", required_argument, NULL, ARG_FORMAT },
|
2015-08-23 13:24:10 +02:00
|
|
|
{ "uid", required_argument, NULL, ARG_UID },
|
2016-04-20 14:41:25 +02:00
|
|
|
{ "setenv", required_argument, NULL, 'E' },
|
2016-08-31 20:06:57 +02:00
|
|
|
{ "max-addresses", required_argument, NULL, ARG_NUMBER_IPS },
|
2013-11-06 18:28:39 +01:00
|
|
|
{}
|
2013-07-02 03:47:23 +02:00
|
|
|
};
|
|
|
|
|
2016-04-23 03:01:55 +02:00
|
|
|
bool reorder = false;
|
2016-06-21 21:30:20 +02:00
|
|
|
int c, r, shell = -1;
|
2013-07-02 03:47:23 +02:00
|
|
|
|
|
|
|
assert(argc >= 0);
|
|
|
|
assert(argv);
|
|
|
|
|
2016-04-23 03:01:55 +02:00
|
|
|
for (;;) {
|
2016-12-06 19:35:31 +01:00
|
|
|
static const char option_string[] = "-hp:als:H:M:qn:o:E:";
|
2016-04-23 03:01:55 +02:00
|
|
|
|
2016-04-24 17:31:19 +02:00
|
|
|
c = getopt_long(argc, argv, option_string + reorder, options, NULL);
|
2016-06-21 21:30:20 +02:00
|
|
|
if (c < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
|
|
|
|
case 1: /* getopt_long() returns 1 if "-" was the first character of the option string, and a
|
|
|
|
* non-option argument was discovered. */
|
|
|
|
|
|
|
|
assert(!reorder);
|
|
|
|
|
2016-04-23 03:01:55 +02:00
|
|
|
/* We generally are fine with the fact that getopt_long() reorders the command line, and looks
|
|
|
|
* for switches after the main verb. However, for "shell" we really don't want that, since we
|
2016-06-21 21:30:20 +02:00
|
|
|
* want that switches specified after the machine name are passed to the program to execute,
|
|
|
|
* and not processed by us. To make this possible, we'll first invoke getopt_long() with
|
|
|
|
* reordering disabled (i.e. with the "-" prefix in the option string), looking for the first
|
|
|
|
* non-option parameter. If it's the verb "shell" we remember its position and continue
|
|
|
|
* processing options. In this case, as soon as we hit the next non-option argument we found
|
|
|
|
* the machine name, and stop further processing. If the first non-option argument is any other
|
|
|
|
* verb than "shell" we switch to normal reordering mode and continue processing arguments
|
|
|
|
* normally. */
|
|
|
|
|
|
|
|
if (shell >= 0) {
|
|
|
|
/* If we already found the "shell" verb on the command line, and now found the next
|
|
|
|
* non-option argument, then this is the machine name and we should stop processing
|
|
|
|
* further arguments. */
|
|
|
|
optind --; /* don't process this argument, go one step back */
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
if (streq(optarg, "shell"))
|
|
|
|
/* Remember the position of the "shell" verb, and continue processing normally. */
|
|
|
|
shell = optind - 1;
|
|
|
|
else {
|
|
|
|
int saved_optind;
|
|
|
|
|
|
|
|
/* OK, this is some other verb. In this case, turn on reordering again, and continue
|
|
|
|
* processing normally. */
|
2016-04-23 03:01:55 +02:00
|
|
|
reorder = true;
|
2016-06-21 21:30:20 +02:00
|
|
|
|
|
|
|
/* We changed the option string. getopt_long() only looks at it again if we invoke it
|
|
|
|
* at least once with a reset option index. Hence, let's reset the option index here,
|
|
|
|
* then invoke getopt_long() again (ignoring what it has to say, after all we most
|
|
|
|
* likely already processed it), and the bump the option index so that we read the
|
|
|
|
* intended argument again. */
|
|
|
|
saved_optind = optind;
|
|
|
|
optind = 0;
|
|
|
|
(void) getopt_long(argc, argv, option_string + reorder, options, NULL);
|
|
|
|
optind = saved_optind - 1; /* go one step back, process this argument again */
|
2016-04-23 03:01:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
2013-07-02 03:47:23 +02:00
|
|
|
|
|
|
|
case 'h':
|
2014-12-19 19:19:05 +01:00
|
|
|
return help(0, NULL, NULL);
|
2013-07-02 03:47:23 +02:00
|
|
|
|
|
|
|
case ARG_VERSION:
|
2015-09-23 03:01:06 +02:00
|
|
|
return version();
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2013-10-30 15:34:50 +01:00
|
|
|
case 'p':
|
|
|
|
r = strv_extend(&arg_property, optarg);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
2013-07-02 03:47:23 +02:00
|
|
|
|
|
|
|
/* If the user asked for a particular
|
|
|
|
* property, show it to him, even if it is
|
|
|
|
* empty. */
|
|
|
|
arg_all = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'a':
|
|
|
|
arg_all = true;
|
|
|
|
break;
|
|
|
|
|
2016-04-06 04:44:42 +02:00
|
|
|
case ARG_VALUE:
|
|
|
|
arg_value = true;
|
|
|
|
break;
|
|
|
|
|
2013-07-02 03:47:23 +02:00
|
|
|
case 'l':
|
|
|
|
arg_full = true;
|
|
|
|
break;
|
|
|
|
|
2015-01-08 15:09:12 +01:00
|
|
|
case 'n':
|
|
|
|
if (safe_atou(optarg, &arg_lines) < 0) {
|
|
|
|
log_error("Failed to parse lines '%s'", optarg);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'o':
|
|
|
|
arg_output = output_mode_from_string(optarg);
|
|
|
|
if (arg_output < 0) {
|
|
|
|
log_error("Unknown output '%s'.", optarg);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2013-07-02 03:47:23 +02:00
|
|
|
case ARG_NO_PAGER:
|
|
|
|
arg_no_pager = true;
|
|
|
|
break;
|
|
|
|
|
2014-02-18 21:09:05 +01:00
|
|
|
case ARG_NO_LEGEND:
|
|
|
|
arg_legend = false;
|
|
|
|
break;
|
|
|
|
|
2013-07-02 03:47:23 +02:00
|
|
|
case ARG_KILL_WHO:
|
|
|
|
arg_kill_who = optarg;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 's':
|
|
|
|
arg_signal = signal_from_string_try_harder(optarg);
|
|
|
|
if (arg_signal < 0) {
|
|
|
|
log_error("Failed to parse signal string %s.", optarg);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2015-01-08 15:23:54 +01:00
|
|
|
case ARG_NO_ASK_PASSWORD:
|
|
|
|
arg_ask_password = false;
|
|
|
|
break;
|
|
|
|
|
2013-07-02 03:47:23 +02:00
|
|
|
case 'H':
|
2013-10-30 16:44:55 +01:00
|
|
|
arg_transport = BUS_TRANSPORT_REMOTE;
|
2013-10-30 15:34:50 +01:00
|
|
|
arg_host = optarg;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'M':
|
2014-12-23 23:38:13 +01:00
|
|
|
arg_transport = BUS_TRANSPORT_MACHINE;
|
2013-10-30 15:34:50 +01:00
|
|
|
arg_host = optarg;
|
2013-07-02 03:47:23 +02:00
|
|
|
break;
|
|
|
|
|
2014-12-17 21:51:45 +01:00
|
|
|
case ARG_READ_ONLY:
|
|
|
|
arg_read_only = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ARG_MKDIR:
|
|
|
|
arg_mkdir = true;
|
|
|
|
break;
|
|
|
|
|
2014-12-29 14:05:17 +01:00
|
|
|
case 'q':
|
|
|
|
arg_quiet = true;
|
|
|
|
break;
|
|
|
|
|
2015-01-22 03:57:15 +01:00
|
|
|
case ARG_VERIFY:
|
2015-01-22 17:30:40 +01:00
|
|
|
arg_verify = import_verify_from_string(optarg);
|
|
|
|
if (arg_verify < 0) {
|
|
|
|
log_error("Failed to parse --verify= setting: %s", optarg);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2015-01-22 03:57:15 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ARG_FORCE:
|
|
|
|
arg_force = true;
|
|
|
|
break;
|
|
|
|
|
2015-03-09 17:55:07 +01:00
|
|
|
case ARG_FORMAT:
|
|
|
|
if (!STR_IN_SET(optarg, "uncompressed", "xz", "gzip", "bzip2")) {
|
|
|
|
log_error("Unknown format: %s", optarg);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
arg_format = optarg;
|
|
|
|
break;
|
|
|
|
|
2015-08-23 13:24:10 +02:00
|
|
|
case ARG_UID:
|
|
|
|
arg_uid = optarg;
|
|
|
|
break;
|
|
|
|
|
2016-04-20 14:41:25 +02:00
|
|
|
case 'E':
|
2015-08-23 13:24:10 +02:00
|
|
|
if (!env_assignment_is_valid(optarg)) {
|
|
|
|
log_error("Environment assignment invalid: %s", optarg);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = strv_extend(&arg_setenv, optarg);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
break;
|
|
|
|
|
2016-08-31 20:06:57 +02:00
|
|
|
case ARG_NUMBER_IPS:
|
|
|
|
if (streq(optarg, "all"))
|
|
|
|
arg_addrs = ALL_IP_ADDRESSES;
|
|
|
|
else if (safe_atoi(optarg, &arg_addrs) < 0) {
|
|
|
|
log_error("Invalid number of IPs");
|
|
|
|
return -EINVAL;
|
|
|
|
} else if (arg_addrs < 0) {
|
|
|
|
log_error("Number of IPs cannot be negative");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2013-07-02 03:47:23 +02:00
|
|
|
case '?':
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
default:
|
2013-11-06 18:28:39 +01:00
|
|
|
assert_not_reached("Unhandled option");
|
2013-07-02 03:47:23 +02:00
|
|
|
}
|
2016-04-23 03:01:55 +02:00
|
|
|
}
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2016-06-21 21:30:20 +02:00
|
|
|
done:
|
|
|
|
if (shell >= 0) {
|
|
|
|
char *t;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* We found the "shell" verb while processing the argument list. Since we turned off reordering of the
|
|
|
|
* argument list initially let's readjust it now, and move the "shell" verb to the back. */
|
|
|
|
|
|
|
|
optind -= 1; /* place the option index where the "shell" verb will be placed */
|
|
|
|
|
|
|
|
t = argv[shell];
|
|
|
|
for (i = shell; i < optind; i++)
|
|
|
|
argv[i] = argv[i+1];
|
|
|
|
argv[optind] = t;
|
|
|
|
}
|
|
|
|
|
2013-07-02 03:47:23 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
|
|
|
|
|
|
|
|
static const Verb verbs[] = {
|
2015-01-22 03:57:15 +01:00
|
|
|
{ "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_machine },
|
2015-02-24 18:23:40 +01:00
|
|
|
{ "image-status", VERB_ANY, VERB_ANY, 0, show_image },
|
2015-01-22 03:57:15 +01:00
|
|
|
{ "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 },
|
2016-06-06 17:06:20 +02:00
|
|
|
{ "stop", 2, VERB_ANY, 0, poweroff_machine }, /* Convenience alias */
|
2015-01-22 03:57:15 +01:00
|
|
|
{ "kill", 2, VERB_ANY, 0, kill_machine },
|
2015-08-24 22:17:52 +02:00
|
|
|
{ "login", VERB_ANY, 2, 0, login_machine },
|
|
|
|
{ "shell", VERB_ANY, VERB_ANY, 0, shell_machine },
|
2015-01-22 03:57:15 +01:00
|
|
|
{ "bind", 3, 4, 0, bind_mount },
|
|
|
|
{ "copy-to", 3, 4, 0, copy_files },
|
|
|
|
{ "copy-from", 3, 4, 0, copy_files },
|
|
|
|
{ "remove", 2, VERB_ANY, 0, remove_image },
|
|
|
|
{ "rename", 3, 3, 0, rename_image },
|
|
|
|
{ "clone", 3, 3, 0, clone_image },
|
|
|
|
{ "read-only", 2, 3, 0, read_only_image },
|
|
|
|
{ "start", 2, VERB_ANY, 0, start_machine },
|
|
|
|
{ "enable", 2, VERB_ANY, 0, enable_machine },
|
|
|
|
{ "disable", 2, VERB_ANY, 0, enable_machine },
|
2015-03-05 00:56:08 +01:00
|
|
|
{ "import-tar", 2, 3, 0, import_tar },
|
|
|
|
{ "import-raw", 2, 3, 0, import_raw },
|
2015-03-09 17:55:07 +01:00
|
|
|
{ "export-tar", 2, 3, 0, export_tar },
|
|
|
|
{ "export-raw", 2, 3, 0, export_raw },
|
2015-01-22 03:57:15 +01:00
|
|
|
{ "pull-tar", 2, 3, 0, pull_tar },
|
|
|
|
{ "pull-raw", 2, 3, 0, pull_raw },
|
|
|
|
{ "list-transfers", VERB_ANY, 1, 0, list_transfers },
|
|
|
|
{ "cancel-transfer", 2, VERB_ANY, 0, cancel_transfer },
|
2015-02-24 23:50:37 +01:00
|
|
|
{ "set-limit", 2, 3, 0, set_limit },
|
2016-04-11 17:24:08 +02:00
|
|
|
{ "clean", VERB_ANY, 1, 0, clean_images },
|
2014-12-19 19:19:05 +01:00
|
|
|
{}
|
2013-07-02 03:47:23 +02:00
|
|
|
};
|
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
return dispatch_verb(argc, argv, verbs, bus);
|
2013-07-02 03:47:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char*argv[]) {
|
2018-01-12 16:09:21 +01:00
|
|
|
sd_bus *bus = NULL;
|
2013-11-06 17:32:51 +01:00
|
|
|
int r;
|
2013-07-02 03:47:23 +02:00
|
|
|
|
|
|
|
setlocale(LC_ALL, "");
|
|
|
|
log_parse_environment();
|
|
|
|
log_open();
|
2017-11-10 21:04:08 +01:00
|
|
|
sigbus_install();
|
2013-07-02 03:47:23 +02:00
|
|
|
|
|
|
|
r = parse_argv(argc, argv);
|
2013-11-06 17:32:51 +01:00
|
|
|
if (r <= 0)
|
2013-07-02 03:47:23 +02:00
|
|
|
goto finish;
|
|
|
|
|
2015-09-24 13:30:10 +02:00
|
|
|
r = bus_connect_transport(arg_transport, arg_host, false, &bus);
|
2013-08-12 14:19:22 +02:00
|
|
|
if (r < 0) {
|
2014-11-28 13:19:16 +01:00
|
|
|
log_error_errno(r, "Failed to create bus connection: %m");
|
2013-08-12 14:19:22 +02:00
|
|
|
goto finish;
|
|
|
|
}
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2015-02-18 11:42:03 +01:00
|
|
|
sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
|
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
r = machinectl_main(argc, argv, bus);
|
2013-07-02 03:47:23 +02:00
|
|
|
|
|
|
|
finish:
|
2018-01-12 16:20:36 +01:00
|
|
|
/* make sure we terminate the bus connection first, and then close the
|
|
|
|
* pager, see issue #3543 for the details. */
|
2018-01-12 16:09:21 +01:00
|
|
|
sd_bus_flush_close_unref(bus);
|
2013-07-02 03:47:23 +02:00
|
|
|
pager_close();
|
2015-01-08 15:23:54 +01:00
|
|
|
polkit_agent_close();
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2013-11-06 17:32:51 +01:00
|
|
|
strv_free(arg_property);
|
2015-08-23 13:24:10 +02:00
|
|
|
strv_free(arg_setenv);
|
2013-11-06 17:32:51 +01:00
|
|
|
|
|
|
|
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
2013-07-02 03:47:23 +02:00
|
|
|
}
|