2020-11-09 13:23:58 +09:00
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2010-07-21 02:57:35 +02:00
2013-02-11 03:46:08 +01:00
# include "env-util.h"
2017-06-23 20:43:48 -04:00
# include "fd-util.h"
# include "fileio.h"
2018-10-23 10:50:38 +02:00
# include "fs-util.h"
2021-01-31 23:33:06 +09:00
# include "parse-util.h"
# include "process-util.h"
2018-10-17 20:40:09 +02:00
# include "serialize.h"
2015-10-24 22:58:24 +02:00
# include "string-util.h"
# include "strv.h"
2021-01-31 23:32:05 +09:00
# include "tests.h"
2015-10-24 22:58:24 +02:00
# include "util.h"
2010-07-21 02:57:35 +02:00
2013-02-08 00:22:26 +01:00
static void test_strv_env_delete ( void ) {
2020-09-28 14:54:16 +02:00
log_info ( " /* %s */ " , __func__ ) ;
2013-02-08 00:22:26 +01:00
_cleanup_strv_free_ char * * a = NULL , * * b = NULL , * * c = NULL , * * d = NULL ;
2018-10-31 17:03:50 +01:00
a = strv_new ( " FOO=BAR " , " WALDO=WALDO " , " WALDO= " , " PIEP " , " SCHLUMPF=SMURF " ) ;
2013-02-11 03:52:32 +01:00
assert_se ( a ) ;
2018-10-31 17:03:50 +01:00
b = strv_new ( " PIEP " , " FOO " ) ;
2013-02-11 03:52:32 +01:00
assert_se ( b ) ;
2018-10-31 17:03:50 +01:00
c = strv_new ( " SCHLUMPF " ) ;
2013-02-11 03:52:32 +01:00
assert_se ( c ) ;
2013-02-08 00:22:26 +01:00
d = strv_env_delete ( a , 2 , b , c ) ;
2013-02-11 03:52:32 +01:00
assert_se ( d ) ;
2013-02-08 00:22:26 +01:00
2013-02-11 03:52:32 +01:00
assert_se ( streq ( d [ 0 ] , " WALDO=WALDO " ) ) ;
assert_se ( streq ( d [ 1 ] , " WALDO= " ) ) ;
assert_se ( strv_length ( d ) = = 2 ) ;
2013-02-08 00:22:26 +01:00
}
2016-08-03 14:35:50 -04:00
static void test_strv_env_get ( void ) {
2020-09-28 14:54:16 +02:00
log_info ( " /* %s */ " , __func__ ) ;
2016-08-03 14:35:50 -04:00
2020-09-28 14:54:16 +02:00
char * * l = STRV_MAKE ( " ONE_OR_TWO=1 " , " THREE=3 " , " ONE_OR_TWO=2 " , " FOUR=4 " ) ;
2016-08-03 14:35:50 -04:00
assert_se ( streq ( strv_env_get ( l , " ONE_OR_TWO " ) , " 2 " ) ) ;
assert_se ( streq ( strv_env_get ( l , " THREE " ) , " 3 " ) ) ;
assert_se ( streq ( strv_env_get ( l , " FOUR " ) , " 4 " ) ) ;
}
2021-01-27 12:51:17 +00:00
static void test_strv_env_pairs_get ( void ) {
log_info ( " /* %s */ " , __func__ ) ;
char * * l = STRV_MAKE ( " ONE_OR_TWO " , " 1 " , " THREE " , " 3 " , " ONE_OR_TWO " , " 2 " , " FOUR " , " 4 " , " FIVE " , " 5 " , " SIX " , " FIVE " , " SEVEN " , " 7 " ) ;
assert_se ( streq ( strv_env_pairs_get ( l , " ONE_OR_TWO " ) , " 2 " ) ) ;
assert_se ( streq ( strv_env_pairs_get ( l , " THREE " ) , " 3 " ) ) ;
assert_se ( streq ( strv_env_pairs_get ( l , " FOUR " ) , " 4 " ) ) ;
assert_se ( streq ( strv_env_pairs_get ( l , " FIVE " ) , " 5 " ) ) ;
}
2013-02-08 00:22:26 +01:00
static void test_strv_env_unset ( void ) {
2020-09-28 14:54:16 +02:00
log_info ( " /* %s */ " , __func__ ) ;
2013-02-08 00:22:26 +01:00
_cleanup_strv_free_ char * * l = NULL ;
2018-10-31 17:03:50 +01:00
l = strv_new ( " PIEP " , " SCHLUMPF=SMURFF " , " NANANANA=YES " ) ;
2013-02-11 03:52:32 +01:00
assert_se ( l ) ;
2013-02-08 00:22:26 +01:00
2013-02-11 03:52:32 +01:00
assert_se ( strv_env_unset ( l , " SCHLUMPF " ) = = l ) ;
2013-02-08 00:22:26 +01:00
2013-02-11 03:52:32 +01:00
assert_se ( streq ( l [ 0 ] , " PIEP " ) ) ;
assert_se ( streq ( l [ 1 ] , " NANANANA=YES " ) ) ;
assert_se ( strv_length ( l ) = = 2 ) ;
2013-02-08 00:22:26 +01:00
}
2013-02-07 21:10:31 +01:00
static void test_strv_env_merge ( void ) {
2020-09-28 14:54:16 +02:00
log_info ( " /* %s */ " , __func__ ) ;
2021-08-10 16:53:00 +02:00
char * * a = STRV_MAKE ( " FOO=BAR " , " WALDO=WALDO " , " WALDO= " , " PIEP " , " SCHLUMPF=SMURF " , " EQ=== " ) ;
char * * b = STRV_MAKE ( " FOO=KKK " , " FOO= " , " PIEP= " , " SCHLUMPF=SMURFF " , " NANANANA=YES " ) ;
2013-02-07 21:10:31 +01:00
2021-08-10 16:53:00 +02:00
_cleanup_strv_free_ char * * r = strv_env_merge ( NULL , a , NULL , b , NULL , a , b , b , NULL ) ;
2013-02-11 03:52:32 +01:00
assert_se ( r ) ;
assert_se ( streq ( r [ 0 ] , " FOO= " ) ) ;
assert_se ( streq ( r [ 1 ] , " WALDO= " ) ) ;
assert_se ( streq ( r [ 2 ] , " PIEP " ) ) ;
assert_se ( streq ( r [ 3 ] , " SCHLUMPF=SMURFF " ) ) ;
2021-08-10 16:53:00 +02:00
assert_se ( streq ( r [ 4 ] , " EQ=== " ) ) ;
assert_se ( streq ( r [ 5 ] , " PIEP= " ) ) ;
assert_se ( streq ( r [ 6 ] , " NANANANA=YES " ) ) ;
assert_se ( strv_length ( r ) = = 7 ) ;
2013-02-11 03:52:32 +01:00
assert_se ( strv_env_clean ( r ) = = r ) ;
assert_se ( streq ( r [ 0 ] , " FOO= " ) ) ;
assert_se ( streq ( r [ 1 ] , " WALDO= " ) ) ;
assert_se ( streq ( r [ 2 ] , " SCHLUMPF=SMURFF " ) ) ;
2021-08-10 16:53:00 +02:00
assert_se ( streq ( r [ 3 ] , " EQ=== " ) ) ;
assert_se ( streq ( r [ 4 ] , " PIEP= " ) ) ;
assert_se ( streq ( r [ 5 ] , " NANANANA=YES " ) ) ;
assert_se ( strv_length ( r ) = = 6 ) ;
2013-02-07 21:10:31 +01:00
}
2021-02-15 15:01:52 +01:00
static void test_strv_env_replace_strdup ( void ) {
log_info ( " /* %s */ " , __func__ ) ;
_cleanup_strv_free_ char * * a = NULL ;
assert_se ( strv_env_replace_strdup ( & a , " a=a " ) = = 1 ) ;
assert_se ( strv_env_replace_strdup ( & a , " b=b " ) = = 1 ) ;
assert_se ( strv_env_replace_strdup ( & a , " a=A " ) = = 0 ) ;
2021-08-10 17:03:12 +02:00
assert_se ( strv_env_replace_strdup ( & a , " c " ) = = - EINVAL ) ;
2021-02-15 15:01:52 +01:00
assert_se ( strv_length ( a ) = = 2 ) ;
strv_sort ( a ) ;
assert_se ( streq ( a [ 0 ] , " a=A " ) ) ;
assert_se ( streq ( a [ 1 ] , " b=b " ) ) ;
}
2021-08-10 17:03:12 +02:00
static void test_strv_env_replace_strdup_passthrough ( void ) {
log_info ( " /* %s */ " , __func__ ) ;
_cleanup_strv_free_ char * * a = NULL ;
assert_se ( putenv ( ( char * ) " a=a " ) = = 0 ) ;
assert_se ( putenv ( ( char * ) " b= " ) = = 0 ) ;
assert_se ( unsetenv ( " c " ) = = 0 ) ;
assert_se ( strv_env_replace_strdup_passthrough ( & a , " a " ) = = 1 ) ;
assert_se ( strv_env_replace_strdup_passthrough ( & a , " b " ) = = 1 ) ;
assert_se ( strv_env_replace_strdup_passthrough ( & a , " c " ) = = 1 ) ;
assert_se ( strv_env_replace_strdup_passthrough ( & a , " a " ) = = 0 ) ;
assert_se ( strv_env_replace_strdup_passthrough ( & a , " $a " ) = = - EINVAL ) ;
assert_se ( strv_length ( a ) = = 3 ) ;
assert_se ( streq ( a [ 0 ] , " a=a " ) ) ;
assert_se ( streq ( a [ 1 ] , " b= " ) ) ;
assert_se ( streq ( a [ 2 ] , " c= " ) ) ;
}
2021-02-15 15:01:52 +01:00
static void test_strv_env_assign ( void ) {
log_info ( " /* %s */ " , __func__ ) ;
_cleanup_strv_free_ char * * a = NULL ;
assert_se ( strv_env_assign ( & a , " a " , " a " ) = = 1 ) ;
assert_se ( strv_env_assign ( & a , " b " , " b " ) = = 1 ) ;
assert_se ( strv_env_assign ( & a , " a " , " A " ) = = 0 ) ;
assert_se ( strv_env_assign ( & a , " b " , NULL ) = = 0 ) ;
assert_se ( strv_env_assign ( & a , " a= " , " B " ) = = - EINVAL ) ;
assert_se ( strv_length ( a ) = = 1 ) ;
assert_se ( streq ( a [ 0 ] , " a=A " ) ) ;
}
2016-08-04 12:00:00 -04:00
static void test_env_strv_get_n ( void ) {
2020-09-28 14:54:16 +02:00
log_info ( " /* %s */ " , __func__ ) ;
2016-08-04 12:00:00 -04:00
const char * _env [ ] = {
" FOO=NO NO NO " ,
" FOO=BAR BAR " ,
" BAR=waldo " ,
" PATH=unset " ,
NULL
} ;
char * * env = ( char * * ) _env ;
assert_se ( streq ( strv_env_get_n ( env , " FOO__ " , 3 , 0 ) , " BAR BAR " ) ) ;
assert_se ( streq ( strv_env_get_n ( env , " FOO__ " , 3 , REPLACE_ENV_USE_ENVIRONMENT ) , " BAR BAR " ) ) ;
assert_se ( streq ( strv_env_get_n ( env , " FOO " , 3 , 0 ) , " BAR BAR " ) ) ;
assert_se ( streq ( strv_env_get_n ( env , " FOO " , 3 , REPLACE_ENV_USE_ENVIRONMENT ) , " BAR BAR " ) ) ;
assert_se ( streq ( strv_env_get_n ( env , " PATH__ " , 4 , 0 ) , " unset " ) ) ;
assert_se ( streq ( strv_env_get_n ( env , " PATH " , 4 , 0 ) , " unset " ) ) ;
assert_se ( streq ( strv_env_get_n ( env , " PATH__ " , 4 , REPLACE_ENV_USE_ENVIRONMENT ) , " unset " ) ) ;
assert_se ( streq ( strv_env_get_n ( env , " PATH " , 4 , REPLACE_ENV_USE_ENVIRONMENT ) , " unset " ) ) ;
env [ 3 ] = NULL ; /* kill our $PATH */
assert_se ( ! strv_env_get_n ( env , " PATH__ " , 4 , 0 ) ) ;
assert_se ( ! strv_env_get_n ( env , " PATH " , 4 , 0 ) ) ;
2019-04-12 08:55:39 +02:00
assert_se ( streq_ptr ( strv_env_get_n ( env , " PATH__ " , 4 , REPLACE_ENV_USE_ENVIRONMENT ) ,
getenv ( " PATH " ) ) ) ;
assert_se ( streq_ptr ( strv_env_get_n ( env , " PATH " , 4 , REPLACE_ENV_USE_ENVIRONMENT ) ,
getenv ( " PATH " ) ) ) ;
2016-08-04 12:00:00 -04:00
}
2017-02-11 14:05:10 -05:00
static void test_replace_env ( bool braceless ) {
2020-09-28 14:54:16 +02:00
log_info ( " /* %s(braceless=%s) */ " , __func__ , yes_no ( braceless ) ) ;
2017-02-11 14:05:10 -05:00
const char * env [ ] = {
" FOO=BAR BAR " ,
" BAR=waldo " ,
NULL
} ;
_cleanup_free_ char * t = NULL , * s = NULL , * q = NULL , * r = NULL , * p = NULL ;
unsigned flags = REPLACE_ENV_ALLOW_BRACELESS * braceless ;
t = replace_env ( " FOO=$FOO=${FOO} " , ( char * * ) env , flags ) ;
assert_se ( streq ( t , braceless ? " FOO=BAR BAR=BAR BAR " : " FOO=$FOO=BAR BAR " ) ) ;
s = replace_env ( " BAR=$BAR=${BAR} " , ( char * * ) env , flags ) ;
assert_se ( streq ( s , braceless ? " BAR=waldo=waldo " : " BAR=$BAR=waldo " ) ) ;
q = replace_env ( " BARBAR=$BARBAR=${BARBAR} " , ( char * * ) env , flags ) ;
assert_se ( streq ( q , braceless ? " BARBAR== " : " BARBAR=$BARBAR= " ) ) ;
2017-02-21 09:58:50 -05:00
r = replace_env ( " BAR=$BAR$BAR${BAR}${BAR} " , ( char * * ) env , flags ) ;
assert_se ( streq ( r , braceless ? " BAR=waldowaldowaldowaldo " : " BAR=$BAR$BARwaldowaldo " ) ) ;
2017-02-11 14:05:10 -05:00
p = replace_env ( " ${BAR}$BAR$BAR " , ( char * * ) env , flags ) ;
assert_se ( streq ( p , braceless ? " waldowaldowaldo " : " waldo$BAR$BAR " ) ) ;
}
2017-02-20 23:21:26 -05:00
static void test_replace_env2 ( bool extended ) {
2020-09-28 14:54:16 +02:00
log_info ( " /* %s(extended=%s) */ " , __func__ , yes_no ( extended ) ) ;
2017-02-20 23:21:26 -05:00
const char * env [ ] = {
" FOO=foo " ,
" BAR=bar " ,
NULL
} ;
2021-10-05 22:55:27 -04:00
_cleanup_free_ char * t = NULL , * s = NULL , * q = NULL , * r = NULL , * p = NULL , * x = NULL , * y = NULL ;
2017-02-20 23:21:26 -05:00
unsigned flags = REPLACE_ENV_ALLOW_EXTENDED * extended ;
t = replace_env ( " FOO=${FOO:-${BAR}} " , ( char * * ) env , flags ) ;
assert_se ( streq ( t , extended ? " FOO=foo " : " FOO=${FOO:-bar} " ) ) ;
s = replace_env ( " BAR=${XXX:-${BAR}} " , ( char * * ) env , flags ) ;
assert_se ( streq ( s , extended ? " BAR=bar " : " BAR=${XXX:-bar} " ) ) ;
q = replace_env ( " XXX=${XXX:+${BAR}} " , ( char * * ) env , flags ) ;
assert_se ( streq ( q , extended ? " XXX= " : " XXX=${XXX:+bar} " ) ) ;
r = replace_env ( " FOO=${FOO:+${BAR}} " , ( char * * ) env , flags ) ;
assert_se ( streq ( r , extended ? " FOO=bar " : " FOO=${FOO:+bar} " ) ) ;
p = replace_env ( " FOO=${FOO:-${BAR}post} " , ( char * * ) env , flags ) ;
assert_se ( streq ( p , extended ? " FOO=foo " : " FOO=${FOO:-barpost} " ) ) ;
x = replace_env ( " XXX=${XXX:+${BAR}post} " , ( char * * ) env , flags ) ;
assert_se ( streq ( x , extended ? " XXX= " : " XXX=${XXX:+barpost} " ) ) ;
2021-10-05 22:55:27 -04:00
y = replace_env ( " FOO=${FOO}between${BAR:-baz} " , ( char * * ) env , flags ) ;
assert_se ( streq ( y , extended ? " FOO=foobetweenbar " : " FOO=foobetween${BAR:-baz} " ) ) ;
2017-02-20 23:21:26 -05:00
}
2017-02-11 14:05:10 -05:00
static void test_replace_env_argv ( void ) {
2020-09-28 14:54:16 +02:00
log_info ( " /* %s */ " , __func__ ) ;
2010-07-21 02:57:35 +02:00
const char * env [ ] = {
" FOO=BAR BAR " ,
" BAR=waldo " ,
NULL
} ;
const char * line [ ] = {
" FOO$FOO " ,
" FOO$FOOFOO " ,
" FOO${FOO}$FOO " ,
" FOO${FOO} " ,
" ${FOO} " ,
" $FOO " ,
" $FOO$FOO " ,
" ${FOO}${BAR} " ,
" ${FOO " ,
2015-10-07 14:40:44 +02:00
" FOO$$${FOO} " ,
" $$FOO${FOO} " ,
2016-08-09 10:20:22 -04:00
" ${FOO:-${BAR}} " ,
" ${QUUX:-${FOO}} " ,
" ${FOO:+${BAR}} " ,
" ${QUUX:+${BAR}} " ,
" ${FOO:+|${BAR}|}} " ,
" ${FOO:+|${BAR}{|} " ,
2010-07-21 02:57:35 +02:00
NULL
} ;
2013-02-07 21:10:31 +01:00
_cleanup_strv_free_ char * * r = NULL ;
2010-07-21 02:57:35 +02:00
r = replace_env_argv ( ( char * * ) line , ( char * * ) env ) ;
2013-02-11 03:52:32 +01:00
assert_se ( r ) ;
assert_se ( streq ( r [ 0 ] , " FOO$FOO " ) ) ;
assert_se ( streq ( r [ 1 ] , " FOO$FOOFOO " ) ) ;
assert_se ( streq ( r [ 2 ] , " FOOBAR BAR$FOO " ) ) ;
assert_se ( streq ( r [ 3 ] , " FOOBAR BAR " ) ) ;
assert_se ( streq ( r [ 4 ] , " BAR BAR " ) ) ;
assert_se ( streq ( r [ 5 ] , " BAR " ) ) ;
assert_se ( streq ( r [ 6 ] , " BAR " ) ) ;
assert_se ( streq ( r [ 7 ] , " BAR BARwaldo " ) ) ;
assert_se ( streq ( r [ 8 ] , " ${FOO " ) ) ;
2015-10-07 14:40:44 +02:00
assert_se ( streq ( r [ 9 ] , " FOO$BAR BAR " ) ) ;
assert_se ( streq ( r [ 10 ] , " $FOOBAR BAR " ) ) ;
2016-08-09 10:20:22 -04:00
assert_se ( streq ( r [ 11 ] , " ${FOO:-waldo} " ) ) ;
assert_se ( streq ( r [ 12 ] , " ${QUUX:-BAR BAR} " ) ) ;
assert_se ( streq ( r [ 13 ] , " ${FOO:+waldo} " ) ) ;
assert_se ( streq ( r [ 14 ] , " ${QUUX:+waldo} " ) ) ;
assert_se ( streq ( r [ 15 ] , " ${FOO:+|waldo|}} " ) ) ;
assert_se ( streq ( r [ 16 ] , " ${FOO:+|waldo{|} " ) ) ;
assert_se ( strv_length ( r ) = = 17 ) ;
2013-02-07 21:10:31 +01:00
}
2011-01-06 20:38:02 +01:00
2013-02-11 03:46:08 +01:00
static void test_env_clean ( void ) {
2020-09-28 14:54:16 +02:00
log_info ( " /* %s */ " , __func__ ) ;
_cleanup_strv_free_ char * * e = strv_new ( " FOOBAR=WALDO " ,
" FOOBAR=WALDO " ,
" FOOBAR " ,
" F " ,
" X= " ,
" F=F " ,
" = " ,
" =F " ,
" " ,
" 0000=000 " ,
" äöüß=abcd " ,
" abcd=äöüß " ,
" xyz \n =xyz " ,
" xyz=xyz \n " ,
" another=one " ,
basic/env-util: (mostly) follow POSIX for what variable names are allowed
There was some confusion about what POSIX says about variable names:
names shall not contain the character '='. For values to be portable
across systems conforming to POSIX.1-2008, the value shall be composed
of characters from the portable character set (except NUL and as
indicated below).
i.e. it allows almost all ASCII in variable names (without NUL and DEL and
'='). OTOH, it says that *utilities* use a smaller set of characters:
Environment variable names used by the utilities in the Shell and
Utilities volume of POSIX.1-2008 consist solely of uppercase letters,
digits, and the <underscore> ( '_' ) from the characters defined in
Portable Character Set and do not begin with a digit.
When enforcing variable names in environment blocks, we need to use this
first definition, so that we can propagate all valid variables.
I think having non-printable characters in variable names is too much, so
I took out the whitespace stuff from the first definition.
OTOH, when we use *shell syntax*, for example doing variable expansion,
it seems enough to support expansion of variables that the shell would allow.
Fixes #14878,
https://bugzilla.redhat.com/show_bug.cgi?id=1754395,
https://bugzilla.redhat.com/show_bug.cgi?id=1879216.
2020-09-28 16:30:53 +02:00
" another=final one " ,
2020-10-21 22:40:18 +02:00
" CRLF= \r \n " ,
Allow control characters in environment variable values
So far, we would allow certain control characters (NL since
b4346b9a77bc6129dd3e, TAB since 6294aa76d818e831de45), but not others. Having
other control characters in environment variable *value* is expected and widely
used, for various prompts like $LESS, $LESS_TERMCAP_*, and other similar
variables. The typical environment exported by bash already contains a dozen or
so such variables, so programs need to handle them.
We handle then correctly too, for example in 'systemctl show-environment',
since 804ee07c1370d49aa9a. But we would still disallow setting such variables
by the user, in unit file Environment= and in set-environment/import-environment
operations. This is unexpected and confusing and doesn't help with anything
because such variables are present in the environment through other means.
When printing such variables, 'show-environment' escapes all special
characters, so variables with control characters are plainly visible.
In other uses, e.g. 'cat -v' can be used in similar fashion. This would already
need to be done to suppress color codes starting with \[.
Note that we still forbid invalid utf-8 with this patch. (Control characters
are valid, since they are valid 7-bit ascii.) I'm not sure if we should do
that, but since people haven't been actually asking for invalid utf-8, and only
for control characters, and invalid utf-8 causes other issues, I think it's OK
to leave this unchanged.
Fixes #4446, https://gitlab.gnome.org/GNOME/gnome-session/-/issues/45.
2021-01-03 22:26:52 +01:00
" LESS_TERMCAP_mb= \x1b [01;31m " ,
basic/env-util: (mostly) follow POSIX for what variable names are allowed
There was some confusion about what POSIX says about variable names:
names shall not contain the character '='. For values to be portable
across systems conforming to POSIX.1-2008, the value shall be composed
of characters from the portable character set (except NUL and as
indicated below).
i.e. it allows almost all ASCII in variable names (without NUL and DEL and
'='). OTOH, it says that *utilities* use a smaller set of characters:
Environment variable names used by the utilities in the Shell and
Utilities volume of POSIX.1-2008 consist solely of uppercase letters,
digits, and the <underscore> ( '_' ) from the characters defined in
Portable Character Set and do not begin with a digit.
When enforcing variable names in environment blocks, we need to use this
first definition, so that we can propagate all valid variables.
I think having non-printable characters in variable names is too much, so
I took out the whitespace stuff from the first definition.
OTOH, when we use *shell syntax*, for example doing variable expansion,
it seems enough to support expansion of variables that the shell would allow.
Fixes #14878,
https://bugzilla.redhat.com/show_bug.cgi?id=1754395,
https://bugzilla.redhat.com/show_bug.cgi?id=1879216.
2020-09-28 16:30:53 +02:00
" BASH_FUNC_foo%%=() { echo foo \n } " ) ;
2013-02-11 03:52:32 +01:00
assert_se ( e ) ;
assert_se ( ! strv_env_is_valid ( e ) ) ;
assert_se ( strv_env_clean ( e ) = = e ) ;
assert_se ( strv_env_is_valid ( e ) ) ;
2013-02-11 03:46:08 +01:00
assert_se ( streq ( e [ 0 ] , " FOOBAR=WALDO " ) ) ;
assert_se ( streq ( e [ 1 ] , " X= " ) ) ;
assert_se ( streq ( e [ 2 ] , " F=F " ) ) ;
2020-10-23 14:24:32 +02:00
assert_se ( streq ( e [ 3 ] , " abcd=äöüß " ) ) ;
assert_se ( streq ( e [ 4 ] , " xyz=xyz \n " ) ) ;
assert_se ( streq ( e [ 5 ] , " another=final one " ) ) ;
Allow control characters in environment variable values
So far, we would allow certain control characters (NL since
b4346b9a77bc6129dd3e, TAB since 6294aa76d818e831de45), but not others. Having
other control characters in environment variable *value* is expected and widely
used, for various prompts like $LESS, $LESS_TERMCAP_*, and other similar
variables. The typical environment exported by bash already contains a dozen or
so such variables, so programs need to handle them.
We handle then correctly too, for example in 'systemctl show-environment',
since 804ee07c1370d49aa9a. But we would still disallow setting such variables
by the user, in unit file Environment= and in set-environment/import-environment
operations. This is unexpected and confusing and doesn't help with anything
because such variables are present in the environment through other means.
When printing such variables, 'show-environment' escapes all special
characters, so variables with control characters are plainly visible.
In other uses, e.g. 'cat -v' can be used in similar fashion. This would already
need to be done to suppress color codes starting with \[.
Note that we still forbid invalid utf-8 with this patch. (Control characters
are valid, since they are valid 7-bit ascii.) I'm not sure if we should do
that, but since people haven't been actually asking for invalid utf-8, and only
for control characters, and invalid utf-8 causes other issues, I think it's OK
to leave this unchanged.
Fixes #4446, https://gitlab.gnome.org/GNOME/gnome-session/-/issues/45.
2021-01-03 22:26:52 +01:00
assert_se ( streq ( e [ 6 ] , " CRLF= \r \n " ) ) ;
assert_se ( streq ( e [ 7 ] , " LESS_TERMCAP_mb= \x1b [01;31m " ) ) ;
assert_se ( e [ 8 ] = = NULL ) ;
2013-02-11 03:46:08 +01:00
}
2013-02-11 21:40:59 +01:00
static void test_env_name_is_valid ( void ) {
2020-09-28 14:54:16 +02:00
log_info ( " /* %s */ " , __func__ ) ;
2013-02-11 21:40:59 +01:00
assert_se ( env_name_is_valid ( " test " ) ) ;
assert_se ( ! env_name_is_valid ( NULL ) ) ;
assert_se ( ! env_name_is_valid ( " " ) ) ;
2016-03-21 16:45:37 -04:00
assert_se ( ! env_name_is_valid ( " xxx \a " ) ) ;
assert_se ( ! env_name_is_valid ( " xxx \007 b " ) ) ;
assert_se ( ! env_name_is_valid ( " \007 \00 9 " ) ) ;
2020-10-23 14:24:32 +02:00
assert_se ( ! env_name_is_valid ( " 5_starting_with_a_number_is_wrong " ) ) ;
2013-02-11 21:40:59 +01:00
assert_se ( ! env_name_is_valid ( " #¤%&?_only_numbers_letters_and_underscore_allowed " ) ) ;
}
2016-03-21 16:45:37 -04:00
static void test_env_value_is_valid ( void ) {
2020-09-28 14:54:16 +02:00
log_info ( " /* %s */ " , __func__ ) ;
2016-03-21 16:45:37 -04:00
assert_se ( env_value_is_valid ( " " ) ) ;
assert_se ( env_value_is_valid ( " głąb kapuściany " ) ) ;
assert_se ( env_value_is_valid ( " printf \" \\ x1b]0;<mock-chroot> \\ x07<mock-chroot> \" " ) ) ;
2018-03-16 13:41:54 -07:00
assert_se ( env_value_is_valid ( " tab \t character " ) ) ;
assert_se ( env_value_is_valid ( " new \n line " ) ) ;
Allow control characters in environment variable values
So far, we would allow certain control characters (NL since
b4346b9a77bc6129dd3e, TAB since 6294aa76d818e831de45), but not others. Having
other control characters in environment variable *value* is expected and widely
used, for various prompts like $LESS, $LESS_TERMCAP_*, and other similar
variables. The typical environment exported by bash already contains a dozen or
so such variables, so programs need to handle them.
We handle then correctly too, for example in 'systemctl show-environment',
since 804ee07c1370d49aa9a. But we would still disallow setting such variables
by the user, in unit file Environment= and in set-environment/import-environment
operations. This is unexpected and confusing and doesn't help with anything
because such variables are present in the environment through other means.
When printing such variables, 'show-environment' escapes all special
characters, so variables with control characters are plainly visible.
In other uses, e.g. 'cat -v' can be used in similar fashion. This would already
need to be done to suppress color codes starting with \[.
Note that we still forbid invalid utf-8 with this patch. (Control characters
are valid, since they are valid 7-bit ascii.) I'm not sure if we should do
that, but since people haven't been actually asking for invalid utf-8, and only
for control characters, and invalid utf-8 causes other issues, I think it's OK
to leave this unchanged.
Fixes #4446, https://gitlab.gnome.org/GNOME/gnome-session/-/issues/45.
2021-01-03 22:26:52 +01:00
assert_se ( env_value_is_valid ( " Show this? \r Nope. Show that! " ) ) ;
assert_se ( env_value_is_valid ( " new DOS \r \n line " ) ) ;
assert_se ( ! env_value_is_valid ( " \xc5 " ) ) ; /* A truncated utf-8-encoded "ł".
* We currently disallow that . */
2016-03-21 16:45:37 -04:00
}
static void test_env_assignment_is_valid ( void ) {
2020-09-28 14:54:16 +02:00
log_info ( " /* %s */ " , __func__ ) ;
2016-03-21 16:45:37 -04:00
assert_se ( env_assignment_is_valid ( " a= " ) ) ;
assert_se ( env_assignment_is_valid ( " b=głąb kapuściany " ) ) ;
assert_se ( env_assignment_is_valid ( " c= \\ 007 \\ 009 \\ 011 " ) ) ;
assert_se ( env_assignment_is_valid ( " e=printf \" \\ x1b]0;<mock-chroot> \\ x07<mock-chroot> \" " ) ) ;
2018-03-16 13:41:54 -07:00
assert_se ( env_assignment_is_valid ( " f=tab \t character " ) ) ;
assert_se ( env_assignment_is_valid ( " g=new \n line " ) ) ;
2016-03-21 16:45:37 -04:00
assert_se ( ! env_assignment_is_valid ( " = " ) ) ;
assert_se ( ! env_assignment_is_valid ( " a b= " ) ) ;
assert_se ( ! env_assignment_is_valid ( " a = " ) ) ;
assert_se ( ! env_assignment_is_valid ( " b= " ) ) ;
2020-10-23 14:24:32 +02:00
/* no dots or dashes: http://tldp.org/LDP/abs/html/gotchas.html */
assert_se ( ! env_assignment_is_valid ( " a.b= " ) ) ;
assert_se ( ! env_assignment_is_valid ( " a-b= " ) ) ;
2016-03-21 16:45:37 -04:00
assert_se ( ! env_assignment_is_valid ( " \007 =głąb kapuściany " ) ) ;
assert_se ( ! env_assignment_is_valid ( " c \00 9= \007 \00 9 \011 " ) ) ;
assert_se ( ! env_assignment_is_valid ( " głąb=printf \" \x1b ]0;<mock-chroot> \x07 <mock-chroot> \" " ) ) ;
}
2021-02-20 19:25:32 +01:00
static void test_putenv_dup ( void ) {
log_info ( " /* %s */ " , __func__ ) ;
assert_se ( putenv_dup ( " A=a1 " , true ) = = 0 ) ;
2021-05-21 13:39:24 +01:00
assert_se ( streq_ptr ( getenv ( " A " ) , " a1 " ) ) ;
2021-02-20 19:25:32 +01:00
assert_se ( putenv_dup ( " A=a1 " , true ) = = 0 ) ;
2021-05-21 13:39:24 +01:00
assert_se ( streq_ptr ( getenv ( " A " ) , " a1 " ) ) ;
2021-02-20 19:25:32 +01:00
assert_se ( putenv_dup ( " A=a2 " , false ) = = 0 ) ;
2021-05-21 13:39:24 +01:00
assert_se ( streq_ptr ( getenv ( " A " ) , " a1 " ) ) ;
2021-02-20 19:25:32 +01:00
assert_se ( putenv_dup ( " A=a2 " , true ) = = 0 ) ;
2021-05-21 13:39:24 +01:00
assert_se ( streq_ptr ( getenv ( " A " ) , " a2 " ) ) ;
2021-02-20 19:25:32 +01:00
}
2021-01-31 23:33:06 +09:00
static void test_setenv_systemd_exec_pid ( void ) {
_cleanup_free_ char * saved = NULL ;
const char * e ;
pid_t p ;
log_info ( " /* %s */ " , __func__ ) ;
e = getenv ( " SYSTEMD_EXEC_PID " ) ;
if ( e )
assert_se ( saved = strdup ( e ) ) ;
assert_se ( unsetenv ( " SYSTEMD_EXEC_PID " ) > = 0 ) ;
assert_se ( setenv_systemd_exec_pid ( true ) = = 0 ) ;
assert_se ( ! getenv ( " SYSTEMD_EXEC_PID " ) ) ;
assert_se ( setenv ( " SYSTEMD_EXEC_PID " , " * " , 1 ) > = 0 ) ;
assert_se ( setenv_systemd_exec_pid ( true ) = = 0 ) ;
assert_se ( e = getenv ( " SYSTEMD_EXEC_PID " ) ) ;
assert_se ( streq ( e , " * " ) ) ;
assert_se ( setenv ( " SYSTEMD_EXEC_PID " , " 123abc " , 1 ) > = 0 ) ;
assert_se ( setenv_systemd_exec_pid ( true ) = = 1 ) ;
assert_se ( e = getenv ( " SYSTEMD_EXEC_PID " ) ) ;
assert_se ( parse_pid ( e , & p ) > = 0 ) ;
assert_se ( p = = getpid_cached ( ) ) ;
assert_se ( unsetenv ( " SYSTEMD_EXEC_PID " ) > = 0 ) ;
assert_se ( setenv_systemd_exec_pid ( false ) = = 1 ) ;
assert_se ( e = getenv ( " SYSTEMD_EXEC_PID " ) ) ;
assert_se ( parse_pid ( e , & p ) > = 0 ) ;
assert_se ( p = = getpid_cached ( ) ) ;
assert_se ( set_unset_env ( " SYSTEMD_EXEC_PID " , saved , 1 ) > = 0 ) ;
}
2021-08-16 16:41:34 +02:00
static void test_unsetenv_erase ( void ) {
int r ;
log_info ( " /* %s */ " , __func__ ) ;
r = safe_fork ( " (sd-unsetenverase) " , FORK_DEATHSIG | FORK_LOG | FORK_WAIT , NULL ) ;
if ( r = = 0 ) {
_cleanup_strv_free_ char * * l = NULL ;
char * * e ;
/* child */
assert_se ( unsetenv_erase ( " thisenvvardefinitelywontexist " ) = = 0 ) ;
l = strv_new ( " FOO=BAR " , " QUUX=PIFF " , " ONE=TWO " , " A=B " ) ;
assert_se ( strv_length ( l ) = = 4 ) ;
environ = l ;
STRV_FOREACH ( e , environ ) {
_cleanup_free_ char * n = NULL ;
char * eq ;
eq = strchr ( * e , ' = ' ) ;
if ( ! eq )
continue ;
n = strndup ( * e , eq - * e ) ;
assert_se ( n ) ;
assert_se ( streq_ptr ( getenv ( n ) , eq + 1 ) ) ;
assert_se ( getenv ( n ) = = eq + 1 ) ;
assert_se ( unsetenv_erase ( n ) > 0 ) ;
assert_se ( isempty ( eq + 1 ) ) ;
assert_se ( ! getenv ( n ) ) ;
}
environ = NULL ;
l = strv_free ( l ) ;
_exit ( EXIT_SUCCESS ) ;
}
assert_se ( r > 0 ) ;
}
2013-02-07 21:10:31 +01:00
int main ( int argc , char * argv [ ] ) {
2021-01-31 23:32:05 +09:00
test_setup_logging ( LOG_DEBUG ) ;
2013-02-08 00:22:26 +01:00
test_strv_env_delete ( ) ;
2016-08-03 14:35:50 -04:00
test_strv_env_get ( ) ;
2021-01-27 12:51:17 +00:00
test_strv_env_pairs_get ( ) ;
2013-02-08 00:22:26 +01:00
test_strv_env_unset ( ) ;
2013-02-07 21:10:31 +01:00
test_strv_env_merge ( ) ;
2021-02-15 15:01:52 +01:00
test_strv_env_replace_strdup ( ) ;
2021-08-10 17:03:12 +02:00
test_strv_env_replace_strdup_passthrough ( ) ;
2021-02-15 15:01:52 +01:00
test_strv_env_assign ( ) ;
2016-08-04 12:00:00 -04:00
test_env_strv_get_n ( ) ;
2017-02-11 14:05:10 -05:00
test_replace_env ( false ) ;
test_replace_env ( true ) ;
2017-02-20 23:21:26 -05:00
test_replace_env2 ( false ) ;
test_replace_env2 ( true ) ;
2017-02-11 14:05:10 -05:00
test_replace_env_argv ( ) ;
2013-02-11 03:46:08 +01:00
test_env_clean ( ) ;
2013-02-11 21:40:59 +01:00
test_env_name_is_valid ( ) ;
2016-03-21 16:45:37 -04:00
test_env_value_is_valid ( ) ;
test_env_assignment_is_valid ( ) ;
2021-02-20 19:25:32 +01:00
test_putenv_dup ( ) ;
2021-01-31 23:33:06 +09:00
test_setenv_systemd_exec_pid ( ) ;
2021-08-16 16:41:34 +02:00
test_unsetenv_erase ( ) ;
2011-01-06 20:38:02 +01:00
2011-01-05 16:06:35 +01:00
return 0 ;
2010-07-21 02:57:35 +02:00
}