chiark / gitweb /
main: disable nscd if we can to avoid deadlock, just in case
[elogind.git] / src / install.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 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   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/stat.h>
23 #include <stdio.h>
24 #include <getopt.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28
29 #include "log.h"
30 #include "path-lookup.h"
31 #include "util.h"
32 #include "macro.h"
33 #include "strv.h"
34 #include "conf-parser.h"
35 #include "dbus-common.h"
36 #include "sd-daemon.h"
37
38 static bool arg_force = false;
39
40 static enum {
41         WHERE_SYSTEM,
42         WHERE_SESSION,
43         WHERE_GLOBAL,
44 } arg_where = WHERE_SYSTEM;
45
46 static enum {
47         ACTION_INVALID,
48         ACTION_ENABLE,
49         ACTION_DISABLE,
50         ACTION_REALIZE,
51         ACTION_TEST
52 } arg_action = ACTION_INVALID;
53
54 static enum {
55         REALIZE_NO,        /* Don't reload/start/stop or anything */
56         REALIZE_RELOAD,    /* Only reload daemon config, don't stop/start */
57         REALIZE_MINIMAL,   /* Only shutdown/restart if running. */
58         REALIZE_MAYBE,     /* Start if WantedBy= suggests */
59         REALIZE_YES        /* Start unconditionally */
60 } arg_realize = REALIZE_NO;
61
62 typedef struct {
63         char *name;
64         char *path;
65
66         char **aliases;
67         char **wanted_by;
68 } InstallInfo;
69
70 Hashmap *will_install = NULL, *have_installed = NULL;
71
72 static int help(void) {
73
74         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
75                "Install init system units.\n\n"
76                "  -h --help           Show this help\n"
77                "     --force          Override existing links\n"
78                "     --system         Install into system\n"
79                "     --session        Install into session\n"
80                "     --global         Install into all sessions\n"
81                "     --realize[=MODE] Start/stop/restart unit after installation\n"
82                "                      Takes 'no', 'minimal', 'maybe' or 'yes'\n\n"
83                "Commands:\n"
84                "  enable [NAME...]    Enable one or more units\n"
85                "  disable [NAME...]   Disable one or more units\n"
86                "  realize [NAME...]   Test whether any of the specified units are enabled\n"
87                "                      and the start/stop/restart units accordingly\n"
88                "  test [NAME...]      Test whether any of the specified units are enabled\n",
89                program_invocation_short_name);
90
91         return 0;
92 }
93
94 static int parse_argv(int argc, char *argv[]) {
95
96         enum {
97                 ARG_SESSION = 0x100,
98                 ARG_SYSTEM,
99                 ARG_GLOBAL,
100                 ARG_FORCE,
101                 ARG_REALIZE
102         };
103
104         static const struct option options[] = {
105                 { "help",      no_argument,       NULL, 'h'         },
106                 { "session",   no_argument,       NULL, ARG_SESSION },
107                 { "system",    no_argument,       NULL, ARG_SYSTEM  },
108                 { "global",    no_argument,       NULL, ARG_GLOBAL  },
109                 { "force",     no_argument,       NULL, ARG_FORCE   },
110                 { "realize",   optional_argument, NULL, ARG_REALIZE },
111                 { NULL,        0,                 NULL, 0           }
112         };
113
114         int c;
115         bool realize_switch = false;
116
117         assert(argc >= 1);
118         assert(argv);
119
120         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
121
122                 switch (c) {
123
124                 case 'h':
125                         help();
126                         return 0;
127
128                 case ARG_SESSION:
129                         arg_where = WHERE_SESSION;
130                         break;
131
132                 case ARG_SYSTEM:
133                         arg_where = WHERE_SYSTEM;
134                         break;
135
136                 case ARG_GLOBAL:
137                         arg_where = WHERE_GLOBAL;
138                         break;
139
140                 case ARG_FORCE:
141                         arg_force = true;
142                         break;
143
144                 case ARG_REALIZE:
145
146                         realize_switch = true;
147
148                         if (!optarg)
149                                 arg_realize = REALIZE_MAYBE;
150                         else if (streq(optarg, "no"))
151                                 arg_realize = REALIZE_NO;
152                         else if (streq(optarg, "minimal"))
153                                 arg_realize = REALIZE_MINIMAL;
154                         else if (streq(optarg, "maybe"))
155                                 arg_realize = REALIZE_MAYBE;
156                         else if (streq(optarg, "yes"))
157                                 arg_realize = REALIZE_YES;
158                         else if (streq(optarg, "reload"))
159                                 arg_realize = REALIZE_RELOAD;
160                         else {
161                                 log_error("Invalid --realize argument %s", optarg);
162                                 return -EINVAL;
163                         }
164
165                         break;
166
167                 case '?':
168                         return -EINVAL;
169
170                 default:
171                         log_error("Unknown option code %c", c);
172                         return -EINVAL;
173                 }
174         }
175
176         if (optind >= argc) {
177                 help();
178                 return -EINVAL;
179         }
180
181         if (streq(argv[optind], "enable"))
182                 arg_action = ACTION_ENABLE;
183         else if (streq(argv[optind], "disable"))
184                 arg_action = ACTION_DISABLE;
185         else if (streq(argv[optind], "test"))
186                 arg_action = ACTION_TEST;
187         else if (streq(argv[optind], "realize")) {
188                 arg_action = ACTION_REALIZE;
189
190                 if (!realize_switch)
191                         arg_realize = REALIZE_MAYBE;
192         } else {
193                 log_error("Unknown verb %s.", argv[optind]);
194                 return -EINVAL;
195         }
196
197         optind++;
198
199         if (optind >= argc) {
200                 log_error("Missing unit name.");
201                 return -EINVAL;
202         }
203
204
205         return 1;
206 }
207
208 static void install_info_free(InstallInfo *i) {
209         assert(i);
210
211         free(i->name);
212         free(i->path);
213         strv_free(i->aliases);
214         strv_free(i->wanted_by);
215         free(i);
216 }
217
218 static void install_info_hashmap_free(Hashmap *m) {
219         InstallInfo *i;
220
221         while ((i = hashmap_steal_first(m)))
222                 install_info_free(i);
223
224         hashmap_free(m);
225 }
226
227 static bool unit_name_valid(const char *name) {
228
229         /* This is a minimal version of unit_name_valid() from
230          * unit-name.c */
231
232         if (!*name)
233                 return false;
234
235         if (ignore_file(name))
236                 return false;
237
238         return true;
239 }
240
241 static int install_info_add(const char *name) {
242         InstallInfo *i;
243         int r;
244
245         if (!unit_name_valid(name))
246                 return -EINVAL;
247
248         if (hashmap_get(have_installed, name) ||
249             hashmap_get(will_install, name))
250                 return 0;
251
252         if (!(i = new0(InstallInfo, 1))) {
253                 r = -ENOMEM;
254                 goto fail;
255         }
256
257         if (!(i->name = strdup(name))) {
258                 r = -ENOMEM;
259                 goto fail;
260         }
261
262         if ((r = hashmap_put(will_install, i->name, i)) < 0)
263                 goto fail;
264
265         return 0;
266
267 fail:
268         if (i)
269                 install_info_free(i);
270
271         return r;
272 }
273
274 static int daemon_reload(DBusConnection *bus) {
275         DBusMessage *m = NULL, *reply = NULL;
276         DBusError error;
277         int r;
278
279         assert(bus);
280
281         dbus_error_init(&error);
282
283         if (!(m = dbus_message_new_method_call(
284                               "org.freedesktop.systemd1",
285                               "/org/freedesktop/systemd1",
286                               "org.freedesktop.systemd1.Manager",
287                               "Reload"))) {
288                 log_error("Could not allocate message.");
289                 return -ENOMEM;
290         }
291
292         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
293                 log_error("Failed to reload configuration: %s", error.message);
294                 r = -EIO;
295                 goto finish;
296         }
297
298         r = 0;
299
300 finish:
301         if (m)
302                 dbus_message_unref(m);
303
304         if (reply)
305                 dbus_message_unref(reply);
306
307         dbus_error_free(&error);
308
309         return r;
310 }
311
312 static int install_info_run(DBusConnection *bus, InstallInfo *i, bool enabled) {
313         DBusMessage *m = NULL, *reply = NULL;
314         DBusError error;
315         int r;
316         const char *mode = "replace";
317
318         assert(bus);
319         assert(i);
320
321         dbus_error_init(&error);
322
323         if (arg_action == ACTION_ENABLE ||
324             (arg_action == ACTION_REALIZE && enabled)) {
325
326                 if (arg_realize == REALIZE_MAYBE) {
327                         char **k;
328                         bool yes_please = false;
329
330                         STRV_FOREACH(k, i->wanted_by) {
331                                 DBusMessageIter sub, iter;
332
333                                 const char *path, *state;
334                                 const char *interface = "org.freedesktop.systemd1.Unit";
335                                 const char *property = "ActiveState";
336
337                                 if (!(m = dbus_message_new_method_call(
338                                                       "org.freedesktop.systemd1",
339                                                       "/org/freedesktop/systemd1",
340                                                       "org.freedesktop.systemd1.Manager",
341                                                       "GetUnit"))) {
342                                         log_error("Could not allocate message.");
343                                         r = -ENOMEM;
344                                         goto finish;
345                                 }
346
347                                 if (!dbus_message_append_args(m,
348                                                               DBUS_TYPE_STRING, k,
349                                                               DBUS_TYPE_INVALID)) {
350                                         log_error("Could not append arguments to message.");
351                                         r = -ENOMEM;
352                                         goto finish;
353                                 }
354
355                                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
356                                         /* Hmm, this unit doesn't exist, let's try the next one */
357                                         dbus_message_unref(m);
358                                         m = NULL;
359                                         continue;
360                                 }
361
362                                 if (!dbus_message_get_args(reply, &error,
363                                                            DBUS_TYPE_OBJECT_PATH, &path,
364                                                            DBUS_TYPE_INVALID)) {
365                                         log_error("Failed to parse reply: %s", error.message);
366                                         r = -EIO;
367                                         goto finish;
368                                 }
369
370                                 dbus_message_unref(m);
371                                 if (!(m = dbus_message_new_method_call(
372                                                       "org.freedesktop.systemd1",
373                                                       path,
374                                                       "org.freedesktop.DBus.Properties",
375                                                       "Get"))) {
376                                         log_error("Could not allocate message.");
377                                         r = -ENOMEM;
378                                         goto finish;
379                                 }
380
381                                 if (!dbus_message_append_args(m,
382                                                               DBUS_TYPE_STRING, &interface,
383                                                               DBUS_TYPE_STRING, &property,
384                                                               DBUS_TYPE_INVALID)) {
385                                         log_error("Could not append arguments to message.");
386                                         r = -ENOMEM;
387                                         goto finish;
388                                 }
389
390                                 dbus_message_unref(reply);
391                                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
392                                         log_error("Failed to issue method call: %s", error.message);
393                                         r = -EIO;
394                                         goto finish;
395                                 }
396
397                                 if (!dbus_message_iter_init(reply, &iter) ||
398                                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
399                                         log_error("Failed to parse reply.");
400                                         r = -EIO;
401                                         goto finish;
402                                 }
403
404                                 dbus_message_iter_recurse(&iter, &sub);
405
406                                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
407                                         log_error("Failed to parse reply.");
408                                         r = -EIO;
409                                         goto finish;
410                                 }
411
412                                 dbus_message_iter_get_basic(&sub, &state);
413
414                                 dbus_message_unref(m);
415                                 dbus_message_unref(reply);
416                                 m = reply = NULL;
417
418                                 if (streq(state, "active") ||
419                                     startswith(state, "reloading") ||
420                                     startswith(state, "activating")) {
421                                         yes_please = true;
422                                         break;
423                                 }
424                         }
425
426                         if (!yes_please) {
427                                 r = 0;
428                                 goto finish;
429                         }
430                 }
431
432                 if (!(m = dbus_message_new_method_call(
433                                       "org.freedesktop.systemd1",
434                                       "/org/freedesktop/systemd1",
435                                       "org.freedesktop.systemd1.Manager",
436                                       arg_realize == REALIZE_MINIMAL ? "TryRestartUnit" : "RestartUnit"))) {
437                         log_error("Could not allocate message.");
438                         r = -ENOMEM;
439                         goto finish;
440                 }
441
442                 if (!dbus_message_append_args(m,
443                                               DBUS_TYPE_STRING, &i->name,
444                                               DBUS_TYPE_STRING, &mode,
445                                               DBUS_TYPE_INVALID)) {
446                         log_error("Could not append arguments to message.");
447                         r = -ENOMEM;
448                         goto finish;
449                 }
450
451
452         } else if (arg_action == ACTION_DISABLE ||
453                    (arg_action == ACTION_REALIZE && !enabled)) {
454
455                 if (!(m = dbus_message_new_method_call(
456                                       "org.freedesktop.systemd1",
457                                       "/org/freedesktop/systemd1",
458                                       "org.freedesktop.systemd1.Manager",
459                                       "StopUnit"))) {
460                         log_error("Could not allocate message.");
461                         r = -ENOMEM;
462                         goto finish;
463                 }
464
465                 if (!dbus_message_append_args(m,
466                                               DBUS_TYPE_STRING, &i->name,
467                                               DBUS_TYPE_STRING, &mode,
468                                               DBUS_TYPE_INVALID)) {
469                         log_error("Could not append arguments to message.");
470                         r = -ENOMEM;
471                         goto finish;
472                 }
473         } else
474                 assert_not_reached("install_info_run() called but nothing to do?");
475
476         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
477                 log_error("Failed to realize unit: %s", error.message);
478                 r = -EIO;
479                 goto finish;
480         }
481
482         r = 0;
483
484 finish:
485         if (m)
486                 dbus_message_unref(m);
487
488         if (reply)
489                 dbus_message_unref(reply);
490
491         dbus_error_free(&error);
492
493         return r;
494 }
495
496 static int config_parse_also(
497                 const char *filename,
498                 unsigned line,
499                 const char *section,
500                 const char *lvalue,
501                 const char *rvalue,
502                 void *data,
503                 void *userdata) {
504
505         char *w;
506         size_t l;
507         char *state;
508
509         assert(filename);
510         assert(lvalue);
511         assert(rvalue);
512
513         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
514                 char *n;
515                 int r;
516
517                 if (!(n = strndup(w, l)))
518                         return -ENOMEM;
519
520                 r = install_info_add(n);
521                 free(n);
522
523                 if (r < 0)
524                         return r;
525         }
526
527         return 0;
528 }
529
530 static int create_symlink(const char *old_path, const char *new_path) {
531         int r;
532
533         assert(old_path);
534         assert(new_path);
535
536         if (arg_action == ACTION_ENABLE) {
537                 char *dest;
538
539                 mkdir_parents(new_path, 0755);
540
541                 if (symlink(old_path, new_path) >= 0)
542                         return 0;
543
544                 if (errno != EEXIST) {
545                         log_error("Cannot link %s to %s: %m", old_path, new_path);
546                         return -errno;
547                 }
548
549                 if ((r = readlink_and_make_absolute(new_path, &dest)) < 0) {
550
551                         if (errno == EINVAL) {
552                                 log_error("Cannot link %s to %s, file exists already and is not a symlink.", old_path, new_path);
553                                 return -EEXIST;
554                         }
555
556                         log_error("readlink() failed: %s", strerror(-r));
557                         return r;
558                 }
559
560                 if (streq(dest, old_path)) {
561                         free(dest);
562                         return 0;
563                 }
564
565                 if (!arg_force) {
566                         log_error("Cannot link %s to %s, symlink exists already and points to %s.", old_path, new_path, dest);
567                         free(dest);
568                         return -EEXIST;
569                 }
570
571                 free(dest);
572                 unlink(new_path);
573
574                 if (symlink(old_path, new_path) >= 0)
575                         return 0;
576
577                 log_error("Cannot link %s to %s: %m", old_path, new_path);
578                 return -errno;
579
580         } else if (arg_action == ACTION_DISABLE) {
581                 char *dest;
582
583                 if ((r = readlink_and_make_absolute(new_path, &dest)) < 0) {
584                         if (errno == ENOENT)
585                                 return 0;
586
587                         if (errno == EINVAL) {
588                                 log_warning("File %s not a symlink, ignoring.", old_path);
589                                 return 0;
590                         }
591
592                         log_error("readlink() failed: %s", strerror(-r));
593                         return r;
594                 }
595
596                 if (!streq(dest, old_path)) {
597                         log_warning("File %s not a symlink to %s but points to %s, ignoring.", new_path, old_path, dest);
598                         free(dest);
599                         return 0;
600                 }
601
602                 free(dest);
603                 if (unlink(new_path) >= 0)
604                         return 0;
605
606                 log_error("Cannot unlink %s: %m", new_path);
607                 return -errno;
608
609         } else if (arg_action == ACTION_TEST || arg_action == ACTION_REALIZE) {
610                 char *dest;
611
612                 if ((r = readlink_and_make_absolute(new_path, &dest)) < 0) {
613
614                         if (errno == ENOENT || errno == EINVAL)
615                                 return 0;
616
617                         log_error("readlink() failed: %s", strerror(-r));
618                         return r;
619                 }
620
621                 if (streq(dest, old_path)) {
622                         free(dest);
623                         return 1;
624                 }
625
626                 return 0;
627         }
628
629         assert_not_reached("Unknown action.");
630 }
631
632 static int install_info_symlink_alias(InstallInfo *i, const char *config_path) {
633         char **s;
634         char *alias_path = NULL;
635         int r;
636
637         assert(i);
638
639         STRV_FOREACH(s, i->aliases) {
640
641                 if (!unit_name_valid(*s)) {
642                         log_error("Invalid name %s.", *s);
643                         r = -EINVAL;
644                         goto finish;
645                 }
646
647                 free(alias_path);
648                 if (!(alias_path = path_make_absolute(*s, config_path))) {
649                         log_error("Out of memory");
650                         r = -ENOMEM;
651                         goto finish;
652                 }
653
654                 if ((r = create_symlink(i->path, alias_path)) != 0)
655                         goto finish;
656
657                 if (arg_action == ACTION_DISABLE)
658                         rmdir_parents(alias_path, config_path);
659         }
660
661         r = 0;
662
663 finish:
664         free(alias_path);
665
666         return r;
667 }
668
669 static int install_info_symlink_wants(InstallInfo *i, const char *config_path) {
670         char **s;
671         char *alias_path = NULL;
672         int r;
673
674         assert(i);
675
676         STRV_FOREACH(s, i->wanted_by) {
677                 if (!unit_name_valid(*s)) {
678                         log_error("Invalid name %s.", *s);
679                         r = -EINVAL;
680                         goto finish;
681                 }
682
683                 free(alias_path);
684                 alias_path = NULL;
685
686                 if (asprintf(&alias_path, "%s/%s.wants/%s", config_path, *s, i->name) < 0) {
687                         log_error("Out of memory");
688                         r = -ENOMEM;
689                         goto finish;
690                 }
691
692                 if ((r = create_symlink(i->path, alias_path)) != 0)
693                         goto finish;
694
695                 if (arg_action == ACTION_DISABLE)
696                         rmdir_parents(alias_path, config_path);
697         }
698
699         r = 0;
700
701 finish:
702         free(alias_path);
703
704         return r;
705 }
706
707 static int install_info_apply(LookupPaths *paths, InstallInfo *i, const char *config_path) {
708
709         const ConfigItem items[] = {
710                 { "Alias",    config_parse_strv, &i->aliases,   "Install" },
711                 { "WantedBy", config_parse_strv, &i->wanted_by, "Install" },
712                 { "Also",     config_parse_also, NULL,          "Install" },
713
714                 { NULL, NULL, NULL, NULL }
715         };
716
717         char **p;
718         char *filename = NULL;
719         FILE *f = NULL;
720         int r;
721
722         assert(paths);
723         assert(i);
724
725         STRV_FOREACH(p, paths->unit_path) {
726                 int fd;
727
728                 if (!(filename = path_make_absolute(i->name, *p))) {
729                         log_error("Out of memory");
730                         return -ENOMEM;
731                 }
732
733                 /* Ensure that we don't follow symlinks */
734                 if ((fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NOCTTY)) >= 0)
735                         if ((f = fdopen(fd, "re")))
736                                 break;
737
738                 if (errno == ELOOP) {
739                         log_error("Refusing to operate on symlinks, please pass unit names or absolute paths to unit files.");
740                         free(filename);
741                         return -errno;
742                 }
743
744                 if (errno != ENOENT) {
745                         log_error("Failed to open %s: %m", filename);
746                         free(filename);
747                         return -errno;
748                 }
749
750                 free(filename);
751                 filename = NULL;
752         }
753
754         if (!f) {
755                 log_error("Couldn't find %s.", i->name);
756                 return -ENOENT;
757         }
758
759         i->path = filename;
760
761         if ((r = config_parse(filename, f, NULL, items, true, i)) < 0) {
762                 fclose(f);
763                 return r;
764         }
765
766         fclose(f);
767
768         if ((r = install_info_symlink_alias(i, config_path)) != 0)
769                 return r;
770
771         if ((r = install_info_symlink_wants(i, config_path)) != 0)
772                 return r;
773
774         return 0;
775 }
776
777 static char *get_config_path(void) {
778
779         switch (arg_where) {
780
781         case WHERE_SYSTEM:
782                 return strdup(SYSTEM_CONFIG_UNIT_PATH);
783
784         case WHERE_GLOBAL:
785                 return strdup(SESSION_CONFIG_UNIT_PATH);
786
787         case WHERE_SESSION: {
788                 char *p;
789
790                 if (session_config_home(&p) < 0)
791                         return NULL;
792
793                 return p;
794         }
795
796         default:
797                 assert_not_reached("Unknown config path.");
798         }
799 }
800
801 static int do_realize(bool enabled) {
802         DBusConnection *bus = NULL;
803         DBusError error;
804         int r, q;
805         Iterator i;
806         InstallInfo *j;
807
808         dbus_error_init(&error);
809
810         if (arg_realize == REALIZE_NO)
811                 return 0;
812
813         if (arg_where == WHERE_GLOBAL) {
814                 log_warning("Warning: --realize has no effect with --global.");
815                 return 0;
816         }
817
818         if (arg_action == ACTION_TEST) {
819                 log_warning("Warning: --realize has no effect with test.");
820                 return 0;
821         }
822
823         if (arg_where == WHERE_SYSTEM && sd_booted() <= 0) {
824                 log_info("systemd is not running, --realize has no effect.");
825                 return 0;
826         }
827
828         if (arg_where == WHERE_SYSTEM && running_in_chroot() > 0) {
829                 log_info("Running in a chroot() environment, --realize has no effect.");
830                 return 0;
831         }
832
833         if ((r = bus_connect(arg_where == WHERE_SESSION ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &bus, NULL, &error)) < 0) {
834                 log_error("Failed to get D-Bus connection: %s", error.message);
835                 goto finish;
836         }
837
838         r = 0;
839
840         if (arg_action == ACTION_ENABLE || arg_action == ACTION_REALIZE)
841                 if ((r = daemon_reload(bus)) < 0)
842                         goto finish;
843
844         if (arg_realize != REALIZE_RELOAD) {
845                 HASHMAP_FOREACH(j, have_installed, i)
846                         if ((q = install_info_run(bus, j, enabled)) < 0)
847                                 r = q;
848         }
849
850         if (arg_action == ACTION_DISABLE)
851                 if ((q = daemon_reload(bus)) < 0)
852                         r = q;
853
854 finish:
855         if (bus) {
856                 dbus_connection_close(bus);
857                 dbus_connection_unref(bus);
858         }
859
860         dbus_error_free(&error);
861
862         dbus_shutdown();
863         return r;
864 }
865
866 int main(int argc, char *argv[]) {
867         int r, retval = 1, j;
868         LookupPaths paths;
869         InstallInfo *i;
870         char *config_path = NULL;
871
872         zero(paths);
873
874         log_parse_environment();
875
876         if ((r = parse_argv(argc, argv)) < 0)
877                 goto finish;
878         else if (r == 0) {
879                 retval = 0;
880                 goto finish;
881         }
882
883         if ((r = lookup_paths_init(&paths, arg_where == WHERE_SYSTEM ? MANAGER_SYSTEM : MANAGER_SESSION)) < 0) {
884                 log_error("Failed to determine lookup paths: %s", strerror(-r));
885                 goto finish;
886         }
887
888         if (!(config_path = get_config_path())) {
889                 log_error("Failed to determine config path");
890                 goto finish;
891         }
892
893         will_install = hashmap_new(string_hash_func, string_compare_func);
894         have_installed = hashmap_new(string_hash_func, string_compare_func);
895
896         if (!will_install || !have_installed) {
897                 log_error("Failed to allocate unit sets.");
898                 goto finish;
899         }
900
901         for (j = optind; j < argc; j++)
902                 if ((r = install_info_add(argv[j])) < 0)
903                         goto finish;
904
905         while ((i = hashmap_first(will_install))) {
906                 assert_se(hashmap_move_one(have_installed, will_install, i->name) == 0);
907
908                 if ((r = install_info_apply(&paths, i, config_path)) != 0) {
909
910                         if (r < 0)
911                                 goto finish;
912
913                         /* In test mode and found something */
914                         retval = 0;
915                         break;
916                 }
917         }
918
919         if (do_realize(!retval) < 0)
920                 goto finish;
921
922 finish:
923         install_info_hashmap_free(will_install);
924         install_info_hashmap_free(have_installed);
925
926         lookup_paths_free(&paths);
927
928         free(config_path);
929
930         return retval;
931 }