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