LCOV - code coverage report
Current view: top level - core - unit-printf.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 96 182 52.7 %
Date: 2015-07-29 18:47:03 Functions: 11 15 73.3 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       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 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 "unit.h"
      23             : #include "specifier.h"
      24             : #include "strv.h"
      25             : #include "unit-name.h"
      26             : #include "unit-printf.h"
      27             : #include "macro.h"
      28             : #include "cgroup-util.h"
      29             : #include "formats-util.h"
      30             : 
      31           2 : static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) {
      32           2 :         Unit *u = userdata;
      33             : 
      34           2 :         assert(u);
      35             : 
      36           2 :         return unit_name_to_prefix_and_instance(u->id, ret);
      37             : }
      38             : 
      39           2 : static int specifier_prefix(char specifier, void *data, void *userdata, char **ret) {
      40           2 :         Unit *u = userdata;
      41             : 
      42           2 :         assert(u);
      43             : 
      44           2 :         return unit_name_to_prefix(u->id, ret);
      45             : }
      46             : 
      47           2 : static int specifier_prefix_unescaped(char specifier, void *data, void *userdata, char **ret) {
      48           4 :         _cleanup_free_ char *p = NULL;
      49           2 :         Unit *u = userdata;
      50             :         int r;
      51             : 
      52           2 :         assert(u);
      53             : 
      54           2 :         r = unit_name_to_prefix(u->id, &p);
      55           2 :         if (r < 0)
      56           0 :                 return r;
      57             : 
      58           2 :         return unit_name_unescape(p, ret);
      59             : }
      60             : 
      61           1 : static int specifier_instance_unescaped(char specifier, void *data, void *userdata, char **ret) {
      62           1 :         Unit *u = userdata;
      63             : 
      64           1 :         assert(u);
      65             : 
      66           1 :         if (!u->instance)
      67           0 :                 return -EINVAL;
      68             : 
      69           1 :         return unit_name_unescape(u->instance, ret);
      70             : }
      71             : 
      72           2 : static int specifier_filename(char specifier, void *data, void *userdata, char **ret) {
      73           2 :         Unit *u = userdata;
      74             : 
      75           2 :         assert(u);
      76             : 
      77           2 :         if (u->instance)
      78           1 :                 return unit_name_path_unescape(u->instance, ret);
      79             :         else
      80           1 :                 return unit_name_to_path(u->id, ret);
      81             : }
      82             : 
      83           0 : static int specifier_cgroup(char specifier, void *data, void *userdata, char **ret) {
      84           0 :         Unit *u = userdata;
      85             :         char *n;
      86             : 
      87           0 :         assert(u);
      88             : 
      89           0 :         if (u->cgroup_path)
      90           0 :                 n = strdup(u->cgroup_path);
      91             :         else
      92           0 :                 n = unit_default_cgroup_path(u);
      93           0 :         if (!n)
      94           0 :                 return -ENOMEM;
      95             : 
      96           0 :         *ret = n;
      97           0 :         return 0;
      98             : }
      99             : 
     100           0 : static int specifier_cgroup_root(char specifier, void *data, void *userdata, char **ret) {
     101           0 :         Unit *u = userdata;
     102             :         char *n;
     103             : 
     104           0 :         assert(u);
     105             : 
     106           0 :         n = strdup(u->manager->cgroup_root);
     107           0 :         if (!n)
     108           0 :                 return -ENOMEM;
     109             : 
     110           0 :         *ret = n;
     111           0 :         return 0;
     112             : }
     113             : 
     114           0 : static int specifier_cgroup_slice(char specifier, void *data, void *userdata, char **ret) {
     115           0 :         Unit *u = userdata;
     116             :         char *n;
     117             : 
     118           0 :         assert(u);
     119             : 
     120           0 :         if (UNIT_ISSET(u->slice)) {
     121             :                 Unit *slice;
     122             : 
     123           0 :                 slice = UNIT_DEREF(u->slice);
     124             : 
     125           0 :                 if (slice->cgroup_path)
     126           0 :                         n = strdup(slice->cgroup_path);
     127             :                 else
     128           0 :                         n = unit_default_cgroup_path(slice);
     129             :         } else
     130           0 :                 n = strdup(u->manager->cgroup_root);
     131             : 
     132           0 :         *ret = n;
     133           0 :         return 0;
     134             : }
     135             : 
     136           2 : static int specifier_runtime(char specifier, void *data, void *userdata, char **ret) {
     137           2 :         Unit *u = userdata;
     138             :         const char *e;
     139           2 :         char *n = NULL;
     140             : 
     141           2 :         assert(u);
     142             : 
     143           2 :         if (u->manager->running_as == MANAGER_SYSTEM)
     144           0 :                 e = "/run";
     145             :         else {
     146           2 :                 e = getenv("XDG_RUNTIME_DIR");
     147           2 :                 if (!e)
     148           0 :                         return -EOPNOTSUPP;
     149             :         }
     150             : 
     151           2 :         n = strdup(e);
     152           2 :         if (!n)
     153           0 :                 return -ENOMEM;
     154             : 
     155           2 :         *ret = n;
     156           2 :         return 0;
     157             : }
     158             : 
     159           4 : static int specifier_user_name(char specifier, void *data, void *userdata, char **ret) {
     160           4 :         char *printed = NULL;
     161           4 :         Unit *u = userdata;
     162             :         ExecContext *c;
     163           4 :         int r = 0;
     164             : 
     165           4 :         assert(u);
     166             : 
     167           4 :         c = unit_get_exec_context(u);
     168           4 :         if (!c)
     169           0 :                 return -EINVAL;
     170             : 
     171           4 :         if (u->manager->running_as == MANAGER_SYSTEM) {
     172             : 
     173             :                 /* We cannot use NSS from PID 1, hence try to make the
     174             :                  * best of it in that case, and fail if we can't help
     175             :                  * it */
     176             : 
     177           0 :                 if (!c->user || streq(c->user, "root") || streq(c->user, "0"))
     178           0 :                         printed = strdup(specifier == 'u' ? "root" : "0");
     179             :                 else {
     180           0 :                         if (specifier == 'u')
     181           0 :                                 printed = strdup(c->user);
     182             :                         else {
     183             :                                 uid_t uid;
     184             : 
     185           0 :                                 r = parse_uid(c->user, &uid);
     186           0 :                                 if (r < 0)
     187           0 :                                         return -ENODATA;
     188             : 
     189           0 :                                 r = asprintf(&printed, UID_FMT, uid);
     190             :                         }
     191             :                 }
     192             : 
     193             :         } else {
     194           8 :                 _cleanup_free_ char *tmp = NULL;
     195           4 :                 const char *username = NULL;
     196             :                 uid_t uid;
     197             : 
     198           4 :                 if (c->user)
     199           0 :                         username = c->user;
     200             :                 else
     201             :                         /* get USER env from env or our own uid */
     202           4 :                         username = tmp = getusername_malloc();
     203             : 
     204             :                 /* fish username from passwd */
     205           4 :                 r = get_user_creds(&username, &uid, NULL, NULL, NULL);
     206           4 :                 if (r < 0)
     207           0 :                         return r;
     208             : 
     209           4 :                 if (specifier == 'u')
     210           2 :                         printed = strdup(username);
     211             :                 else
     212           2 :                         r = asprintf(&printed, UID_FMT, uid);
     213             :         }
     214             : 
     215           4 :         if (r < 0 || !printed)
     216           0 :                 return -ENOMEM;
     217             : 
     218           4 :         *ret = printed;
     219           4 :         return 0;
     220             : }
     221             : 
     222           2 : static int specifier_user_home(char specifier, void *data, void *userdata, char **ret) {
     223           2 :         Unit *u = userdata;
     224             :         ExecContext *c;
     225             :         char *n;
     226             :         int r;
     227             : 
     228           2 :         assert(u);
     229             : 
     230           2 :         c = unit_get_exec_context(u);
     231           2 :         if (!c)
     232           0 :                 return -EOPNOTSUPP;
     233             : 
     234           2 :         if (u->manager->running_as == MANAGER_SYSTEM) {
     235             : 
     236             :                 /* We cannot use NSS from PID 1, hence try to make the
     237             :                  * best of it if we can, but fail if we can't */
     238             : 
     239           0 :                 if (!c->user || streq(c->user, "root") || streq(c->user, "0"))
     240           0 :                         n = strdup("/root");
     241             :                 else
     242           0 :                         return -EOPNOTSUPP;
     243             : 
     244             :         } else {
     245             : 
     246             :                 /* return HOME if set, otherwise from passwd */
     247           2 :                 if (!c || !c->user) {
     248           2 :                         r = get_home_dir(&n);
     249           4 :                         if (r < 0)
     250           0 :                                 return r;
     251             :                 } else {
     252             :                         const char *username, *home;
     253             : 
     254           0 :                         username = c->user;
     255           0 :                         r = get_user_creds(&username, NULL, NULL, &home, NULL);
     256           0 :                         if (r < 0)
     257           0 :                                 return r;
     258             : 
     259           0 :                         n = strdup(home);
     260             :                 }
     261             :         }
     262             : 
     263           2 :         if (!n)
     264           0 :                 return -ENOMEM;
     265             : 
     266           2 :         *ret = n;
     267           2 :         return 0;
     268             : }
     269             : 
     270           0 : static int specifier_user_shell(char specifier, void *data, void *userdata, char **ret) {
     271           0 :         Unit *u = userdata;
     272             :         ExecContext *c;
     273             :         char *n;
     274             :         int r;
     275             : 
     276           0 :         assert(u);
     277             : 
     278           0 :         c = unit_get_exec_context(u);
     279           0 :         if (!c)
     280           0 :                 return -EOPNOTSUPP;
     281             : 
     282           0 :         if (u->manager->running_as == MANAGER_SYSTEM) {
     283             : 
     284             :                 /* We cannot use NSS from PID 1, hence try to make the
     285             :                  * best of it if we can, but fail if we can't */
     286             : 
     287           0 :                 if (!c->user || streq(c->user, "root") || streq(c->user, "0"))
     288           0 :                         n = strdup("/bin/sh");
     289             :                 else
     290           0 :                         return -EOPNOTSUPP;
     291             : 
     292             :         } else {
     293             : 
     294             :                 /* return /bin/sh for root, otherwise the value from passwd */
     295           0 :                 if (!c->user) {
     296           0 :                         r = get_shell(&n);
     297           0 :                         if (r < 0)
     298           0 :                                 return r;
     299             :                 } else {
     300             :                         const char *username, *shell;
     301             : 
     302           0 :                         username = c->user;
     303           0 :                         r = get_user_creds(&username, NULL, NULL, NULL, &shell);
     304           0 :                         if (r < 0)
     305           0 :                                 return r;
     306             : 
     307           0 :                         n = strdup(shell);
     308             :                 }
     309             :         }
     310             : 
     311           0 :         if (!n)
     312           0 :                 return -ENOMEM;
     313             : 
     314           0 :         *ret = n;
     315           0 :         return 0;
     316             : }
     317             : 
     318         196 : int unit_name_printf(Unit *u, const char* format, char **ret) {
     319             : 
     320             :         /*
     321             :          * This will use the passed string as format string and
     322             :          * replace the following specifiers:
     323             :          *
     324             :          * %n: the full id of the unit                 (foo@bar.waldo)
     325             :          * %N: the id of the unit without the suffix   (foo@bar)
     326             :          * %p: the prefix                              (foo)
     327             :          * %i: the instance                            (bar)
     328             :          */
     329             : 
     330         588 :         const Specifier table[] = {
     331         196 :                 { 'n', specifier_string,              u->id },
     332             :                 { 'N', specifier_prefix_and_instance, NULL },
     333             :                 { 'p', specifier_prefix,              NULL },
     334         196 :                 { 'i', specifier_string,              u->instance },
     335             :                 { 0, NULL, NULL }
     336             :         };
     337             : 
     338         196 :         assert(u);
     339         196 :         assert(format);
     340         196 :         assert(ret);
     341             : 
     342         196 :         return specifier_printf(format, table, u, ret);
     343             : }
     344             : 
     345         195 : int unit_full_printf(Unit *u, const char *format, char **ret) {
     346             : 
     347             :         /* This is similar to unit_name_printf() but also supports
     348             :          * unescaping. Also, adds a couple of additional codes:
     349             :          *
     350             :          * %f the instance if set, otherwise the id
     351             :          * %c cgroup path of unit
     352             :          * %r where units in this slice are placed in the cgroup tree
     353             :          * %R the root of this systemd's instance tree
     354             :          * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
     355             :          * %U the UID of the configured user or running user
     356             :          * %u the username of the configured user or running user
     357             :          * %h the homedir of the configured user or running user
     358             :          * %s the shell of the configured user or running user
     359             :          * %m the machine ID of the running system
     360             :          * %H the host name of the running system
     361             :          * %b the boot ID of the running system
     362             :          * %v `uname -r` of the running system
     363             :          */
     364             : 
     365         585 :         const Specifier table[] = {
     366         195 :                 { 'n', specifier_string,              u->id },
     367             :                 { 'N', specifier_prefix_and_instance, NULL },
     368             :                 { 'p', specifier_prefix,              NULL },
     369             :                 { 'P', specifier_prefix_unescaped,    NULL },
     370         195 :                 { 'i', specifier_string,              u->instance },
     371             :                 { 'I', specifier_instance_unescaped,  NULL },
     372             : 
     373             :                 { 'f', specifier_filename,            NULL },
     374             :                 { 'c', specifier_cgroup,              NULL },
     375             :                 { 'r', specifier_cgroup_slice,        NULL },
     376             :                 { 'R', specifier_cgroup_root,         NULL },
     377             :                 { 't', specifier_runtime,             NULL },
     378             :                 { 'U', specifier_user_name,           NULL },
     379             :                 { 'u', specifier_user_name,           NULL },
     380             :                 { 'h', specifier_user_home,           NULL },
     381             :                 { 's', specifier_user_shell,          NULL },
     382             : 
     383             :                 { 'm', specifier_machine_id,          NULL },
     384             :                 { 'H', specifier_host_name,           NULL },
     385             :                 { 'b', specifier_boot_id,             NULL },
     386             :                 { 'v', specifier_kernel_release,      NULL },
     387             :                 {}
     388             :         };
     389             : 
     390         195 :         assert(u);
     391         195 :         assert(format);
     392         195 :         assert(ret);
     393             : 
     394         195 :         return specifier_printf(format, table, u, ret);
     395             : }
     396             : 
     397           6 : int unit_full_printf_strv(Unit *u, char **l, char ***ret) {
     398             :         size_t n;
     399             :         char **r, **i, **j;
     400             :         int q;
     401             : 
     402             :         /* Applies unit_full_printf to every entry in l */
     403             : 
     404           6 :         assert(u);
     405             : 
     406           6 :         n = strv_length(l);
     407           6 :         r = new(char*, n+1);
     408           6 :         if (!r)
     409           0 :                 return -ENOMEM;
     410             : 
     411          12 :         for (i = l, j = r; *i; i++, j++) {
     412           6 :                 q = unit_full_printf(u, *i, j);
     413           6 :                 if (q < 0)
     414           0 :                         goto fail;
     415             :         }
     416             : 
     417           6 :         *j = NULL;
     418           6 :         *ret = r;
     419           6 :         return 0;
     420             : 
     421             : fail:
     422           0 :         for (j--; j >= r; j--)
     423           0 :                 free(*j);
     424             : 
     425           0 :         free(r);
     426           0 :         return q;
     427             : }

Generated by: LCOV version 1.11