LCOV - code coverage report
Current view: top level - analyze - analyze-verify.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 0 159 0.0 %
Date: 2019-08-22 15:41:25 Functions: 0 8 0.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <stdlib.h>
       4             : 
       5             : #include "alloc-util.h"
       6             : #include "all-units.h"
       7             : #include "analyze-verify.h"
       8             : #include "bus-error.h"
       9             : #include "bus-util.h"
      10             : #include "log.h"
      11             : #include "manager.h"
      12             : #include "pager.h"
      13             : #include "path-util.h"
      14             : #include "strv.h"
      15             : #include "unit-name.h"
      16             : 
      17           0 : static int prepare_filename(const char *filename, char **ret) {
      18             :         int r;
      19             :         const char *name;
      20           0 :         _cleanup_free_ char *abspath = NULL;
      21           0 :         _cleanup_free_ char *dir = NULL;
      22           0 :         _cleanup_free_ char *with_instance = NULL;
      23             :         char *c;
      24             : 
      25           0 :         assert(filename);
      26           0 :         assert(ret);
      27             : 
      28           0 :         r = path_make_absolute_cwd(filename, &abspath);
      29           0 :         if (r < 0)
      30           0 :                 return r;
      31             : 
      32           0 :         name = basename(abspath);
      33           0 :         if (!unit_name_is_valid(name, UNIT_NAME_ANY))
      34           0 :                 return -EINVAL;
      35             : 
      36           0 :         if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) {
      37           0 :                 r = unit_name_replace_instance(name, "i", &with_instance);
      38           0 :                 if (r < 0)
      39           0 :                         return r;
      40             :         }
      41             : 
      42           0 :         dir = dirname_malloc(abspath);
      43           0 :         if (!dir)
      44           0 :                 return -ENOMEM;
      45             : 
      46           0 :         c = path_join(dir, with_instance ?: name);
      47           0 :         if (!c)
      48           0 :                 return -ENOMEM;
      49             : 
      50           0 :         *ret = c;
      51           0 :         return 0;
      52             : }
      53             : 
      54           0 : static int generate_path(char **var, char **filenames) {
      55             :         const char *old;
      56             :         char **filename;
      57             : 
      58           0 :         _cleanup_strv_free_ char **ans = NULL;
      59             :         int r;
      60             : 
      61           0 :         STRV_FOREACH(filename, filenames) {
      62             :                 char *t;
      63             : 
      64           0 :                 t = dirname_malloc(*filename);
      65           0 :                 if (!t)
      66           0 :                         return -ENOMEM;
      67             : 
      68           0 :                 r = strv_consume(&ans, t);
      69           0 :                 if (r < 0)
      70           0 :                         return r;
      71             :         }
      72             : 
      73           0 :         assert_se(strv_uniq(ans));
      74             : 
      75             :         /* First, prepend our directories. Second, if some path was specified, use that, and
      76             :          * otherwise use the defaults. Any duplicates will be filtered out in path-lookup.c.
      77             :          * Treat explicit empty path to mean that nothing should be appended.
      78             :          */
      79           0 :         old = getenv("SYSTEMD_UNIT_PATH");
      80           0 :         if (!streq_ptr(old, "")) {
      81           0 :                 if (!old)
      82           0 :                         old = ":";
      83             : 
      84           0 :                 r = strv_extend(&ans, old);
      85           0 :                 if (r < 0)
      86           0 :                         return r;
      87             :         }
      88             : 
      89           0 :         *var = strv_join(ans, ":");
      90           0 :         if (!*var)
      91           0 :                 return -ENOMEM;
      92             : 
      93           0 :         return 0;
      94             : }
      95             : 
      96           0 : static int verify_socket(Unit *u) {
      97             :         int r;
      98             : 
      99           0 :         assert(u);
     100             : 
     101           0 :         if (u->type != UNIT_SOCKET)
     102           0 :                 return 0;
     103             : 
     104             :         /* Cannot run this without the service being around */
     105             : 
     106             :         /* This makes sure instance is created if necessary. */
     107           0 :         r = socket_instantiate_service(SOCKET(u));
     108           0 :         if (r < 0)
     109           0 :                 return log_unit_error_errno(u, r, "Socket cannot be started, failed to create instance: %m");
     110             : 
     111             :         /* This checks both type of sockets */
     112           0 :         if (UNIT_ISSET(SOCKET(u)->service)) {
     113             :                 Service *service;
     114             : 
     115           0 :                 service = SERVICE(UNIT_DEREF(SOCKET(u)->service));
     116           0 :                 log_unit_debug(u, "Using %s", UNIT(service)->id);
     117             : 
     118           0 :                 if (UNIT(service)->load_state != UNIT_LOADED) {
     119           0 :                         log_unit_error(u, "Service %s not loaded, %s cannot be started.", UNIT(service)->id, u->id);
     120           0 :                         return -ENOENT;
     121             :                 }
     122             :         }
     123             : 
     124           0 :         return 0;
     125             : }
     126             : 
     127           0 : static int verify_executable(Unit *u, ExecCommand *exec) {
     128           0 :         if (!exec)
     129           0 :                 return 0;
     130             : 
     131           0 :         if (access(exec->path, X_OK) < 0)
     132           0 :                 return log_unit_error_errno(u, errno, "Command %s is not executable: %m", exec->path);
     133             : 
     134           0 :         return 0;
     135             : }
     136             : 
     137           0 : static int verify_executables(Unit *u) {
     138             :         ExecCommand *exec;
     139           0 :         int r = 0, k;
     140             :         unsigned i;
     141             : 
     142           0 :         assert(u);
     143             : 
     144           0 :         exec =  u->type == UNIT_SOCKET ? SOCKET(u)->control_command :
     145           0 :                 u->type == UNIT_MOUNT ? MOUNT(u)->control_command :
     146           0 :                 u->type == UNIT_SWAP ? SWAP(u)->control_command : NULL;
     147           0 :         k = verify_executable(u, exec);
     148           0 :         if (k < 0 && r == 0)
     149           0 :                 r = k;
     150             : 
     151           0 :         if (u->type == UNIT_SERVICE)
     152           0 :                 for (i = 0; i < ELEMENTSOF(SERVICE(u)->exec_command); i++) {
     153           0 :                         k = verify_executable(u, SERVICE(u)->exec_command[i]);
     154           0 :                         if (k < 0 && r == 0)
     155           0 :                                 r = k;
     156             :                 }
     157             : 
     158           0 :         if (u->type == UNIT_SOCKET)
     159           0 :                 for (i = 0; i < ELEMENTSOF(SOCKET(u)->exec_command); i++) {
     160           0 :                         k = verify_executable(u, SOCKET(u)->exec_command[i]);
     161           0 :                         if (k < 0 && r == 0)
     162           0 :                                 r = k;
     163             :                 }
     164             : 
     165           0 :         return r;
     166             : }
     167             : 
     168           0 : static int verify_documentation(Unit *u, bool check_man) {
     169             :         char **p;
     170           0 :         int r = 0, k;
     171             : 
     172           0 :         STRV_FOREACH(p, u->documentation) {
     173           0 :                 log_unit_debug(u, "Found documentation item: %s", *p);
     174             : 
     175           0 :                 if (check_man && startswith(*p, "man:")) {
     176           0 :                         k = show_man_page(*p + 4, true);
     177           0 :                         if (k != 0) {
     178           0 :                                 if (k < 0)
     179           0 :                                         log_unit_error_errno(u, k, "Can't show %s: %m", *p + 4);
     180             :                                 else {
     181           0 :                                         log_unit_error(u, "Command 'man %s' failed with code %d", *p + 4, k);
     182           0 :                                         k = -ENOEXEC;
     183             :                                 }
     184           0 :                                 if (r == 0)
     185           0 :                                         r = k;
     186             :                         }
     187             :                 }
     188             :         }
     189             : 
     190             :         /* Check remote URLs? */
     191             : 
     192           0 :         return r;
     193             : }
     194             : 
     195           0 : static int verify_unit(Unit *u, bool check_man) {
     196           0 :         _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
     197             :         int r, k;
     198             : 
     199           0 :         assert(u);
     200             : 
     201           0 :         if (DEBUG_LOGGING)
     202           0 :                 unit_dump(u, stdout, "\t");
     203             : 
     204           0 :         log_unit_debug(u, "Creating %s/start job", u->id);
     205           0 :         r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, NULL, &err, NULL);
     206           0 :         if (r < 0)
     207           0 :                 log_unit_error_errno(u, r, "Failed to create %s/start: %s", u->id, bus_error_message(&err, r));
     208             : 
     209           0 :         k = verify_socket(u);
     210           0 :         if (k < 0 && r == 0)
     211           0 :                 r = k;
     212             : 
     213           0 :         k = verify_executables(u);
     214           0 :         if (k < 0 && r == 0)
     215           0 :                 r = k;
     216             : 
     217           0 :         k = verify_documentation(u, check_man);
     218           0 :         if (k < 0 && r == 0)
     219           0 :                 r = k;
     220             : 
     221           0 :         return r;
     222             : }
     223             : 
     224           0 : int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators) {
     225           0 :         const ManagerTestRunFlags flags =
     226             :                 MANAGER_TEST_RUN_BASIC |
     227           0 :                 MANAGER_TEST_RUN_ENV_GENERATORS |
     228           0 :                 run_generators * MANAGER_TEST_RUN_GENERATORS;
     229             : 
     230           0 :         _cleanup_(manager_freep) Manager *m = NULL;
     231           0 :         Unit *units[strv_length(filenames)];
     232           0 :         _cleanup_free_ char *var = NULL;
     233           0 :         int r = 0, k, i, count = 0;
     234             :         char **filename;
     235             : 
     236           0 :         if (strv_isempty(filenames))
     237           0 :                 return 0;
     238             : 
     239             :         /* set the path */
     240           0 :         r = generate_path(&var, filenames);
     241           0 :         if (r < 0)
     242           0 :                 return log_error_errno(r, "Failed to generate unit load path: %m");
     243             : 
     244           0 :         assert_se(set_unit_path(var) >= 0);
     245             : 
     246           0 :         r = manager_new(scope, flags, &m);
     247           0 :         if (r < 0)
     248           0 :                 return log_error_errno(r, "Failed to initialize manager: %m");
     249             : 
     250           0 :         log_debug("Starting manager...");
     251             : 
     252           0 :         r = manager_startup(m, NULL, NULL);
     253           0 :         if (r < 0)
     254           0 :                 return r;
     255             : 
     256           0 :         manager_clear_jobs(m);
     257             : 
     258           0 :         log_debug("Loading remaining units from the command line...");
     259             : 
     260           0 :         STRV_FOREACH(filename, filenames) {
     261           0 :                 _cleanup_free_ char *prepared = NULL;
     262             : 
     263           0 :                 log_debug("Handling %s...", *filename);
     264             : 
     265           0 :                 k = prepare_filename(*filename, &prepared);
     266           0 :                 if (k < 0) {
     267           0 :                         log_error_errno(k, "Failed to prepare filename %s: %m", *filename);
     268           0 :                         if (r == 0)
     269           0 :                                 r = k;
     270           0 :                         continue;
     271             :                 }
     272             : 
     273           0 :                 k = manager_load_startable_unit_or_warn(m, NULL, prepared, &units[count]);
     274           0 :                 if (k < 0 && r == 0)
     275           0 :                         r = k;
     276             :                 else
     277           0 :                         count++;
     278             :         }
     279             : 
     280           0 :         for (i = 0; i < count; i++) {
     281           0 :                 k = verify_unit(units[i], check_man);
     282           0 :                 if (k < 0 && r == 0)
     283           0 :                         r = k;
     284             :         }
     285             : 
     286           0 :         return r;
     287             : }

Generated by: LCOV version 1.14