2010-08-14 21:59:25 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2010-06-15 16:45:15 +04:00
/***
This file is part of systemd .
Copyright 2010 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
2012-04-12 02:20:58 +04:00
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
2010-06-15 16:45:15 +04:00
( 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
2012-04-12 02:20:58 +04:00
Lesser General Public License for more details .
2010-06-15 16:45:15 +04:00
2012-04-12 02:20:58 +04:00
You should have received a copy of the GNU Lesser General Public License
2010-06-15 16:45:15 +04:00
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
# include <assert.h>
# include <stdlib.h>
# include <stdio.h>
2012-09-18 19:11:12 +04:00
# include <string.h>
2010-06-15 16:45:15 +04:00
# include <unistd.h>
# include <errno.h>
# include "util.h"
2012-04-10 23:54:31 +04:00
# include "mkdir.h"
2010-06-15 16:45:15 +04:00
# include "strv.h"
2012-05-07 23:36:12 +04:00
# include "path-util.h"
2010-06-15 16:45:15 +04:00
# include "path-lookup.h"
2012-09-18 19:11:12 +04:00
static const char * const systemd_running_as_table [ _SYSTEMD_RUNNING_AS_MAX ] = {
[ SYSTEMD_SYSTEM ] = " system " ,
[ SYSTEMD_USER ] = " user "
} ;
DEFINE_STRING_TABLE_LOOKUP ( systemd_running_as , SystemdRunningAs ) ;
2010-11-16 00:12:41 +03:00
int user_config_home ( char * * config_home ) {
2010-06-16 03:58:50 +04:00
const char * e ;
2013-02-27 21:50:41 +04:00
char * r ;
2010-06-16 03:58:50 +04:00
2012-05-23 05:43:29 +04:00
e = getenv ( " XDG_CONFIG_HOME " ) ;
if ( e ) {
2013-02-27 21:50:41 +04:00
r = strappend ( e , " /systemd/user " ) ;
if ( ! r )
2010-06-16 03:58:50 +04:00
return - ENOMEM ;
2013-02-27 21:50:41 +04:00
* config_home = r ;
2010-06-16 03:58:50 +04:00
return 1 ;
} else {
const char * home ;
2012-05-23 05:43:29 +04:00
home = getenv ( " HOME " ) ;
if ( home ) {
2013-02-27 21:50:41 +04:00
r = strappend ( home , " /.config/systemd/user " ) ;
if ( ! r )
2010-06-16 03:58:50 +04:00
return - ENOMEM ;
2013-02-27 21:50:41 +04:00
* config_home = r ;
2010-06-16 03:58:50 +04:00
return 1 ;
}
}
return 0 ;
}
2012-05-23 05:43:29 +04:00
static char * * user_dirs (
const char * generator ,
const char * generator_early ,
const char * generator_late ) {
2011-07-22 06:19:29 +04:00
const char * const config_unit_paths [ ] = {
USER_CONFIG_UNIT_PATH ,
2011-07-23 02:47:50 +04:00
" /etc/systemd/user " ,
2012-03-14 17:25:05 +04:00
" /run/systemd/user " ,
2011-07-23 02:47:50 +04:00
NULL
2011-07-22 06:19:29 +04:00
} ;
const char * const data_unit_paths [ ] = {
" /usr/local/lib/systemd/user " ,
" /usr/local/share/systemd/user " ,
USER_DATA_UNIT_PATH ,
" /usr/lib/systemd/user " ,
2011-07-23 02:47:50 +04:00
" /usr/share/systemd/user " ,
NULL
2011-07-22 06:19:29 +04:00
} ;
2010-06-15 16:45:15 +04:00
const char * home , * e ;
2014-01-04 05:35:27 +04:00
_cleanup_free_ char * config_home = NULL , * data_home = NULL ;
_cleanup_strv_free_ char * * config_dirs = NULL , * * data_dirs = NULL ;
char * * r = NULL ;
2010-06-15 16:45:15 +04:00
/* Implement the mechanisms defined in
*
* http : //standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
*
* We look in both the config and the data dirs because we
* want to encourage that distributors ship their unit files
* as data , and allow overriding as configuration .
*/
2010-11-16 00:12:41 +03:00
if ( user_config_home ( & config_home ) < 0 )
2010-06-16 03:58:50 +04:00
goto fail ;
2010-06-15 16:45:15 +04:00
2010-06-16 03:58:50 +04:00
home = getenv ( " HOME " ) ;
2010-06-15 16:45:15 +04:00
2012-05-23 05:43:29 +04:00
e = getenv ( " XDG_CONFIG_DIRS " ) ;
if ( e ) {
config_dirs = strv_split ( e , " : " ) ;
if ( ! config_dirs )
2010-06-15 16:45:15 +04:00
goto fail ;
2012-05-23 05:43:29 +04:00
}
2010-06-15 16:45:15 +04:00
/* We don't treat /etc/xdg/systemd here as the spec
* suggests because we assume that that is a link to
* / etc / systemd / anyway . */
2012-05-23 05:43:29 +04:00
e = getenv ( " XDG_DATA_HOME " ) ;
if ( e ) {
2010-11-16 00:12:41 +03:00
if ( asprintf ( & data_home , " %s/systemd/user " , e ) < 0 )
2010-06-15 16:45:15 +04:00
goto fail ;
} else if ( home ) {
2010-11-16 00:12:41 +03:00
if ( asprintf ( & data_home , " %s/.local/share/systemd/user " , home ) < 0 )
2010-06-15 16:45:15 +04:00
goto fail ;
/* There is really no need for two unit dirs in $HOME,
* except to be fully compliant with the XDG spec . We
* now try to link the two dirs , so that we can
* minimize disk seeks a little . Further down we ' ll
* then filter out this link , if it is actually is
* one . */
2012-05-31 14:40:20 +04:00
mkdir_parents_label ( data_home , 0777 ) ;
2010-11-16 00:12:41 +03:00
( void ) symlink ( " ../../../.config/systemd/user " , data_home ) ;
2010-06-15 16:45:15 +04:00
}
2012-05-23 05:43:29 +04:00
e = getenv ( " XDG_DATA_DIRS " ) ;
if ( e )
2010-06-15 16:45:15 +04:00
data_dirs = strv_split ( e , " : " ) ;
else
2011-04-04 21:02:32 +04:00
data_dirs = strv_new ( " /usr/local/share " ,
" /usr/share " ,
NULL ) ;
2010-06-15 16:45:15 +04:00
if ( ! data_dirs )
goto fail ;
/* Now merge everything we found. */
2014-01-04 05:35:27 +04:00
if ( generator_early )
if ( strv_extend ( & r , generator_early ) < 0 )
2012-05-23 05:43:29 +04:00
goto fail ;
2014-01-04 05:35:27 +04:00
if ( config_home )
if ( strv_extend ( & r , config_home ) < 0 )
2010-06-15 16:45:15 +04:00
goto fail ;
2014-01-04 05:35:27 +04:00
if ( ! strv_isempty ( config_dirs ) )
if ( strv_extend_strv_concat ( & r , config_dirs , " /systemd/user " ) < 0 )
goto fail ;
2010-06-15 16:45:15 +04:00
2014-01-04 05:35:27 +04:00
if ( strv_extend_strv ( & r , ( char * * ) config_unit_paths ) < 0 )
2010-06-15 16:45:15 +04:00
goto fail ;
2014-01-04 05:35:27 +04:00
if ( generator )
if ( strv_extend ( & r , generator ) < 0 )
2012-05-23 05:43:29 +04:00
goto fail ;
2014-01-04 05:35:27 +04:00
if ( data_home )
if ( strv_extend ( & r , data_home ) < 0 )
2010-06-15 16:45:15 +04:00
goto fail ;
2014-01-04 05:35:27 +04:00
if ( ! strv_isempty ( data_dirs ) )
if ( strv_extend_strv_concat ( & r , data_dirs , " /systemd/user " ) < 0 )
2011-07-22 06:19:29 +04:00
goto fail ;
2010-06-15 16:45:15 +04:00
2014-01-04 05:35:27 +04:00
if ( strv_extend_strv ( & r , ( char * * ) data_unit_paths ) < 0 )
2010-06-15 16:45:15 +04:00
goto fail ;
2014-01-04 05:35:27 +04:00
if ( generator_late )
if ( strv_extend ( & r , generator_late ) < 0 )
2012-05-23 05:43:29 +04:00
goto fail ;
2012-05-07 23:36:12 +04:00
if ( ! path_strv_make_absolute_cwd ( r ) )
2012-05-23 05:43:29 +04:00
goto fail ;
2010-06-15 16:45:15 +04:00
return r ;
fail :
strv_free ( r ) ;
2014-01-04 05:35:27 +04:00
return NULL ;
2010-06-15 16:45:15 +04:00
}
2012-05-23 05:43:29 +04:00
int lookup_paths_init (
LookupPaths * p ,
2012-09-18 19:11:12 +04:00
SystemdRunningAs running_as ,
2012-05-23 05:43:29 +04:00
bool personal ,
const char * generator ,
const char * generator_early ,
const char * generator_late ) {
2010-06-15 16:45:15 +04:00
const char * e ;
assert ( p ) ;
/* First priority is whatever has been passed to us via env
* vars */
2012-05-23 05:43:29 +04:00
e = getenv ( " SYSTEMD_UNIT_PATH " ) ;
if ( e ) {
p - > unit_path = path_split_and_make_absolute ( e ) ;
if ( ! p - > unit_path )
2010-06-15 16:45:15 +04:00
return - ENOMEM ;
2012-05-23 05:43:29 +04:00
} else
p - > unit_path = NULL ;
2010-06-15 16:45:15 +04:00
if ( strv_isempty ( p - > unit_path ) ) {
/* Nothing is set, so let's figure something out. */
strv_free ( p - > unit_path ) ;
2012-05-23 05:43:29 +04:00
/* For the user units we include share/ in the search
* path in order to comply with the XDG basedir
* spec . For the system stuff we avoid such
* nonsense . OTOH we include / lib in the search path
* for the system stuff but avoid it for user
* stuff . */
2012-09-18 19:11:12 +04:00
if ( running_as = = SYSTEMD_USER ) {
2011-07-22 06:17:38 +04:00
if ( personal )
2012-05-23 05:43:29 +04:00
p - > unit_path = user_dirs ( generator , generator_early , generator_late ) ;
2011-07-22 06:17:38 +04:00
else
p - > unit_path = strv_new (
/* If you modify this you also want to modify
* systemduserunitpath = in systemd . pc . in , and
* the arrays in user_dirs ( ) above ! */
2012-05-23 05:43:29 +04:00
STRV_IFNOTNULL ( generator_early ) ,
2011-07-22 06:17:38 +04:00
USER_CONFIG_UNIT_PATH ,
2011-08-24 15:39:06 +04:00
" /etc/systemd/user " ,
2012-03-14 17:25:05 +04:00
" /run/systemd/user " ,
2012-05-23 05:43:29 +04:00
STRV_IFNOTNULL ( generator ) ,
2011-07-22 06:17:38 +04:00
" /usr/local/lib/systemd/user " ,
" /usr/local/share/systemd/user " ,
USER_DATA_UNIT_PATH ,
" /usr/lib/systemd/user " ,
" /usr/share/systemd/user " ,
2012-05-23 05:43:29 +04:00
STRV_IFNOTNULL ( generator_late ) ,
2011-07-22 06:17:38 +04:00
NULL ) ;
if ( ! p - > unit_path )
2010-06-15 16:45:15 +04:00
return - ENOMEM ;
2011-07-22 06:17:38 +04:00
2012-05-23 05:43:29 +04:00
} else {
p - > unit_path = strv_new (
/* If you modify this you also want to modify
* systemdsystemunitpath = in systemd . pc . in ! */
STRV_IFNOTNULL ( generator_early ) ,
SYSTEM_CONFIG_UNIT_PATH ,
" /etc/systemd/system " ,
" /run/systemd/system " ,
STRV_IFNOTNULL ( generator ) ,
" /usr/local/lib/systemd/system " ,
SYSTEM_DATA_UNIT_PATH ,
" /usr/lib/systemd/system " ,
2012-02-14 03:24:49 +04:00
# ifdef HAVE_SPLIT_USR
2012-05-23 05:43:29 +04:00
" /lib/systemd/system " ,
2012-02-14 03:24:49 +04:00
# endif
2012-05-23 05:43:29 +04:00
STRV_IFNOTNULL ( generator_late ) ,
NULL ) ;
if ( ! p - > unit_path )
2010-06-15 16:45:15 +04:00
return - ENOMEM ;
2012-05-23 05:43:29 +04:00
}
2010-06-15 16:45:15 +04:00
}
2014-02-01 03:35:04 +04:00
if ( ! path_strv_canonicalize_absolute ( p - > unit_path , NULL ) )
2012-05-23 05:43:29 +04:00
return - ENOMEM ;
2010-09-21 07:23:12 +04:00
strv_uniq ( p - > unit_path ) ;
if ( ! strv_isempty ( p - > unit_path ) ) {
2013-04-18 11:11:22 +04:00
_cleanup_free_ char * t = strv_join ( p - > unit_path , " \n \t " ) ;
2012-05-23 05:43:29 +04:00
if ( ! t )
2010-09-21 07:23:12 +04:00
return - ENOMEM ;
2013-03-01 17:07:20 +04:00
log_debug ( " Looking for unit files in (higher priority first): \n \t %s " , t ) ;
2010-09-21 07:23:12 +04:00
} else {
2013-03-01 17:07:20 +04:00
log_debug ( " Ignoring unit files. " ) ;
2010-09-21 07:23:12 +04:00
strv_free ( p - > unit_path ) ;
p - > unit_path = NULL ;
}
2012-09-18 19:11:12 +04:00
if ( running_as = = SYSTEMD_SYSTEM ) {
2010-09-21 07:23:12 +04:00
# ifdef HAVE_SYSV_COMPAT
2010-06-15 16:45:15 +04:00
/* /etc/init.d/ compatibility does not matter to users */
2012-05-23 05:43:29 +04:00
e = getenv ( " SYSTEMD_SYSVINIT_PATH " ) ;
if ( e ) {
p - > sysvinit_path = path_split_and_make_absolute ( e ) ;
if ( ! p - > sysvinit_path )
2010-06-15 16:45:15 +04:00
return - ENOMEM ;
2012-05-23 05:43:29 +04:00
} else
p - > sysvinit_path = NULL ;
2010-06-15 16:45:15 +04:00
if ( strv_isempty ( p - > sysvinit_path ) ) {
strv_free ( p - > sysvinit_path ) ;
2012-05-23 05:43:29 +04:00
p - > sysvinit_path = strv_new (
SYSTEM_SYSVINIT_PATH , /* /etc/init.d/ */
NULL ) ;
if ( ! p - > sysvinit_path )
2010-06-15 16:45:15 +04:00
return - ENOMEM ;
}
2012-05-23 05:43:29 +04:00
e = getenv ( " SYSTEMD_SYSVRCND_PATH " ) ;
if ( e ) {
p - > sysvrcnd_path = path_split_and_make_absolute ( e ) ;
if ( ! p - > sysvrcnd_path )
2010-06-15 16:45:15 +04:00
return - ENOMEM ;
2012-05-23 05:43:29 +04:00
} else
p - > sysvrcnd_path = NULL ;
2010-06-15 16:45:15 +04:00
if ( strv_isempty ( p - > sysvrcnd_path ) ) {
strv_free ( p - > sysvrcnd_path ) ;
2012-05-23 05:43:29 +04:00
p - > sysvrcnd_path = strv_new (
SYSTEM_SYSVRCND_PATH , /* /etc/rcN.d/ */
NULL ) ;
if ( ! p - > sysvrcnd_path )
2010-06-15 16:45:15 +04:00
return - ENOMEM ;
}
2014-02-01 03:35:04 +04:00
if ( ! path_strv_canonicalize_absolute ( p - > sysvinit_path , NULL ) )
2012-05-23 05:43:29 +04:00
return - ENOMEM ;
2010-06-15 16:45:15 +04:00
2014-02-01 03:35:04 +04:00
if ( ! path_strv_canonicalize_absolute ( p - > sysvrcnd_path , NULL ) )
2012-05-23 05:43:29 +04:00
return - ENOMEM ;
2010-06-15 16:45:15 +04:00
2010-09-21 07:23:12 +04:00
strv_uniq ( p - > sysvinit_path ) ;
strv_uniq ( p - > sysvrcnd_path ) ;
2011-04-28 06:55:05 +04:00
2010-09-21 07:23:12 +04:00
if ( ! strv_isempty ( p - > sysvinit_path ) ) {
2013-04-18 11:11:22 +04:00
_cleanup_free_ char * t = strv_join ( p - > sysvinit_path , " \n \t " ) ;
2012-05-23 05:43:29 +04:00
if ( ! t )
2010-09-21 07:23:12 +04:00
return - ENOMEM ;
2013-03-01 17:07:20 +04:00
log_debug ( " Looking for SysV init scripts in: \n \t %s " , t ) ;
2010-09-21 07:23:12 +04:00
} else {
2013-03-01 17:07:20 +04:00
log_debug ( " Ignoring SysV init scripts. " ) ;
2010-09-21 07:23:12 +04:00
strv_free ( p - > sysvinit_path ) ;
p - > sysvinit_path = NULL ;
}
2010-06-15 16:45:15 +04:00
2010-09-21 07:23:12 +04:00
if ( ! strv_isempty ( p - > sysvrcnd_path ) ) {
2013-04-18 11:11:22 +04:00
_cleanup_free_ char * t =
2013-02-02 19:36:11 +04:00
strv_join ( p - > sysvrcnd_path , " \n \t " ) ;
2012-05-23 05:43:29 +04:00
if ( ! t )
2010-09-21 07:23:12 +04:00
return - ENOMEM ;
2010-06-15 16:45:15 +04:00
2010-09-21 07:23:12 +04:00
log_debug ( " Looking for SysV rcN.d links in: \n \t %s " , t ) ;
} else {
log_debug ( " Ignoring SysV rcN.d links. " ) ;
strv_free ( p - > sysvrcnd_path ) ;
p - > sysvrcnd_path = NULL ;
}
# else
2013-03-01 17:07:20 +04:00
log_debug ( " SysV init scripts and rcN.d links support disabled " ) ;
2010-09-21 07:23:12 +04:00
# endif
2010-06-15 16:45:15 +04:00
}
return 0 ;
}
void lookup_paths_free ( LookupPaths * p ) {
assert ( p ) ;
strv_free ( p - > unit_path ) ;
2010-09-21 07:23:12 +04:00
p - > unit_path = NULL ;
# ifdef HAVE_SYSV_COMPAT
2010-06-15 16:45:15 +04:00
strv_free ( p - > sysvinit_path ) ;
strv_free ( p - > sysvrcnd_path ) ;
2010-09-21 07:23:12 +04:00
p - > sysvinit_path = p - > sysvrcnd_path = NULL ;
# endif
2010-06-15 16:45:15 +04:00
}