2009-11-18 02:42:52 +03:00
/*-*- Mode: C; c-basic-offset: 8 -*-*/
# 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>
2009-11-18 02:42:52 +03:00
# include "macro.h"
# include "util.h"
usec_t now ( clockid_t clock ) {
struct timespec ts ;
assert_se ( clock_gettime ( clock , & ts ) = = 0 ) ;
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-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 ) {
/* like close_nointr() but cannot fail, and guarantees errno
* is unchanged */
assert_se ( close_nointr ( fd ) = = 0 ) ;
}
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. */
char * split_spaces ( 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 ) ;
* l = strcspn ( current , WHITESPACE ) ;
* 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 ;
}
const char * sigchld_code ( int code ) {
if ( code = = CLD_EXITED )
return " exited " ;
else if ( code = = CLD_KILLED )
return " killed " ;
else if ( code = = CLD_DUMPED )
return " dumped " ;
else if ( code = = CLD_TRAPPED )
return " trapped " ;
else if ( code = = CLD_STOPPED )
return " stopped " ;
else if ( code = = CLD_CONTINUED )
return " continued " ;
return " unknown " ;
}
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 ;
char t [ 64 ] , * c ;
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
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 ) ;
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
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 ;
}
return 0 ;
}
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 ;
}
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 ;
}