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
under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 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
General Public License for more details .
You should have received a copy of the GNU General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
# include <assert.h>
# include <stdlib.h>
# include <stdio.h>
# include <unistd.h>
# include <errno.h>
# include "util.h"
# include "strv.h"
# 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 ;
if ( ( e = getenv ( " XDG_CONFIG_HOME " ) ) ) {
2010-11-16 00:12:41 +03:00
if ( asprintf ( config_home , " %s/systemd/user " , e ) < 0 )
2010-06-16 03:58:50 +04:00
return - ENOMEM ;
return 1 ;
} else {
const char * home ;
if ( ( home = getenv ( " HOME " ) ) ) {
2010-11-16 00:12:41 +03:00
if ( asprintf ( config_home , " %s/.config/systemd/user " , home ) < 0 )
2010-06-16 03:58:50 +04:00
return - ENOMEM ;
return 1 ;
}
}
return 0 ;
}
2010-11-16 00:12:41 +03:00
static char * * user_dirs ( void ) {
2011-07-22 06:19:29 +04:00
const char * const config_unit_paths [ ] = {
" /run/systemd/user " ,
USER_CONFIG_UNIT_PATH ,
2011-07-23 02:47:50 +04:00
" /etc/systemd/user " ,
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 ;
char * config_home = NULL , * data_home = NULL ;
char * * config_dirs = NULL , * * data_dirs = NULL ;
char * * r = NULL , * * t ;
/* 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
if ( ( e = getenv ( " XDG_CONFIG_DIRS " ) ) )
if ( ! ( config_dirs = strv_split ( e , " : " ) ) )
goto fail ;
/* We don't treat /etc/xdg/systemd here as the spec
* suggests because we assume that that is a link to
* / etc / systemd / anyway . */
if ( ( e = getenv ( " XDG_DATA_HOME " ) ) ) {
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 . */
mkdir_parents ( 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
}
if ( ( e = getenv ( " XDG_DATA_DIRS " ) ) )
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. */
if ( config_home ) {
if ( ! ( t = strv_append ( r , config_home ) ) )
goto fail ;
strv_free ( r ) ;
r = t ;
}
2011-07-22 06:19:29 +04:00
if ( ! strv_isempty ( config_dirs ) ) {
if ( ! ( t = strv_merge_concat ( r , config_dirs , " /systemd/user " ) ) )
goto finish ;
strv_free ( r ) ;
r = t ;
}
2010-06-15 16:45:15 +04:00
2011-07-22 06:19:29 +04:00
if ( ! ( t = strv_merge ( r , ( char * * ) config_unit_paths ) ) )
2010-06-15 16:45:15 +04:00
goto fail ;
strv_free ( r ) ;
r = t ;
if ( data_home ) {
if ( ! ( t = strv_append ( r , data_home ) ) )
goto fail ;
strv_free ( r ) ;
r = t ;
}
2011-07-22 06:19:29 +04:00
if ( ! strv_isempty ( data_dirs ) ) {
if ( ! ( t = strv_merge_concat ( r , data_dirs , " /systemd/user " ) ) )
goto fail ;
strv_free ( r ) ;
r = t ;
}
2010-06-15 16:45:15 +04:00
2011-07-22 06:19:29 +04:00
if ( ! ( t = strv_merge ( r , ( char * * ) data_unit_paths ) ) )
2010-06-15 16:45:15 +04:00
goto fail ;
strv_free ( r ) ;
r = t ;
if ( ! strv_path_make_absolute_cwd ( r ) )
goto fail ;
finish :
free ( config_home ) ;
strv_free ( config_dirs ) ;
free ( data_home ) ;
strv_free ( data_dirs ) ;
return r ;
fail :
strv_free ( r ) ;
r = NULL ;
goto finish ;
}
2011-07-22 06:17:38 +04:00
int lookup_paths_init ( LookupPaths * p , ManagerRunningAs running_as , bool personal ) {
2010-06-15 16:45:15 +04:00
const char * e ;
char * t ;
assert ( p ) ;
/* First priority is whatever has been passed to us via env
* vars */
if ( ( e = getenv ( " SYSTEMD_UNIT_PATH " ) ) )
if ( ! ( p - > unit_path = split_path_and_make_absolute ( e ) ) )
return - ENOMEM ;
if ( strv_isempty ( p - > unit_path ) ) {
/* Nothing is set, so let's figure something out. */
strv_free ( p - > unit_path ) ;
2010-11-16 00:12:41 +03:00
if ( running_as = = MANAGER_USER ) {
2011-07-22 06:17:38 +04:00
if ( personal )
p - > unit_path = user_dirs ( ) ;
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 ! */
" /run/systemd/user " ,
USER_CONFIG_UNIT_PATH ,
2011-08-24 15:39:06 +04:00
" /etc/systemd/user " ,
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 " ,
NULL ) ;
if ( ! p - > unit_path )
2010-06-15 16:45:15 +04:00
return - ENOMEM ;
2011-07-22 06:17:38 +04:00
2010-06-15 16:45:15 +04:00
} else
if ( ! ( p - > unit_path = strv_new (
2011-03-09 22:15:44 +03:00
/* If you modify this you also want to modify
* systemdsystemunitpath = in systemd . pc . in ! */
2011-03-25 07:07:20 +03:00
" /run/systemd/system " ,
2010-07-01 22:43:52 +04:00
SYSTEM_CONFIG_UNIT_PATH ,
" /etc/systemd/system " ,
2011-04-04 21:02:32 +04:00
" /usr/local/lib/systemd/system " ,
" /usr/lib/systemd/system " ,
2011-04-04 21:14:38 +04:00
SYSTEM_DATA_UNIT_PATH ,
2012-02-14 03:24:49 +04:00
# ifdef HAVE_SPLIT_USR
2011-07-22 06:17:38 +04:00
" /lib/systemd/system " ,
2012-02-14 03:24:49 +04:00
# endif
2010-06-15 16:45:15 +04:00
NULL ) ) )
return - ENOMEM ;
}
2010-09-21 07:23:12 +04:00
if ( p - > unit_path )
if ( ! strv_path_canonicalize ( p - > unit_path ) )
return - ENOMEM ;
strv_uniq ( p - > unit_path ) ;
2011-04-28 06:55:05 +04:00
strv_path_remove_empty ( p - > unit_path ) ;
2010-09-21 07:23:12 +04:00
if ( ! strv_isempty ( p - > unit_path ) ) {
if ( ! ( t = strv_join ( p - > unit_path , " \n \t " ) ) )
return - ENOMEM ;
log_debug ( " Looking for unit files in: \n \t %s " , t ) ;
free ( t ) ;
} else {
log_debug ( " Ignoring unit files. " ) ;
strv_free ( p - > unit_path ) ;
p - > unit_path = NULL ;
}
2010-06-19 05:15:59 +04:00
if ( running_as = = MANAGER_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 */
if ( ( e = getenv ( " SYSTEMD_SYSVINIT_PATH " ) ) )
if ( ! ( p - > sysvinit_path = split_path_and_make_absolute ( e ) ) )
return - ENOMEM ;
if ( strv_isempty ( p - > sysvinit_path ) ) {
strv_free ( p - > sysvinit_path ) ;
if ( ! ( p - > sysvinit_path = strv_new (
SYSTEM_SYSVINIT_PATH , /* /etc/init.d/ */
NULL ) ) )
return - ENOMEM ;
}
if ( ( e = getenv ( " SYSTEMD_SYSVRCND_PATH " ) ) )
if ( ! ( p - > sysvrcnd_path = split_path_and_make_absolute ( e ) ) )
return - ENOMEM ;
if ( strv_isempty ( p - > sysvrcnd_path ) ) {
strv_free ( p - > sysvrcnd_path ) ;
if ( ! ( p - > sysvrcnd_path = strv_new (
SYSTEM_SYSVRCND_PATH , /* /etc/rcN.d/ */
NULL ) ) )
return - ENOMEM ;
}
2010-09-21 07:23:12 +04:00
if ( p - > sysvinit_path )
if ( ! strv_path_canonicalize ( p - > sysvinit_path ) )
return - ENOMEM ;
2010-06-15 16:45:15 +04:00
2010-09-21 07:23:12 +04:00
if ( p - > sysvrcnd_path )
if ( ! strv_path_canonicalize ( p - > sysvrcnd_path ) )
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 ) ;
2010-06-15 16:45:15 +04:00
2011-04-28 06:55:05 +04:00
strv_path_remove_empty ( p - > sysvinit_path ) ;
strv_path_remove_empty ( p - > sysvrcnd_path ) ;
2010-09-21 07:23:12 +04:00
if ( ! strv_isempty ( p - > sysvinit_path ) ) {
2010-06-15 16:45:15 +04:00
2010-09-21 07:23:12 +04:00
if ( ! ( t = strv_join ( p - > sysvinit_path , " \n \t " ) ) )
return - ENOMEM ;
2010-06-15 16:45:15 +04:00
2010-09-21 07:23:12 +04:00
log_debug ( " Looking for SysV init scripts in: \n \t %s " , t ) ;
free ( t ) ;
} else {
log_debug ( " Ignoring SysV init scripts. " ) ;
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 ) ) {
2010-06-15 16:45:15 +04:00
2010-09-21 07:23:12 +04:00
if ( ! ( t = strv_join ( p - > sysvrcnd_path , " \n \t " ) ) )
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 ) ;
free ( t ) ;
} else {
log_debug ( " Ignoring SysV rcN.d links. " ) ;
strv_free ( p - > sysvrcnd_path ) ;
p - > sysvrcnd_path = NULL ;
}
# else
log_debug ( " Disabled SysV init scripts and rcN.d links support " ) ;
# 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
}