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