LCOV - code coverage report
Current view: top level - shared - specifier.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 105 142 73.9 %
Date: 2019-08-22 15:41:25 Functions: 12 15 80.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <errno.h>
       4             : #include <stdbool.h>
       5             : #include <stddef.h>
       6             : #include <stdlib.h>
       7             : #include <string.h>
       8             : #include <sys/utsname.h>
       9             : 
      10             : #include "sd-id128.h"
      11             : 
      12             : #include "alloc-util.h"
      13             : #include "format-util.h"
      14             : #include "fs-util.h"
      15             : #include "hostname-util.h"
      16             : #include "macro.h"
      17             : #include "specifier.h"
      18             : #include "string-util.h"
      19             : #include "strv.h"
      20             : #include "user-util.h"
      21             : 
      22             : /*
      23             :  * Generic infrastructure for replacing %x style specifiers in
      24             :  * strings. Will call a callback for each replacement.
      25             :  */
      26             : 
      27             : /* Any ASCII character or digit: our pool of potential specifiers,
      28             :  * and "%" used for escaping. */
      29             : #define POSSIBLE_SPECIFIERS ALPHANUMERICAL "%"
      30             : 
      31         809 : int specifier_printf(const char *text, const Specifier table[], const void *userdata, char **_ret) {
      32         809 :         size_t l, allocated = 0;
      33         809 :         _cleanup_free_ char *ret = NULL;
      34             :         char *t;
      35             :         const char *f;
      36         809 :         bool percent = false;
      37             :         int r;
      38             : 
      39         809 :         assert(text);
      40         809 :         assert(table);
      41             : 
      42         809 :         l = strlen(text);
      43         809 :         if (!GREEDY_REALLOC(ret, allocated, l + 1))
      44           0 :                 return -ENOMEM;
      45         809 :         t = ret;
      46             : 
      47       10932 :         for (f = text; *f; f++, l--)
      48       10132 :                 if (percent) {
      49         122 :                         if (*f == '%')
      50           4 :                                 *(t++) = '%';
      51             :                         else {
      52             :                                 const Specifier *i;
      53             : 
      54        1101 :                                 for (i = table; i->specifier; i++)
      55        1092 :                                         if (i->specifier == *f)
      56         109 :                                                 break;
      57             : 
      58         118 :                                 if (i->lookup) {
      59         109 :                                         _cleanup_free_ char *w = NULL;
      60             :                                         size_t k, j;
      61             : 
      62         109 :                                         r = i->lookup(i->specifier, i->data, userdata, &w);
      63         109 :                                         if (r < 0)
      64           1 :                                                 return r;
      65             : 
      66         108 :                                         j = t - ret;
      67         108 :                                         k = strlen(w);
      68             : 
      69         108 :                                         if (!GREEDY_REALLOC(ret, allocated, j + k + l + 1))
      70           0 :                                                 return -ENOMEM;
      71         108 :                                         memcpy(ret + j, w, k);
      72         108 :                                         t = ret + j + k;
      73           9 :                                 } else if (strchr(POSSIBLE_SPECIFIERS, *f))
      74             :                                         /* Oops, an unknown specifier. */
      75           8 :                                         return -EBADSLT;
      76             :                                 else {
      77           1 :                                         *(t++) = '%';
      78           1 :                                         *(t++) = *f;
      79             :                                 }
      80             :                         }
      81             : 
      82         113 :                         percent = false;
      83       10010 :                 } else if (*f == '%')
      84         123 :                         percent = true;
      85             :                 else
      86        9887 :                         *(t++) = *f;
      87             : 
      88             :         /* If string ended with a stray %, also end with % */
      89         800 :         if (percent)
      90           1 :                 *(t++) = '%';
      91         800 :         *(t++) = 0;
      92             : 
      93             :         /* Try to deallocate unused bytes, but don't sweat it too much */
      94         800 :         if ((size_t)(t - ret) < allocated) {
      95         800 :                 t = realloc(ret, t - ret);
      96         800 :                 if (t)
      97         800 :                         ret = t;
      98             :         }
      99             : 
     100         800 :         *_ret = TAKE_PTR(ret);
     101         800 :         return 0;
     102             : }
     103             : 
     104             : /* Generic handler for simple string replacements */
     105             : 
     106          10 : int specifier_string(char specifier, const void *data, const void *userdata, char **ret) {
     107             :         char *n;
     108             : 
     109          10 :         n = strdup(strempty(data));
     110          10 :         if (!n)
     111           0 :                 return -ENOMEM;
     112             : 
     113          10 :         *ret = n;
     114          10 :         return 0;
     115             : }
     116             : 
     117           9 : int specifier_machine_id(char specifier, const void *data, const void *userdata, char **ret) {
     118             :         sd_id128_t id;
     119             :         char *n;
     120             :         int r;
     121             : 
     122           9 :         r = sd_id128_get_machine(&id);
     123           9 :         if (r < 0)
     124           0 :                 return r;
     125             : 
     126           9 :         n = new(char, 33);
     127           9 :         if (!n)
     128           0 :                 return -ENOMEM;
     129             : 
     130           9 :         *ret = sd_id128_to_string(id, n);
     131           9 :         return 0;
     132             : }
     133             : 
     134           9 : int specifier_boot_id(char specifier, const void *data, const void *userdata, char **ret) {
     135             :         sd_id128_t id;
     136             :         char *n;
     137             :         int r;
     138             : 
     139           9 :         r = sd_id128_get_boot(&id);
     140           9 :         if (r < 0)
     141           0 :                 return r;
     142             : 
     143           9 :         n = new(char, 33);
     144           9 :         if (!n)
     145           0 :                 return -ENOMEM;
     146             : 
     147           9 :         *ret = sd_id128_to_string(id, n);
     148           9 :         return 0;
     149             : }
     150             : 
     151           7 : int specifier_host_name(char specifier, const void *data, const void *userdata, char **ret) {
     152             :         char *n;
     153             : 
     154           7 :         n = gethostname_malloc();
     155           7 :         if (!n)
     156           0 :                 return -ENOMEM;
     157             : 
     158           7 :         *ret = n;
     159           7 :         return 0;
     160             : }
     161             : 
     162           7 : int specifier_kernel_release(char specifier, const void *data, const void *userdata, char **ret) {
     163             :         struct utsname uts;
     164             :         char *n;
     165             :         int r;
     166             : 
     167           7 :         r = uname(&uts);
     168           7 :         if (r < 0)
     169           0 :                 return -errno;
     170             : 
     171           7 :         n = strdup(uts.release);
     172           7 :         if (!n)
     173           0 :                 return -ENOMEM;
     174             : 
     175           7 :         *ret = n;
     176           7 :         return 0;
     177             : }
     178             : 
     179           8 : int specifier_group_name(char specifier, const void *data, const void *userdata, char **ret) {
     180             :         char *t;
     181             : 
     182           8 :         t = gid_to_name(getgid());
     183           8 :         if (!t)
     184           0 :                 return -ENOMEM;
     185             : 
     186           8 :         *ret = t;
     187           8 :         return 0;
     188             : }
     189             : 
     190           8 : int specifier_group_id(char specifier, const void *data, const void *userdata, char **ret) {
     191           8 :         if (asprintf(ret, UID_FMT, getgid()) < 0)
     192           0 :                 return -ENOMEM;
     193             : 
     194           8 :         return 0;
     195             : }
     196             : 
     197           8 : int specifier_user_name(char specifier, const void *data, const void *userdata, char **ret) {
     198             :         char *t;
     199             : 
     200             :         /* If we are UID 0 (root), this will not result in NSS, otherwise it might. This is good, as we want to be able
     201             :          * to run this in PID 1, where our user ID is 0, but where NSS lookups are not allowed.
     202             : 
     203             :          * We don't use getusername_malloc() here, because we don't want to look at $USER, to remain consistent with
     204             :          * specifer_user_id() below.
     205             :          */
     206             : 
     207           8 :         t = uid_to_name(getuid());
     208           8 :         if (!t)
     209           0 :                 return -ENOMEM;
     210             : 
     211           8 :         *ret = t;
     212           8 :         return 0;
     213             : }
     214             : 
     215           8 : int specifier_user_id(char specifier, const void *data, const void *userdata, char **ret) {
     216             : 
     217           8 :         if (asprintf(ret, UID_FMT, getuid()) < 0)
     218           0 :                 return -ENOMEM;
     219             : 
     220           8 :         return 0;
     221             : }
     222             : 
     223           4 : int specifier_user_home(char specifier, const void *data, const void *userdata, char **ret) {
     224             : 
     225             :         /* On PID 1 (which runs as root) this will not result in NSS,
     226             :          * which is good. See above */
     227             : 
     228           4 :         return get_home_dir(ret);
     229             : }
     230             : 
     231           0 : int specifier_user_shell(char specifier, const void *data, const void *userdata, char **ret) {
     232             : 
     233             :         /* On PID 1 (which runs as root) this will not result in NSS,
     234             :          * which is good. See above */
     235             : 
     236           0 :         return get_shell(ret);
     237             : }
     238             : 
     239           0 : int specifier_tmp_dir(char specifier, const void *data, const void *userdata, char **ret) {
     240             :         const char *p;
     241             :         char *copy;
     242             :         int r;
     243             : 
     244           0 :         r = tmp_dir(&p);
     245           0 :         if (r < 0)
     246           0 :                 return r;
     247             : 
     248           0 :         copy = strdup(p);
     249           0 :         if (!copy)
     250           0 :                 return -ENOMEM;
     251             : 
     252           0 :         *ret = copy;
     253           0 :         return 0;
     254             : }
     255             : 
     256           0 : int specifier_var_tmp_dir(char specifier, const void *data, const void *userdata, char **ret) {
     257             :         const char *p;
     258             :         char *copy;
     259             :         int r;
     260             : 
     261           0 :         r = var_tmp_dir(&p);
     262           0 :         if (r < 0)
     263           0 :                 return r;
     264             : 
     265           0 :         copy = strdup(p);
     266           0 :         if (!copy)
     267           0 :                 return -ENOMEM;
     268             : 
     269           0 :         *ret = copy;
     270           0 :         return 0;
     271             : }
     272             : 
     273           6 : int specifier_escape_strv(char **l, char ***ret) {
     274             :         char **z, **p, **q;
     275             : 
     276           6 :         assert(ret);
     277             : 
     278           6 :         if (strv_isempty(l)) {
     279           2 :                 *ret = NULL;
     280           2 :                 return 0;
     281             :         }
     282             : 
     283           4 :         z = new(char*, strv_length(l)+1);
     284           4 :         if (!z)
     285           0 :                 return -ENOMEM;
     286             : 
     287          14 :         for (p = l, q = z; *p; p++, q++) {
     288             : 
     289          10 :                 *q = specifier_escape(*p);
     290          10 :                 if (!*q) {
     291           0 :                         strv_free(z);
     292           0 :                         return -ENOMEM;
     293             :                 }
     294             :         }
     295             : 
     296           4 :         *q = NULL;
     297           4 :         *ret = z;
     298             : 
     299           4 :         return 0;
     300             : }

Generated by: LCOV version 1.14