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