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