2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2013-07-02 03:47:23 +02:00
|
|
|
|
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"
|
2018-10-01 17:44:46 +02:00
|
|
|
#include "def.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"
|
2018-04-11 20:12:52 +02:00
|
|
|
#include "format-table.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"
|
2018-04-11 20:12:52 +02:00
|
|
|
#include "locale-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "log.h"
|
|
|
|
#include "logs-show.h"
|
|
|
|
#include "macro.h"
|
2018-11-20 10:21:01 +01:00
|
|
|
#include "main-func.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#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"
|
2018-11-20 15:42:57 +01:00
|
|
|
#include "pretty-print.h"
|
2015-04-10 19:10:00 +02:00
|
|
|
#include "process-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "ptyfwd.h"
|
2018-10-01 17:44:46 +02:00
|
|
|
#include "rlimit-util.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"
|
2018-05-22 12:10:56 +02:00
|
|
|
#include "string-table.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;
|
2018-11-11 12:56:29 +01:00
|
|
|
static PagerFlags arg_pager_flags = 0;
|
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;
|
2018-11-20 10:21:01 +01:00
|
|
|
static const 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;
|
|
|
|
|
2018-11-20 10:21:01 +01:00
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_property, strv_freep);
|
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_setenv, strv_freep);
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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, ...) {
|
2018-04-11 20:12:52 +02:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
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,
|
2018-04-11 20:12:52 +02:00
|
|
|
&error,
|
|
|
|
&reply, "s", name);
|
2016-08-21 05:39:07 +02:00
|
|
|
if (r < 0)
|
2018-04-11 20:12:52 +02:00
|
|
|
return log_debug_errno(r, "Failed to call '%s()': %s", method, bus_error_message(&error, r));
|
2016-08-21 05:39:07 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
static int call_get_addresses(sd_bus *bus, const char *name, int ifi, const char *prefix, const char *prefix2, int n_addr, char **ret) {
|
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;
|
2018-04-11 20:12:52 +02:00
|
|
|
_cleanup_free_ char *addresses = NULL;
|
|
|
|
bool truncate = false;
|
|
|
|
unsigned n = 0;
|
2013-07-02 03:47:23 +02:00
|
|
|
int r;
|
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
assert(bus);
|
2018-04-11 20:12:52 +02:00
|
|
|
assert(name);
|
|
|
|
assert(prefix);
|
|
|
|
assert(prefix2);
|
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",
|
2018-04-11 20:12:52 +02:00
|
|
|
"GetMachineAddresses",
|
|
|
|
NULL,
|
2016-04-06 05:03:46 +02:00
|
|
|
&reply,
|
2018-04-11 20:12:52 +02:00
|
|
|
"s", name);
|
|
|
|
if (r < 0)
|
|
|
|
return log_debug_errno(r, "Could not get addresses: %s", bus_error_message(&error, r));
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
addresses = strdup(prefix);
|
|
|
|
if (!addresses)
|
|
|
|
return log_oom();
|
|
|
|
prefix = "";
|
|
|
|
|
|
|
|
r = sd_bus_message_enter_container(reply, 'a', "(iay)");
|
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);
|
2015-01-07 19:13:48 +01:00
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
|
|
|
|
int family;
|
|
|
|
const void *a;
|
|
|
|
size_t sz;
|
|
|
|
char buf_ifi[DECIMAL_STR_MAX(int) + 2], buffer[MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)];
|
2016-08-21 05:39:07 +02:00
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
r = sd_bus_message_read(reply, "i", &family);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
2016-12-29 12:09:54 +01:00
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
r = sd_bus_message_read_array(reply, 'y', &a, &sz);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
2015-01-07 19:13:48 +01:00
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
if (n_addr != 0) {
|
|
|
|
if (family == AF_INET6 && ifi > 0)
|
|
|
|
xsprintf(buf_ifi, "%%%i", ifi);
|
|
|
|
else
|
|
|
|
strcpy(buf_ifi, "");
|
2015-01-07 19:13:48 +01:00
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
if (!strextend(&addresses, prefix, inet_ntop(family, a, buffer, sizeof(buffer)), buf_ifi, NULL))
|
|
|
|
return log_oom();
|
|
|
|
} else
|
|
|
|
truncate = true;
|
2015-01-07 19:13:48 +01:00
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
r = sd_bus_message_exit_container(reply);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
2015-01-07 19:13:48 +01:00
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
prefix = prefix2;
|
2016-08-21 05:39:07 +02:00
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
if (n_addr > 0)
|
|
|
|
n_addr --;
|
2016-08-31 20:06:57 +02:00
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
n++;
|
2016-08-21 05:39:07 +02:00
|
|
|
}
|
2018-04-11 20:12:52 +02:00
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
2013-08-12 14:19:22 +02:00
|
|
|
|
|
|
|
r = sd_bus_message_exit_container(reply);
|
2018-04-11 20:12:52 +02:00
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
|
|
if (truncate) {
|
|
|
|
|
|
|
|
if (!strextend(&addresses, special_glyph(ELLIPSIS), NULL))
|
|
|
|
return -ENOMEM;
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2016-08-31 20:06:57 +02:00
|
|
|
}
|
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
*ret = TAKE_PTR(addresses);
|
|
|
|
return (int) n;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int show_table(Table *table, const char *word) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(table);
|
|
|
|
assert(word);
|
|
|
|
|
|
|
|
if (table_get_rows(table) > 1) {
|
|
|
|
r = table_set_sort(table, (size_t) 0, (size_t) -1);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to sort table: %m");
|
|
|
|
|
|
|
|
table_set_header(table, arg_legend);
|
|
|
|
|
|
|
|
r = table_print(table, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to show table: %m");
|
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) {
|
2018-04-11 20:12:52 +02:00
|
|
|
if (table_get_rows(table) > 1)
|
|
|
|
printf("\n%zu %s listed.\n", table_get_rows(table) - 1, word);
|
2016-11-06 15:19:57 +01:00
|
|
|
else
|
2018-04-11 20:12:52 +02:00
|
|
|
printf("No %s.\n", word);
|
2016-11-06 15:19:57 +01:00
|
|
|
}
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
return 0;
|
2013-07-02 03:47:23 +02:00
|
|
|
}
|
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
static int list_machines(int argc, char *argv[], void *userdata) {
|
|
|
|
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
|
|
|
_cleanup_(table_unrefp) Table *table = NULL;
|
|
|
|
sd_bus *bus = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
2018-11-11 12:56:29 +01:00
|
|
|
(void) pager_open(arg_pager_flags);
|
2018-04-11 20:12:52 +02:00
|
|
|
|
|
|
|
r = sd_bus_call_method(bus,
|
|
|
|
"org.freedesktop.machine1",
|
|
|
|
"/org/freedesktop/machine1",
|
|
|
|
"org.freedesktop.machine1.Manager",
|
|
|
|
"ListMachines",
|
|
|
|
&error,
|
|
|
|
&reply,
|
|
|
|
NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not get machines: %s", bus_error_message(&error, r));
|
|
|
|
|
|
|
|
table = table_new("MACHINE", "CLASS", "SERVICE", "OS", "VERSION", "ADDRESSES");
|
|
|
|
if (!table)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
r = sd_bus_message_enter_container(reply, 'a', "(ssso)");
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
_cleanup_free_ char *os = NULL, *version_id = NULL, *addresses = NULL;
|
2018-06-19 07:09:13 +02:00
|
|
|
const char *name, *class, *service;
|
2018-04-11 20:12:52 +02:00
|
|
|
|
2018-06-19 07:09:13 +02:00
|
|
|
r = sd_bus_message_read(reply, "(ssso)", &name, &class, &service, NULL);
|
2018-04-11 20:12:52 +02:00
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
if (r == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (name[0] == '.' && !arg_all)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
(void) call_get_os_release(
|
|
|
|
bus,
|
|
|
|
"GetMachineOSRelease",
|
|
|
|
name,
|
|
|
|
"ID\0"
|
|
|
|
"VERSION_ID\0",
|
|
|
|
&os,
|
|
|
|
&version_id);
|
|
|
|
|
|
|
|
(void) call_get_addresses(
|
|
|
|
bus,
|
|
|
|
name,
|
|
|
|
0,
|
|
|
|
"",
|
|
|
|
"",
|
|
|
|
arg_addrs,
|
|
|
|
&addresses);
|
|
|
|
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_STRING, name,
|
|
|
|
TABLE_STRING, class,
|
2018-05-10 18:55:46 +02:00
|
|
|
TABLE_STRING, empty_to_dash(service),
|
|
|
|
TABLE_STRING, empty_to_dash(os),
|
|
|
|
TABLE_STRING, empty_to_dash(version_id),
|
|
|
|
TABLE_STRING, empty_to_dash(addresses));
|
2018-04-11 20:12:52 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add table row: %m");
|
|
|
|
}
|
2014-12-19 18:42:50 +01:00
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
r = sd_bus_message_exit_container(reply);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
2014-12-19 18:42:50 +01:00
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
return show_table(table, "machines");
|
2014-12-19 18:42:50 +01:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
2018-04-11 20:12:52 +02:00
|
|
|
_cleanup_(table_unrefp) Table *table = NULL;
|
2014-12-19 19:19:05 +01:00
|
|
|
sd_bus *bus = userdata;
|
2018-04-11 20:12:52 +02:00
|
|
|
int r;
|
2014-12-19 18:42:50 +01:00
|
|
|
|
2014-12-19 19:19:05 +01:00
|
|
|
assert(bus);
|
|
|
|
|
2018-11-11 12:56:29 +01:00
|
|
|
(void) pager_open(arg_pager_flags);
|
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,
|
2018-04-11 20:12:52 +02:00
|
|
|
NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not get images: %s", bus_error_message(&error, r));
|
|
|
|
|
|
|
|
table = table_new("NAME", "TYPE", "RO", "USAGE", "CREATED", "MODIFIED");
|
|
|
|
if (!table)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
(void) table_set_align_percent(table, TABLE_HEADER_CELL(3), 100);
|
2014-12-19 18:42:50 +01:00
|
|
|
|
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);
|
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
for (;;) {
|
|
|
|
uint64_t crtime, mtime, size;
|
2018-06-19 07:09:13 +02:00
|
|
|
const char *name, *type;
|
2018-04-11 20:12:52 +02:00
|
|
|
TableCell *cell;
|
|
|
|
bool ro_bool;
|
|
|
|
int ro_int;
|
|
|
|
|
2018-06-19 07:09:13 +02:00
|
|
|
r = sd_bus_message_read(reply, "(ssbttto)", &name, &type, &ro_int, &crtime, &mtime, &size, NULL);
|
2018-04-11 20:12:52 +02:00
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
if (r == 0)
|
|
|
|
break;
|
2014-12-19 18:42:50 +01:00
|
|
|
|
|
|
|
if (name[0] == '.' && !arg_all)
|
|
|
|
continue;
|
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_STRING, name,
|
|
|
|
TABLE_STRING, type);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add table row: %m");
|
2014-12-25 03:19:19 +01:00
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
ro_bool = ro_int;
|
|
|
|
r = table_add_cell(table, &cell, TABLE_BOOLEAN, &ro_bool);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add table cell: %m");
|
2014-12-19 18:42:50 +01:00
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
if (ro_bool) {
|
|
|
|
r = table_set_color(table, cell, ansi_highlight_red());
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to set table cell color: %m");
|
2014-12-28 02:05:28 +01:00
|
|
|
}
|
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_SIZE, size,
|
|
|
|
TABLE_TIMESTAMP, crtime,
|
|
|
|
TABLE_TIMESTAMP, mtime);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add table row: %m");
|
2014-12-19 18:42:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_bus_message_exit_container(reply);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
return show_table(table, "images");
|
2014-12-19 18:42:50 +01:00
|
|
|
}
|
|
|
|
|
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) {
|
2018-04-11 20:12:52 +02:00
|
|
|
_cleanup_free_ char *s = NULL;
|
2014-05-18 13:48:53 +02:00
|
|
|
int r;
|
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
r = call_get_addresses(bus, name, ifi, prefix, prefix2, n_addr, &s);
|
2014-05-18 13:48:53 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
if (r > 0)
|
|
|
|
fputs(s, stdout);
|
2014-05-18 13:48:53 +02:00
|
|
|
|
2018-04-11 20:12:52 +02:00
|
|
|
return r;
|
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;
|
2018-10-09 09:45:55 +02:00
|
|
|
size_t 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) {
|
2018-05-24 09:36:56 +02:00
|
|
|
char since1[FORMAT_TIMESTAMP_RELATIVE_MAX];
|
|
|
|
char since2[FORMAT_TIMESTAMP_MAX];
|
|
|
|
const char *s1, *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) {
|
2018-10-09 09:45:55 +02:00
|
|
|
size_t c;
|
2014-07-10 23:12:32 +02:00
|
|
|
|
|
|
|
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,
|
2018-03-28 13:37:27 +02:00
|
|
|
0,
|
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
|
|
|
|
2018-03-19 16:37:00 +01:00
|
|
|
r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, NULL, arg_property, arg_value, arg_all, NULL);
|
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-11-11 12:56:29 +01:00
|
|
|
(void) pager_open(arg_pager_flags);
|
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]);
|
2018-08-07 03:14:30 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not get path to machine: %s", bus_error_message(&error, -r));
|
2013-08-12 14:19:22 +02:00
|
|
|
|
|
|
|
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) {
|
2018-05-24 09:36:56 +02:00
|
|
|
char ts_relative[FORMAT_TIMESTAMP_RELATIVE_MAX];
|
|
|
|
char ts_absolute[FORMAT_TIMESTAMP_MAX];
|
|
|
|
char bs[FORMAT_BYTES_MAX];
|
|
|
|
char bs_exclusive[FORMAT_BYTES_MAX];
|
|
|
|
const char *s1, *s2, *s3, *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,
|
2018-03-28 13:37:27 +02:00
|
|
|
BUS_MAP_BOOLEAN_AS_BOOL,
|
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,
|
2018-03-28 13:37:27 +02:00
|
|
|
0,
|
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;
|
|
|
|
|
2018-03-19 16:37:00 +01:00
|
|
|
r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, NULL, arg_property, arg_value, arg_all, NULL);
|
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-11-11 12:56:29 +01:00
|
|
|
(void) pager_open(arg_pager_flags);
|
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]);
|
2018-08-07 03:14:30 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not get path to image: %s", bus_error_message(&error, -r));
|
2014-12-26 20:09:04 +01:00
|
|
|
|
|
|
|
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);
|
2018-08-07 03:14:30 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not kill machine: %s", bus_error_message(&error, -r));
|
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]);
|
2018-08-07 03:14:30 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not terminate machine: %s", bus_error_message(&error, -r));
|
2014-02-12 02:07:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2018-08-07 03:14:30 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to bind mount: %s", bus_error_message(&error, -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
|
|
|
|
2018-10-12 18:53:17 +02:00
|
|
|
(void) sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
|
|
|
|
(void) sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
|
2015-08-23 13:24:10 +02:00
|
|
|
|
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;
|
2018-06-19 07:09:13 +02:00
|
|
|
const char *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);
|
2018-08-07 03:14:30 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get login PTY: %s", bus_error_message(&error, -r));
|
2013-10-31 01:25:44 +01:00
|
|
|
|
2018-06-19 07:09:13 +02:00
|
|
|
r = sd_bus_message_read(reply, "hs", &master, NULL);
|
2014-12-22 21:17:29 +01:00
|
|
|
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;
|
2018-06-19 07:09:13 +02:00
|
|
|
const char *match, *machine, *path;
|
2016-09-26 17:45:31 +02:00
|
|
|
_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);
|
2018-08-06 15:47:03 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get shell PTY: %s", bus_error_message(&error, -r));
|
2015-08-23 13:24:10 +02:00
|
|
|
|
2018-06-19 07:09:13 +02:00
|
|
|
r = sd_bus_message_read(reply, "hs", &master, NULL);
|
2015-08-23 13:24:10 +02:00
|
|
|
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]);
|
2018-08-07 03:14:30 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not rename image: %s", bus_error_message(&error, -r));
|
2014-12-27 17:44:04 +01:00
|
|
|
|
|
|
|
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);
|
2018-08-07 03:14:30 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not mark image read-only: %s", bus_error_message(&error, -r));
|
2014-12-27 17:44:04 +01:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2018-11-20 23:40:44 +01:00
|
|
|
if (!machine_name_is_valid(name))
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Invalid machine name %s.", name);
|
2015-04-30 20:21:00 +02:00
|
|
|
|
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");
|
2018-08-07 03:14:30 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to start unit: %s", bus_error_message(&error, -r));
|
2014-12-29 12:41:26 +01:00
|
|
|
|
|
|
|
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;
|
tree-wide: be more careful with the type of array sizes
Previously we were a bit sloppy with the index and size types of arrays,
we'd regularly use unsigned. While I don't think this ever resulted in
real issues I think we should be more careful there and follow a
stricter regime: unless there's a strong reason not to use size_t for
array sizes and indexes, size_t it should be. Any allocations we do
ultimately will use size_t anyway, and converting forth and back between
unsigned and size_t will always be a source of problems.
Note that on 32bit machines "unsigned" and "size_t" are equivalent, and
on 64bit machines our arrays shouldn't grow that large anyway, and if
they do we have a problem, however that kind of overly large allocation
we have protections for usually, but for overflows we do not have that
so much, hence let's add it.
So yeah, it's a story of the current code being already "good enough",
but I think some extra type hygiene is better.
This patch tries to be comprehensive, but it probably isn't and I missed
a few cases. But I guess we can cover that later as we notice it. Among
smaller fixes, this changes:
1. strv_length()' return type becomes size_t
2. the unit file changes array size becomes size_t
3. DNS answer and query array sizes become size_t
Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=76745
2018-04-27 14:09:31 +02:00
|
|
|
size_t n_changes = 0;
|
2014-12-29 14:05:17 +01:00
|
|
|
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);
|
2018-08-07 03:14:30 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to enable or disable unit: %s", bus_error_message(&error, -r));
|
2014-12-29 14:05:17 +01:00
|
|
|
|
|
|
|
if (streq(argv[0], "enable")) {
|
2018-06-19 07:09:13 +02:00
|
|
|
r = sd_bus_message_read(reply, "b", NULL);
|
2014-12-29 14:05:17 +01:00
|
|
|
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);
|
2018-08-07 03:14:30 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to transfer image: %s", bus_error_message(&error, -r));
|
2015-01-22 03:57:15 +01:00
|
|
|
|
2018-07-08 18:14:37 +02: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
|
|
|
|
2018-10-12 18:53:17 +02:00
|
|
|
(void) sd_event_add_signal(event, NULL, SIGINT, transfer_signal_handler, UINT32_TO_PTR(id));
|
|
|
|
(void) sd_event_add_signal(event, NULL, SIGTERM, transfer_signal_handler, UINT32_TO_PTR(id));
|
2015-01-22 17:31:59 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2018-09-18 01:39:24 +02:00
|
|
|
static int compare_transfer_info(const TransferInfo *a, const TransferInfo *b) {
|
|
|
|
return strcmp(a->local, b->local);
|
2015-01-22 03:57:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2018-06-19 07:09:13 +02:00
|
|
|
const char *type, *remote, *local;
|
2015-01-22 03:57:15 +01:00
|
|
|
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-11-11 12:56:29 +01:00
|
|
|
(void) pager_open(arg_pager_flags);
|
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);
|
2018-08-07 03:14:30 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not get transfers: %s", bus_error_message(&error, -r));
|
2015-01-22 03:57:15 +01:00
|
|
|
|
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);
|
|
|
|
|
2018-06-19 07:09:13 +02:00
|
|
|
while ((r = sd_bus_message_read(reply, "(usssdo)", &id, &type, &remote, &local, &progress, NULL)) > 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);
|
|
|
|
|
2018-09-18 01:39:24 +02:00
|
|
|
typesafe_qsort(transfers, n_transfers, compare_transfer_info);
|
2015-01-22 03:57:15 +01:00
|
|
|
|
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);
|
2018-08-07 03:14:30 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not cancel transfer: %s", bus_error_message(&error, -r));
|
2015-01-22 03:57:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2018-04-05 12:38:25 +02:00
|
|
|
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
|
|
|
|
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)
|
2018-04-05 12:38:25 +02:00
|
|
|
return log_error_errno(r, "Failed to parse size: %s", argv[argc-1]);
|
2015-02-24 23:50:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2018-04-05 12:38:25 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not set limit: %s", bus_error_message(&error, r));
|
2015-02-24 23:50:37 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2018-04-05 12:38:25 +02:00
|
|
|
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
|
|
|
|
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-08-09 10:32:31 +02:00
|
|
|
_cleanup_free_ char *link = NULL;
|
|
|
|
int r;
|
|
|
|
|
2018-11-11 12:56:29 +01:00
|
|
|
(void) pager_open(arg_pager_flags);
|
2014-12-19 19:19:05 +01:00
|
|
|
|
2018-08-09 10:32:31 +02:00
|
|
|
r = terminal_urlify_man("machinectl", "1", &link);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
|
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"
|
2018-07-23 20:22:30 +02:00
|
|
|
" json, json-pretty, json-sse, json-seq, cat,\n"
|
|
|
|
" with-unit)\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"
|
2018-08-09 10:32:31 +02:00
|
|
|
"\nSee the %s for details.\n"
|
|
|
|
, program_invocation_short_name
|
|
|
|
, link
|
|
|
|
);
|
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':
|
2018-11-20 23:40:44 +01:00
|
|
|
if (safe_atou(optarg, &arg_lines) < 0)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Failed to parse lines '%s'", optarg);
|
2015-01-08 15:09:12 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'o':
|
2018-05-22 12:10:56 +02:00
|
|
|
if (streq(optarg, "help")) {
|
|
|
|
DUMP_STRING_TABLE(output_mode, OutputMode, _OUTPUT_MODE_MAX);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-01-08 15:09:12 +01:00
|
|
|
arg_output = output_mode_from_string(optarg);
|
2018-11-20 23:40:44 +01:00
|
|
|
if (arg_output < 0)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Unknown output '%s'.", optarg);
|
2015-01-08 15:09:12 +01:00
|
|
|
break;
|
|
|
|
|
2013-07-02 03:47:23 +02:00
|
|
|
case ARG_NO_PAGER:
|
2018-11-11 12:56:29 +01:00
|
|
|
arg_pager_flags |= PAGER_DISABLE;
|
2013-07-02 03:47:23 +02:00
|
|
|
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':
|
2018-05-22 12:10:56 +02:00
|
|
|
if (streq(optarg, "help")) {
|
|
|
|
DUMP_STRING_TABLE(signal, int, _NSIG);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-05-03 09:38:57 +02:00
|
|
|
arg_signal = signal_from_string(optarg);
|
2018-11-20 23:40:44 +01:00
|
|
|
if (arg_signal < 0)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Failed to parse signal string %s.", optarg);
|
2013-07-02 03:47:23 +02:00
|
|
|
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:
|
2018-05-22 12:10:56 +02:00
|
|
|
if (streq(optarg, "help")) {
|
|
|
|
DUMP_STRING_TABLE(import_verify, ImportVerify, _IMPORT_VERIFY_MAX);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-01-22 17:30:40 +01:00
|
|
|
arg_verify = import_verify_from_string(optarg);
|
2018-11-20 23:40:44 +01:00
|
|
|
if (arg_verify < 0)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Failed to parse --verify= setting: %s", optarg);
|
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:
|
2018-11-20 23:40:44 +01:00
|
|
|
if (!STR_IN_SET(optarg, "uncompressed", "xz", "gzip", "bzip2"))
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Unknown format: %s", optarg);
|
2015-03-09 17:55:07 +01:00
|
|
|
|
|
|
|
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':
|
2018-11-20 23:40:44 +01:00
|
|
|
if (!env_assignment_is_valid(optarg))
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Environment assignment invalid: %s", optarg);
|
2015-08-23 13:24:10 +02:00
|
|
|
|
|
|
|
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;
|
2018-11-20 23:40:44 +01:00
|
|
|
else if (safe_atoi(optarg, &arg_addrs) < 0)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Invalid number of IPs");
|
|
|
|
else if (arg_addrs < 0)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Number of IPs cannot be negative");
|
2016-08-31 20:06:57 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2018-11-20 10:21:01 +01:00
|
|
|
static int run(int argc, char*argv[]) {
|
|
|
|
_cleanup_(sd_bus_flush_close_unrefp) 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();
|
2018-10-01 17:44:46 +02:00
|
|
|
|
|
|
|
/* The journal merging logic potentially needs a lot of fds. */
|
|
|
|
(void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
|
|
|
|
|
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)
|
2018-11-20 10:21:01 +01:00
|
|
|
return r;
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2015-09-24 13:30:10 +02:00
|
|
|
r = bus_connect_transport(arg_transport, arg_host, false, &bus);
|
2018-11-20 10:21:01 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to create bus connection: %m");
|
2013-07-02 03:47:23 +02:00
|
|
|
|
2018-04-05 12:38:25 +02:00
|
|
|
(void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
|
2015-02-18 11:42:03 +01:00
|
|
|
|
2018-11-20 10:21:01 +01:00
|
|
|
return machinectl_main(argc, argv, bus);
|
2013-07-02 03:47:23 +02:00
|
|
|
}
|
2018-11-20 10:21:01 +01:00
|
|
|
|
|
|
|
DEFINE_MAIN_FUNCTION(run);
|