2009-11-18 02:42:52 +03:00
/*-*- Mode: C; c-basic-offset: 8 -*-*/
2010-02-03 15:03:47 +03: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/>.
* * */
2009-11-18 02:42:52 +03:00
# include <assert.h>
# include <string.h>
# include <unistd.h>
# include <errno.h>
2009-11-19 02:46:47 +03:00
# include <stdlib.h>
2010-01-26 06:18:44 +03:00
# include <signal.h>
# include <stdio.h>
2010-01-30 03:52:32 +03:00
# include <syslog.h>
# include <sched.h>
# include <sys/resource.h>
2010-02-02 12:30:04 +03:00
# include <linux/sched.h>
2010-02-12 04:01:14 +03:00
# include <sys/types.h>
# include <sys/stat.h>
2010-04-06 23:53:02 +04:00
# include <fcntl.h>
2010-04-07 01:35:59 +04:00
# include <dirent.h>
2010-04-11 01:36:43 +04:00
# include <sys/ioctl.h>
# include <linux/vt.h>
# include <linux/tiocl.h>
2010-04-13 04:06:27 +04:00
# include <termios.h>
# include <stdarg.h>
# include <sys/inotify.h>
# include <sys/poll.h>
2010-04-17 01:24:39 +04:00
# include <libgen.h>
2009-11-18 02:42:52 +03:00
# include "macro.h"
# include "util.h"
2010-01-30 03:52:32 +03:00
# include "ioprio.h"
# include "missing.h"
2010-02-12 04:01:14 +03:00
# include "log.h"
2010-02-13 03:05:12 +03:00
# include "strv.h"
2009-11-18 02:42:52 +03:00
2010-04-10 06:38:14 +04:00
bool streq_ptr ( const char * a , const char * b ) {
/* Like streq(), but tries to make sense of NULL pointers */
if ( a & & b )
return streq ( a , b ) ;
if ( ! a & & ! b )
return true ;
return false ;
}
2010-02-03 16:21:48 +03:00
usec_t now ( clockid_t clock_id ) {
2009-11-18 02:42:52 +03:00
struct timespec ts ;
2010-02-03 16:21:48 +03:00
assert_se ( clock_gettime ( clock_id , & ts ) = = 0 ) ;
2009-11-18 02:42:52 +03:00
return timespec_load ( & ts ) ;
}
usec_t timespec_load ( const struct timespec * ts ) {
assert ( ts ) ;
return
( usec_t ) ts - > tv_sec * USEC_PER_SEC +
( usec_t ) ts - > tv_nsec / NSEC_PER_USEC ;
}
struct timespec * timespec_store ( struct timespec * ts , usec_t u ) {
assert ( ts ) ;
ts - > tv_sec = ( time_t ) ( u / USEC_PER_SEC ) ;
ts - > tv_nsec = ( long int ) ( ( u % USEC_PER_SEC ) * NSEC_PER_USEC ) ;
return ts ;
}
usec_t timeval_load ( const struct timeval * tv ) {
assert ( tv ) ;
return
( usec_t ) tv - > tv_sec * USEC_PER_SEC +
( usec_t ) tv - > tv_usec ;
}
struct timeval * timeval_store ( struct timeval * tv , usec_t u ) {
assert ( tv ) ;
tv - > tv_sec = ( time_t ) ( u / USEC_PER_SEC ) ;
tv - > tv_usec = ( suseconds_t ) ( u % USEC_PER_SEC ) ;
return tv ;
}
bool endswith ( const char * s , const char * postfix ) {
size_t sl , pl ;
assert ( s ) ;
assert ( postfix ) ;
sl = strlen ( s ) ;
pl = strlen ( postfix ) ;
if ( sl < pl )
return false ;
return memcmp ( s + sl - pl , postfix , pl ) = = 0 ;
}
bool startswith ( const char * s , const char * prefix ) {
size_t sl , pl ;
assert ( s ) ;
assert ( prefix ) ;
sl = strlen ( s ) ;
pl = strlen ( prefix ) ;
if ( sl < pl )
return false ;
return memcmp ( s , prefix , pl ) = = 0 ;
}
2010-01-30 03:52:44 +03:00
bool first_word ( const char * s , const char * word ) {
size_t sl , wl ;
assert ( s ) ;
assert ( word ) ;
sl = strlen ( s ) ;
wl = strlen ( word ) ;
if ( sl < wl )
return false ;
if ( memcmp ( s , word , wl ) ! = 0 )
return false ;
return ( s [ wl ] = = 0 | |
strchr ( WHITESPACE , s [ wl ] ) ) ;
}
2010-01-19 04:56:37 +03:00
int close_nointr ( int fd ) {
2009-11-18 02:42:52 +03:00
assert ( fd > = 0 ) ;
for ( ; ; ) {
int r ;
if ( ( r = close ( fd ) ) > = 0 )
return r ;
if ( errno ! = EINTR )
return r ;
}
}
2009-11-19 02:46:47 +03:00
2010-01-28 03:53:15 +03:00
void close_nointr_nofail ( int fd ) {
2010-04-13 04:06:27 +04:00
int saved_errno = errno ;
2010-01-28 03:53:15 +03:00
/* like close_nointr() but cannot fail, and guarantees errno
* is unchanged */
assert_se ( close_nointr ( fd ) = = 0 ) ;
2010-04-13 04:06:27 +04:00
errno = saved_errno ;
2010-01-28 03:53:15 +03:00
}
2009-11-19 02:46:47 +03:00
int parse_boolean ( const char * v ) {
assert ( v ) ;
2010-01-26 09:02:51 +03:00
if ( streq ( v , " 1 " ) | | v [ 0 ] = = ' y ' | | v [ 0 ] = = ' Y ' | | v [ 0 ] = = ' t ' | | v [ 0 ] = = ' T ' | | ! strcasecmp ( v , " on " ) )
2009-11-19 02:46:47 +03:00
return 1 ;
2010-01-26 09:02:51 +03:00
else if ( streq ( v , " 0 " ) | | v [ 0 ] = = ' n ' | | v [ 0 ] = = ' N ' | | v [ 0 ] = = ' f ' | | v [ 0 ] = = ' F ' | | ! strcasecmp ( v , " off " ) )
2009-11-19 02:46:47 +03:00
return 0 ;
return - EINVAL ;
}
int safe_atou ( const char * s , unsigned * ret_u ) {
char * x = NULL ;
2010-01-26 06:18:44 +03:00
unsigned long l ;
2009-11-19 02:46:47 +03:00
assert ( s ) ;
assert ( ret_u ) ;
errno = 0 ;
l = strtoul ( s , & x , 0 ) ;
if ( ! x | | * x | | errno )
return errno ? - errno : - EINVAL ;
2010-01-26 06:18:44 +03:00
if ( ( unsigned long ) ( unsigned ) l ! = l )
2009-11-19 02:46:47 +03:00
return - ERANGE ;
* ret_u = ( unsigned ) l ;
return 0 ;
}
int safe_atoi ( const char * s , int * ret_i ) {
char * x = NULL ;
2010-01-26 06:18:44 +03:00
long l ;
2009-11-19 02:46:47 +03:00
assert ( s ) ;
assert ( ret_i ) ;
errno = 0 ;
l = strtol ( s , & x , 0 ) ;
if ( ! x | | * x | | errno )
return errno ? - errno : - EINVAL ;
2010-01-26 06:18:44 +03:00
if ( ( long ) ( int ) l ! = l )
2009-11-19 02:46:47 +03:00
return - ERANGE ;
2010-01-26 06:18:44 +03:00
* ret_i = ( int ) l ;
return 0 ;
}
int safe_atolu ( const char * s , long unsigned * ret_lu ) {
char * x = NULL ;
unsigned long l ;
assert ( s ) ;
assert ( ret_lu ) ;
errno = 0 ;
l = strtoul ( s , & x , 0 ) ;
if ( ! x | | * x | | errno )
return errno ? - errno : - EINVAL ;
* ret_lu = l ;
return 0 ;
}
int safe_atoli ( const char * s , long int * ret_li ) {
char * x = NULL ;
long l ;
assert ( s ) ;
assert ( ret_li ) ;
errno = 0 ;
l = strtol ( s , & x , 0 ) ;
if ( ! x | | * x | | errno )
return errno ? - errno : - EINVAL ;
* ret_li = l ;
return 0 ;
}
int safe_atollu ( const char * s , long long unsigned * ret_llu ) {
char * x = NULL ;
unsigned long long l ;
assert ( s ) ;
assert ( ret_llu ) ;
errno = 0 ;
l = strtoull ( s , & x , 0 ) ;
if ( ! x | | * x | | errno )
return errno ? - errno : - EINVAL ;
* ret_llu = l ;
return 0 ;
}
int safe_atolli ( const char * s , long long int * ret_lli ) {
char * x = NULL ;
long long l ;
assert ( s ) ;
assert ( ret_lli ) ;
errno = 0 ;
l = strtoll ( s , & x , 0 ) ;
if ( ! x | | * x | | errno )
return errno ? - errno : - EINVAL ;
* ret_lli = l ;
2009-11-19 02:46:47 +03:00
return 0 ;
}
2009-11-19 04:50:21 +03:00
/* Split a string into words. */
2010-02-13 03:05:12 +03:00
char * split ( const char * c , size_t * l , const char * separator , char * * state ) {
2009-11-19 04:50:21 +03:00
char * current ;
current = * state ? * state : ( char * ) c ;
if ( ! * current | | * c = = 0 )
return NULL ;
2010-02-13 03:05:12 +03:00
current + = strspn ( current , separator ) ;
* l = strcspn ( current , separator ) ;
2010-02-12 04:00:49 +03:00
* state = current + * l ;
return ( char * ) current ;
}
2010-01-26 06:18:44 +03:00
/* Split a string into words, but consider strings enclosed in '' and
* " " as words even if they include spaces . */
char * split_quoted ( const char * c , size_t * l , char * * state ) {
char * current ;
current = * state ? * state : ( char * ) c ;
if ( ! * current | | * c = = 0 )
return NULL ;
current + = strspn ( current , WHITESPACE ) ;
if ( * current = = ' \' ' ) {
current + + ;
* l = strcspn ( current , " ' " ) ;
* state = current + * l ;
if ( * * state = = ' \' ' )
( * state ) + + ;
} else if ( * current = = ' \" ' ) {
current + + ;
2010-01-27 04:16:51 +03:00
* l = strcspn ( current , " \" " ) ;
2010-01-26 06:18:44 +03:00
* state = current + * l ;
if ( * * state = = ' \" ' )
( * state ) + + ;
} else {
* l = strcspn ( current , WHITESPACE ) ;
* state = current + * l ;
}
2010-01-26 09:02:51 +03:00
/* FIXME: Cannot deal with strings that have spaces AND ticks
* in them */
2010-01-26 06:18:44 +03:00
return ( char * ) current ;
}
2010-02-13 03:05:12 +03:00
char * * split_path_and_make_absolute ( const char * p ) {
char * * l ;
assert ( p ) ;
if ( ! ( l = strv_split ( p , " : " ) ) )
return NULL ;
if ( ! strv_path_make_absolute_cwd ( l ) ) {
strv_free ( l ) ;
return NULL ;
}
return l ;
}
2010-01-26 06:18:44 +03:00
int get_parent_of_pid ( pid_t pid , pid_t * _ppid ) {
int r ;
FILE * f ;
char fn [ 132 ] , line [ 256 ] , * p ;
long long unsigned ppid ;
assert ( pid > = 0 ) ;
assert ( _ppid ) ;
assert_se ( snprintf ( fn , sizeof ( fn ) - 1 , " /proc/%llu/stat " , ( unsigned long long ) pid ) < ( int ) ( sizeof ( fn ) - 1 ) ) ;
fn [ sizeof ( fn ) - 1 ] = 0 ;
if ( ! ( f = fopen ( fn , " r " ) ) )
return - errno ;
if ( ! ( fgets ( line , sizeof ( line ) , f ) ) ) {
r = - errno ;
fclose ( f ) ;
return r ;
}
fclose ( f ) ;
/* Let's skip the pid and comm fields. The latter is enclosed
* in ( ) but does not escape any ( ) in its value , so let ' s
* skip over it manually */
if ( ! ( p = strrchr ( line , ' ) ' ) ) )
return - EIO ;
p + + ;
if ( sscanf ( p , " "
" %*c " /* state */
" %llu " , /* ppid */
& ppid ) ! = 1 )
return - EIO ;
if ( ( long long unsigned ) ( pid_t ) ppid ! = ppid )
return - ERANGE ;
* _ppid = ( pid_t ) ppid ;
return 0 ;
}
int write_one_line_file ( const char * fn , const char * line ) {
FILE * f ;
int r ;
assert ( fn ) ;
assert ( line ) ;
if ( ! ( f = fopen ( fn , " we " ) ) )
return - errno ;
if ( fputs ( line , f ) < 0 ) {
r = - errno ;
goto finish ;
}
r = 0 ;
finish :
fclose ( f ) ;
return r ;
}
int read_one_line_file ( const char * fn , char * * line ) {
FILE * f ;
int r ;
2010-04-08 03:43:25 +04:00
char t [ 2048 ] , * c ;
2010-01-26 06:18:44 +03:00
assert ( fn ) ;
assert ( line ) ;
if ( ! ( f = fopen ( fn , " re " ) ) )
return - errno ;
if ( ! ( fgets ( t , sizeof ( t ) , f ) ) ) {
r = - errno ;
goto finish ;
}
if ( ! ( c = strdup ( t ) ) ) {
r = - ENOMEM ;
goto finish ;
}
* line = c ;
r = 0 ;
finish :
fclose ( f ) ;
return r ;
}
2010-01-26 09:02:51 +03:00
2010-04-08 05:22:25 +04:00
char * truncate_nl ( char * s ) {
assert ( s ) ;
s [ strcspn ( s , NEWLINE ) ] = 0 ;
return s ;
}
int get_process_name ( pid_t pid , char * * name ) {
char * p ;
int r ;
assert ( pid > = 1 ) ;
assert ( name ) ;
if ( asprintf ( & p , " /proc/%llu/comm " , ( unsigned long long ) pid ) < 0 )
return - ENOMEM ;
r = read_one_line_file ( p , name ) ;
free ( p ) ;
if ( r < 0 )
return r ;
truncate_nl ( * name ) ;
return 0 ;
}
2010-01-26 09:02:51 +03:00
char * strappend ( const char * s , const char * suffix ) {
size_t a , b ;
char * r ;
assert ( s ) ;
assert ( suffix ) ;
a = strlen ( s ) ;
b = strlen ( suffix ) ;
if ( ! ( r = new ( char , a + b + 1 ) ) )
return NULL ;
memcpy ( r , s , a ) ;
memcpy ( r + a , suffix , b ) ;
r [ a + b ] = 0 ;
return r ;
}
2010-01-26 23:39:06 +03:00
int readlink_malloc ( const char * p , char * * r ) {
size_t l = 100 ;
assert ( p ) ;
assert ( r ) ;
for ( ; ; ) {
char * c ;
ssize_t n ;
if ( ! ( c = new ( char , l ) ) )
return - ENOMEM ;
if ( ( n = readlink ( p , c , l - 1 ) ) < 0 ) {
int ret = - errno ;
free ( c ) ;
return ret ;
}
if ( ( size_t ) n < l - 1 ) {
c [ n ] = 0 ;
* r = c ;
return 0 ;
}
free ( c ) ;
l * = 2 ;
}
}
char * file_name_from_path ( const char * p ) {
char * r ;
assert ( p ) ;
if ( ( r = strrchr ( p , ' / ' ) ) )
return r + 1 ;
return ( char * ) p ;
}
2010-01-27 02:15:56 +03:00
bool path_is_absolute ( const char * p ) {
assert ( p ) ;
return p [ 0 ] = = ' / ' ;
}
bool is_path ( const char * p ) {
return ! ! strchr ( p , ' / ' ) ;
}
char * path_make_absolute ( const char * p , const char * prefix ) {
char * r ;
assert ( p ) ;
2010-02-13 03:05:12 +03:00
/* Makes every item in the list an absolute path by prepending
* the prefix , if specified and necessary */
2010-01-27 02:15:56 +03:00
if ( path_is_absolute ( p ) | | ! prefix )
return strdup ( p ) ;
if ( asprintf ( & r , " %s/%s " , prefix , p ) < 0 )
return NULL ;
return r ;
}
2010-01-27 08:19:28 +03:00
2010-02-13 03:05:12 +03:00
char * path_make_absolute_cwd ( const char * p ) {
char * cwd , * r ;
assert ( p ) ;
/* Similar to path_make_absolute(), but prefixes with the
* current working directory . */
if ( path_is_absolute ( p ) )
return strdup ( p ) ;
if ( ! ( cwd = get_current_dir_name ( ) ) )
return NULL ;
r = path_make_absolute ( p , cwd ) ;
free ( cwd ) ;
return r ;
}
char * * strv_path_make_absolute_cwd ( char * * l ) {
char * * s ;
/* Goes through every item in the string list and makes it
* absolute . This works in place and won ' t rollback any
* changes on failure . */
STRV_FOREACH ( s , l ) {
char * t ;
if ( ! ( t = path_make_absolute_cwd ( * s ) ) )
return NULL ;
free ( * s ) ;
* s = t ;
}
return l ;
}
2010-01-27 08:19:28 +03:00
int reset_all_signal_handlers ( void ) {
int sig ;
for ( sig = 1 ; sig < _NSIG ; sig + + ) {
struct sigaction sa ;
if ( sig = = SIGKILL | | sig = = SIGSTOP )
continue ;
zero ( sa ) ;
sa . sa_handler = SIG_DFL ;
2010-01-28 03:53:39 +03:00
sa . sa_flags = SA_RESTART ;
2010-01-27 08:19:28 +03:00
/* On Linux the first two RT signals are reserved by
* glibc , and sigaction ( ) will return EINVAL for them . */
if ( ( sigaction ( sig , & sa , NULL ) < 0 ) )
if ( errno ! = EINVAL )
return - errno ;
}
2010-03-31 18:29:55 +04:00
return 0 ;
2010-01-27 08:19:28 +03:00
}
2010-01-28 00:37:50 +03:00
char * strstrip ( char * s ) {
char * e , * l = NULL ;
/* Drops trailing whitespace. Modifies the string in
* place . Returns pointer to first non - space character */
s + = strspn ( s , WHITESPACE ) ;
for ( e = s ; * e ; e + + )
if ( ! strchr ( WHITESPACE , * e ) )
l = e ;
if ( l )
* ( l + 1 ) = 0 ;
else
* s = 0 ;
return s ;
}
2010-04-07 22:27:05 +04:00
char * delete_chars ( char * s , const char * bad ) {
char * f , * t ;
/* Drops all whitespace, regardless where in the string */
for ( f = s , t = s ; * f ; f + + ) {
if ( strchr ( bad , * f ) )
continue ;
* ( t + + ) = * f ;
}
* t = 0 ;
return s ;
}
2010-01-28 00:37:50 +03:00
char * file_in_same_dir ( const char * path , const char * filename ) {
char * e , * r ;
size_t k ;
assert ( path ) ;
assert ( filename ) ;
/* This removes the last component of path and appends
* filename , unless the latter is absolute anyway or the
* former isn ' t */
if ( path_is_absolute ( filename ) )
return strdup ( filename ) ;
if ( ! ( e = strrchr ( path , ' / ' ) ) )
return strdup ( filename ) ;
k = strlen ( filename ) ;
if ( ! ( r = new ( char , e - path + 1 + k + 1 ) ) )
return NULL ;
memcpy ( r , path , e - path + 1 ) ;
memcpy ( r + ( e - path ) + 1 , filename , k + 1 ) ;
return r ;
}
2010-01-28 08:45:04 +03:00
2010-02-12 04:01:14 +03:00
int mkdir_parents ( const char * path , mode_t mode ) {
const char * p , * e ;
assert ( path ) ;
/* Creates every parent directory in the path except the last
* component . */
p = path + strspn ( path , " / " ) ;
for ( ; ; ) {
int r ;
char * t ;
e = p + strcspn ( p , " / " ) ;
p = e + strspn ( e , " / " ) ;
/* Is this the last component? If so, then we're
* done */
if ( * p = = 0 )
return 0 ;
if ( ! ( t = strndup ( path , e - path ) ) )
return - ENOMEM ;
r = mkdir ( t , mode ) ;
free ( t ) ;
if ( r < 0 & & errno ! = EEXIST )
return - errno ;
}
}
2010-04-10 06:38:33 +04:00
int mkdir_p ( const char * path , mode_t mode ) {
int r ;
/* Like mkdir -p */
if ( ( r = mkdir_parents ( path , mode ) ) < 0 )
return r ;
if ( mkdir ( path , mode ) < 0 )
return - errno ;
return 0 ;
}
2010-01-28 08:45:04 +03:00
char hexchar ( int x ) {
static const char table [ 16 ] = " 0123456789abcdef " ;
return table [ x & 15 ] ;
}
2010-01-29 03:48:57 +03:00
int unhexchar ( char c ) {
if ( c > = ' 0 ' & & c < = ' 9 ' )
return c - ' 0 ' ;
if ( c > = ' a ' & & c < = ' f ' )
2010-02-01 05:33:24 +03:00
return c - ' a ' + 10 ;
2010-01-29 03:48:57 +03:00
if ( c > = ' A ' & & c < = ' F ' )
2010-02-01 05:33:24 +03:00
return c - ' A ' + 10 ;
2010-01-29 03:48:57 +03:00
return - 1 ;
}
char octchar ( int x ) {
return ' 0 ' + ( x & 7 ) ;
}
int unoctchar ( char c ) {
if ( c > = ' 0 ' & & c < = ' 7 ' )
return c - ' 0 ' ;
return - 1 ;
}
2010-04-06 04:41:03 +04:00
char decchar ( int x ) {
return ' 0 ' + ( x % 10 ) ;
}
int undecchar ( char c ) {
if ( c > = ' 0 ' & & c < = ' 9 ' )
return c - ' 0 ' ;
return - 1 ;
}
2010-01-29 03:48:57 +03:00
char * cescape ( const char * s ) {
char * r , * t ;
const char * f ;
assert ( s ) ;
/* Does C style string escaping. */
if ( ! ( r = new ( char , strlen ( s ) * 4 + 1 ) ) )
return NULL ;
for ( f = s , t = r ; * f ; f + + )
switch ( * f ) {
case ' \a ' :
* ( t + + ) = ' \\ ' ;
* ( t + + ) = ' a ' ;
break ;
case ' \b ' :
* ( t + + ) = ' \\ ' ;
* ( t + + ) = ' b ' ;
break ;
case ' \f ' :
* ( t + + ) = ' \\ ' ;
* ( t + + ) = ' f ' ;
break ;
case ' \n ' :
* ( t + + ) = ' \\ ' ;
* ( t + + ) = ' n ' ;
break ;
case ' \r ' :
* ( t + + ) = ' \\ ' ;
* ( t + + ) = ' r ' ;
break ;
case ' \t ' :
* ( t + + ) = ' \\ ' ;
* ( t + + ) = ' t ' ;
break ;
case ' \v ' :
* ( t + + ) = ' \\ ' ;
* ( t + + ) = ' v ' ;
break ;
case ' \\ ' :
* ( t + + ) = ' \\ ' ;
* ( t + + ) = ' \\ ' ;
break ;
case ' " ' :
* ( t + + ) = ' \\ ' ;
* ( t + + ) = ' " ' ;
break ;
case ' \' ' :
* ( t + + ) = ' \\ ' ;
* ( t + + ) = ' \' ' ;
break ;
default :
/* For special chars we prefer octal over
* hexadecimal encoding , simply because glib ' s
* g_strescape ( ) does the same */
if ( ( * f < ' ' ) | | ( * f > = 127 ) ) {
* ( t + + ) = ' \\ ' ;
* ( t + + ) = octchar ( ( unsigned char ) * f > > 6 ) ;
* ( t + + ) = octchar ( ( unsigned char ) * f > > 3 ) ;
* ( t + + ) = octchar ( ( unsigned char ) * f ) ;
} else
* ( t + + ) = * f ;
break ;
}
* t = 0 ;
return r ;
}
char * cunescape ( const char * s ) {
char * r , * t ;
const char * f ;
assert ( s ) ;
/* Undoes C style string escaping */
if ( ! ( r = new ( char , strlen ( s ) + 1 ) ) )
return r ;
for ( f = s , t = r ; * f ; f + + ) {
if ( * f ! = ' \\ ' ) {
* ( t + + ) = * f ;
continue ;
}
f + + ;
switch ( * f ) {
case ' a ' :
* ( t + + ) = ' \a ' ;
break ;
case ' b ' :
* ( t + + ) = ' \b ' ;
break ;
case ' f ' :
* ( t + + ) = ' \f ' ;
break ;
case ' n ' :
* ( t + + ) = ' \n ' ;
break ;
case ' r ' :
* ( t + + ) = ' \r ' ;
break ;
case ' t ' :
* ( t + + ) = ' \t ' ;
break ;
case ' v ' :
* ( t + + ) = ' \v ' ;
break ;
case ' \\ ' :
* ( t + + ) = ' \\ ' ;
break ;
case ' " ' :
* ( t + + ) = ' " ' ;
break ;
case ' \' ' :
* ( t + + ) = ' \' ' ;
break ;
case ' x ' : {
/* hexadecimal encoding */
int a , b ;
if ( ( a = unhexchar ( f [ 1 ] ) ) < 0 | |
( b = unhexchar ( f [ 2 ] ) ) < 0 ) {
/* Invalid escape code, let's take it literal then */
* ( t + + ) = ' \\ ' ;
* ( t + + ) = ' x ' ;
} else {
* ( t + + ) = ( char ) ( ( a < < 4 ) | b ) ;
f + = 2 ;
}
break ;
}
case ' 0 ' :
case ' 1 ' :
case ' 2 ' :
case ' 3 ' :
case ' 4 ' :
case ' 5 ' :
case ' 6 ' :
case ' 7 ' : {
/* octal encoding */
int a , b , c ;
if ( ( a = unoctchar ( f [ 0 ] ) ) < 0 | |
( b = unoctchar ( f [ 1 ] ) ) < 0 | |
( c = unoctchar ( f [ 2 ] ) ) < 0 ) {
/* Invalid escape code, let's take it literal then */
* ( t + + ) = ' \\ ' ;
* ( t + + ) = f [ 0 ] ;
} else {
* ( t + + ) = ( char ) ( ( a < < 6 ) | ( b < < 3 ) | c ) ;
f + = 2 ;
}
break ;
}
case 0 :
/* premature end of string.*/
* ( t + + ) = ' \\ ' ;
goto finish ;
default :
/* Invalid escape code, let's take it literal then */
* ( t + + ) = ' \\ ' ;
* ( t + + ) = ' f ' ;
break ;
}
}
finish :
* t = 0 ;
return r ;
}
char * xescape ( const char * s , const char * bad ) {
char * r , * t ;
const char * f ;
/* Escapes all chars in bad, in addition to \ and all special
* chars , in \ xFF style escaping . May be reversed with
* cunescape . */
if ( ! ( r = new ( char , strlen ( s ) * 4 + 1 ) ) )
return NULL ;
for ( f = s , t = r ; * f ; f + + ) {
2010-03-31 22:08:05 +04:00
if ( ( * f < ' ' ) | | ( * f > = 127 ) | |
( * f = = ' \\ ' ) | | strchr ( bad , * f ) ) {
2010-01-29 03:48:57 +03:00
* ( t + + ) = ' \\ ' ;
* ( t + + ) = ' x ' ;
* ( t + + ) = hexchar ( * f > > 4 ) ;
* ( t + + ) = hexchar ( * f ) ;
} else
* ( t + + ) = * f ;
}
* t = 0 ;
return r ;
}
2010-02-01 05:33:24 +03:00
char * bus_path_escape ( const char * s ) {
char * r , * t ;
const char * f ;
2010-02-03 16:21:48 +03:00
assert ( s ) ;
2010-02-01 05:33:24 +03:00
/* Escapes all chars that D-Bus' object path cannot deal
* with . Can be reverse with bus_path_unescape ( ) */
if ( ! ( r = new ( char , strlen ( s ) * 3 + 1 ) ) )
return NULL ;
for ( f = s , t = r ; * f ; f + + ) {
if ( ! ( * f > = ' A ' & & * f < = ' Z ' ) & &
! ( * f > = ' a ' & & * f < = ' z ' ) & &
! ( * f > = ' 0 ' & & * f < = ' 9 ' ) ) {
* ( t + + ) = ' _ ' ;
* ( t + + ) = hexchar ( * f > > 4 ) ;
* ( t + + ) = hexchar ( * f ) ;
} else
* ( t + + ) = * f ;
}
* t = 0 ;
return r ;
}
2010-04-15 05:11:11 +04:00
char * bus_path_unescape ( const char * f ) {
2010-02-01 05:33:24 +03:00
char * r , * t ;
2010-04-15 05:11:11 +04:00
assert ( f ) ;
2010-02-03 16:21:48 +03:00
2010-04-15 05:11:11 +04:00
if ( ! ( r = strdup ( f ) ) )
2010-02-01 05:33:24 +03:00
return NULL ;
2010-04-15 05:11:11 +04:00
for ( t = r ; * f ; f + + ) {
2010-02-01 05:33:24 +03:00
if ( * f = = ' _ ' ) {
int a , b ;
if ( ( a = unhexchar ( f [ 1 ] ) ) < 0 | |
( b = unhexchar ( f [ 2 ] ) ) < 0 ) {
/* Invalid escape code, let's take it literal then */
* ( t + + ) = ' _ ' ;
} else {
* ( t + + ) = ( char ) ( ( a < < 4 ) | b ) ;
f + = 2 ;
}
} else
* ( t + + ) = * f ;
}
* t = 0 ;
return r ;
}
2010-01-29 03:48:57 +03:00
char * path_kill_slashes ( char * path ) {
char * f , * t ;
bool slash = false ;
/* Removes redundant inner and trailing slashes. Modifies the
* passed string in - place .
*
* ///foo///bar/ becomes /foo/bar
*/
for ( f = path , t = path ; * f ; f + + ) {
if ( * f = = ' / ' ) {
slash = true ;
continue ;
}
if ( slash ) {
slash = false ;
* ( t + + ) = ' / ' ;
}
* ( t + + ) = * f ;
}
/* Special rule, if we are talking of the root directory, a
trailing slash is good */
if ( t = = path & & slash )
* ( t + + ) = ' / ' ;
* t = 0 ;
return path ;
}
bool path_startswith ( const char * path , const char * prefix ) {
assert ( path ) ;
assert ( prefix ) ;
if ( ( path [ 0 ] = = ' / ' ) ! = ( prefix [ 0 ] = = ' / ' ) )
return false ;
for ( ; ; ) {
size_t a , b ;
path + = strspn ( path , " / " ) ;
prefix + = strspn ( prefix , " / " ) ;
if ( * prefix = = 0 )
return true ;
if ( * path = = 0 )
return false ;
a = strcspn ( path , " / " ) ;
b = strcspn ( prefix , " / " ) ;
if ( a ! = b )
return false ;
if ( memcmp ( path , prefix , a ) ! = 0 )
return false ;
path + = a ;
prefix + = b ;
}
}
2010-04-22 00:15:06 +04:00
bool path_equal ( const char * a , const char * b ) {
assert ( a ) ;
assert ( b ) ;
if ( ( a [ 0 ] = = ' / ' ) ! = ( b [ 0 ] = = ' / ' ) )
return false ;
for ( ; ; ) {
size_t j , k ;
a + = strspn ( a , " / " ) ;
b + = strspn ( b , " / " ) ;
if ( * a = = 0 & & * b = = 0 )
return true ;
if ( * a = = 0 | | * b = = 0 )
return false ;
j = strcspn ( a , " / " ) ;
k = strcspn ( b , " / " ) ;
if ( j ! = k )
return false ;
if ( memcmp ( a , b , j ) ! = 0 )
return false ;
a + = j ;
b + = k ;
}
}
2010-04-06 19:14:04 +04:00
char * ascii_strlower ( char * t ) {
2010-01-29 03:48:57 +03:00
char * p ;
2010-04-06 19:14:04 +04:00
assert ( t ) ;
2010-01-29 03:48:57 +03:00
2010-04-06 19:14:04 +04:00
for ( p = t ; * p ; p + + )
2010-01-29 03:48:57 +03:00
if ( * p > = ' A ' & & * p < = ' Z ' )
* p = * p - ' A ' + ' a ' ;
2010-04-06 19:14:04 +04:00
return t ;
2010-01-29 03:48:57 +03:00
}
2010-01-30 03:52:32 +03:00
2010-02-14 03:07:01 +03:00
bool ignore_file ( const char * filename ) {
assert ( filename ) ;
return
filename [ 0 ] = = ' . ' | |
endswith ( filename , " ~ " ) | |
endswith ( filename , " .rpmnew " ) | |
endswith ( filename , " .rpmsave " ) | |
endswith ( filename , " .rpmorig " ) | |
endswith ( filename , " .dpkg-old " ) | |
endswith ( filename , " .dpkg-new " ) | |
endswith ( filename , " .swp " ) ;
}
2010-04-06 23:53:02 +04:00
int fd_nonblock ( int fd , bool nonblock ) {
int flags ;
assert ( fd > = 0 ) ;
if ( ( flags = fcntl ( fd , F_GETFL , 0 ) ) < 0 )
return - errno ;
if ( nonblock )
flags | = O_NONBLOCK ;
else
flags & = ~ O_NONBLOCK ;
if ( fcntl ( fd , F_SETFL , flags ) < 0 )
return - errno ;
return 0 ;
}
int fd_cloexec ( int fd , bool cloexec ) {
int flags ;
assert ( fd > = 0 ) ;
if ( ( flags = fcntl ( fd , F_GETFD , 0 ) ) < 0 )
return - errno ;
if ( cloexec )
flags | = FD_CLOEXEC ;
else
flags & = ~ FD_CLOEXEC ;
if ( fcntl ( fd , F_SETFD , flags ) < 0 )
return - errno ;
return 0 ;
}
2010-04-07 01:35:59 +04:00
int close_all_fds ( const int except [ ] , unsigned n_except ) {
DIR * d ;
struct dirent * de ;
int r = 0 ;
if ( ! ( d = opendir ( " /proc/self/fd " ) ) )
return - errno ;
while ( ( de = readdir ( d ) ) ) {
2010-04-07 18:39:07 +04:00
int fd = - 1 ;
2010-04-07 01:35:59 +04:00
2010-04-21 05:27:44 +04:00
if ( ignore_file ( de - > d_name ) )
2010-04-07 01:35:59 +04:00
continue ;
if ( ( r = safe_atoi ( de - > d_name , & fd ) ) < 0 )
goto finish ;
if ( fd < 3 )
continue ;
if ( fd = = dirfd ( d ) )
continue ;
if ( except ) {
bool found ;
unsigned i ;
found = false ;
for ( i = 0 ; i < n_except ; i + + )
if ( except [ i ] = = fd ) {
found = true ;
break ;
}
if ( found )
continue ;
}
2010-04-07 02:09:59 +04:00
if ( ( r = close_nointr ( fd ) ) < 0 ) {
/* Valgrind has its own FD and doesn't want to have it closed */
if ( errno ! = EBADF )
goto finish ;
}
2010-04-07 01:35:59 +04:00
}
2010-04-07 02:09:59 +04:00
r = 0 ;
2010-04-07 01:35:59 +04:00
finish :
closedir ( d ) ;
return r ;
}
2010-04-07 22:27:19 +04:00
bool chars_intersect ( const char * a , const char * b ) {
const char * p ;
/* Returns true if any of the chars in a are in b. */
for ( p = a ; * p ; p + + )
if ( strchr ( b , * p ) )
return true ;
return false ;
}
2010-04-10 06:38:49 +04:00
char * format_timestamp ( char * buf , size_t l , usec_t t ) {
struct tm tm ;
time_t sec ;
assert ( buf ) ;
assert ( l > 0 ) ;
if ( t < = 0 )
return NULL ;
sec = ( time_t ) t / USEC_PER_SEC ;
if ( strftime ( buf , l , " %a, %d %b %Y %H:%M:%S %z " , localtime_r ( & sec , & tm ) ) < = 0 )
return NULL ;
return buf ;
}
2010-04-10 19:41:34 +04:00
bool fstype_is_network ( const char * fstype ) {
static const char * const table [ ] = {
" cifs " ,
" smbfs " ,
" ncpfs " ,
" nfs " ,
" nfs4 "
} ;
unsigned i ;
for ( i = 0 ; i < ELEMENTSOF ( table ) ; i + + )
if ( streq ( table [ i ] , fstype ) )
return true ;
return false ;
}
2010-04-11 01:36:43 +04:00
int chvt ( int vt ) {
int fd , r = 0 ;
if ( ( fd = open ( " /dev/tty0 " , O_RDWR | O_NOCTTY | O_CLOEXEC ) ) < 0 )
return - errno ;
if ( vt < 0 ) {
int tiocl [ 2 ] = {
TIOCL_GETKMSGREDIRECT ,
0
} ;
if ( ioctl ( fd , TIOCLINUX , tiocl ) < 0 )
return - errno ;
vt = tiocl [ 0 ] < = 0 ? 1 : tiocl [ 0 ] ;
}
if ( ioctl ( fd , VT_ACTIVATE , vt ) < 0 )
r = - errno ;
2010-04-21 05:27:44 +04:00
close_nointr_nofail ( r ) ;
2010-04-11 01:36:43 +04:00
return r ;
}
2010-04-13 04:06:27 +04:00
int read_one_char ( FILE * f , char * ret , bool * need_nl ) {
struct termios old_termios , new_termios ;
char c ;
char line [ 1024 ] ;
assert ( f ) ;
assert ( ret ) ;
if ( tcgetattr ( fileno ( f ) , & old_termios ) > = 0 ) {
new_termios = old_termios ;
new_termios . c_lflag & = ~ ICANON ;
new_termios . c_cc [ VMIN ] = 1 ;
new_termios . c_cc [ VTIME ] = 0 ;
if ( tcsetattr ( fileno ( f ) , TCSADRAIN , & new_termios ) > = 0 ) {
size_t k ;
k = fread ( & c , 1 , 1 , f ) ;
tcsetattr ( fileno ( f ) , TCSADRAIN , & old_termios ) ;
if ( k < = 0 )
return - EIO ;
if ( need_nl )
* need_nl = c ! = ' \n ' ;
* ret = c ;
return 0 ;
}
}
if ( ! ( fgets ( line , sizeof ( line ) , f ) ) )
return - EIO ;
truncate_nl ( line ) ;
if ( strlen ( line ) ! = 1 )
return - EBADMSG ;
if ( need_nl )
* need_nl = false ;
* ret = line [ 0 ] ;
return 0 ;
}
int ask ( char * ret , const char * replies , const char * text , . . . ) {
assert ( ret ) ;
assert ( replies ) ;
assert ( text ) ;
for ( ; ; ) {
va_list ap ;
char c ;
int r ;
bool need_nl = true ;
va_start ( ap , text ) ;
vprintf ( text , ap ) ;
va_end ( ap ) ;
fflush ( stdout ) ;
if ( ( r = read_one_char ( stdin , & c , & need_nl ) ) < 0 ) {
if ( r = = - EBADMSG ) {
puts ( " Bad input, please try again. " ) ;
continue ;
}
putchar ( ' \n ' ) ;
return r ;
}
if ( need_nl )
putchar ( ' \n ' ) ;
if ( strchr ( replies , c ) ) {
* ret = c ;
return 0 ;
}
puts ( " Read unexpected character, please try again. " ) ;
}
}
int reset_terminal ( int fd ) {
struct termios termios ;
int r = 0 ;
assert ( fd > = 0 ) ;
2010-04-13 20:51:22 +04:00
/* Set terminal to some sane defaults */
2010-04-13 04:06:27 +04:00
if ( tcgetattr ( fd , & termios ) < 0 ) {
r = - errno ;
goto finish ;
}
2010-04-13 20:51:22 +04:00
/* We only reset the stuff that matters to the software. How
* hardware is set up we don ' t touch assuming that somebody
* else will do that for us */
termios . c_iflag & = ~ ( IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | IUCLC ) ;
2010-04-13 04:06:27 +04:00
termios . c_iflag | = ICRNL | IMAXBEL | IUTF8 ;
termios . c_oflag | = ONLCR ;
termios . c_cflag | = CREAD ;
termios . c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOPRT | ECHOKE ;
termios . c_cc [ VINTR ] = 03 ; /* ^C */
termios . c_cc [ VQUIT ] = 034 ; /* ^\ */
termios . c_cc [ VERASE ] = 0177 ;
termios . c_cc [ VKILL ] = 025 ; /* ^X */
termios . c_cc [ VEOF ] = 04 ; /* ^D */
termios . c_cc [ VSTART ] = 021 ; /* ^Q */
termios . c_cc [ VSTOP ] = 023 ; /* ^S */
termios . c_cc [ VSUSP ] = 032 ; /* ^Z */
termios . c_cc [ VLNEXT ] = 026 ; /* ^V */
termios . c_cc [ VWERASE ] = 027 ; /* ^W */
termios . c_cc [ VREPRINT ] = 022 ; /* ^R */
2010-04-13 20:51:22 +04:00
termios . c_cc [ VEOL ] = 0 ;
termios . c_cc [ VEOL2 ] = 0 ;
2010-04-13 04:06:27 +04:00
termios . c_cc [ VTIME ] = 0 ;
termios . c_cc [ VMIN ] = 1 ;
if ( tcsetattr ( fd , TCSANOW , & termios ) < 0 )
r = - errno ;
finish :
/* Just in case, flush all crap out */
tcflush ( fd , TCIOFLUSH ) ;
return r ;
}
int open_terminal ( const char * name , int mode ) {
int fd , r ;
if ( ( fd = open ( name , mode ) ) < 0 )
return - errno ;
if ( ( r = isatty ( fd ) ) < 0 ) {
close_nointr_nofail ( fd ) ;
return - errno ;
}
if ( ! r ) {
close_nointr_nofail ( fd ) ;
return - ENOTTY ;
}
return fd ;
}
int flush_fd ( int fd ) {
struct pollfd pollfd ;
zero ( pollfd ) ;
pollfd . fd = fd ;
pollfd . events = POLLIN ;
for ( ; ; ) {
char buf [ 1024 ] ;
ssize_t l ;
int r ;
if ( ( r = poll ( & pollfd , 1 , 0 ) ) < 0 ) {
if ( errno = = EINTR )
continue ;
return - errno ;
}
if ( r = = 0 )
return 0 ;
if ( ( l = read ( fd , buf , sizeof ( buf ) ) ) < 0 ) {
if ( errno = = EINTR )
continue ;
if ( errno = = EAGAIN )
return 0 ;
return - errno ;
}
if ( l < = 0 )
return 0 ;
}
}
int acquire_terminal ( const char * name , bool fail , bool force ) {
int fd = - 1 , notify = - 1 , r , wd ;
assert ( name ) ;
/* We use inotify to be notified when the tty is closed. We
* create the watch before checking if we can actually acquire
* it , so that we don ' t lose any event .
*
* Note : strictly speaking this actually watches for the
* device being closed , it does * not * really watch whether a
* tty loses its controlling process . However , unless some
* rogue process uses TIOCNOTTY on / dev / tty * after * closing
* its tty otherwise this will not become a problem . As long
* as the administrator makes sure not configure any service
* on the same tty as an untrusted user this should not be a
* problem . ( Which he probably should not do anyway . ) */
if ( ! fail & & ! force ) {
if ( ( notify = inotify_init1 ( IN_CLOEXEC ) ) < 0 ) {
r = - errno ;
goto fail ;
}
if ( ( wd = inotify_add_watch ( notify , name , IN_CLOSE ) ) < 0 ) {
r = - errno ;
goto fail ;
}
}
for ( ; ; ) {
if ( ( r = flush_fd ( notify ) ) < 0 )
goto fail ;
/* We pass here O_NOCTTY only so that we can check the return
* value TIOCSCTTY and have a reliable way to figure out if we
* successfully became the controlling process of the tty */
if ( ( fd = open_terminal ( name , O_RDWR | O_NOCTTY ) ) < 0 )
return - errno ;
/* First, try to get the tty */
if ( ( r = ioctl ( fd , TIOCSCTTY , force ) ) < 0 & &
( force | | fail | | errno ! = EPERM ) ) {
r = - errno ;
goto fail ;
}
if ( r > = 0 )
break ;
assert ( ! fail ) ;
assert ( ! force ) ;
assert ( notify > = 0 ) ;
for ( ; ; ) {
struct inotify_event e ;
ssize_t l ;
if ( ( l = read ( notify , & e , sizeof ( e ) ) ) ! = sizeof ( e ) ) {
if ( l < 0 ) {
if ( errno = = EINTR )
continue ;
r = - errno ;
} else
r = - EIO ;
goto fail ;
}
if ( e . wd ! = wd | | ! ( e . mask & IN_CLOSE ) ) {
r = - errno ;
goto fail ;
}
break ;
}
/* We close the tty fd here since if the old session
* ended our handle will be dead . It ' s important that
* we do this after sleeping , so that we don ' t enter
* an endless loop . */
close_nointr_nofail ( fd ) ;
}
if ( notify > = 0 )
2010-04-21 05:27:44 +04:00
close_nointr_nofail ( notify ) ;
2010-04-13 04:06:27 +04:00
if ( ( r = reset_terminal ( fd ) ) < 0 )
log_warning ( " Failed to reset terminal: %s " , strerror ( - r ) ) ;
return fd ;
fail :
if ( fd > = 0 )
2010-04-21 05:27:44 +04:00
close_nointr_nofail ( fd ) ;
2010-04-13 04:06:27 +04:00
if ( notify > = 0 )
2010-04-21 05:27:44 +04:00
close_nointr_nofail ( notify ) ;
2010-04-13 04:06:27 +04:00
return r ;
}
int release_terminal ( void ) {
int r = 0 , fd ;
if ( ( fd = open ( " /dev/tty " , O_RDWR ) ) < 0 )
return - errno ;
if ( ioctl ( fd , TIOCNOTTY ) < 0 )
r = - errno ;
close_nointr_nofail ( fd ) ;
return r ;
}
2010-04-13 04:36:19 +04:00
int ignore_signal ( int sig ) {
struct sigaction sa ;
zero ( sa ) ;
sa . sa_handler = SIG_IGN ;
sa . sa_flags = SA_RESTART ;
return sigaction ( sig , & sa , NULL ) ;
}
2010-04-17 01:24:39 +04:00
int close_pipe ( int p [ ] ) {
int a = 0 , b = 0 ;
assert ( p ) ;
if ( p [ 0 ] > = 0 ) {
a = close_nointr ( p [ 0 ] ) ;
p [ 0 ] = - 1 ;
}
if ( p [ 1 ] > = 0 ) {
b = close_nointr ( p [ 1 ] ) ;
p [ 1 ] = - 1 ;
}
return a < 0 ? a : b ;
}
ssize_t loop_read ( int fd , void * buf , size_t nbytes ) {
uint8_t * p ;
ssize_t n = 0 ;
assert ( fd > = 0 ) ;
assert ( buf ) ;
p = buf ;
while ( nbytes > 0 ) {
ssize_t k ;
if ( ( k = read ( fd , p , nbytes ) ) < = 0 ) {
if ( errno = = EINTR )
continue ;
if ( errno = = EAGAIN ) {
struct pollfd pollfd ;
zero ( pollfd ) ;
pollfd . fd = fd ;
pollfd . events = POLLIN ;
if ( poll ( & pollfd , 1 , - 1 ) < 0 ) {
if ( errno = = EINTR )
continue ;
return n > 0 ? n : - errno ;
}
if ( pollfd . revents ! = POLLIN )
return n > 0 ? n : - EIO ;
continue ;
}
return n > 0 ? n : ( k < 0 ? - errno : 0 ) ;
}
p + = k ;
nbytes - = k ;
n + = k ;
}
return n ;
}
int path_is_mount_point ( const char * t ) {
struct stat a , b ;
char * copy ;
if ( lstat ( t , & a ) < 0 ) {
if ( errno = = ENOENT )
return 0 ;
return - errno ;
}
if ( ! ( copy = strdup ( t ) ) )
return - ENOMEM ;
if ( lstat ( dirname ( copy ) , & b ) < 0 ) {
free ( copy ) ;
return - errno ;
}
free ( copy ) ;
return a . st_dev ! = b . st_dev ;
}
2010-01-30 03:52:32 +03:00
static const char * const ioprio_class_table [ ] = {
[ IOPRIO_CLASS_NONE ] = " none " ,
[ IOPRIO_CLASS_RT ] = " realtime " ,
[ IOPRIO_CLASS_BE ] = " best-effort " ,
[ IOPRIO_CLASS_IDLE ] = " idle "
} ;
DEFINE_STRING_TABLE_LOOKUP ( ioprio_class , int ) ;
static const char * const sigchld_code_table [ ] = {
[ CLD_EXITED ] = " exited " ,
[ CLD_KILLED ] = " killed " ,
[ CLD_DUMPED ] = " dumped " ,
[ CLD_TRAPPED ] = " trapped " ,
[ CLD_STOPPED ] = " stopped " ,
[ CLD_CONTINUED ] = " continued " ,
} ;
DEFINE_STRING_TABLE_LOOKUP ( sigchld_code , int ) ;
static const char * const log_facility_table [ LOG_NFACILITIES ] = {
[ LOG_FAC ( LOG_KERN ) ] = " kern " ,
[ LOG_FAC ( LOG_USER ) ] = " user " ,
[ LOG_FAC ( LOG_MAIL ) ] = " mail " ,
[ LOG_FAC ( LOG_DAEMON ) ] = " daemon " ,
[ LOG_FAC ( LOG_AUTH ) ] = " auth " ,
[ LOG_FAC ( LOG_SYSLOG ) ] = " syslog " ,
[ LOG_FAC ( LOG_LPR ) ] = " lpr " ,
[ LOG_FAC ( LOG_NEWS ) ] = " news " ,
[ LOG_FAC ( LOG_UUCP ) ] = " uucp " ,
[ LOG_FAC ( LOG_CRON ) ] = " cron " ,
[ LOG_FAC ( LOG_AUTHPRIV ) ] = " authpriv " ,
[ LOG_FAC ( LOG_FTP ) ] = " ftp " ,
[ LOG_FAC ( LOG_LOCAL0 ) ] = " local0 " ,
[ LOG_FAC ( LOG_LOCAL1 ) ] = " local1 " ,
[ LOG_FAC ( LOG_LOCAL2 ) ] = " local2 " ,
[ LOG_FAC ( LOG_LOCAL3 ) ] = " local3 " ,
[ LOG_FAC ( LOG_LOCAL4 ) ] = " local4 " ,
[ LOG_FAC ( LOG_LOCAL5 ) ] = " local5 " ,
[ LOG_FAC ( LOG_LOCAL6 ) ] = " local6 " ,
[ LOG_FAC ( LOG_LOCAL7 ) ] = " local7 "
} ;
DEFINE_STRING_TABLE_LOOKUP ( log_facility , int ) ;
static const char * const log_level_table [ ] = {
[ LOG_EMERG ] = " emerg " ,
[ LOG_ALERT ] = " alert " ,
[ LOG_CRIT ] = " crit " ,
[ LOG_ERR ] = " err " ,
[ LOG_WARNING ] = " warning " ,
[ LOG_NOTICE ] = " notice " ,
[ LOG_INFO ] = " info " ,
[ LOG_DEBUG ] = " debug "
} ;
DEFINE_STRING_TABLE_LOOKUP ( log_level , int ) ;
static const char * const sched_policy_table [ ] = {
[ SCHED_OTHER ] = " other " ,
[ SCHED_BATCH ] = " batch " ,
[ SCHED_IDLE ] = " idle " ,
[ SCHED_FIFO ] = " fifo " ,
[ SCHED_RR ] = " rr "
} ;
DEFINE_STRING_TABLE_LOOKUP ( sched_policy , int ) ;
static const char * const rlimit_table [ ] = {
[ RLIMIT_CPU ] = " LimitCPU " ,
[ RLIMIT_FSIZE ] = " LimitFSIZE " ,
[ RLIMIT_DATA ] = " LimitDATA " ,
[ RLIMIT_STACK ] = " LimitSTACK " ,
[ RLIMIT_CORE ] = " LimitCORE " ,
[ RLIMIT_RSS ] = " LimitRSS " ,
[ RLIMIT_NOFILE ] = " LimitNOFILE " ,
[ RLIMIT_AS ] = " LimitAS " ,
[ RLIMIT_NPROC ] = " LimitNPROC " ,
[ RLIMIT_MEMLOCK ] = " LimitMEMLOCK " ,
[ RLIMIT_LOCKS ] = " LimitLOCKS " ,
[ RLIMIT_SIGPENDING ] = " LimitSIGPENDING " ,
[ RLIMIT_MSGQUEUE ] = " LimitMSGQUEUE " ,
[ RLIMIT_NICE ] = " LimitNICE " ,
[ RLIMIT_RTPRIO ] = " LimitRTPRIO " ,
[ RLIMIT_RTTIME ] = " LimitRTTIME "
} ;
DEFINE_STRING_TABLE_LOOKUP ( rlimit , int ) ;