]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/run/run.c
sd-bus: rename sd_bus_open_system_container() to sd_bus_open_system_machine()
[thirdparty/systemd.git] / src / run / run.c
CommitLineData
c2756a68
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <stdio.h>
6c12b52e 23#include <getopt.h>
c2756a68
LP
24
25#include "sd-bus.h"
9b15b784 26#include "sd-event.h"
40ca29a1 27#include "bus-util.h"
9b15b784 28#include "event-util.h"
c2756a68 29#include "strv.h"
6c12b52e
LP
30#include "build.h"
31#include "unit-name.h"
4de33e7f 32#include "env-util.h"
4bcc8c3c 33#include "path-util.h"
94676f3e 34#include "bus-error.h"
4c213d6c 35#include "calendarspec.h"
9b15b784 36#include "ptyfwd.h"
c2756a68 37
6c12b52e 38static bool arg_scope = false;
6577c7ce 39static bool arg_remain_after_exit = false;
6c12b52e 40static const char *arg_unit = NULL;
9f2e86af 41static const char *arg_description = NULL;
c221420b 42static const char *arg_slice = NULL;
a6c0353b 43static bool arg_send_sighup = false;
d21ed1ea 44static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
1ac67edb 45static const char *arg_host = NULL;
d21ed1ea 46static bool arg_user = false;
c7040b5d
LP
47static const char *arg_service_type = NULL;
48static const char *arg_exec_user = NULL;
49static const char *arg_exec_group = NULL;
50static int arg_nice = 0;
51static bool arg_nice_set = false;
52static char **arg_environment = NULL;
df31a6c0 53static char **arg_property = NULL;
9b15b784 54static bool arg_pty = false;
4c213d6c
WC
55static usec_t arg_on_active = 0;
56static usec_t arg_on_boot = 0;
57static usec_t arg_on_startup = 0;
58static usec_t arg_on_unit_active = 0;
59static usec_t arg_on_unit_inactive = 0;
60static char *arg_on_calendar = NULL;
61static char **arg_timer_property = NULL;
095dc596 62static bool arg_quiet = false;
c2756a68 63
601185b4 64static void help(void) {
4c213d6c
WC
65 printf("%s [OPTIONS...] {COMMAND} [ARGS...]\n\n"
66 "Run the specified command in a transient scope or service or timer\n"
67 "unit. If timer option is specified and unit is exist which is\n"
68 "specified with --unit option then command can be ommited.\n\n"
69 " -h --help Show this help\n"
70 " --version Show package version\n"
71 " --user Run as user unit\n"
72 " -H --host=[USER@]HOST Operate on remote host\n"
73 " -M --machine=CONTAINER Operate on local container\n"
74 " --scope Run this as scope rather than service\n"
75 " --unit=UNIT Run under the specified unit name\n"
76 " -p --property=NAME=VALUE Set unit property\n"
77 " --description=TEXT Description for unit\n"
78 " --slice=SLICE Run in the specified slice\n"
79 " -r --remain-after-exit Leave service around until explicitly stopped\n"
80 " --send-sighup Send SIGHUP when terminating\n"
81 " --service-type=TYPE Service type\n"
82 " --uid=USER Run as system user\n"
83 " --gid=GROUP Run as system group\n"
84 " --nice=NICE Nice level\n"
9b15b784 85 " --setenv=NAME=VALUE Set environment\n"
095dc596
LP
86 " -t --pty Run service on pseudo tty\n"
87 " -q --quiet Suppress information messages during runtime\n\n"
4c213d6c
WC
88 "Timer options:\n\n"
89 " --on-active=SEC Run after seconds\n"
90 " --on-boot=SEC Run after seconds from machine was booted up\n"
91 " --on-startup=SEC Run after seconds from systemd was first started\n"
92 " --on-unit-active=SEC Run after seconds from the last activation\n"
93 " --on-unit-inactive=SEC Run after seconds from the last deactivation\n"
94 " --on-calendar=SPEC Realtime timer\n"
95 " --timer-property=NAME=VALUE Set timer unit property\n",
6c12b52e 96 program_invocation_short_name);
6c12b52e
LP
97}
98
4c213d6c
WC
99static bool with_timer(void) {
100 return arg_on_active || arg_on_boot || arg_on_startup || arg_on_unit_active || arg_on_unit_inactive || arg_on_calendar;
101}
102
6c12b52e
LP
103static int parse_argv(int argc, char *argv[]) {
104
105 enum {
106 ARG_VERSION = 0x100,
107 ARG_USER,
66b1e746 108 ARG_SYSTEM,
6c12b52e 109 ARG_SCOPE,
9f2e86af 110 ARG_UNIT,
c221420b 111 ARG_DESCRIPTION,
a6c0353b
LP
112 ARG_SLICE,
113 ARG_SEND_SIGHUP,
c7040b5d
LP
114 ARG_EXEC_USER,
115 ARG_EXEC_GROUP,
116 ARG_SERVICE_TYPE,
117 ARG_NICE,
4c213d6c 118 ARG_SETENV,
9b15b784 119 ARG_TTY,
4c213d6c
WC
120 ARG_ON_ACTIVE,
121 ARG_ON_BOOT,
122 ARG_ON_STARTUP,
123 ARG_ON_UNIT_ACTIVE,
124 ARG_ON_UNIT_INACTIVE,
125 ARG_ON_CALENDAR,
126 ARG_TIMER_PROPERTY
6c12b52e
LP
127 };
128
129 static const struct option options[] = {
4c213d6c
WC
130 { "help", no_argument, NULL, 'h' },
131 { "version", no_argument, NULL, ARG_VERSION },
132 { "user", no_argument, NULL, ARG_USER },
133 { "system", no_argument, NULL, ARG_SYSTEM },
134 { "scope", no_argument, NULL, ARG_SCOPE },
135 { "unit", required_argument, NULL, ARG_UNIT },
136 { "description", required_argument, NULL, ARG_DESCRIPTION },
137 { "slice", required_argument, NULL, ARG_SLICE },
138 { "remain-after-exit", no_argument, NULL, 'r' },
139 { "send-sighup", no_argument, NULL, ARG_SEND_SIGHUP },
140 { "host", required_argument, NULL, 'H' },
141 { "machine", required_argument, NULL, 'M' },
142 { "service-type", required_argument, NULL, ARG_SERVICE_TYPE },
143 { "uid", required_argument, NULL, ARG_EXEC_USER },
144 { "gid", required_argument, NULL, ARG_EXEC_GROUP },
145 { "nice", required_argument, NULL, ARG_NICE },
146 { "setenv", required_argument, NULL, ARG_SETENV },
147 { "property", required_argument, NULL, 'p' },
9b15b784 148 { "tty", no_argument, NULL, 't' },
095dc596 149 { "quiet", no_argument, NULL, 'q' },
4c213d6c
WC
150 { "on-active", required_argument, NULL, ARG_ON_ACTIVE },
151 { "on-boot", required_argument, NULL, ARG_ON_BOOT },
152 { "on-startup", required_argument, NULL, ARG_ON_STARTUP },
153 { "on-unit-active", required_argument, NULL, ARG_ON_UNIT_ACTIVE },
154 { "on-unit-inactive", required_argument, NULL, ARG_ON_UNIT_INACTIVE },
155 { "on-calendar", required_argument, NULL, ARG_ON_CALENDAR },
156 { "timer-property", required_argument, NULL, ARG_TIMER_PROPERTY },
eb9da376 157 {},
6c12b52e
LP
158 };
159
c7040b5d 160 int r, c;
4c213d6c 161 CalendarSpec *spec = NULL;
6c12b52e
LP
162
163 assert(argc >= 0);
164 assert(argv);
165
095dc596 166 while ((c = getopt_long(argc, argv, "+hrH:M:p:tq", options, NULL)) >= 0)
6c12b52e
LP
167
168 switch (c) {
169
170 case 'h':
601185b4
ZJS
171 help();
172 return 0;
6c12b52e
LP
173
174 case ARG_VERSION:
175 puts(PACKAGE_STRING);
176 puts(SYSTEMD_FEATURES);
177 return 0;
178
179 case ARG_USER:
180 arg_user = true;
181 break;
182
66b1e746
LP
183 case ARG_SYSTEM:
184 arg_user = false;
185 break;
186
6c12b52e
LP
187 case ARG_SCOPE:
188 arg_scope = true;
189 break;
190
191 case ARG_UNIT:
192 arg_unit = optarg;
193 break;
194
9f2e86af
LP
195 case ARG_DESCRIPTION:
196 arg_description = optarg;
197 break;
198
c221420b
LP
199 case ARG_SLICE:
200 arg_slice = optarg;
201 break;
202
a6c0353b
LP
203 case ARG_SEND_SIGHUP:
204 arg_send_sighup = true;
205 break;
206
6577c7ce
LP
207 case 'r':
208 arg_remain_after_exit = true;
209 break;
210
d21ed1ea
LP
211 case 'H':
212 arg_transport = BUS_TRANSPORT_REMOTE;
213 arg_host = optarg;
214 break;
215
216 case 'M':
de33fc62 217 arg_transport = BUS_TRANSPORT_MACHINE;
d21ed1ea
LP
218 arg_host = optarg;
219 break;
220
c7040b5d
LP
221 case ARG_SERVICE_TYPE:
222 arg_service_type = optarg;
223 break;
224
225 case ARG_EXEC_USER:
226 arg_exec_user = optarg;
227 break;
228
229 case ARG_EXEC_GROUP:
230 arg_exec_group = optarg;
231 break;
232
233 case ARG_NICE:
234 r = safe_atoi(optarg, &arg_nice);
1ac67edb 235 if (r < 0 || arg_nice < PRIO_MIN || arg_nice >= PRIO_MAX) {
c7040b5d
LP
236 log_error("Failed to parse nice value");
237 return -EINVAL;
238 }
239
240 arg_nice_set = true;
241 break;
242
243 case ARG_SETENV:
244
245 if (strv_extend(&arg_environment, optarg) < 0)
246 return log_oom();
247
248 break;
249
df31a6c0
LP
250 case 'p':
251
252 if (strv_extend(&arg_property, optarg) < 0)
253 return log_oom();
254
255 break;
256
9b15b784
LP
257 case 't':
258 arg_pty = true;
259 break;
260
095dc596
LP
261 case 'q':
262 arg_quiet = true;
263 break;
264
4c213d6c
WC
265 case ARG_ON_ACTIVE:
266
267 r = parse_sec(optarg, &arg_on_active);
268 if (r < 0) {
269 log_error("Failed to parse timer value: %s", optarg);
270 return r;
271 }
272
273 break;
274
275 case ARG_ON_BOOT:
276
277 r = parse_sec(optarg, &arg_on_boot);
278 if (r < 0) {
279 log_error("Failed to parse timer value: %s", optarg);
280 return r;
281 }
282
283 break;
284
285 case ARG_ON_STARTUP:
286
287 r = parse_sec(optarg, &arg_on_startup);
288 if (r < 0) {
289 log_error("Failed to parse timer value: %s", optarg);
290 return r;
291 }
292
293 break;
294
295 case ARG_ON_UNIT_ACTIVE:
296
297 r = parse_sec(optarg, &arg_on_unit_active);
298 if (r < 0) {
299 log_error("Failed to parse timer value: %s", optarg);
300 return r;
301 }
302
303 break;
304
305 case ARG_ON_UNIT_INACTIVE:
306
307 r = parse_sec(optarg, &arg_on_unit_inactive);
308 if (r < 0) {
309 log_error("Failed to parse timer value: %s", optarg);
310 return r;
311 }
312
313 break;
314
315 case ARG_ON_CALENDAR:
316
317 r = calendar_spec_from_string(optarg, &spec);
318 if (r < 0) {
319 log_error("Invalid calendar spec: %s", optarg);
320 return r;
321 }
322 free(spec);
323 arg_on_calendar = optarg;
324 break;
325
326 case ARG_TIMER_PROPERTY:
327
328 if (strv_extend(&arg_timer_property, optarg) < 0)
329 return log_oom();
330
331 break;
332
6c12b52e
LP
333 case '?':
334 return -EINVAL;
335
336 default:
eb9da376 337 assert_not_reached("Unhandled option");
6c12b52e 338 }
6c12b52e 339
4c213d6c 340 if ((optind >= argc) && (!arg_unit || !with_timer())) {
6c12b52e
LP
341 log_error("Command line to execute required.");
342 return -EINVAL;
343 }
344
d21ed1ea
LP
345 if (arg_user && arg_transport != BUS_TRANSPORT_LOCAL) {
346 log_error("Execution in user context is not supported on non-local systems.");
347 return -EINVAL;
348 }
349
350 if (arg_scope && arg_transport != BUS_TRANSPORT_LOCAL) {
351 log_error("Scope execution is not supported on non-local systems.");
352 return -EINVAL;
353 }
354
4de33e7f
LP
355 if (arg_scope && (arg_remain_after_exit || arg_service_type)) {
356 log_error("--remain-after-exit and --service-type= are not supported in --scope mode.");
c7040b5d
LP
357 return -EINVAL;
358 }
359
9b15b784
LP
360 if (arg_pty && (with_timer() || arg_scope)) {
361 log_error("--pty is not compatible in timer or --scope mode.");
362 return -EINVAL;
363 }
364
4c213d6c
WC
365 if (arg_scope && with_timer()) {
366 log_error("Timer options are not supported in --scope mode.");
367 return -EINVAL;
368 }
369
370 if (arg_timer_property && !with_timer()) {
371 log_error("--timer-property= has no effect without any other timer options.");
372 return -EINVAL;
373 }
374
6c12b52e
LP
375 return 1;
376}
377
9b15b784 378static int transient_unit_set_properties(sd_bus_message *m, char **properties) {
df31a6c0 379 char **i;
c2756a68
LP
380 int r;
381
9b15b784
LP
382 r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description);
383 if (r < 0)
384 return r;
385
386 STRV_FOREACH(i, properties) {
df31a6c0
LP
387 r = sd_bus_message_open_container(m, 'r', "sv");
388 if (r < 0)
389 return r;
390
391 r = bus_append_unit_property_assignment(m, *i);
4c213d6c
WC
392 if (r < 0) {
393 r = sd_bus_message_append(m, "sv", 0);
394 if (r < 0)
395 return r;
396 }
df31a6c0
LP
397
398 r = sd_bus_message_close_container(m);
399 if (r < 0)
400 return r;
401 }
402
9b15b784
LP
403 return 0;
404}
405
406static int transient_cgroup_set_properties(sd_bus_message *m) {
407 int r;
408 assert(m);
c2756a68 409
c221420b
LP
410 if (!isempty(arg_slice)) {
411 _cleanup_free_ char *slice;
412
f78e6385 413 slice = unit_name_mangle_with_suffix(arg_slice, MANGLE_NOGLOB, ".slice");
c221420b
LP
414 if (!slice)
415 return -ENOMEM;
416
417 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
418 if (r < 0)
419 return r;
420 }
421
9b15b784
LP
422 return 0;
423}
424
425static int transient_kill_set_properties(sd_bus_message *m) {
426 int r;
427 assert(m);
428
429 if (arg_send_sighup) {
df31a6c0
LP
430 r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", arg_send_sighup);
431 if (r < 0)
432 return r;
433 }
a6c0353b 434
9b15b784 435 return r;
6c12b52e
LP
436}
437
9b15b784 438static int transient_service_set_properties(sd_bus_message *m, char **argv, const char *pty_path) {
6c12b52e
LP
439 int r;
440
8159d91a
LP
441 assert(m);
442
9b15b784
LP
443 r = transient_unit_set_properties(m, arg_property);
444 if (r < 0)
445 return r;
446
447 r = transient_kill_set_properties(m);
448 if (r < 0)
449 return r;
450
451 r = transient_cgroup_set_properties(m);
86b8d289
LP
452 if (r < 0)
453 return r;
454
df31a6c0
LP
455 if (arg_remain_after_exit) {
456 r = sd_bus_message_append(m, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit);
457 if (r < 0)
4c213d6c 458 return r;
df31a6c0 459 }
6577c7ce 460
c7040b5d
LP
461 if (arg_service_type) {
462 r = sd_bus_message_append(m, "(sv)", "Type", "s", arg_service_type);
463 if (r < 0)
4c213d6c 464 return r;
c7040b5d
LP
465 }
466
467 if (arg_exec_user) {
468 r = sd_bus_message_append(m, "(sv)", "User", "s", arg_exec_user);
469 if (r < 0)
4c213d6c 470 return r;
c7040b5d
LP
471 }
472
473 if (arg_exec_group) {
474 r = sd_bus_message_append(m, "(sv)", "Group", "s", arg_exec_group);
475 if (r < 0)
4c213d6c 476 return r;
c7040b5d
LP
477 }
478
479 if (arg_nice_set) {
480 r = sd_bus_message_append(m, "(sv)", "Nice", "i", arg_nice);
481 if (r < 0)
4c213d6c 482 return r;
c7040b5d
LP
483 }
484
9b15b784
LP
485 if (pty_path) {
486 const char *e;
487
488 r = sd_bus_message_append(m,
489 "(sv)(sv)(sv)(sv)",
490 "StandardInput", "s", "tty",
491 "StandardOutput", "s", "tty",
492 "StandardError", "s", "tty",
493 "TTYPath", "s", pty_path);
494 if (r < 0)
495 return r;
496
497 e = getenv("TERM");
498 if (e) {
499 char *n;
500
501 n = strappenda("TERM=", e);
502 r = sd_bus_message_append(m,
503 "(sv)",
504 "Environment", "as", 1, n);
505 if (r < 0)
506 return r;
507 }
508 }
509
c7040b5d
LP
510 if (!strv_isempty(arg_environment)) {
511 r = sd_bus_message_open_container(m, 'r', "sv");
512 if (r < 0)
4c213d6c 513 return r;
c7040b5d
LP
514
515 r = sd_bus_message_append(m, "s", "Environment");
516 if (r < 0)
4c213d6c 517 return r;
c7040b5d
LP
518
519 r = sd_bus_message_open_container(m, 'v', "as");
520 if (r < 0)
4c213d6c 521 return r;
c7040b5d
LP
522
523 r = sd_bus_message_append_strv(m, arg_environment);
524 if (r < 0)
4c213d6c 525 return r;
c7040b5d
LP
526
527 r = sd_bus_message_close_container(m);
528 if (r < 0)
4c213d6c 529 return r;
c7040b5d
LP
530
531 r = sd_bus_message_close_container(m);
532 if (r < 0)
4c213d6c
WC
533 return r;
534 }
535
536 /* Exec container */
537 {
538 r = sd_bus_message_open_container(m, 'r', "sv");
539 if (r < 0)
540 return r;
541
542 r = sd_bus_message_append(m, "s", "ExecStart");
543 if (r < 0)
544 return r;
545
546 r = sd_bus_message_open_container(m, 'v', "a(sasb)");
547 if (r < 0)
548 return r;
549
550 r = sd_bus_message_open_container(m, 'a', "(sasb)");
551 if (r < 0)
552 return r;
553
554 r = sd_bus_message_open_container(m, 'r', "sasb");
555 if (r < 0)
556 return r;
557
558 r = sd_bus_message_append(m, "s", argv[0]);
559 if (r < 0)
560 return r;
561
562 r = sd_bus_message_append_strv(m, argv);
563 if (r < 0)
564 return r;
565
566 r = sd_bus_message_append(m, "b", false);
567 if (r < 0)
568 return r;
569
570 r = sd_bus_message_close_container(m);
571 if (r < 0)
572 return r;
573
574 r = sd_bus_message_close_container(m);
575 if (r < 0)
576 return r;
577
578 r = sd_bus_message_close_container(m);
579 if (r < 0)
580 return r;
581
582 r = sd_bus_message_close_container(m);
583 if (r < 0)
584 return r;
585 }
586
587 return 0;
588}
589
9b15b784
LP
590static int transient_scope_set_properties(sd_bus_message *m) {
591 int r;
592
593 assert(m);
594
595 r = transient_unit_set_properties(m, arg_property);
596 if (r < 0)
597 return r;
598
599 r = transient_kill_set_properties(m);
600 if (r < 0)
601 return r;
602
603 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
604 if (r < 0)
605 return r;
606
607 return 0;
608}
609
4c213d6c
WC
610static int transient_timer_set_properties(sd_bus_message *m) {
611 int r;
612
613 assert(m);
614
9b15b784 615 r = transient_unit_set_properties(m, arg_timer_property);
4c213d6c
WC
616 if (r < 0)
617 return r;
618
619 if (arg_on_active) {
620 r = sd_bus_message_append(m, "(sv)", "OnActiveSec", "t", arg_on_active);
621 if (r < 0)
622 return r;
c7040b5d
LP
623 }
624
4c213d6c
WC
625 if (arg_on_boot) {
626 r = sd_bus_message_append(m, "(sv)", "OnBootSec", "t", arg_on_boot);
627 if (r < 0)
628 return r;
629 }
630
631 if (arg_on_startup) {
632 r = sd_bus_message_append(m, "(sv)", "OnStartupSec", "t", arg_on_startup);
633 if (r < 0)
634 return r;
635 }
636
637 if (arg_on_unit_active) {
638 r = sd_bus_message_append(m, "(sv)", "OnUnitActiveSec", "t", arg_on_unit_active);
639 if (r < 0)
640 return r;
641 }
642
643 if (arg_on_unit_inactive) {
644 r = sd_bus_message_append(m, "(sv)", "OnUnitInactiveSec", "t", arg_on_unit_inactive);
645 if (r < 0)
646 return r;
647 }
648
649 if (arg_on_calendar) {
650 r = sd_bus_message_append(m, "(sv)", "OnCalendar", "s", arg_on_calendar);
651 if (r < 0)
652 return r;
653 }
654
655 return 0;
656}
657
4c213d6c
WC
658static int start_transient_service(
659 sd_bus *bus,
ee451d76 660 char **argv) {
4c213d6c 661
ee451d76 662 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4c213d6c 663 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
ee451d76 664 _cleanup_free_ char *service = NULL, *pty_path = NULL;
9b15b784 665 _cleanup_close_ int master = -1;
4c213d6c
WC
666 int r;
667
668 assert(bus);
669 assert(argv);
670
9b15b784 671 if (arg_pty) {
9b15b784 672
ee451d76
LP
673 if (arg_transport == BUS_TRANSPORT_LOCAL) {
674 master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY);
675 if (master < 0)
676 return log_error_errno(errno, "Failed to acquire pseudo tty: %m");
677
678 r = ptsname_malloc(master, &pty_path);
679 if (r < 0)
680 return log_error_errno(r, "Failed to determine tty name: %m");
681
de33fc62 682 } else if (arg_transport == BUS_TRANSPORT_MACHINE) {
ee451d76
LP
683 _cleanup_bus_unref_ sd_bus *system_bus = NULL;
684 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
685 const char *s;
686
687 r = sd_bus_open_system(&system_bus);
688 if (r < 0)
689 log_error_errno(r, "Failed to connect to system bus: %m");
690
691 r = sd_bus_call_method(system_bus,
692 "org.freedesktop.machine1",
693 "/org/freedesktop/machine1",
694 "org.freedesktop.machine1.Manager",
695 "OpenMachinePTY",
696 &error,
697 &reply,
698 "s", arg_host);
699 if (r < 0) {
700 log_error("Failed to get machine PTY: %s", bus_error_message(&error, -r));
701 return r;
702 }
703
704 r = sd_bus_message_read(reply, "hs", &master, &s);
705 if (r < 0)
706 return bus_log_parse_error(r);
707
708 master = fcntl(master, F_DUPFD_CLOEXEC, 3);
709 if (master < 0)
710 return log_error_errno(errno, "Failed to duplicate master fd: %m");
711
712 pty_path = strdup(s);
713 if (!pty_path)
714 return log_oom();
715 } else
716 assert_not_reached("Can't allocate tty via ssh");
9b15b784
LP
717
718 if (unlockpt(master) < 0)
719 return log_error_errno(errno, "Failed to unlock tty: %m");
720 }
721
4c213d6c
WC
722 if (arg_unit) {
723 service = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".service");
724 if (!service)
725 return log_oom();
726 } else if (asprintf(&service, "run-"PID_FMT".service", getpid()) < 0)
727 return log_oom();
728
729 r = sd_bus_message_new_method_call(
730 bus,
731 &m,
732 "org.freedesktop.systemd1",
733 "/org/freedesktop/systemd1",
734 "org.freedesktop.systemd1.Manager",
735 "StartTransientUnit");
9f2e86af 736 if (r < 0)
7040b626 737 return bus_log_create_error(r);
9f2e86af 738
9b15b784 739 /* Name and mode */
4c213d6c 740 r = sd_bus_message_append(m, "ss", service, "fail");
c2756a68 741 if (r < 0)
7040b626 742 return bus_log_create_error(r);
c2756a68 743
9b15b784 744 /* Properties */
4c213d6c 745 r = sd_bus_message_open_container(m, 'a', "(sv)");
c2756a68 746 if (r < 0)
7040b626 747 return bus_log_create_error(r);
c2756a68 748
9b15b784 749 r = transient_service_set_properties(m, argv, pty_path);
c2756a68 750 if (r < 0)
7040b626 751 return bus_log_create_error(r);
c2756a68 752
4c213d6c 753 r = sd_bus_message_close_container(m);
c2756a68 754 if (r < 0)
7040b626 755 return bus_log_create_error(r);
c2756a68 756
9b15b784 757 /* Auxiliary units */
4c213d6c 758 r = sd_bus_message_append(m, "a(sa(sv))", 0);
c2756a68 759 if (r < 0)
7040b626 760 return bus_log_create_error(r);
c2756a68 761
ee451d76
LP
762 r = sd_bus_call(bus, m, 0, &error, NULL);
763 if (r < 0) {
764 log_error("Failed to start transient service unit: %s", bus_error_message(&error, -r));
765 return r;
766 }
c2756a68 767
9b15b784
LP
768 if (master >= 0) {
769 _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
770 _cleanup_event_unref_ sd_event *event = NULL;
771 sigset_t mask;
772 char last_char = 0;
4c213d6c 773
9b15b784 774 r = sd_event_default(&event);
4c213d6c 775 if (r < 0)
9b15b784 776 return log_error_errno(r, "Failed to get event loop: %m");
4c213d6c 777
9b15b784
LP
778 assert_se(sigemptyset(&mask) == 0);
779 sigset_add_many(&mask, SIGWINCH, SIGTERM, SIGINT, -1);
780 assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
4c213d6c 781
9b15b784
LP
782 sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
783 sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
4c213d6c 784
095dc596
LP
785 if (!arg_quiet)
786 log_info("Running as unit %s.\nPress ^] three times within 1s to disconnect TTY.", service);
4c213d6c 787
9b15b784 788 r = pty_forward_new(event, master, false, &forward);
4c213d6c 789 if (r < 0)
9b15b784 790 return log_error_errno(r, "Failed to create PTY forwarder: %m");
4c213d6c 791
9b15b784 792 r = sd_event_loop(event);
4c213d6c 793 if (r < 0)
9b15b784 794 return log_error_errno(r, "Failed to run event loop: %m");
4c213d6c 795
9b15b784 796 pty_forward_last_char(forward, &last_char);
4c213d6c 797
9b15b784 798 forward = pty_forward_free(forward);
4c213d6c 799
095dc596 800 if (!arg_quiet && last_char != '\n')
9b15b784 801 fputc('\n', stdout);
9f2e86af 802
095dc596 803 } else if (!arg_quiet)
9b15b784 804 log_info("Running as unit %s.", service);
7040b626
LP
805
806 return 0;
6c12b52e
LP
807}
808
809static int start_transient_scope(
810 sd_bus *bus,
ee451d76 811 char **argv) {
6c12b52e 812
ee451d76 813 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
9b15b784 814 _cleanup_strv_free_ char **env = NULL, **user_env = NULL;
8159d91a 815 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
4c213d6c 816 _cleanup_free_ char *scope = NULL;
6c12b52e
LP
817 int r;
818
8159d91a 819 assert(bus);
4c213d6c 820 assert(argv);
8159d91a 821
7de80bfe 822 if (arg_unit) {
4c213d6c
WC
823 scope = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".scope");
824 if (!scope)
7de80bfe 825 return log_oom();
4c213d6c 826 } else if (asprintf(&scope, "run-"PID_FMT".scope", getpid()) < 0)
7040b626 827 return log_oom();
6c12b52e 828
4c213d6c 829 r = sd_bus_message_new_method_call(
9b15b784
LP
830 bus,
831 &m,
832 "org.freedesktop.systemd1",
833 "/org/freedesktop/systemd1",
834 "org.freedesktop.systemd1.Manager",
835 "StartTransientUnit");
c2756a68 836 if (r < 0)
7040b626 837 return bus_log_create_error(r);
c2756a68 838
9b15b784 839 /* Name and Mode */
4c213d6c
WC
840 r = sd_bus_message_append(m, "ss", scope, "fail");
841 if (r < 0)
842 return bus_log_create_error(r);
843
9b15b784 844 /* Properties */
4c213d6c
WC
845 r = sd_bus_message_open_container(m, 'a', "(sv)");
846 if (r < 0)
847 return bus_log_create_error(r);
848
849 r = transient_scope_set_properties(m);
850 if (r < 0)
851 return bus_log_create_error(r);
852
853 r = sd_bus_message_close_container(m);
854 if (r < 0)
855 return bus_log_create_error(r);
856
ee451d76 857 /* Auxiliary units */
4c213d6c 858 r = sd_bus_message_append(m, "a(sa(sv))", 0);
6c12b52e 859 if (r < 0)
7040b626 860 return bus_log_create_error(r);
6c12b52e 861
ee451d76
LP
862 r = sd_bus_call(bus, m, 0, &error, NULL);
863 if (r < 0) {
864 log_error("Failed to start transient scope unit: %s", bus_error_message(&error, -r));
865 return r;
866 }
c2756a68 867
4de33e7f 868 if (arg_nice_set) {
4a62c710
MS
869 if (setpriority(PRIO_PROCESS, 0, arg_nice) < 0)
870 return log_error_errno(errno, "Failed to set nice level: %m");
4de33e7f
LP
871 }
872
873 if (arg_exec_group) {
874 gid_t gid;
875
876 r = get_group_creds(&arg_exec_group, &gid);
f647962d
MS
877 if (r < 0)
878 return log_error_errno(r, "Failed to resolve group %s: %m", arg_exec_group);
4de33e7f 879
4a62c710
MS
880 if (setresgid(gid, gid, gid) < 0)
881 return log_error_errno(errno, "Failed to change GID to " GID_FMT ": %m", gid);
4de33e7f
LP
882 }
883
884 if (arg_exec_user) {
885 const char *home, *shell;
886 uid_t uid;
887 gid_t gid;
888
889 r = get_user_creds(&arg_exec_user, &uid, &gid, &home, &shell);
f647962d
MS
890 if (r < 0)
891 return log_error_errno(r, "Failed to resolve user %s: %m", arg_exec_user);
4de33e7f
LP
892
893 r = strv_extendf(&user_env, "HOME=%s", home);
894 if (r < 0)
895 return log_oom();
896
897 r = strv_extendf(&user_env, "SHELL=%s", shell);
898 if (r < 0)
899 return log_oom();
900
901 r = strv_extendf(&user_env, "USER=%s", arg_exec_user);
902 if (r < 0)
903 return log_oom();
904
905 r = strv_extendf(&user_env, "LOGNAME=%s", arg_exec_user);
906 if (r < 0)
907 return log_oom();
908
909 if (!arg_exec_group) {
4a62c710
MS
910 if (setresgid(gid, gid, gid) < 0)
911 return log_error_errno(errno, "Failed to change GID to " GID_FMT ": %m", gid);
4de33e7f
LP
912 }
913
4a62c710
MS
914 if (setresuid(uid, uid, uid) < 0)
915 return log_error_errno(errno, "Failed to change UID to " UID_FMT ": %m", uid);
4de33e7f
LP
916 }
917
918 env = strv_env_merge(3, environ, user_env, arg_environment);
919 if (!env)
920 return log_oom();
921
095dc596
LP
922 if (!arg_quiet)
923 log_info("Running as unit %s.", scope);
7040b626 924
4de33e7f 925 execvpe(argv[0], argv, env);
9b15b784
LP
926
927 return log_error_errno(errno, "Failed to execute: %m");
928}
929
930static int start_transient_timer(
931 sd_bus *bus,
ee451d76 932 char **argv) {
9b15b784 933
ee451d76 934 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
9b15b784
LP
935 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
936 _cleanup_free_ char *timer = NULL, *service = NULL;
937 int r;
938
939 assert(bus);
940 assert(argv);
941
942 if (arg_unit) {
943 switch(unit_name_to_type(arg_unit)) {
944
945 case UNIT_SERVICE:
946 service = strdup(arg_unit);
947 if (!service)
948 return log_oom();
949
950 timer = unit_name_change_suffix(service, ".timer");
951 if (!timer)
952 return log_oom();
953 break;
954
955 case UNIT_TIMER:
956 timer = strdup(arg_unit);
957 if (!timer)
958 return log_oom();
959
960 service = unit_name_change_suffix(timer, ".service");
961 if (!service)
962 return log_oom();
963 break;
964
965 default:
966 service = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".service");
967 if (!service)
968 return log_oom();
969
970 timer = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".timer");
971 if (!timer)
972 return log_oom();
973
974 break;
975 }
976 } else if ((asprintf(&service, "run-"PID_FMT".service", getpid()) < 0) ||
977 (asprintf(&timer, "run-"PID_FMT".timer", getpid()) < 0))
978 return log_oom();
979
980 r = sd_bus_message_new_method_call(
981 bus,
982 &m,
983 "org.freedesktop.systemd1",
984 "/org/freedesktop/systemd1",
985 "org.freedesktop.systemd1.Manager",
986 "StartTransientUnit");
987 if (r < 0)
988 return bus_log_create_error(r);
989
990 /* Name and Mode */
991 r = sd_bus_message_append(m, "ss", timer, "fail");
992 if (r < 0)
993 return bus_log_create_error(r);
994
995 /* Properties */
996 r = sd_bus_message_open_container(m, 'a', "(sv)");
997 if (r < 0)
998 return bus_log_create_error(r);
999
1000 r = transient_timer_set_properties(m);
1001 if (r < 0)
1002 return bus_log_create_error(r);
1003
1004 r = sd_bus_message_close_container(m);
1005 if (r < 0)
1006 return bus_log_create_error(r);
1007
1008 r = sd_bus_message_open_container(m, 'a', "(sa(sv))");
1009 if (r < 0)
1010 return bus_log_create_error(r);
1011
1012 if (argv[0]) {
1013 r = sd_bus_message_open_container(m, 'r', "sa(sv)");
1014 if (r < 0)
1015 return bus_log_create_error(r);
1016
1017 r = sd_bus_message_append(m, "s", service);
1018 if (r < 0)
1019 return bus_log_create_error(r);
1020
1021 r = sd_bus_message_open_container(m, 'a', "(sv)");
1022 if (r < 0)
1023 return bus_log_create_error(r);
1024
1025 r = transient_service_set_properties(m, argv, NULL);
1026 if (r < 0)
1027 return bus_log_create_error(r);
1028
1029 r = sd_bus_message_close_container(m);
1030 if (r < 0)
1031 return bus_log_create_error(r);
1032
1033 r = sd_bus_message_close_container(m);
1034 if (r < 0)
1035 return bus_log_create_error(r);
1036 }
1037
1038 r = sd_bus_message_close_container(m);
1039 if (r < 0)
1040 return bus_log_create_error(r);
1041
ee451d76
LP
1042 r = sd_bus_call(bus, m, 0, &error, NULL);
1043 if (r < 0) {
1044 log_error("Failed to start transient timer unit: %s", bus_error_message(&error, -r));
1045 return r;
1046 }
9b15b784
LP
1047
1048 log_info("Running as unit %s.", timer);
1049 if (argv[0])
1050 log_info("Will run as unit %s.", service);
1051
1052 return 0;
c2756a68
LP
1053}
1054
1055int main(int argc, char* argv[]) {
24996861 1056 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
c9d954b2 1057 _cleanup_free_ char *description = NULL, *command = NULL;
c2756a68
LP
1058 int r;
1059
1060 log_parse_environment();
1061 log_open();
1062
6c12b52e
LP
1063 r = parse_argv(argc, argv);
1064 if (r <= 0)
66b1e746 1065 goto finish;
c2756a68 1066
4c213d6c
WC
1067 if (argc > optind) {
1068 r = find_binary(argv[optind], arg_transport == BUS_TRANSPORT_LOCAL, &command);
1069 if (r < 0) {
1070 log_error_errno(r, "Failed to find executable %s%s: %m",
1071 argv[optind],
1072 arg_transport == BUS_TRANSPORT_LOCAL ? "" : " on local system");
1073 goto finish;
1074 }
1075 argv[optind] = command;
c9d954b2 1076 }
c9d954b2 1077
9f2e86af
LP
1078 if (!arg_description) {
1079 description = strv_join(argv + optind, " ");
1080 if (!description) {
1081 r = log_oom();
66b1e746 1082 goto finish;
9f2e86af
LP
1083 }
1084
4c213d6c
WC
1085 if (arg_unit && isempty(description)) {
1086 free(description);
1087 description = strdup(arg_unit);
1088
1089 if (!description) {
1090 r = log_oom();
1091 goto finish;
1092 }
1093 }
1094
9f2e86af
LP
1095 arg_description = description;
1096 }
1097
1f89214e 1098 r = bus_open_transport_systemd(arg_transport, arg_host, arg_user, &bus);
c2756a68 1099 if (r < 0) {
da927ba9 1100 log_error_errno(r, "Failed to create bus connection: %m");
66b1e746 1101 goto finish;
c2756a68
LP
1102 }
1103
6c12b52e 1104 if (arg_scope)
ee451d76 1105 r = start_transient_scope(bus, argv + optind);
4c213d6c 1106 else if (with_timer())
ee451d76 1107 r = start_transient_timer(bus, argv + optind);
6c12b52e 1108 else
ee451d76 1109 r = start_transient_service(bus, argv + optind);
c2756a68 1110
66b1e746 1111finish:
df31a6c0
LP
1112 strv_free(arg_environment);
1113 strv_free(arg_property);
4c213d6c 1114 strv_free(arg_timer_property);
df31a6c0 1115
c2756a68
LP
1116 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1117}