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