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