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