2012-09-18 13:27:56 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd .
Copyright 2010 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 of the License , or
( at your option ) any later version .
systemd is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
# include "systemd/sd-id128.h"
# include "unit.h"
# include "specifier.h"
# include "path-util.h"
# include "strv.h"
# include "unit-name.h"
# include "unit-printf.h"
2013-01-29 19:32:39 +04:00
# include "macro.h"
2013-06-20 05:45:08 +04:00
# include "cgroup-util.h"
# include "special.h"
2012-09-18 13:27:56 +04:00
2013-09-17 19:03:46 +04:00
static int specifier_prefix_and_instance ( char specifier , void * data , void * userdata , char * * ret ) {
2012-09-18 13:27:56 +04:00
Unit * u = userdata ;
2013-09-17 19:03:46 +04:00
char * n ;
2012-09-18 13:27:56 +04:00
assert ( u ) ;
2013-09-17 19:03:46 +04:00
n = unit_name_to_prefix_and_instance ( u - > id ) ;
if ( ! n )
return - ENOMEM ;
* ret = n ;
return 0 ;
2012-09-18 13:27:56 +04:00
}
2013-09-17 19:03:46 +04:00
static int specifier_prefix ( char specifier , void * data , void * userdata , char * * ret ) {
2012-09-18 13:27:56 +04:00
Unit * u = userdata ;
2013-09-17 19:03:46 +04:00
char * n ;
2012-09-18 13:27:56 +04:00
assert ( u ) ;
2013-09-17 19:03:46 +04:00
n = unit_name_to_prefix ( u - > id ) ;
if ( ! n )
return - ENOMEM ;
* ret = n ;
return 0 ;
2012-09-18 13:27:56 +04:00
}
2013-09-17 19:03:46 +04:00
static int specifier_prefix_unescaped ( char specifier , void * data , void * userdata , char * * ret ) {
2012-09-18 13:27:56 +04:00
Unit * u = userdata ;
2013-09-17 19:03:46 +04:00
_cleanup_free_ char * p = NULL ;
char * n ;
2012-09-18 13:27:56 +04:00
assert ( u ) ;
p = unit_name_to_prefix ( u - > id ) ;
if ( ! p )
2013-09-17 19:03:46 +04:00
return - ENOMEM ;
2012-09-18 13:27:56 +04:00
2013-09-17 19:03:46 +04:00
n = unit_name_unescape ( p ) ;
if ( ! n )
return - ENOMEM ;
2012-09-18 13:27:56 +04:00
2013-09-17 19:03:46 +04:00
* ret = n ;
return 0 ;
2012-09-18 13:27:56 +04:00
}
2013-09-17 19:03:46 +04:00
static int specifier_instance_unescaped ( char specifier , void * data , void * userdata , char * * ret ) {
2012-09-18 13:27:56 +04:00
Unit * u = userdata ;
2013-09-17 19:03:46 +04:00
char * n ;
2012-09-18 13:27:56 +04:00
assert ( u ) ;
2013-12-16 07:59:31 +04:00
if ( ! u - > instance )
return - ENOTSUP ;
2013-09-17 19:03:46 +04:00
2013-12-16 07:59:31 +04:00
n = unit_name_unescape ( u - > instance ) ;
2013-09-17 19:03:46 +04:00
if ( ! n )
return - ENOMEM ;
2012-09-18 13:27:56 +04:00
2013-09-17 19:03:46 +04:00
* ret = n ;
return 0 ;
2012-09-18 13:27:56 +04:00
}
2013-09-17 19:03:46 +04:00
static int specifier_filename ( char specifier , void * data , void * userdata , char * * ret ) {
2012-09-18 13:27:56 +04:00
Unit * u = userdata ;
2013-09-17 19:03:46 +04:00
char * n ;
2012-09-18 13:27:56 +04:00
assert ( u ) ;
if ( u - > instance )
2013-09-17 19:03:46 +04:00
n = unit_name_path_unescape ( u - > instance ) ;
else
n = unit_name_to_path ( u - > id ) ;
if ( ! n )
return - ENOMEM ;
* ret = n ;
return 0 ;
2012-09-18 13:27:56 +04:00
}
2013-09-17 19:03:46 +04:00
static int specifier_cgroup ( char specifier , void * data , void * userdata , char * * ret ) {
2012-09-18 13:27:56 +04:00
Unit * u = userdata ;
2013-09-17 19:03:46 +04:00
char * n ;
2012-09-18 13:27:56 +04:00
assert ( u ) ;
2013-12-16 07:59:31 +04:00
if ( u - > cgroup_path )
n = strdup ( u - > cgroup_path ) ;
else
n = unit_default_cgroup_path ( u ) ;
2013-09-17 19:03:46 +04:00
if ( ! n )
return - ENOMEM ;
* ret = n ;
return 0 ;
2012-09-18 13:27:56 +04:00
}
2013-09-17 19:03:46 +04:00
static int specifier_cgroup_root ( char specifier , void * data , void * userdata , char * * ret ) {
2012-09-18 13:27:56 +04:00
Unit * u = userdata ;
2013-06-20 05:45:08 +04:00
const char * slice ;
2013-09-17 19:03:46 +04:00
char * n ;
2013-06-20 05:45:08 +04:00
int r ;
2012-09-18 13:27:56 +04:00
2013-06-20 05:45:08 +04:00
assert ( u ) ;
2012-09-18 13:27:56 +04:00
2013-06-20 05:45:08 +04:00
slice = unit_slice_name ( u ) ;
if ( specifier = = ' R ' | | ! slice )
2013-09-17 19:03:46 +04:00
n = strdup ( u - > manager - > cgroup_root ) ;
else {
_cleanup_free_ char * p = NULL ;
2012-09-18 13:27:56 +04:00
2013-09-17 19:03:46 +04:00
r = cg_slice_to_path ( slice , & p ) ;
if ( r < 0 )
return r ;
n = strjoin ( u - > manager - > cgroup_root , " / " , p , NULL ) ;
if ( ! n )
return - ENOMEM ;
}
2012-09-18 13:27:56 +04:00
2013-09-17 19:03:46 +04:00
* ret = n ;
return 0 ;
2012-09-18 13:27:56 +04:00
}
2013-09-17 19:03:46 +04:00
static int specifier_runtime ( char specifier , void * data , void * userdata , char * * ret ) {
2012-09-18 13:27:56 +04:00
Unit * u = userdata ;
2013-12-16 07:59:31 +04:00
const char * e ;
2013-09-17 19:03:46 +04:00
char * n = NULL ;
2012-09-18 13:27:56 +04:00
assert ( u ) ;
2013-12-16 07:59:31 +04:00
if ( u - > manager - > running_as = = SYSTEMD_SYSTEM )
e = " /run " ;
else {
2012-09-18 13:27:56 +04:00
e = getenv ( " XDG_RUNTIME_DIR " ) ;
2013-12-16 07:59:31 +04:00
if ( ! e )
return - ENOTSUP ;
2012-09-18 13:27:56 +04:00
}
2013-12-16 07:59:31 +04:00
n = strdup ( e ) ;
if ( ! n )
return - ENOMEM ;
2013-09-17 19:03:46 +04:00
* ret = n ;
return 0 ;
2012-09-18 13:27:56 +04:00
}
2013-09-17 19:03:46 +04:00
static int specifier_user_name ( char specifier , void * data , void * userdata , char * * ret ) {
2013-12-16 07:59:31 +04:00
char * printed = NULL ;
2012-09-18 13:40:01 +04:00
Unit * u = userdata ;
ExecContext * c ;
2012-09-18 13:27:56 +04:00
int r ;
2012-09-18 13:53:47 +04:00
assert ( u ) ;
2012-09-18 13:40:01 +04:00
c = unit_get_exec_context ( u ) ;
2013-12-16 07:59:31 +04:00
if ( ! c )
return - ENOTSUP ;
2012-09-18 13:40:01 +04:00
2013-12-16 07:59:31 +04:00
if ( u - > manager - > running_as = = SYSTEMD_SYSTEM ) {
/* We cannot use NSS from PID 1, hence try to make the
* best of it in that case , and fail if we can ' t help
* it */
if ( ! c - > user | | streq ( c - > user , " root " ) | | streq ( c - > user , " 0 " ) )
printed = strdup ( specifier = = ' u ' ? " root " : " 0 " ) ;
else {
if ( specifier = = ' u ' )
printed = strdup ( c - > user ) ;
else {
uid_t uid ;
r = parse_uid ( c - > user , & uid ) ;
if ( r < 0 )
return - ENODATA ;
asprintf ( & printed , " %lu " , ( unsigned long ) uid ) ;
}
}
} else {
_cleanup_free_ char * tmp = NULL ;
const char * username = NULL ;
uid_t uid ;
if ( c - > user )
username = c - > user ;
else
/* get USER env from env or our own uid */
username = tmp = getusername_malloc ( ) ;
/* fish username from passwd */
r = get_user_creds ( & username , & uid , NULL , NULL , NULL ) ;
if ( r < 0 )
return r ;
if ( specifier = = ' u ' )
2012-12-07 09:01:15 +04:00
printed = strdup ( username ) ;
2013-12-16 07:59:31 +04:00
else
asprintf ( & printed , " %lu " , ( unsigned long ) uid ) ;
2012-12-07 09:01:15 +04:00
}
2013-09-17 19:03:46 +04:00
if ( ! printed )
return - ENOMEM ;
* ret = printed ;
return 0 ;
2012-09-18 13:27:56 +04:00
}
2013-09-17 19:03:46 +04:00
static int specifier_user_home ( char specifier , void * data , void * userdata , char * * ret ) {
2012-09-18 13:40:01 +04:00
Unit * u = userdata ;
ExecContext * c ;
2013-09-17 19:03:46 +04:00
char * n ;
2013-12-16 07:59:31 +04:00
int r ;
2012-09-18 13:27:56 +04:00
2012-09-18 13:53:47 +04:00
assert ( u ) ;
2012-09-18 13:40:01 +04:00
c = unit_get_exec_context ( u ) ;
2013-12-16 07:59:31 +04:00
if ( ! c )
return - ENOTSUP ;
2012-09-18 13:40:01 +04:00
2013-12-16 07:59:31 +04:00
if ( u - > manager - > running_as = = SYSTEMD_SYSTEM ) {
2012-09-18 13:27:56 +04:00
2013-12-16 07:59:31 +04:00
/* We cannot use NSS from PID 1, hence try to make the
* best of it if we can , but fail if we can ' t */
2012-09-18 13:27:56 +04:00
2013-12-16 07:59:31 +04:00
if ( ! c - > user | | streq ( c - > user , " root " ) | | streq ( c - > user , " 0 " ) )
n = strdup ( " /root " ) ;
else
return - ENOTSUP ;
} else {
2012-09-18 13:27:56 +04:00
2013-12-16 07:59:31 +04:00
/* return HOME if set, otherwise from passwd */
if ( ! c | | ! c - > user ) {
r = get_home_dir ( & n ) ;
if ( r < 0 )
return r ;
} else {
const char * username , * home ;
username = c - > user ;
r = get_user_creds ( & username , NULL , NULL , & home , NULL ) ;
if ( r < 0 )
return r ;
n = strdup ( home ) ;
}
}
2012-09-18 13:27:56 +04:00
2013-09-17 19:03:46 +04:00
if ( ! n )
return - ENOMEM ;
* ret = n ;
return 0 ;
2012-09-18 13:27:56 +04:00
}
2013-09-17 19:03:46 +04:00
static int specifier_user_shell ( char specifier , void * data , void * userdata , char * * ret ) {
2012-09-18 13:40:01 +04:00
Unit * u = userdata ;
ExecContext * c ;
2013-09-17 19:03:46 +04:00
char * n ;
2013-12-16 07:59:31 +04:00
int r ;
2012-09-18 13:27:56 +04:00
2012-09-18 13:53:47 +04:00
assert ( u ) ;
2012-09-18 13:40:01 +04:00
c = unit_get_exec_context ( u ) ;
2013-12-16 07:59:31 +04:00
if ( ! c )
return - ENOTSUP ;
2012-09-18 13:40:01 +04:00
2013-12-16 07:59:31 +04:00
if ( u - > manager - > running_as = = SYSTEMD_SYSTEM ) {
/* We cannot use NSS from PID 1, hence try to make the
* best of it if we can , but fail if we can ' t */
if ( ! c - > user | | streq ( c - > user , " root " ) | | streq ( c - > user , " 0 " ) )
n = strdup ( " /bin/sh " ) ;
else
return - ENOTSUP ;
2012-09-18 13:27:56 +04:00
2013-12-16 07:59:31 +04:00
} else {
/* return /bin/sh for root, otherwise the value from passwd */
if ( ! c - > user ) {
r = get_shell ( & n ) ;
if ( r < 0 )
return r ;
} else {
const char * username , * shell ;
username = c - > user ;
r = get_user_creds ( & username , NULL , NULL , NULL , & shell ) ;
if ( r < 0 )
return r ;
n = strdup ( shell ) ;
}
}
2012-09-18 13:27:56 +04:00
2013-09-17 19:03:46 +04:00
if ( ! n )
return - ENOMEM ;
2012-09-18 13:27:56 +04:00
2013-09-17 19:03:46 +04:00
* ret = n ;
return 0 ;
2012-09-18 13:27:56 +04:00
}
2013-09-17 19:03:46 +04:00
int unit_name_printf ( Unit * u , const char * format , char * * ret ) {
2012-09-18 13:27:56 +04:00
/*
* This will use the passed string as format string and
* replace the following specifiers :
*
* % n : the full id of the unit ( foo @ bar . waldo )
* % N : the id of the unit without the suffix ( foo @ bar )
* % p : the prefix ( foo )
* % i : the instance ( bar )
*/
const Specifier table [ ] = {
{ ' n ' , specifier_string , u - > id } ,
{ ' N ' , specifier_prefix_and_instance , NULL } ,
{ ' p ' , specifier_prefix , NULL } ,
{ ' i ' , specifier_string , u - > instance } ,
{ 0 , NULL , NULL }
} ;
assert ( u ) ;
assert ( format ) ;
2013-09-17 19:03:46 +04:00
assert ( ret ) ;
2012-09-18 13:27:56 +04:00
2013-09-17 19:03:46 +04:00
return specifier_printf ( format , table , u , ret ) ;
2012-09-18 13:27:56 +04:00
}
2013-09-17 19:03:46 +04:00
int unit_full_printf ( Unit * u , const char * format , char * * ret ) {
2012-09-18 13:27:56 +04:00
/* This is similar to unit_name_printf() but also supports
* unescaping . Also , adds a couple of additional codes :
*
2014-05-08 03:28:44 +04:00
* % f the instance if set , otherwise the id
2012-09-18 13:27:56 +04:00
* % c cgroup path of unit
2013-12-16 07:59:31 +04:00
* % r where units in this slice are placed in the cgroup tree
2013-06-20 05:45:08 +04:00
* % R the root of this systemd ' s instance tree
2012-09-18 13:27:56 +04:00
* % t the runtime directory to place sockets in ( e . g . " /run " or $ XDG_RUNTIME_DIR )
2013-01-28 08:11:31 +04:00
* % U the UID of the configured user or running user
2012-09-18 13:27:56 +04:00
* % u the username of the configured user or running user
* % h the homedir of the configured user or running user
* % s the shell of the configured user or running user
2012-09-18 13:53:47 +04:00
* % m the machine ID of the running system
* % H the host name of the running system
2013-01-28 08:11:31 +04:00
* % b the boot ID of the running system
2013-07-19 10:45:27 +04:00
* % v ` uname - r ` of the running system
2012-09-18 13:27:56 +04:00
*/
const Specifier table [ ] = {
{ ' n ' , specifier_string , u - > id } ,
{ ' N ' , specifier_prefix_and_instance , NULL } ,
{ ' p ' , specifier_prefix , NULL } ,
{ ' P ' , specifier_prefix_unescaped , NULL } ,
{ ' i ' , specifier_string , u - > instance } ,
{ ' I ' , specifier_instance_unescaped , NULL } ,
{ ' f ' , specifier_filename , NULL } ,
{ ' c ' , specifier_cgroup , NULL } ,
{ ' r ' , specifier_cgroup_root , NULL } ,
{ ' R ' , specifier_cgroup_root , NULL } ,
{ ' t ' , specifier_runtime , NULL } ,
2012-12-07 09:01:15 +04:00
{ ' U ' , specifier_user_name , NULL } ,
2012-09-18 13:27:56 +04:00
{ ' u ' , specifier_user_name , NULL } ,
{ ' h ' , specifier_user_home , NULL } ,
{ ' s ' , specifier_user_shell , NULL } ,
2012-09-18 13:53:47 +04:00
{ ' m ' , specifier_machine_id , NULL } ,
{ ' H ' , specifier_host_name , NULL } ,
{ ' b ' , specifier_boot_id , NULL } ,
2013-07-19 10:45:27 +04:00
{ ' v ' , specifier_kernel_release , NULL } ,
{ }
2012-09-18 13:27:56 +04:00
} ;
2013-09-17 19:03:46 +04:00
assert ( u ) ;
2012-09-18 13:27:56 +04:00
assert ( format ) ;
2013-09-17 19:03:46 +04:00
assert ( ret ) ;
2012-09-18 13:27:56 +04:00
2013-09-17 19:03:46 +04:00
return specifier_printf ( format , table , u , ret ) ;
2012-09-18 13:27:56 +04:00
}
2013-09-17 19:03:46 +04:00
int unit_full_printf_strv ( Unit * u , char * * l , char * * * ret ) {
2012-09-18 13:27:56 +04:00
size_t n ;
char * * r , * * i , * * j ;
2013-09-17 19:03:46 +04:00
int q ;
2012-09-18 13:27:56 +04:00
/* Applies unit_full_printf to every entry in l */
assert ( u ) ;
n = strv_length ( l ) ;
r = new ( char * , n + 1 ) ;
if ( ! r )
2013-09-17 19:03:46 +04:00
return - ENOMEM ;
2012-09-18 13:27:56 +04:00
for ( i = l , j = r ; * i ; i + + , j + + ) {
2013-09-17 19:03:46 +04:00
q = unit_full_printf ( u , * i , j ) ;
if ( q < 0 )
2012-09-18 13:27:56 +04:00
goto fail ;
}
* j = NULL ;
2013-09-17 19:03:46 +04:00
* ret = r ;
return 0 ;
2012-09-18 13:27:56 +04:00
fail :
for ( j - - ; j > = r ; j - - )
free ( * j ) ;
free ( r ) ;
2013-09-17 19:03:46 +04:00
return q ;
2012-09-18 13:27:56 +04:00
}