LCOV - code coverage report
Current view: top level - shared - pretty-print.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 62 158 39.2 %
Date: 2019-08-23 13:36:53 Functions: 7 10 70.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 55 169 32.5 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <sys/utsname.h>
       4                 :            : #include <errno.h>
       5                 :            : #include <stdio.h>
       6                 :            : 
       7                 :            : #include "alloc-util.h"
       8                 :            : #include "conf-files.h"
       9                 :            : #include "def.h"
      10                 :            : #include "env-util.h"
      11                 :            : #include "fd-util.h"
      12                 :            : #include "fileio.h"
      13                 :            : #include "pager.h"
      14                 :            : #include "path-util.h"
      15                 :            : #include "pretty-print.h"
      16                 :            : #include "string-util.h"
      17                 :            : #include "strv.h"
      18                 :            : #include "terminal-util.h"
      19                 :            : #include "util.h"
      20                 :            : 
      21                 :        527 : static bool urlify_enabled(void) {
      22                 :            :         static int cached_urlify_enabled = -1;
      23                 :            : 
      24                 :            :         /* Unfortunately 'less' doesn't support links like this yet 😭, hence let's disable this as long as there's a
      25                 :            :          * pager in effect. Let's drop this check as soon as less got fixed a and enough time passed so that it's safe
      26                 :            :          * to assume that a link-enabled 'less' version has hit most installations. */
      27                 :            : 
      28         [ +  + ]:        527 :         if (cached_urlify_enabled < 0) {
      29                 :            :                 int val;
      30                 :            : 
      31                 :        499 :                 val = getenv_bool("SYSTEMD_URLIFY");
      32         [ -  + ]:        499 :                 if (val >= 0)
      33                 :          0 :                         cached_urlify_enabled = val;
      34                 :            :                 else
      35   [ -  +  #  # ]:        499 :                         cached_urlify_enabled = colors_enabled() && !pager_have();
      36                 :            :         }
      37                 :            : 
      38                 :        527 :         return cached_urlify_enabled;
      39                 :            : }
      40                 :            : 
      41                 :        507 : int terminal_urlify(const char *url, const char *text, char **ret) {
      42                 :            :         char *n;
      43                 :            : 
      44         [ -  + ]:        507 :         assert(url);
      45                 :            : 
      46                 :            :         /* Takes an URL and a pretty string and formats it as clickable link for the terminal. See
      47                 :            :          * https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda for details. */
      48                 :            : 
      49         [ -  + ]:        507 :         if (isempty(text))
      50                 :          0 :                 text = url;
      51                 :            : 
      52         [ -  + ]:        507 :         if (urlify_enabled())
      53                 :          0 :                 n = strjoin("\x1B]8;;", url, "\a", text, "\x1B]8;;\a");
      54                 :            :         else
      55                 :        507 :                 n = strdup(text);
      56         [ -  + ]:        507 :         if (!n)
      57                 :          0 :                 return -ENOMEM;
      58                 :            : 
      59                 :        507 :         *ret = n;
      60                 :        507 :         return 0;
      61                 :            : }
      62                 :            : 
      63                 :          0 : int file_url_from_path(const char *path, char **ret) {
      64                 :          0 :         _cleanup_free_ char *absolute = NULL;
      65                 :            :         struct utsname u;
      66                 :          0 :         char *url = NULL;
      67                 :            :         int r;
      68                 :            : 
      69         [ #  # ]:          0 :         if (uname(&u) < 0)
      70                 :          0 :                 return -errno;
      71                 :            : 
      72         [ #  # ]:          0 :         if (!path_is_absolute(path)) {
      73                 :          0 :                 r = path_make_absolute_cwd(path, &absolute);
      74         [ #  # ]:          0 :                 if (r < 0)
      75                 :          0 :                         return r;
      76                 :            : 
      77                 :          0 :                 path = absolute;
      78                 :            :         }
      79                 :            : 
      80                 :            :         /* As suggested by https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda, let's include the local
      81                 :            :          * hostname here. Note that we don't use gethostname_malloc() or gethostname_strict() since we are interested
      82                 :            :          * in the raw string the kernel has set, whatever it may be, under the assumption that terminals are not overly
      83                 :            :          * careful with validating the strings either. */
      84                 :            : 
      85                 :          0 :         url = strjoin("file://", u.nodename, path);
      86         [ #  # ]:          0 :         if (!url)
      87                 :          0 :                 return -ENOMEM;
      88                 :            : 
      89                 :          0 :         *ret = url;
      90                 :          0 :         return 0;
      91                 :            : }
      92                 :            : 
      93                 :         20 : int terminal_urlify_path(const char *path, const char *text, char **ret) {
      94                 :         20 :         _cleanup_free_ char *url = NULL;
      95                 :            :         int r;
      96                 :            : 
      97         [ -  + ]:         20 :         assert(path);
      98                 :            : 
      99                 :            :         /* Much like terminal_urlify() above, but takes a file system path as input
     100                 :            :          * and turns it into a proper file:// URL first. */
     101                 :            : 
     102         [ -  + ]:         20 :         if (isempty(path))
     103                 :          0 :                 return -EINVAL;
     104                 :            : 
     105         [ +  + ]:         20 :         if (isempty(text))
     106                 :         12 :                 text = path;
     107                 :            : 
     108         [ +  - ]:         20 :         if (!urlify_enabled()) {
     109                 :            :                 char *n;
     110                 :            : 
     111                 :         20 :                 n = strdup(text);
     112         [ -  + ]:         20 :                 if (!n)
     113                 :          0 :                         return -ENOMEM;
     114                 :            : 
     115                 :         20 :                 *ret = n;
     116                 :         20 :                 return 0;
     117                 :            :         }
     118                 :            : 
     119                 :          0 :         r = file_url_from_path(path, &url);
     120         [ #  # ]:          0 :         if (r < 0)
     121                 :          0 :                 return r;
     122                 :            : 
     123                 :          0 :         return terminal_urlify(url, text, ret);
     124                 :            : }
     125                 :            : 
     126                 :        491 : int terminal_urlify_man(const char *page, const char *section, char **ret) {
     127                 :            :         const char *url, *text;
     128                 :            : 
     129   [ +  +  +  -  :       5401 :         url = strjoina("man:", page, "(", section, ")");
          -  +  -  +  +  
                +  +  - ]
     130   [ +  +  +  -  :       4419 :         text = strjoina(page, "(", section, ") man page");
          -  +  -  +  +  
                +  +  - ]
     131                 :            : 
     132                 :        491 :         return terminal_urlify(url, text, ret);
     133                 :            : }
     134                 :            : 
     135                 :         20 : static int cat_file(const char *filename, bool newline) {
     136                 :         20 :         _cleanup_fclose_ FILE *f = NULL;
     137                 :         20 :         _cleanup_free_ char *urlified = NULL;
     138                 :            :         int r;
     139                 :            : 
     140                 :         20 :         f = fopen(filename, "re");
     141         [ +  + ]:         20 :         if (!f)
     142                 :          8 :                 return -errno;
     143                 :            : 
     144                 :         12 :         r = terminal_urlify_path(filename, NULL, &urlified);
     145         [ -  + ]:         12 :         if (r < 0)
     146                 :          0 :                 return r;
     147                 :            : 
     148         [ +  + ]:         12 :         printf("%s%s# %s%s\n",
     149                 :            :                newline ? "\n" : "",
     150                 :            :                ansi_highlight_blue(),
     151                 :            :                urlified,
     152                 :            :                ansi_normal());
     153                 :         12 :         fflush(stdout);
     154                 :            : 
     155                 :        204 :         for (;;) {
     156      [ +  -  + ]:        216 :                 _cleanup_free_ char *line = NULL;
     157                 :            : 
     158                 :        216 :                 r = read_line(f, LONG_LINE_MAX, &line);
     159         [ -  + ]:        216 :                 if (r < 0)
     160         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to read \"%s\": %m", filename);
     161         [ +  + ]:        216 :                 if (r == 0)
     162                 :         12 :                         break;
     163                 :            : 
     164                 :        204 :                 puts(line);
     165                 :            :         }
     166                 :            : 
     167                 :         12 :         return 0;
     168                 :            : }
     169                 :            : 
     170                 :         12 : int cat_files(const char *file, char **dropins, CatFlags flags) {
     171                 :            :         char **path;
     172                 :            :         int r;
     173                 :            : 
     174         [ +  - ]:         12 :         if (file) {
     175                 :         12 :                 r = cat_file(file, false);
     176   [ +  +  +  + ]:         12 :                 if (r == -ENOENT && (flags & CAT_FLAGS_MAIN_FILE_OPTIONAL))
     177                 :          4 :                         printf("%s# config file %s not found%s\n",
     178                 :            :                                ansi_highlight_magenta(),
     179                 :            :                                file,
     180                 :            :                                ansi_normal());
     181         [ +  + ]:          8 :                 else if (r < 0)
     182         [ +  - ]:          4 :                         return log_warning_errno(r, "Failed to cat %s: %m", file);
     183                 :            :         }
     184                 :            : 
     185   [ +  +  +  + ]:         16 :         STRV_FOREACH(path, dropins) {
     186   [ -  +  #  # ]:          8 :                 r = cat_file(*path, file || path != dropins);
     187         [ -  + ]:          8 :                 if (r < 0)
     188         [ #  # ]:          0 :                         return log_warning_errno(r, "Failed to cat %s: %m", *path);
     189                 :            :         }
     190                 :            : 
     191                 :          8 :         return 0;
     192                 :            : }
     193                 :            : 
     194                 :          4 : void print_separator(void) {
     195                 :            : 
     196                 :            :         /* Outputs a separator line that resolves to whitespace when copied from the terminal. We do that by outputting
     197                 :            :          * one line filled with spaces with ANSI underline set, followed by a second (empty) line. */
     198                 :            : 
     199         [ -  + ]:          4 :         if (underline_enabled()) {
     200                 :            :                 size_t i, c;
     201                 :            : 
     202                 :          0 :                 c = columns();
     203                 :            : 
     204                 :          0 :                 flockfile(stdout);
     205                 :          0 :                 fputs_unlocked(ANSI_UNDERLINE, stdout);
     206                 :            : 
     207         [ #  # ]:          0 :                 for (i = 0; i < c; i++)
     208                 :          0 :                         fputc_unlocked(' ', stdout);
     209                 :            : 
     210                 :          0 :                 fputs_unlocked(ANSI_NORMAL "\n\n", stdout);
     211                 :          0 :                 funlockfile(stdout);
     212                 :            :         } else
     213                 :          4 :                 fputs("\n\n", stdout);
     214                 :          4 : }
     215                 :            : 
     216                 :          0 : static int guess_type(const char **name, char ***prefixes, bool *is_collection, const char **extension) {
     217                 :            :         /* Try to figure out if name is like tmpfiles.d/ or systemd/system-presets/,
     218                 :            :          * i.e. a collection of directories without a main config file. */
     219                 :            : 
     220                 :          0 :         _cleanup_free_ char *n = NULL;
     221                 :          0 :         bool usr = false, run = false, coll = false;
     222                 :          0 :         const char *ext = ".conf";
     223                 :            :         /* This is static so that the array doesn't get deallocated when we exit the function */
     224                 :            :         static const char* const std_prefixes[] = { CONF_PATHS(""), NULL };
     225                 :            :         static const char* const usr_prefixes[] = { CONF_PATHS_USR(""), NULL };
     226                 :            :         static const char* const run_prefixes[] = { "/run/", NULL };
     227                 :            : 
     228         [ #  # ]:          0 :         if (path_equal(*name, "environment.d"))
     229                 :            :                 /* Special case: we need to include /etc/environment in the search path, even
     230                 :            :                  * though the whole concept is called environment.d. */
     231                 :          0 :                 *name = "environment";
     232                 :            : 
     233                 :          0 :         n = strdup(*name);
     234         [ #  # ]:          0 :         if (!n)
     235                 :          0 :                 return log_oom();
     236                 :            : 
     237                 :          0 :         delete_trailing_chars(n, "/");
     238                 :            : 
     239         [ #  # ]:          0 :         if (endswith(n, ".d"))
     240                 :          0 :                 coll = true;
     241                 :            : 
     242         [ #  # ]:          0 :         if (path_equal(n, "environment"))
     243                 :          0 :                 usr = true;
     244                 :            : 
     245         [ #  # ]:          0 :         if (path_equal(n, "udev/hwdb.d"))
     246                 :          0 :                 ext = ".hwdb";
     247                 :            : 
     248         [ #  # ]:          0 :         if (path_equal(n, "udev/rules.d"))
     249                 :          0 :                 ext = ".rules";
     250                 :            : 
     251         [ #  # ]:          0 :         if (path_equal(n, "kernel/install.d"))
     252                 :          0 :                 ext = ".install";
     253                 :            : 
     254         [ #  # ]:          0 :         if (path_equal(n, "systemd/ntp-units.d")) {
     255                 :          0 :                 coll = true;
     256                 :          0 :                 ext = ".list";
     257                 :            :         }
     258                 :            : 
     259         [ #  # ]:          0 :         if (path_equal(n, "systemd/relabel-extra.d")) {
     260                 :          0 :                 coll = run = true;
     261                 :          0 :                 ext = ".relabel";
     262                 :            :         }
     263                 :            : 
     264   [ #  #  #  #  :          0 :         if (PATH_IN_SET(n, "systemd/system-preset", "systemd/user-preset")) {
             #  #  #  # ]
     265                 :          0 :                 coll = true;
     266                 :          0 :                 ext = ".preset";
     267                 :            :         }
     268                 :            : 
     269         [ #  # ]:          0 :         if (path_equal(n, "systemd/user-preset"))
     270                 :          0 :                 usr = true;
     271                 :            : 
     272   [ #  #  #  # ]:          0 :         *prefixes = (char**) (usr ? usr_prefixes : run ? run_prefixes : std_prefixes);
     273                 :          0 :         *is_collection = coll;
     274                 :          0 :         *extension = ext;
     275                 :          0 :         return 0;
     276                 :            : }
     277                 :            : 
     278                 :          0 : int conf_files_cat(const char *root, const char *name) {
     279                 :          0 :         _cleanup_strv_free_ char **dirs = NULL, **files = NULL;
     280                 :          0 :         _cleanup_free_ char *path = NULL;
     281                 :            :         char **prefixes, **prefix;
     282                 :            :         bool is_collection;
     283                 :            :         const char *extension;
     284                 :            :         char **t;
     285                 :            :         int r;
     286                 :            : 
     287                 :          0 :         r = guess_type(&name, &prefixes, &is_collection, &extension);
     288         [ #  # ]:          0 :         if (r < 0)
     289                 :          0 :                 return r;
     290                 :            : 
     291   [ #  #  #  # ]:          0 :         STRV_FOREACH(prefix, prefixes) {
     292         [ #  # ]:          0 :                 assert(endswith(*prefix, "/"));
     293                 :          0 :                 r = strv_extendf(&dirs, "%s%s%s", *prefix, name,
     294         [ #  # ]:          0 :                                  is_collection ? "" : ".d");
     295         [ #  # ]:          0 :                 if (r < 0)
     296         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to build directory list: %m");
     297                 :            :         }
     298                 :            : 
     299                 :          0 :         r = conf_files_list_strv(&files, extension, root, 0, (const char* const*) dirs);
     300         [ #  # ]:          0 :         if (r < 0)
     301         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to query file list: %m");
     302                 :            : 
     303         [ #  # ]:          0 :         if (!is_collection) {
     304                 :          0 :                 path = path_join(root, "/etc", name);
     305         [ #  # ]:          0 :                 if (!path)
     306                 :          0 :                         return log_oom();
     307                 :            :         }
     308                 :            : 
     309         [ #  # ]:          0 :         if (DEBUG_LOGGING) {
     310         [ #  # ]:          0 :                 log_debug("Looking for configuration in:");
     311         [ #  # ]:          0 :                 if (path)
     312         [ #  # ]:          0 :                         log_debug("   %s", path);
     313   [ #  #  #  # ]:          0 :                 STRV_FOREACH(t, dirs)
     314         [ #  # ]:          0 :                         log_debug("   %s/*%s", *t, extension);
     315                 :            :         }
     316                 :            : 
     317                 :            :         /* show */
     318                 :          0 :         return cat_files(path, files, CAT_FLAGS_MAIN_FILE_OPTIONAL);
     319                 :            : }

Generated by: LCOV version 1.14