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"
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 ;
}
2014-10-02 16:01:00 +04:00
int user_runtime_dir ( char * * runtime_dir ) {
2014-09-29 01:54:25 +04:00
const char * e ;
char * r ;
e = getenv ( " XDG_RUNTIME_DIR " ) ;
if ( e ) {
r = strappend ( e , " /systemd/user " ) ;
if ( ! r )
return - ENOMEM ;
2014-10-02 16:01:00 +04:00
* runtime_dir = r ;
2014-09-29 01:54:25 +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 " ,
NULL
2011-07-22 06:19:29 +04:00
} ;
2014-09-29 01:54:25 +04:00
const char * const runtime_unit_path = " /run/systemd/user " ;
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-10-02 16:01:00 +04:00
_cleanup_free_ char * config_home = NULL , * runtime_dir = NULL , * data_home = NULL ;
2014-01-04 05:35:27 +04:00
_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
2014-10-02 16:01:00 +04:00
if ( user_runtime_dir ( & runtime_dir ) < 0 )
2014-09-29 01:54:25 +04:00
goto fail ;
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 ;
}
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-10-02 16:01:00 +04:00
if ( runtime_dir )
if ( strv_extend ( & r , runtime_dir ) < 0 )
2014-09-29 01:54:25 +04:00
goto fail ;
if ( strv_extend ( & r , runtime_unit_path ) < 0 )
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 ,
2014-04-24 09:44:10 +04:00
const char * root_dir ,
2012-05-23 05:43:29 +04:00
const char * generator ,
const char * generator_early ,
const char * generator_late ) {
2010-06-15 16:45:15 +04:00
const char * e ;
2014-07-21 01:56:57 +04:00
bool append = false ; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
2010-06-15 16:45:15 +04:00
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 ) {
2014-07-21 01:56:57 +04:00
if ( endswith ( e , " : " ) ) {
e = strndupa ( e , strlen ( e ) - 1 ) ;
append = true ;
}
/* FIXME: empty components in other places should be
* rejected . */
2012-05-23 05:43:29 +04:00
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
2014-07-21 01:56:57 +04:00
if ( ! p - > unit_path | | append ) {
/* Let's figure something out. */
2014-07-22 05:11:54 +04:00
_cleanup_strv_free_ char * * unit_path ;
2014-07-21 01:56:57 +04:00
int r ;
2010-06-15 16:45:15 +04:00
2012-05-23 05:43:29 +04:00
/* For the user units we include share/ in the search
2014-07-21 01:56:57 +04:00
* 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-05-23 05:43:29 +04:00
2012-09-18 19:11:12 +04:00
if ( running_as = = SYSTEMD_USER ) {
2011-07-22 06:17:38 +04:00
if ( personal )
2014-07-21 01:56:57 +04:00
unit_path = user_dirs ( generator , generator_early , generator_late ) ;
2011-07-22 06:17:38 +04:00
else
2014-07-21 01:56:57 +04:00
unit_path = strv_new (
2012-05-23 05:43:29 +04:00
/* If you modify this you also want to modify
2014-07-21 01:56:57 +04:00
* systemduserunitpath = in systemd . pc . in , and
* the arrays in user_dirs ( ) above ! */
2012-05-23 05:43:29 +04:00
STRV_IFNOTNULL ( generator_early ) ,
2014-07-21 01:56:57 +04:00
USER_CONFIG_UNIT_PATH ,
" /etc/systemd/user " ,
" /run/systemd/user " ,
2012-05-23 05:43:29 +04:00
STRV_IFNOTNULL ( generator ) ,
2014-07-21 01:56:57 +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 ) ,
NULL ) ;
2014-07-21 01:56:57 +04:00
} else
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 " ,
# ifdef HAVE_SPLIT_USR
" /lib/systemd/system " ,
# endif
STRV_IFNOTNULL ( generator_late ) ,
NULL ) ;
2012-05-23 05:43:29 +04:00
2014-07-21 01:56:57 +04:00
if ( ! unit_path )
return - ENOMEM ;
r = strv_extend_strv ( & p - > unit_path , unit_path ) ;
if ( r < 0 )
return r ;
2010-06-15 16:45:15 +04:00
}
2014-06-20 06:07:02 +04:00
if ( ! path_strv_resolve_uniq ( p - > unit_path , root_dir ) )
2012-05-23 05:43:29 +04:00
return - ENOMEM ;
2010-09-21 07:23:12 +04:00
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-06-20 06:07:02 +04:00
if ( ! path_strv_resolve_uniq ( p - > sysvinit_path , root_dir ) )
2012-05-23 05:43:29 +04:00
return - ENOMEM ;
2010-06-15 16:45:15 +04:00
2014-06-20 06:07:02 +04:00
if ( ! path_strv_resolve_uniq ( p - > sysvrcnd_path , root_dir ) )
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
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
}