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