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