2012-06-29 13:59:09 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
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 Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 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
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
# include <string.h>
# include <unistd.h>
# include <errno.h>
# include <fcntl.h>
# include <sys/types.h>
# include <sys/syscall.h>
# include "util.h"
static inline pid_t gettid ( void ) {
return ( pid_t ) syscall ( SYS_gettid ) ;
}
size_t page_size ( void ) {
static __thread size_t pgsz = 0 ;
long r ;
if ( _likely_ ( pgsz > 0 ) )
return pgsz ;
assert_se ( ( r = sysconf ( _SC_PAGESIZE ) ) > 0 ) ;
pgsz = ( size_t ) r ;
return pgsz ;
}
bool endswith ( const char * s , const char * postfix ) {
size_t sl , pl ;
assert ( s ) ;
assert ( postfix ) ;
sl = strlen ( s ) ;
pl = strlen ( postfix ) ;
if ( pl = = 0 )
return true ;
if ( sl < pl )
return false ;
return memcmp ( s + sl - pl , postfix , pl ) = = 0 ;
}
int close_nointr ( int fd ) {
assert ( fd > = 0 ) ;
for ( ; ; ) {
int r ;
r = close ( fd ) ;
if ( r > = 0 )
return r ;
if ( errno ! = EINTR )
return - errno ;
}
}
void close_nointr_nofail ( int fd ) {
int saved_errno = errno ;
/* like close_nointr() but cannot fail, and guarantees errno
* is unchanged */
assert_se ( close_nointr ( fd ) = = 0 ) ;
errno = saved_errno ;
}
int open_terminal ( const char * name , int mode ) {
int fd , r ;
unsigned c = 0 ;
/*
* If a TTY is in the process of being closed opening it might
* cause EIO . This is horribly awful , but unlikely to be
* changed in the kernel . Hence we work around this problem by
* retrying a couple of times .
*
* https : //bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245
*/
for ( ; ; ) {
if ( ( fd = open ( name , mode ) ) > = 0 )
break ;
if ( errno ! = EIO )
return - errno ;
if ( c > = 20 )
return - errno ;
usleep ( 50 * USEC_PER_MSEC ) ;
c + + ;
}
if ( fd < 0 )
return - errno ;
if ( ( r = isatty ( fd ) ) < 0 ) {
close_nointr_nofail ( fd ) ;
return - errno ;
}
if ( ! r ) {
close_nointr_nofail ( fd ) ;
return - ENOTTY ;
}
return fd ;
}
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 ;
}
bool is_main_thread ( void ) {
static __thread int cached = 0 ;
if ( _unlikely_ ( cached = = 0 ) )
cached = getpid ( ) = = gettid ( ) ? 1 : - 1 ;
return cached > 0 ;
}
int safe_atou ( const char * s , unsigned * ret_u ) {
char * x = NULL ;
unsigned long l ;
assert ( s ) ;
assert ( ret_u ) ;
errno = 0 ;
l = strtoul ( s , & x , 0 ) ;
if ( ! x | | * x | | errno )
return errno ? - errno : - EINVAL ;
if ( ( unsigned long ) ( unsigned ) l ! = l )
return - ERANGE ;
* ret_u = ( unsigned ) l ;
return 0 ;
}
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 ) ;
2013-06-06 13:06:55 +04:00
char * strnappend ( const char * s , const char * suffix , size_t b ) {
size_t a ;
char * r ;
if ( ! s & & ! suffix )
return strdup ( " " ) ;
if ( ! s )
return strndup ( suffix , b ) ;
if ( ! suffix )
return strdup ( s ) ;
assert ( s ) ;
assert ( suffix ) ;
a = strlen ( s ) ;
if ( b > ( ( size_t ) - 1 ) - a )
return NULL ;
r = new ( char , a + b + 1 ) ;
if ( ! r )
return NULL ;
memcpy ( r , s , a ) ;
memcpy ( r + a , suffix , b ) ;
r [ a + b ] = 0 ;
return r ;
}
char * strappend ( const char * s , const char * suffix ) {
return strnappend ( s , suffix , suffix ? strlen ( suffix ) : 0 ) ;
}
char * strjoin ( const char * x , . . . ) {
va_list ap ;
size_t l ;
char * r , * p ;
va_start ( ap , x ) ;
if ( x ) {
l = strlen ( x ) ;
for ( ; ; ) {
const char * t ;
size_t n ;
t = va_arg ( ap , const char * ) ;
if ( ! t )
break ;
n = strlen ( t ) ;
if ( n > ( ( size_t ) - 1 ) - l ) {
va_end ( ap ) ;
return NULL ;
}
l + = n ;
}
} else
l = 0 ;
va_end ( ap ) ;
r = new ( char , l + 1 ) ;
if ( ! r )
return NULL ;
if ( x ) {
p = stpcpy ( r , x ) ;
va_start ( ap , x ) ;
for ( ; ; ) {
const char * t ;
t = va_arg ( ap , const char * ) ;
if ( ! t )
break ;
p = stpcpy ( p , t ) ;
}
va_end ( ap ) ;
} else
r [ 0 ] = 0 ;
return r ;
}