2010-08-14 21:59:25 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2009-11-18 02:42:52 +03:00
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>
2010-05-09 20:13:02 +04:00
# include <ctype.h>
2010-06-16 23:54:17 +04:00
# include <sys/prctl.h>
2010-06-18 04:28:35 +04:00
# include <sys/utsname.h>
# include <pwd.h>
2010-07-01 02:29:17 +04:00
# include <netinet/ip.h>
2010-07-12 23:40:43 +04:00
# include <linux/kd.h>
2010-08-12 01:31:07 +04:00
# include <dlfcn.h>
2010-09-15 16:37:16 +04:00
# include <sys/wait.h>
2011-04-12 23:08:44 +04:00
# include <sys/capability.h>
2011-05-24 22:23:07 +04:00
# include <sys/time.h>
# include <linux/rtc.h>
2011-07-07 04:07:39 +04:00
# include <glob.h>
2011-07-23 03:17:59 +04:00
# include <grp.h>
2011-10-07 23:06:39 +04:00
# include <sys/mman.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"
2010-08-12 00:58:34 +04:00
# include "label.h"
2010-08-19 05:18:49 +04:00
# include "exit-status.h"
2011-02-15 02:30:11 +03:00
# include "hashmap.h"
Systemd is causing mislabeled devices to be created and then attempting to read them.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 07/28/2010 05:57 AM, Kay Sievers wrote:
> On Wed, Jul 28, 2010 at 11:43, Lennart Poettering
> <lennart@poettering.net> wrote:
>> On Mon, 26.07.10 16:42, Daniel J Walsh (dwalsh@redhat.com) wrote:
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>> type=1400 audit(1280174589.476:7): avc: denied { read } for pid=1
>>> comm="systemd" name="autofs" dev=devtmpfs ino=9482
>>> scontext=system_u:system_r:init_t:s0
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>> type=1400 audit(1280174589.476:8): avc: denied { read } for pid=1
>>> comm="systemd" name="autofs" dev=devtmpfs ino=9482
>>> scontext=system_u:system_r:init_t:s0
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>>
>>> Lennart, we talked about this earlier. I think this is caused by the
>>> modprobe calls to create /dev/autofs. Since udev is not created at the
>>> point that init loads the kernel modules, the devices get created with
>>> the wrong label. Once udev starts the labels get fixed.
>>>
>>> I can allow init_t to read device_t chr_files.
>>
>> Hmm, I think a cleaner fix would be to make systemd relabel this device
>> properly before accessing it? Given that this is only one device this
>> should not be a problem for us to maintain, I think? How would the
>> fixing of the label work? Would we have to spawn restorecon for this, or
>> can we actually do this in C without too much work?
>
> I guess we can just do what udev is doing, and call setfilecon(), with
> a context of an earlier matchpathcon().
>
> Kay
> _______________________________________________
> systemd-devel mailing list
> systemd-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Here is the updated patch with a fix for the labeling of /dev/autofs
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.14 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/
iEYEARECAAYFAkxQMyoACgkQrlYvE4MpobNviACfWgxsjW2xzz1qznFex8RVAQHf
gIEAmwRmRcLvGqYtwQaZ3WKIg8wmrwNk
=pC2e
2010-07-28 17:39:54 +04:00
2011-06-30 06:16:10 +04:00
int saved_argc = 0 ;
char * * saved_argv = NULL ;
2011-03-18 05:03:41 +03:00
size_t page_size ( void ) {
static __thread size_t pgsz = 0 ;
long r ;
2011-10-07 23:06:39 +04:00
if ( _likely_ ( pgsz > 0 ) )
2011-03-18 05:03:41 +03:00
return pgsz ;
assert_se ( ( r = sysconf ( _SC_PAGESIZE ) ) > 0 ) ;
pgsz = ( size_t ) r ;
return pgsz ;
}
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 ) ;
}
2010-07-01 02:26:44 +04:00
dual_timestamp * dual_timestamp_get ( dual_timestamp * ts ) {
2010-05-24 03:45:54 +04:00
assert ( ts ) ;
ts - > realtime = now ( CLOCK_REALTIME ) ;
ts - > monotonic = now ( CLOCK_MONOTONIC ) ;
return ts ;
}
2011-06-17 17:59:18 +04:00
dual_timestamp * dual_timestamp_from_realtime ( dual_timestamp * ts , usec_t u ) {
int64_t delta ;
assert ( ts ) ;
ts - > realtime = u ;
if ( u = = 0 )
ts - > monotonic = 0 ;
else {
delta = ( int64_t ) now ( CLOCK_REALTIME ) - ( int64_t ) u ;
ts - > monotonic = now ( CLOCK_MONOTONIC ) ;
if ( ( int64_t ) ts - > monotonic > delta )
ts - > monotonic - = delta ;
else
ts - > monotonic = 0 ;
}
return ts ;
}
2009-11-18 02:42:52 +03:00
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 ) ;
2010-04-23 22:29:15 +04:00
if ( pl = = 0 )
return true ;
2009-11-18 02:42:52 +03:00
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 ) ;
2010-04-23 22:29:15 +04:00
if ( pl = = 0 )
return true ;
2009-11-18 02:42:52 +03:00
if ( sl < pl )
return false ;
return memcmp ( s , prefix , pl ) = = 0 ;
}
2010-05-09 20:13:02 +04:00
bool startswith_no_case ( const char * s , const char * prefix ) {
size_t sl , pl ;
unsigned i ;
assert ( s ) ;
assert ( prefix ) ;
sl = strlen ( s ) ;
pl = strlen ( prefix ) ;
if ( pl = = 0 )
return true ;
if ( sl < pl )
return false ;
for ( i = 0 ; i < pl ; + + i ) {
if ( tolower ( s [ i ] ) ! = tolower ( prefix [ i ] ) )
return false ;
}
return true ;
}
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 ;
2010-04-23 22:29:15 +04:00
if ( wl = = 0 )
return true ;
2010-01-30 03:52:44 +03:00
if ( memcmp ( s , word , wl ) ! = 0 )
return false ;
2010-04-23 22:29:15 +04:00
return s [ wl ] = = 0 | |
strchr ( WHITESPACE , s [ wl ] ) ;
2010-01-30 03:52:44 +03:00
}
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 ;
2011-06-15 12:16:09 +04:00
r = close ( fd ) ;
if ( r > = 0 )
2009-11-18 02:42:52 +03:00
return r ;
if ( errno ! = EINTR )
2011-06-15 12:16:09 +04:00
return - errno ;
2009-11-18 02:42:52 +03:00
}
}
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
}
2010-06-16 23:54:17 +04:00
void close_many ( const int fds [ ] , unsigned n_fd ) {
unsigned i ;
for ( i = 0 ; i < n_fd ; i + + )
close_nointr_nofail ( fds [ i ] ) ;
}
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 ;
}
2010-06-18 00:50:35 +04:00
int parse_pid ( const char * s , pid_t * ret_pid ) {
2011-01-22 03:47:37 +03:00
unsigned long ul = 0 ;
2010-06-18 00:50:35 +04:00
pid_t pid ;
int r ;
assert ( s ) ;
assert ( ret_pid ) ;
if ( ( r = safe_atolu ( s , & ul ) ) < 0 )
return r ;
pid = ( pid_t ) ul ;
if ( ( unsigned long ) pid ! = ul )
return - ERANGE ;
if ( pid < = 0 )
return - ERANGE ;
* ret_pid = pid ;
return 0 ;
}
2011-07-22 23:01:15 +04:00
int parse_uid ( const char * s , uid_t * ret_uid ) {
unsigned long ul = 0 ;
uid_t uid ;
int r ;
assert ( s ) ;
assert ( ret_uid ) ;
if ( ( r = safe_atolu ( s , & ul ) ) < 0 )
return r ;
uid = ( uid_t ) ul ;
if ( ( unsigned long ) uid ! = ul )
return - ERANGE ;
* ret_uid = uid ;
return 0 ;
}
2009-11-19 02:46:47 +03:00
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_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 ) {
2010-07-07 22:57:47 +04:00
char * current , * e ;
bool escaped = false ;
2010-01-26 06:18:44 +03:00
current = * state ? * state : ( char * ) c ;
if ( ! * current | | * c = = 0 )
return NULL ;
current + = strspn ( current , WHITESPACE ) ;
if ( * current = = ' \' ' ) {
current + + ;
2010-07-07 22:57:47 +04:00
for ( e = current ; * e ; e + + ) {
if ( escaped )
escaped = false ;
else if ( * e = = ' \\ ' )
escaped = true ;
else if ( * e = = ' \' ' )
break ;
}
* l = e - current ;
* state = * e = = 0 ? e : e + 1 ;
2010-01-26 06:18:44 +03:00
} else if ( * current = = ' \" ' ) {
current + + ;
2010-07-07 22:57:47 +04:00
for ( e = current ; * e ; e + + ) {
if ( escaped )
escaped = false ;
else if ( * e = = ' \\ ' )
escaped = true ;
else if ( * e = = ' \" ' )
break ;
}
* l = e - current ;
* state = * e = = 0 ? e : e + 1 ;
2010-01-26 06:18:44 +03:00
} else {
2010-07-07 22:57:47 +04:00
for ( e = current ; * e ; e + + ) {
if ( escaped )
escaped = false ;
else if ( * e = = ' \\ ' )
escaped = true ;
else if ( strchr ( WHITESPACE , * e ) )
break ;
}
* l = e - current ;
* state = e ;
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 ;
2011-04-07 20:48:50 +04:00
char fn [ PATH_MAX ] , line [ LINE_MAX ] , * p ;
2010-06-19 06:35:52 +04:00
long unsigned ppid ;
2010-01-26 06:18:44 +03:00
2011-04-16 03:45:45 +04:00
assert ( pid > 0 ) ;
2010-01-26 06:18:44 +03:00
assert ( _ppid ) ;
2010-06-19 06:35:52 +04:00
assert_se ( snprintf ( fn , sizeof ( fn ) - 1 , " /proc/%lu/stat " , ( unsigned long ) pid ) < ( int ) ( sizeof ( fn ) - 1 ) ) ;
2011-04-16 03:45:45 +04:00
char_array_0 ( fn ) ;
2010-01-26 06:18:44 +03:00
2011-07-04 01:20:39 +04:00
if ( ! ( f = fopen ( fn , " re " ) ) )
2010-01-26 06:18:44 +03:00
return - errno ;
if ( ! ( fgets ( line , sizeof ( line ) , f ) ) ) {
2011-12-03 03:41:34 +04:00
r = feof ( f ) ? - EIO : - errno ;
2010-01-26 06:18:44 +03:00
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 */
2010-06-19 06:35:52 +04:00
" %lu " , /* ppid */
2010-01-26 06:18:44 +03:00
& ppid ) ! = 1 )
return - EIO ;
2010-06-19 06:35:52 +04:00
if ( ( long unsigned ) ( pid_t ) ppid ! = ppid )
2010-01-26 06:18:44 +03:00
return - ERANGE ;
* _ppid = ( pid_t ) ppid ;
return 0 ;
}
2011-04-16 04:02:54 +04:00
int get_starttime_of_pid ( pid_t pid , unsigned long long * st ) {
int r ;
FILE * f ;
char fn [ PATH_MAX ] , line [ LINE_MAX ] , * p ;
assert ( pid > 0 ) ;
assert ( st ) ;
assert_se ( snprintf ( fn , sizeof ( fn ) - 1 , " /proc/%lu/stat " , ( unsigned long ) pid ) < ( int ) ( sizeof ( fn ) - 1 ) ) ;
char_array_0 ( fn ) ;
2011-07-04 01:20:39 +04:00
if ( ! ( f = fopen ( fn , " re " ) ) )
2011-04-16 04:02:54 +04:00
return - errno ;
if ( ! ( fgets ( line , sizeof ( line ) , f ) ) ) {
2011-12-03 03:41:34 +04:00
r = feof ( f ) ? - EIO : - errno ;
2011-04-16 04:02:54 +04:00
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 */
" %*d " /* ppid */
" %*d " /* pgrp */
" %*d " /* session */
" %*d " /* tty_nr */
" %*d " /* tpgid */
" %*u " /* flags */
" %*u " /* minflt */
" %*u " /* cminflt */
" %*u " /* majflt */
" %*u " /* cmajflt */
" %*u " /* utime */
" %*u " /* stime */
" %*d " /* cutime */
" %*d " /* cstime */
" %*d " /* priority */
" %*d " /* nice */
" %*d " /* num_threads */
" %*d " /* itrealvalue */
" %llu " /* starttime */ ,
st ) ! = 1 )
return - EIO ;
return 0 ;
}
2010-01-26 06:18:44 +03:00
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 ;
2011-06-15 17:35:23 +04:00
errno = 0 ;
2010-01-26 06:18:44 +03:00
if ( fputs ( line , f ) < 0 ) {
r = - errno ;
goto finish ;
}
2010-11-18 23:52:26 +03:00
if ( ! endswith ( line , " \n " ) )
fputc ( ' \n ' , f ) ;
2011-04-04 05:36:42 +04:00
fflush ( f ) ;
if ( ferror ( f ) ) {
if ( errno ! = 0 )
r = - errno ;
else
r = - EIO ;
} else
r = 0 ;
2010-01-26 06:18:44 +03:00
finish :
fclose ( f ) ;
return r ;
}
2011-06-15 17:35:23 +04:00
int fchmod_umask ( int fd , mode_t m ) {
mode_t u ;
int r ;
u = umask ( 0777 ) ;
r = fchmod ( fd , m & ( ~ u ) ) < 0 ? - errno : 0 ;
umask ( u ) ;
return r ;
}
int write_one_line_file_atomic ( const char * fn , const char * line ) {
FILE * f ;
int r ;
char * p ;
assert ( fn ) ;
assert ( line ) ;
r = fopen_temporary ( fn , & f , & p ) ;
if ( r < 0 )
return r ;
fchmod_umask ( fileno ( f ) , 0644 ) ;
errno = 0 ;
if ( fputs ( line , f ) < 0 ) {
r = - errno ;
goto finish ;
}
if ( ! endswith ( line , " \n " ) )
fputc ( ' \n ' , f ) ;
fflush ( f ) ;
if ( ferror ( f ) ) {
if ( errno ! = 0 )
r = - errno ;
else
r = - EIO ;
} else {
if ( rename ( p , fn ) < 0 )
r = - errno ;
else
r = 0 ;
}
finish :
if ( r < 0 )
unlink ( p ) ;
fclose ( f ) ;
free ( p ) ;
return r ;
}
2010-01-26 06:18:44 +03:00
int read_one_line_file ( const char * fn , char * * line ) {
FILE * f ;
int r ;
2010-09-16 02:36:41 +04:00
char t [ LINE_MAX ] , * c ;
2010-01-26 06:18:44 +03:00
assert ( fn ) ;
assert ( line ) ;
2012-02-11 03:27:12 +04:00
f = fopen ( fn , " re " ) ;
if ( ! f )
2010-01-26 06:18:44 +03:00
return - errno ;
2012-02-11 03:27:12 +04:00
if ( ! fgets ( t , sizeof ( t ) , f ) ) {
if ( ferror ( f ) ) {
r = - errno ;
goto finish ;
}
t [ 0 ] = 0 ;
2010-01-26 06:18:44 +03:00
}
2012-02-11 03:27:12 +04:00
c = strdup ( t ) ;
if ( ! c ) {
2010-01-26 06:18:44 +03:00
r = - ENOMEM ;
goto finish ;
}
2011-04-16 03:48:02 +04:00
truncate_nl ( c ) ;
2010-01-26 06:18:44 +03:00
* line = c ;
r = 0 ;
finish :
fclose ( f ) ;
return r ;
}
2010-01-26 09:02:51 +03:00
2011-06-15 17:35:23 +04:00
int read_full_file ( const char * fn , char * * contents , size_t * size ) {
2010-09-16 02:36:41 +04:00
FILE * f ;
int r ;
size_t n , l ;
char * buf = NULL ;
struct stat st ;
if ( ! ( f = fopen ( fn , " re " ) ) )
return - errno ;
if ( fstat ( fileno ( f ) , & st ) < 0 ) {
r = - errno ;
goto finish ;
}
2011-06-15 17:35:23 +04:00
/* Safety check */
if ( st . st_size > 4 * 1024 * 1024 ) {
r = - E2BIG ;
goto finish ;
}
2010-09-16 02:36:41 +04:00
n = st . st_size > 0 ? st . st_size : LINE_MAX ;
l = 0 ;
for ( ; ; ) {
char * t ;
size_t k ;
if ( ! ( t = realloc ( buf , n + 1 ) ) ) {
r = - ENOMEM ;
goto finish ;
}
buf = t ;
k = fread ( buf + l , 1 , n - l , f ) ;
if ( k < = 0 ) {
if ( ferror ( f ) ) {
r = - errno ;
goto finish ;
}
break ;
}
l + = k ;
n * = 2 ;
/* Safety check */
if ( n > 4 * 1024 * 1024 ) {
r = - E2BIG ;
goto finish ;
}
}
2011-09-23 03:44:36 +04:00
buf [ l ] = 0 ;
2010-09-16 02:36:41 +04:00
* contents = buf ;
buf = NULL ;
2011-06-15 17:35:23 +04:00
if ( size )
* size = l ;
2010-09-16 02:36:41 +04:00
r = 0 ;
finish :
fclose ( f ) ;
free ( buf ) ;
return r ;
}
int parse_env_file (
const char * fname ,
2010-09-29 17:13:04 +04:00
const char * separator , . . . ) {
2010-09-16 02:36:41 +04:00
2010-09-21 03:51:23 +04:00
int r = 0 ;
2011-08-01 04:39:22 +04:00
char * contents = NULL , * p ;
2010-09-16 02:36:41 +04:00
assert ( fname ) ;
2010-09-29 17:13:04 +04:00
assert ( separator ) ;
2010-09-16 02:36:41 +04:00
2011-06-15 17:35:23 +04:00
if ( ( r = read_full_file ( fname , & contents , NULL ) ) < 0 )
2010-09-16 02:36:41 +04:00
return r ;
p = contents ;
for ( ; ; ) {
const char * key = NULL ;
2010-09-29 17:13:04 +04:00
p + = strspn ( p , separator ) ;
2010-09-16 02:36:41 +04:00
p + = strspn ( p , WHITESPACE ) ;
if ( ! * p )
break ;
if ( ! strchr ( COMMENTS , * p ) ) {
va_list ap ;
char * * value ;
2010-09-29 17:13:04 +04:00
va_start ( ap , separator ) ;
2010-09-16 02:36:41 +04:00
while ( ( key = va_arg ( ap , char * ) ) ) {
size_t n ;
char * v ;
value = va_arg ( ap , char * * ) ;
n = strlen ( key ) ;
if ( strncmp ( p , key , n ) ! = 0 | |
p [ n ] ! = ' = ' )
continue ;
p + = n + 1 ;
2010-09-29 17:13:04 +04:00
n = strcspn ( p , separator ) ;
2010-09-16 02:36:41 +04:00
if ( n > = 2 & &
2010-09-16 03:57:59 +04:00
strchr ( QUOTES , p [ 0 ] ) & &
p [ n - 1 ] = = p [ 0 ] )
2010-09-16 02:36:41 +04:00
v = strndup ( p + 1 , n - 2 ) ;
else
v = strndup ( p , n ) ;
if ( ! v ) {
r = - ENOMEM ;
va_end ( ap ) ;
goto fail ;
}
2010-09-29 01:41:09 +04:00
if ( v [ 0 ] = = ' \0 ' ) {
/* return empty value strings as NULL */
free ( v ) ;
v = NULL ;
}
2010-09-16 02:36:41 +04:00
free ( * value ) ;
* value = v ;
p + = n ;
2010-09-21 03:51:23 +04:00
r + + ;
2010-09-16 02:36:41 +04:00
break ;
}
va_end ( ap ) ;
}
if ( ! key )
2010-09-29 17:13:04 +04:00
p + = strcspn ( p , separator ) ;
2010-09-16 02:36:41 +04:00
}
fail :
free ( contents ) ;
return r ;
}
2011-03-04 05:44:43 +03:00
int load_env_file (
const char * fname ,
char * * * rl ) {
FILE * f ;
2012-02-29 17:42:49 +04:00
char * * m = NULL ;
2011-03-04 05:44:43 +03:00
int r ;
assert ( fname ) ;
assert ( rl ) ;
if ( ! ( f = fopen ( fname , " re " ) ) )
return - errno ;
while ( ! feof ( f ) ) {
char l [ LINE_MAX ] , * p , * u ;
char * * t ;
if ( ! fgets ( l , sizeof ( l ) , f ) ) {
if ( feof ( f ) )
break ;
r = - errno ;
goto finish ;
}
p = strstrip ( l ) ;
if ( ! * p )
continue ;
if ( strchr ( COMMENTS , * p ) )
continue ;
if ( ! ( u = normalize_env_assignment ( p ) ) ) {
log_error ( " Out of memory " ) ;
r = - ENOMEM ;
goto finish ;
}
t = strv_append ( m , u ) ;
free ( u ) ;
if ( ! t ) {
log_error ( " Out of memory " ) ;
r = - ENOMEM ;
goto finish ;
}
strv_free ( m ) ;
m = t ;
}
r = 0 ;
* rl = m ;
m = NULL ;
finish :
if ( f )
fclose ( f ) ;
strv_free ( m ) ;
return r ;
}
2011-04-16 04:02:54 +04:00
int write_env_file ( const char * fname , char * * l ) {
2011-06-15 17:35:23 +04:00
char * * i , * p ;
2011-04-16 04:02:54 +04:00
FILE * f ;
int r ;
2011-06-15 17:35:23 +04:00
r = fopen_temporary ( fname , & f , & p ) ;
if ( r < 0 )
return r ;
2011-04-16 04:02:54 +04:00
2011-06-15 17:35:23 +04:00
fchmod_umask ( fileno ( f ) , 0644 ) ;
errno = 0 ;
2011-04-16 04:02:54 +04:00
STRV_FOREACH ( i , l ) {
fputs ( * i , f ) ;
fputc ( ' \n ' , f ) ;
}
fflush ( f ) ;
2011-06-15 17:35:23 +04:00
if ( ferror ( f ) ) {
if ( errno ! = 0 )
r = - errno ;
else
r = - EIO ;
} else {
if ( rename ( p , fname ) < 0 )
r = - errno ;
else
r = 0 ;
}
if ( r < 0 )
unlink ( p ) ;
2011-04-16 04:02:54 +04:00
fclose ( f ) ;
2011-06-15 17:35:23 +04:00
free ( p ) ;
2011-04-16 04:02:54 +04:00
return r ;
}
2010-04-08 05:22:25 +04:00
char * truncate_nl ( char * s ) {
assert ( s ) ;
s [ strcspn ( s , NEWLINE ) ] = 0 ;
return s ;
}
2011-10-07 23:06:39 +04:00
int get_process_comm ( pid_t pid , char * * name ) {
2010-04-08 05:22:25 +04:00
int r ;
assert ( name ) ;
2011-10-07 23:06:39 +04:00
if ( pid = = 0 )
r = read_one_line_file ( " /proc/self/comm " , name ) ;
else {
char * p ;
if ( asprintf ( & p , " /proc/%lu/comm " , ( unsigned long ) pid ) < 0 )
return - ENOMEM ;
2010-04-08 05:22:25 +04:00
2011-10-07 23:06:39 +04:00
r = read_one_line_file ( p , name ) ;
free ( p ) ;
}
2010-04-08 05:22:25 +04:00
2011-10-07 23:06:39 +04:00
return r ;
2010-04-08 05:22:25 +04:00
}
2011-10-07 23:06:39 +04:00
int get_process_cmdline ( pid_t pid , size_t max_length , bool comm_fallback , char * * line ) {
char * r , * k ;
2010-07-05 05:06:02 +04:00
int c ;
bool space = false ;
size_t left ;
FILE * f ;
assert ( max_length > 0 ) ;
assert ( line ) ;
2011-10-07 23:06:39 +04:00
if ( pid = = 0 )
f = fopen ( " /proc/self/cmdline " , " re " ) ;
else {
char * p ;
if ( asprintf ( & p , " /proc/%lu/cmdline " , ( unsigned long ) pid ) < 0 )
return - ENOMEM ;
2010-07-05 05:06:02 +04:00
2011-10-07 23:06:39 +04:00
f = fopen ( p , " re " ) ;
free ( p ) ;
}
2010-07-05 05:06:02 +04:00
if ( ! f )
return - errno ;
2011-10-07 23:06:39 +04:00
r = new ( char , max_length ) ;
if ( ! r ) {
2010-07-05 05:06:02 +04:00
fclose ( f ) ;
return - ENOMEM ;
}
k = r ;
left = max_length ;
while ( ( c = getc ( f ) ) ! = EOF ) {
if ( isprint ( c ) ) {
if ( space ) {
if ( left < = 4 )
break ;
* ( k + + ) = ' ' ;
2010-07-06 22:15:08 +04:00
left - - ;
2010-07-05 05:06:02 +04:00
space = false ;
}
if ( left < = 4 )
break ;
* ( k + + ) = ( char ) c ;
2010-07-06 22:15:08 +04:00
left - - ;
2010-07-05 05:06:02 +04:00
} else
space = true ;
}
if ( left < = 4 ) {
size_t n = MIN ( left - 1 , 3U ) ;
memcpy ( k , " ... " , n ) ;
k [ n ] = 0 ;
} else
* k = 0 ;
fclose ( f ) ;
2010-07-12 20:16:44 +04:00
/* Kernel threads have no argv[] */
if ( r [ 0 ] = = 0 ) {
char * t ;
int h ;
free ( r ) ;
2011-10-07 23:06:39 +04:00
if ( ! comm_fallback )
return - ENOENT ;
h = get_process_comm ( pid , & t ) ;
if ( h < 0 )
2010-07-12 20:16:44 +04:00
return h ;
2011-10-07 23:06:39 +04:00
r = join ( " [ " , t , " ] " , NULL ) ;
2010-07-12 20:16:44 +04:00
free ( t ) ;
2011-10-07 23:06:39 +04:00
if ( ! r )
2010-07-12 20:16:44 +04:00
return - ENOMEM ;
}
2010-07-08 23:01:42 +04:00
2010-07-05 05:06:02 +04:00
* line = r ;
return 0 ;
}
2012-01-22 21:18:51 +04:00
int is_kernel_thread ( pid_t pid ) {
char * p ;
size_t count ;
char c ;
bool eof ;
FILE * f ;
if ( pid = = 0 )
return 0 ;
if ( asprintf ( & p , " /proc/%lu/cmdline " , ( unsigned long ) pid ) < 0 )
return - ENOMEM ;
f = fopen ( p , " re " ) ;
free ( p ) ;
if ( ! f )
return - errno ;
count = fread ( & c , 1 , 1 , f ) ;
eof = feof ( f ) ;
fclose ( f ) ;
/* Kernel threads have an empty cmdline */
if ( count < = 0 )
return eof ? 1 : - errno ;
return 0 ;
}
2011-10-07 23:06:39 +04:00
int get_process_exe ( pid_t pid , char * * name ) {
int r ;
assert ( name ) ;
if ( pid = = 0 )
r = readlink_malloc ( " /proc/self/exe " , name ) ;
else {
char * p ;
if ( asprintf ( & p , " /proc/%lu/exe " , ( unsigned long ) pid ) < 0 )
return - ENOMEM ;
r = readlink_malloc ( p , name ) ;
free ( p ) ;
}
return r ;
}
2012-01-10 07:20:55 +04:00
int get_process_uid ( pid_t pid , uid_t * uid ) {
char * p ;
FILE * f ;
int r ;
assert ( uid ) ;
if ( pid = = 0 )
return getuid ( ) ;
if ( asprintf ( & p , " /proc/%lu/status " , ( unsigned long ) pid ) < 0 )
return - ENOMEM ;
f = fopen ( p , " re " ) ;
free ( p ) ;
if ( ! f )
return - errno ;
while ( ! feof ( f ) ) {
char line [ LINE_MAX ] , * l ;
if ( ! fgets ( line , sizeof ( line ) , f ) ) {
if ( feof ( f ) )
break ;
r = - errno ;
goto finish ;
}
l = strstrip ( line ) ;
if ( startswith ( l , " Uid: " ) ) {
l + = 4 ;
l + = strspn ( l , WHITESPACE ) ;
l [ strcspn ( l , WHITESPACE ) ] = 0 ;
r = parse_uid ( l , uid ) ;
goto finish ;
}
}
r = - EIO ;
finish :
fclose ( f ) ;
return r ;
}
2010-07-08 06:09:59 +04:00
char * strnappend ( const char * s , const char * suffix , size_t b ) {
size_t a ;
2010-01-26 09:02:51 +03:00
char * r ;
2010-07-08 06:09:59 +04:00
if ( ! s & & ! suffix )
return strdup ( " " ) ;
if ( ! s )
return strndup ( suffix , b ) ;
if ( ! suffix )
return strdup ( s ) ;
2010-01-26 09:02:51 +03:00
assert ( s ) ;
assert ( suffix ) ;
a = strlen ( s ) ;
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
2010-07-08 06:09:59 +04:00
char * strappend ( const char * s , const char * suffix ) {
return strnappend ( s , suffix , suffix ? strlen ( suffix ) : 0 ) ;
}
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 ;
}
}
2010-06-16 03:56:00 +04:00
int readlink_and_make_absolute ( const char * p , char * * r ) {
char * target , * k ;
int j ;
assert ( p ) ;
assert ( r ) ;
if ( ( j = readlink_malloc ( p , & target ) ) < 0 )
return j ;
k = file_in_same_dir ( p , target ) ;
free ( target ) ;
if ( ! k )
return - ENOMEM ;
* r = k ;
return 0 ;
}
2011-07-22 06:21:18 +04:00
int readlink_and_canonicalize ( const char * p , char * * r ) {
char * t , * s ;
int j ;
assert ( p ) ;
assert ( r ) ;
j = readlink_and_make_absolute ( p , & t ) ;
if ( j < 0 )
return j ;
s = canonicalize_file_name ( t ) ;
if ( s ) {
free ( t ) ;
* r = s ;
} else
* r = t ;
path_kill_slashes ( * r ) ;
return 0 ;
}
2010-07-12 20:16:44 +04:00
int parent_of_path ( const char * path , char * * _r ) {
const char * e , * a = NULL , * b = NULL , * p ;
char * r ;
bool slash = false ;
assert ( path ) ;
assert ( _r ) ;
if ( ! * path )
return - EINVAL ;
for ( e = path ; * e ; e + + ) {
if ( ! slash & & * e = = ' / ' ) {
a = b ;
b = e ;
slash = true ;
} else if ( slash & & * e ! = ' / ' )
slash = false ;
}
if ( * ( e - 1 ) = = ' / ' )
p = a ;
else
p = b ;
if ( ! p )
return - EINVAL ;
if ( p = = path )
r = strdup ( " / " ) ;
else
r = strndup ( path , p - path ) ;
if ( ! r )
return - ENOMEM ;
* _r = r ;
return 0 ;
}
2010-01-26 23:39:06 +03:00
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 ) {
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 ) ;
2011-08-01 04:39:22 +04:00
return join ( prefix , " / " , p , NULL ) ;
2010-01-27 02:15:56 +03:00
}
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-05-22 05:30:46 +04:00
char * * strv_path_canonicalize ( char * * l ) {
char * * s ;
unsigned k = 0 ;
bool enomem = false ;
if ( strv_isempty ( l ) )
return l ;
/* Goes through every item in the string list and canonicalize
* the path . This works in place and won ' t rollback any
* changes on failure . */
STRV_FOREACH ( s , l ) {
char * t , * u ;
t = path_make_absolute_cwd ( * s ) ;
free ( * s ) ;
if ( ! t ) {
enomem = true ;
continue ;
}
errno = 0 ;
u = canonicalize_file_name ( t ) ;
free ( t ) ;
if ( ! u ) {
if ( errno = = ENOMEM | | ! errno )
enomem = true ;
continue ;
}
l [ k + + ] = u ;
}
l [ k ] = NULL ;
if ( enomem )
return NULL ;
return l ;
2011-04-28 06:55:05 +04:00
}
char * * strv_path_remove_empty ( char * * l ) {
char * * f , * * t ;
if ( ! l )
return NULL ;
for ( f = t = l ; * f ; f + + ) {
if ( dir_is_empty ( * f ) > 0 ) {
free ( * f ) ;
continue ;
}
* ( t + + ) = * f ;
}
* t = NULL ;
return l ;
2010-05-22 05:30:46 +04:00
}
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 ) {
2011-08-01 03:18:33 +04:00
char * e ;
2010-01-28 00:37:50 +03:00
/* Drops trailing whitespace. Modifies the string in
* place . Returns pointer to first non - space character */
s + = strspn ( s , WHITESPACE ) ;
2011-08-01 03:18:33 +04:00
for ( e = strchr ( s , 0 ) ; e > s ; e - - )
if ( ! strchr ( WHITESPACE , e [ - 1 ] ) )
break ;
2010-01-28 00:37:50 +03:00
2011-08-01 03:18:33 +04:00
* e = 0 ;
2010-01-28 00:37:50 +03:00
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 ;
}
2011-08-20 02:20:41 +04:00
bool in_charset ( const char * s , const char * charset ) {
const char * i ;
assert ( s ) ;
assert ( charset ) ;
for ( i = s ; * i ; i + + )
if ( ! strchr ( charset , * i ) )
return false ;
return true ;
}
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-06-22 01:27:18 +04:00
int safe_mkdir ( const char * path , mode_t mode , uid_t uid , gid_t gid ) {
struct stat st ;
Systemd is causing mislabeled devices to be created and then attempting to read them.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 07/28/2010 05:57 AM, Kay Sievers wrote:
> On Wed, Jul 28, 2010 at 11:43, Lennart Poettering
> <lennart@poettering.net> wrote:
>> On Mon, 26.07.10 16:42, Daniel J Walsh (dwalsh@redhat.com) wrote:
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>> type=1400 audit(1280174589.476:7): avc: denied { read } for pid=1
>>> comm="systemd" name="autofs" dev=devtmpfs ino=9482
>>> scontext=system_u:system_r:init_t:s0
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>> type=1400 audit(1280174589.476:8): avc: denied { read } for pid=1
>>> comm="systemd" name="autofs" dev=devtmpfs ino=9482
>>> scontext=system_u:system_r:init_t:s0
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>>
>>> Lennart, we talked about this earlier. I think this is caused by the
>>> modprobe calls to create /dev/autofs. Since udev is not created at the
>>> point that init loads the kernel modules, the devices get created with
>>> the wrong label. Once udev starts the labels get fixed.
>>>
>>> I can allow init_t to read device_t chr_files.
>>
>> Hmm, I think a cleaner fix would be to make systemd relabel this device
>> properly before accessing it? Given that this is only one device this
>> should not be a problem for us to maintain, I think? How would the
>> fixing of the label work? Would we have to spawn restorecon for this, or
>> can we actually do this in C without too much work?
>
> I guess we can just do what udev is doing, and call setfilecon(), with
> a context of an earlier matchpathcon().
>
> Kay
> _______________________________________________
> systemd-devel mailing list
> systemd-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Here is the updated patch with a fix for the labeling of /dev/autofs
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.14 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/
iEYEARECAAYFAkxQMyoACgkQrlYvE4MpobNviACfWgxsjW2xzz1qznFex8RVAQHf
gIEAmwRmRcLvGqYtwQaZ3WKIg8wmrwNk
=pC2e
2010-07-28 17:39:54 +04:00
if ( label_mkdir ( path , mode ) > = 0 )
2010-06-22 01:27:18 +04:00
if ( chmod_and_chown ( path , mode , uid , gid ) < 0 )
return - errno ;
if ( lstat ( path , & st ) < 0 )
return - errno ;
if ( ( st . st_mode & 0777 ) ! = mode | |
st . st_uid ! = uid | |
st . st_gid ! = gid | |
! S_ISDIR ( st . st_mode ) ) {
errno = EEXIST ;
return - errno ;
}
return 0 ;
}
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 ;
Systemd is causing mislabeled devices to be created and then attempting to read them.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 07/28/2010 05:57 AM, Kay Sievers wrote:
> On Wed, Jul 28, 2010 at 11:43, Lennart Poettering
> <lennart@poettering.net> wrote:
>> On Mon, 26.07.10 16:42, Daniel J Walsh (dwalsh@redhat.com) wrote:
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>> type=1400 audit(1280174589.476:7): avc: denied { read } for pid=1
>>> comm="systemd" name="autofs" dev=devtmpfs ino=9482
>>> scontext=system_u:system_r:init_t:s0
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>> type=1400 audit(1280174589.476:8): avc: denied { read } for pid=1
>>> comm="systemd" name="autofs" dev=devtmpfs ino=9482
>>> scontext=system_u:system_r:init_t:s0
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>>
>>> Lennart, we talked about this earlier. I think this is caused by the
>>> modprobe calls to create /dev/autofs. Since udev is not created at the
>>> point that init loads the kernel modules, the devices get created with
>>> the wrong label. Once udev starts the labels get fixed.
>>>
>>> I can allow init_t to read device_t chr_files.
>>
>> Hmm, I think a cleaner fix would be to make systemd relabel this device
>> properly before accessing it? Given that this is only one device this
>> should not be a problem for us to maintain, I think? How would the
>> fixing of the label work? Would we have to spawn restorecon for this, or
>> can we actually do this in C without too much work?
>
> I guess we can just do what udev is doing, and call setfilecon(), with
> a context of an earlier matchpathcon().
>
> Kay
> _______________________________________________
> systemd-devel mailing list
> systemd-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Here is the updated patch with a fix for the labeling of /dev/autofs
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.14 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/
iEYEARECAAYFAkxQMyoACgkQrlYvE4MpobNviACfWgxsjW2xzz1qznFex8RVAQHf
gIEAmwRmRcLvGqYtwQaZ3WKIg8wmrwNk
=pC2e
2010-07-28 17:39:54 +04:00
r = label_mkdir ( t , mode ) ;
2010-02-12 04:01:14 +03:00
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 ;
Systemd is causing mislabeled devices to be created and then attempting to read them.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 07/28/2010 05:57 AM, Kay Sievers wrote:
> On Wed, Jul 28, 2010 at 11:43, Lennart Poettering
> <lennart@poettering.net> wrote:
>> On Mon, 26.07.10 16:42, Daniel J Walsh (dwalsh@redhat.com) wrote:
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>> type=1400 audit(1280174589.476:7): avc: denied { read } for pid=1
>>> comm="systemd" name="autofs" dev=devtmpfs ino=9482
>>> scontext=system_u:system_r:init_t:s0
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>> type=1400 audit(1280174589.476:8): avc: denied { read } for pid=1
>>> comm="systemd" name="autofs" dev=devtmpfs ino=9482
>>> scontext=system_u:system_r:init_t:s0
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>>
>>> Lennart, we talked about this earlier. I think this is caused by the
>>> modprobe calls to create /dev/autofs. Since udev is not created at the
>>> point that init loads the kernel modules, the devices get created with
>>> the wrong label. Once udev starts the labels get fixed.
>>>
>>> I can allow init_t to read device_t chr_files.
>>
>> Hmm, I think a cleaner fix would be to make systemd relabel this device
>> properly before accessing it? Given that this is only one device this
>> should not be a problem for us to maintain, I think? How would the
>> fixing of the label work? Would we have to spawn restorecon for this, or
>> can we actually do this in C without too much work?
>
> I guess we can just do what udev is doing, and call setfilecon(), with
> a context of an earlier matchpathcon().
>
> Kay
> _______________________________________________
> systemd-devel mailing list
> systemd-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Here is the updated patch with a fix for the labeling of /dev/autofs
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.14 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/
iEYEARECAAYFAkxQMyoACgkQrlYvE4MpobNviACfWgxsjW2xzz1qznFex8RVAQHf
gIEAmwRmRcLvGqYtwQaZ3WKIg8wmrwNk
=pC2e
2010-07-28 17:39:54 +04:00
if ( label_mkdir ( path , mode ) < 0 & & errno ! = EEXIST )
2010-04-10 06:38:33 +04:00
return - errno ;
return 0 ;
}
2010-06-18 23:33:15 +04:00
int rmdir_parents ( const char * path , const char * stop ) {
size_t l ;
int r = 0 ;
assert ( path ) ;
assert ( stop ) ;
l = strlen ( path ) ;
/* Skip trailing slashes */
while ( l > 0 & & path [ l - 1 ] = = ' / ' )
l - - ;
while ( l > 0 ) {
char * t ;
/* Skip last component */
while ( l > 0 & & path [ l - 1 ] ! = ' / ' )
l - - ;
/* Skip trailing slashes */
while ( l > 0 & & path [ l - 1 ] = = ' / ' )
l - - ;
if ( l < = 0 )
break ;
if ( ! ( t = strndup ( path , l ) ) )
return - ENOMEM ;
if ( path_startswith ( stop , t ) ) {
free ( t ) ;
return 0 ;
}
r = rmdir ( t ) ;
free ( t ) ;
if ( r < 0 )
if ( errno ! = ENOENT )
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 ;
}
2010-07-07 22:58:02 +04:00
char * cunescape_length ( const char * s , size_t length ) {
2010-01-29 03:48:57 +03:00
char * r , * t ;
const char * f ;
assert ( s ) ;
/* Undoes C style string escaping */
2010-07-07 22:58:02 +04:00
if ( ! ( r = new ( char , length + 1 ) ) )
2010-01-29 03:48:57 +03:00
return r ;
2010-07-07 22:58:02 +04:00
for ( f = s , t = r ; f < s + length ; f + + ) {
2010-01-29 03:48:57 +03:00
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 ;
2010-07-08 00:28:51 +04:00
case ' s ' :
/* This is an extension of the XDG syntax files */
* ( t + + ) = ' ' ;
break ;
2010-01-29 03:48:57 +03:00
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 + + ) = ' \\ ' ;
2010-07-07 22:57:10 +04:00
* ( t + + ) = * f ;
2010-01-29 03:48:57 +03:00
break ;
}
}
finish :
* t = 0 ;
return r ;
}
2010-07-07 22:58:02 +04:00
char * cunescape ( const char * s ) {
return cunescape_length ( s , strlen ( s ) ) ;
}
2010-01-29 03:48:57 +03:00
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 ] = = ' . ' | |
2010-04-30 04:16:55 +04:00
streq ( filename , " lost+found " ) | |
2010-10-19 00:39:17 +04:00
streq ( filename , " aquota.user " ) | |
streq ( filename , " aquota.group " ) | |
2010-02-14 03:07:01 +03:00
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 ;
2011-03-11 02:52:13 +03:00
if ( safe_atoi ( de - > d_name , & fd ) < 0 )
/* Let's better ignore this, just in case */
continue ;
2010-04-07 01:35:59 +04:00
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 ;
}
2011-03-11 02:52:13 +03:00
if ( close_nointr ( fd ) < 0 ) {
2010-04-07 02:09:59 +04:00
/* Valgrind has its own FD and doesn't want to have it closed */
2011-03-11 02:52:13 +03:00
if ( errno ! = EBADF & & r = = 0 )
r = - errno ;
2010-04-07 02:09:59 +04:00
}
2010-04-07 01:35:59 +04:00
}
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 ;
2010-06-19 02:14:12 +04:00
sec = ( time_t ) ( t / USEC_PER_SEC ) ;
2010-04-10 06:38:49 +04:00
if ( strftime ( buf , l , " %a, %d %b %Y %H:%M:%S %z " , localtime_r ( & sec , & tm ) ) < = 0 )
return NULL ;
return buf ;
}
2010-08-25 05:13:44 +04:00
char * format_timestamp_pretty ( char * buf , size_t l , usec_t t ) {
usec_t n , d ;
n = now ( CLOCK_REALTIME ) ;
if ( t < = 0 | | t > n | | t + USEC_PER_DAY * 7 < = t )
return NULL ;
d = n - t ;
if ( d > = USEC_PER_YEAR )
snprintf ( buf , l , " %llu years and %llu months ago " ,
( unsigned long long ) ( d / USEC_PER_YEAR ) ,
( unsigned long long ) ( ( d % USEC_PER_YEAR ) / USEC_PER_MONTH ) ) ;
else if ( d > = USEC_PER_MONTH )
snprintf ( buf , l , " %llu months and %llu days ago " ,
( unsigned long long ) ( d / USEC_PER_MONTH ) ,
( unsigned long long ) ( ( d % USEC_PER_MONTH ) / USEC_PER_DAY ) ) ;
else if ( d > = USEC_PER_WEEK )
snprintf ( buf , l , " %llu weeks and %llu days ago " ,
( unsigned long long ) ( d / USEC_PER_WEEK ) ,
( unsigned long long ) ( ( d % USEC_PER_WEEK ) / USEC_PER_DAY ) ) ;
else if ( d > = 2 * USEC_PER_DAY )
snprintf ( buf , l , " %llu days ago " , ( unsigned long long ) ( d / USEC_PER_DAY ) ) ;
else if ( d > = 25 * USEC_PER_HOUR )
snprintf ( buf , l , " 1 day and %lluh ago " ,
( unsigned long long ) ( ( d - USEC_PER_DAY ) / USEC_PER_HOUR ) ) ;
else if ( d > = 6 * USEC_PER_HOUR )
snprintf ( buf , l , " %lluh ago " ,
( unsigned long long ) ( d / USEC_PER_HOUR ) ) ;
else if ( d > = USEC_PER_HOUR )
snprintf ( buf , l , " %lluh %llumin ago " ,
( unsigned long long ) ( d / USEC_PER_HOUR ) ,
( unsigned long long ) ( ( d % USEC_PER_HOUR ) / USEC_PER_MINUTE ) ) ;
else if ( d > = 5 * USEC_PER_MINUTE )
snprintf ( buf , l , " %llumin ago " ,
( unsigned long long ) ( d / USEC_PER_MINUTE ) ) ;
else if ( d > = USEC_PER_MINUTE )
snprintf ( buf , l , " %llumin %llus ago " ,
( unsigned long long ) ( d / USEC_PER_MINUTE ) ,
( unsigned long long ) ( ( d % USEC_PER_MINUTE ) / USEC_PER_SEC ) ) ;
else if ( d > = USEC_PER_SEC )
snprintf ( buf , l , " %llus ago " ,
( unsigned long long ) ( d / USEC_PER_SEC ) ) ;
else if ( d > = USEC_PER_MSEC )
snprintf ( buf , l , " %llums ago " ,
( unsigned long long ) ( d / USEC_PER_MSEC ) ) ;
else if ( d > 0 )
snprintf ( buf , l , " %lluus ago " ,
( unsigned long long ) d ) ;
else
snprintf ( buf , l , " now " ) ;
buf [ l - 1 ] = 0 ;
return buf ;
}
2010-05-24 03:45:54 +04:00
char * format_timespan ( char * buf , size_t l , usec_t t ) {
static const struct {
const char * suffix ;
usec_t usec ;
} table [ ] = {
{ " w " , USEC_PER_WEEK } ,
{ " d " , USEC_PER_DAY } ,
{ " h " , USEC_PER_HOUR } ,
{ " min " , USEC_PER_MINUTE } ,
{ " s " , USEC_PER_SEC } ,
{ " ms " , USEC_PER_MSEC } ,
{ " us " , 1 } ,
} ;
unsigned i ;
char * p = buf ;
assert ( buf ) ;
assert ( l > 0 ) ;
if ( t = = ( usec_t ) - 1 )
return NULL ;
2010-08-06 23:33:53 +04:00
if ( t = = 0 ) {
snprintf ( p , l , " 0 " ) ;
p [ l - 1 ] = 0 ;
return p ;
}
2010-05-24 03:45:54 +04:00
/* The result of this function can be parsed with parse_usec */
for ( i = 0 ; i < ELEMENTSOF ( table ) ; i + + ) {
int k ;
size_t n ;
if ( t < table [ i ] . usec )
continue ;
if ( l < = 1 )
break ;
k = snprintf ( p , l , " %s%llu%s " , p > buf ? " " : " " , ( unsigned long long ) ( t / table [ i ] . usec ) , table [ i ] . suffix ) ;
n = MIN ( ( size_t ) k , l ) ;
l - = n ;
p + = n ;
t % = table [ i ] . usec ;
}
* p = 0 ;
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 " ,
2010-05-16 05:54:40 +04:00
" nfs4 " ,
" gfs " ,
" gfs2 "
2010-04-10 19:41:34 +04:00
} ;
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 ;
2011-05-19 20:10:34 +04:00
if ( ( fd = open_terminal ( " /dev/tty0 " , O_RDWR | O_NOCTTY | O_CLOEXEC ) ) < 0 )
2010-04-11 01:36:43 +04:00
return - errno ;
if ( vt < 0 ) {
int tiocl [ 2 ] = {
TIOCL_GETKMSGREDIRECT ,
0
} ;
2011-10-06 00:31:41 +04:00
if ( ioctl ( fd , TIOCLINUX , tiocl ) < 0 ) {
r = - errno ;
goto fail ;
}
2010-04-11 01:36:43 +04:00
vt = tiocl [ 0 ] < = 0 ? 1 : tiocl [ 0 ] ;
}
if ( ioctl ( fd , VT_ACTIVATE , vt ) < 0 )
r = - errno ;
2011-10-06 00:31:41 +04:00
fail :
close_nointr_nofail ( fd ) ;
2010-04-11 01:36:43 +04:00
return r ;
}
2012-01-22 21:21:15 +04:00
int read_one_char ( FILE * f , char * ret , usec_t t , bool * need_nl ) {
2010-04-13 04:06:27 +04:00
struct termios old_termios , new_termios ;
char c ;
2011-04-07 20:48:50 +04:00
char line [ LINE_MAX ] ;
2010-04-13 04:06:27 +04:00
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 ;
2012-01-22 21:21:15 +04:00
if ( t ! = ( usec_t ) - 1 ) {
if ( fd_wait_for_event ( fileno ( f ) , POLLIN , t ) < = 0 ) {
tcsetattr ( fileno ( f ) , TCSADRAIN , & old_termios ) ;
return - ETIMEDOUT ;
}
}
2010-04-13 04:06:27 +04:00
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 ;
}
}
2012-01-22 21:21:15 +04:00
if ( t ! = ( usec_t ) - 1 )
if ( fd_wait_for_event ( fileno ( f ) , POLLIN , t ) < = 0 )
return - ETIMEDOUT ;
if ( ! fgets ( line , sizeof ( line ) , f ) )
2010-04-13 04:06:27 +04:00
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 , . . . ) {
2010-09-17 04:10:08 +04:00
bool on_tty ;
2010-04-13 04:06:27 +04:00
assert ( ret ) ;
assert ( replies ) ;
assert ( text ) ;
2010-09-17 04:10:08 +04:00
on_tty = isatty ( STDOUT_FILENO ) ;
2010-04-13 04:06:27 +04:00
for ( ; ; ) {
va_list ap ;
char c ;
int r ;
bool need_nl = true ;
2010-09-17 04:10:08 +04:00
if ( on_tty )
2012-01-14 00:56:09 +04:00
fputs ( ANSI_HIGHLIGHT_ON , stdout ) ;
2010-04-23 22:51:06 +04:00
2010-04-13 04:06:27 +04:00
va_start ( ap , text ) ;
vprintf ( text , ap ) ;
va_end ( ap ) ;
2010-09-17 04:10:08 +04:00
if ( on_tty )
2012-01-14 00:56:09 +04:00
fputs ( ANSI_HIGHLIGHT_OFF , stdout ) ;
2010-04-23 22:51:06 +04:00
2010-04-13 04:06:27 +04:00
fflush ( stdout ) ;
2012-01-22 21:21:15 +04:00
r = read_one_char ( stdin , & c , ( usec_t ) - 1 , & need_nl ) ;
if ( r < 0 ) {
2010-04-13 04:06:27 +04:00
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. " ) ;
}
}
2012-01-30 00:55:51 +04:00
int reset_terminal_fd ( int fd , bool switch_to_text ) {
2010-04-13 04:06:27 +04:00
struct termios termios ;
int r = 0 ;
2010-07-12 23:40:43 +04:00
/* Set terminal to some sane defaults */
2010-04-13 04:06:27 +04:00
assert ( fd > = 0 ) ;
2010-09-01 02:10:41 +04:00
/* We leave locked terminal attributes untouched, so that
* Plymouth may set whatever it wants to set , and we don ' t
* interfere with that . */
2010-07-12 23:40:43 +04:00
/* Disable exclusive mode, just in case */
ioctl ( fd , TIOCNXCL ) ;
2012-01-06 04:32:34 +04:00
/* Switch to text mode */
2012-01-30 00:55:51 +04:00
if ( switch_to_text )
ioctl ( fd , KDSETMODE , KD_TEXT ) ;
2012-01-06 04:32:34 +04:00
2010-07-12 23:40:43 +04:00
/* Enable console unicode mode */
2012-01-06 04:28:30 +04:00
ioctl ( fd , KDSKBMODE , K_UNICODE ) ;
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 ;
}
2011-05-18 03:07:31 +04:00
int reset_terminal ( const char * name ) {
int fd , r ;
fd = open_terminal ( name , O_RDWR | O_NOCTTY | O_CLOEXEC ) ;
if ( fd < 0 )
return fd ;
2012-01-30 00:55:51 +04:00
r = reset_terminal_fd ( fd , true ) ;
2011-05-18 03:07:31 +04:00
close_nointr_nofail ( fd ) ;
return r ;
}
2010-04-13 04:06:27 +04:00
int open_terminal ( const char * name , int mode ) {
int fd , r ;
2011-02-17 18:29:47 +03:00
unsigned c = 0 ;
2010-04-13 04:06:27 +04:00
2011-02-17 18:29:47 +03:00
/*
* 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 )
2010-04-13 04:06:27 +04:00
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 ( ; ; ) {
2011-04-07 20:48:50 +04:00
char buf [ LINE_MAX ] ;
2010-04-13 04:06:27 +04:00
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 ;
}
}
2010-05-18 05:40:19 +04:00
int acquire_terminal ( const char * name , bool fail , bool force , bool ignore_tiocstty_eperm ) {
2010-05-10 05:34:31 +04:00
int fd = - 1 , notify = - 1 , r , wd = - 1 ;
2010-04-13 04:06:27 +04:00
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 ( ; ; ) {
2010-05-14 06:36:47 +04:00
if ( notify > = 0 )
if ( ( r = flush_fd ( notify ) ) < 0 )
goto fail ;
2010-04-13 04:06:27 +04:00
/* 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 */
2011-05-18 03:07:31 +04:00
if ( ( fd = open_terminal ( name , O_RDWR | O_NOCTTY | O_CLOEXEC ) ) < 0 )
return fd ;
2010-04-13 04:06:27 +04:00
/* First, try to get the tty */
2010-05-18 05:40:19 +04:00
r = ioctl ( fd , TIOCSCTTY , force ) ;
/* Sometimes it makes sense to ignore TIOCSCTTY
* returning EPERM , i . e . when very likely we already
* are have this controlling terminal . */
if ( r < 0 & & errno = = EPERM & & ignore_tiocstty_eperm )
r = 0 ;
if ( r < 0 & & ( force | | fail | | errno ! = EPERM ) ) {
2010-04-13 04:06:27 +04:00
r = - errno ;
goto fail ;
}
if ( r > = 0 )
break ;
assert ( ! fail ) ;
assert ( ! force ) ;
assert ( notify > = 0 ) ;
for ( ; ; ) {
2010-10-13 04:34:00 +04:00
uint8_t inotify_buffer [ sizeof ( struct inotify_event ) + FILENAME_MAX ] ;
2010-04-13 04:06:27 +04:00
ssize_t l ;
2010-10-13 04:34:00 +04:00
struct inotify_event * e ;
2010-04-13 04:06:27 +04:00
2011-12-20 01:35:46 +04:00
if ( ( l = read ( notify , inotify_buffer , sizeof ( inotify_buffer ) ) ) < 0 ) {
2010-04-13 04:06:27 +04:00
2010-10-13 04:34:00 +04:00
if ( errno = = EINTR )
continue ;
r = - errno ;
goto fail ;
}
e = ( struct inotify_event * ) inotify_buffer ;
2010-04-13 04:06:27 +04:00
2010-10-13 04:34:00 +04:00
while ( l > 0 ) {
size_t step ;
2010-04-13 04:06:27 +04:00
2010-10-13 04:34:00 +04:00
if ( e - > wd ! = wd | | ! ( e - > mask & IN_CLOSE ) ) {
2010-04-13 04:06:27 +04:00
r = - EIO ;
2010-10-13 04:34:00 +04:00
goto fail ;
}
2010-04-13 04:06:27 +04:00
2010-10-13 04:34:00 +04:00
step = sizeof ( struct inotify_event ) + e - > len ;
assert ( step < = ( size_t ) l ) ;
2010-04-13 04:06:27 +04:00
2010-10-13 04:34:00 +04:00
e = ( struct inotify_event * ) ( ( uint8_t * ) e + step ) ;
l - = step ;
2010-04-13 04:06:27 +04:00
}
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
2012-01-30 00:55:51 +04:00
r = reset_terminal_fd ( fd , true ) ;
if ( r < 0 )
2010-04-13 04:06:27 +04:00
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 ;
2010-04-24 04:32:07 +04:00
struct sigaction sa_old , sa_new ;
2010-04-13 04:06:27 +04:00
2011-07-04 01:20:39 +04:00
if ( ( fd = open ( " /dev/tty " , O_RDWR | O_NOCTTY | O_NDELAY | O_CLOEXEC ) ) < 0 )
2010-04-13 04:06:27 +04:00
return - errno ;
2010-04-24 04:32:07 +04:00
/* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
* by our own TIOCNOTTY */
zero ( sa_new ) ;
sa_new . sa_handler = SIG_IGN ;
sa_new . sa_flags = SA_RESTART ;
assert_se ( sigaction ( SIGHUP , & sa_new , & sa_old ) = = 0 ) ;
2010-04-13 04:06:27 +04:00
if ( ioctl ( fd , TIOCNOTTY ) < 0 )
r = - errno ;
2010-04-24 04:32:07 +04:00
assert_se ( sigaction ( SIGHUP , & sa_old , NULL ) = = 0 ) ;
2010-04-13 04:06:27 +04:00
close_nointr_nofail ( fd ) ;
return r ;
}
2010-05-22 03:46:08 +04:00
int sigaction_many ( const struct sigaction * sa , . . . ) {
va_list ap ;
int r = 0 , sig ;
va_start ( ap , sa ) ;
while ( ( sig = va_arg ( ap , int ) ) > 0 )
if ( sigaction ( sig , sa , NULL ) < 0 )
r = - errno ;
va_end ( ap ) ;
return r ;
}
int ignore_signals ( int sig , . . . ) {
2010-04-13 04:36:19 +04:00
struct sigaction sa ;
2010-05-22 03:46:08 +04:00
va_list ap ;
int r = 0 ;
2010-04-13 04:36:19 +04:00
zero ( sa ) ;
sa . sa_handler = SIG_IGN ;
sa . sa_flags = SA_RESTART ;
2010-05-22 03:46:08 +04:00
if ( sigaction ( sig , & sa , NULL ) < 0 )
r = - errno ;
va_start ( ap , sig ) ;
while ( ( sig = va_arg ( ap , int ) ) > 0 )
if ( sigaction ( sig , & sa , NULL ) < 0 )
r = - errno ;
va_end ( ap ) ;
return r ;
}
int default_signals ( int sig , . . . ) {
struct sigaction sa ;
va_list ap ;
int r = 0 ;
zero ( sa ) ;
sa . sa_handler = SIG_DFL ;
sa . sa_flags = SA_RESTART ;
if ( sigaction ( sig , & sa , NULL ) < 0 )
r = - errno ;
va_start ( ap , sig ) ;
while ( ( sig = va_arg ( ap , int ) ) > 0 )
if ( sigaction ( sig , & sa , NULL ) < 0 )
r = - errno ;
va_end ( ap ) ;
return r ;
2010-04-13 04:36:19 +04:00
}
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 ;
}
2010-06-18 06:44:53 +04:00
ssize_t loop_read ( int fd , void * buf , size_t nbytes , bool do_poll ) {
2010-04-17 01:24:39 +04:00
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 ) {
2010-06-18 06:44:53 +04:00
if ( k < 0 & & errno = = EINTR )
2010-04-17 01:24:39 +04:00
continue ;
2010-06-18 06:44:53 +04:00
if ( k < 0 & & errno = = EAGAIN & & do_poll ) {
2010-04-17 01:24:39 +04:00
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 ;
}
2010-06-18 06:44:53 +04:00
ssize_t loop_write ( int fd , const void * buf , size_t nbytes , bool do_poll ) {
const uint8_t * p ;
ssize_t n = 0 ;
assert ( fd > = 0 ) ;
assert ( buf ) ;
p = buf ;
while ( nbytes > 0 ) {
ssize_t k ;
2011-12-23 23:50:48 +04:00
k = write ( fd , p , nbytes ) ;
if ( k < = 0 ) {
2010-06-18 06:44:53 +04:00
if ( k < 0 & & errno = = EINTR )
continue ;
if ( k < 0 & & errno = = EAGAIN & & do_poll ) {
struct pollfd pollfd ;
zero ( pollfd ) ;
pollfd . fd = fd ;
pollfd . events = POLLOUT ;
if ( poll ( & pollfd , 1 , - 1 ) < 0 ) {
if ( errno = = EINTR )
continue ;
return n > 0 ? n : - errno ;
}
if ( pollfd . revents ! = POLLOUT )
return n > 0 ? n : - EIO ;
continue ;
}
return n > 0 ? n : ( k < 0 ? - errno : 0 ) ;
}
p + = k ;
nbytes - = k ;
n + = k ;
}
return n ;
}
2011-08-23 02:37:35 +04:00
int path_is_mount_point ( const char * t , bool allow_symlink ) {
2010-04-17 01:24:39 +04:00
struct stat a , b ;
2010-07-12 20:16:44 +04:00
char * parent ;
int r ;
2010-04-17 01:24:39 +04:00
2011-08-23 02:37:35 +04:00
if ( allow_symlink )
r = stat ( t , & a ) ;
else
r = lstat ( t , & a ) ;
if ( r < 0 ) {
2010-04-17 01:24:39 +04:00
if ( errno = = ENOENT )
return 0 ;
return - errno ;
}
2011-08-23 02:37:35 +04:00
r = parent_of_path ( t , & parent ) ;
if ( r < 0 )
2010-07-12 20:16:44 +04:00
return r ;
2010-04-17 01:24:39 +04:00
2010-07-12 20:16:44 +04:00
r = lstat ( parent , & b ) ;
free ( parent ) ;
2010-04-17 01:24:39 +04:00
2010-07-12 20:16:44 +04:00
if ( r < 0 )
return - errno ;
2010-04-17 01:24:39 +04:00
return a . st_dev ! = b . st_dev ;
}
2010-04-23 22:26:59 +04:00
int parse_usec ( const char * t , usec_t * usec ) {
static const struct {
const char * suffix ;
usec_t usec ;
} table [ ] = {
{ " sec " , USEC_PER_SEC } ,
{ " s " , USEC_PER_SEC } ,
{ " min " , USEC_PER_MINUTE } ,
{ " hr " , USEC_PER_HOUR } ,
{ " h " , USEC_PER_HOUR } ,
{ " d " , USEC_PER_DAY } ,
{ " w " , USEC_PER_WEEK } ,
{ " msec " , USEC_PER_MSEC } ,
{ " ms " , USEC_PER_MSEC } ,
{ " m " , USEC_PER_MINUTE } ,
{ " usec " , 1ULL } ,
{ " us " , 1ULL } ,
{ " " , USEC_PER_SEC } ,
} ;
const char * p ;
usec_t r = 0 ;
assert ( t ) ;
assert ( usec ) ;
p = t ;
do {
long long l ;
char * e ;
unsigned i ;
errno = 0 ;
l = strtoll ( p , & e , 10 ) ;
if ( errno ! = 0 )
return - errno ;
if ( l < 0 )
return - ERANGE ;
if ( e = = p )
return - EINVAL ;
e + = strspn ( e , WHITESPACE ) ;
for ( i = 0 ; i < ELEMENTSOF ( table ) ; i + + )
if ( startswith ( e , table [ i ] . suffix ) ) {
r + = ( usec_t ) l * table [ i ] . usec ;
p = e + strlen ( table [ i ] . suffix ) ;
break ;
}
if ( i > = ELEMENTSOF ( table ) )
return - EINVAL ;
} while ( * p ! = 0 ) ;
* usec = r ;
return 0 ;
}
2011-08-20 02:20:41 +04:00
int parse_bytes ( const char * t , off_t * bytes ) {
static const struct {
const char * suffix ;
off_t factor ;
} table [ ] = {
{ " B " , 1 } ,
{ " K " , 1024ULL } ,
{ " M " , 1024ULL * 1024ULL } ,
{ " G " , 1024ULL * 1024ULL * 1024ULL } ,
{ " T " , 1024ULL * 1024ULL * 1024ULL * 1024ULL } ,
2012-01-14 06:07:29 +04:00
{ " P " , 1024ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL } ,
{ " E " , 1024ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL } ,
2011-08-20 02:20:41 +04:00
{ " " , 1 } ,
} ;
const char * p ;
off_t r = 0 ;
assert ( t ) ;
assert ( bytes ) ;
p = t ;
do {
long long l ;
char * e ;
unsigned i ;
errno = 0 ;
l = strtoll ( p , & e , 10 ) ;
if ( errno ! = 0 )
return - errno ;
if ( l < 0 )
return - ERANGE ;
if ( e = = p )
return - EINVAL ;
e + = strspn ( e , WHITESPACE ) ;
for ( i = 0 ; i < ELEMENTSOF ( table ) ; i + + )
if ( startswith ( e , table [ i ] . suffix ) ) {
r + = ( off_t ) l * table [ i ] . factor ;
p = e + strlen ( table [ i ] . suffix ) ;
break ;
}
if ( i > = ELEMENTSOF ( table ) )
return - EINVAL ;
} while ( * p ! = 0 ) ;
* bytes = r ;
return 0 ;
}
2010-05-15 19:25:08 +04:00
int make_stdio ( int fd ) {
int r , s , t ;
assert ( fd > = 0 ) ;
r = dup2 ( fd , STDIN_FILENO ) ;
s = dup2 ( fd , STDOUT_FILENO ) ;
t = dup2 ( fd , STDERR_FILENO ) ;
if ( fd > = 3 )
close_nointr_nofail ( fd ) ;
if ( r < 0 | | s < 0 | | t < 0 )
return - errno ;
2011-07-04 01:20:56 +04:00
fd_cloexec ( STDIN_FILENO , false ) ;
fd_cloexec ( STDOUT_FILENO , false ) ;
fd_cloexec ( STDERR_FILENO , false ) ;
2010-05-15 19:25:08 +04:00
return 0 ;
}
2010-10-27 07:45:57 +04:00
int make_null_stdio ( void ) {
int null_fd ;
if ( ( null_fd = open ( " /dev/null " , O_RDWR | O_NOCTTY ) ) < 0 )
return - errno ;
return make_stdio ( null_fd ) ;
}
2010-05-16 20:13:58 +04:00
bool is_device_path ( const char * path ) {
/* Returns true on paths that refer to a device, either in
* sysfs or in / dev */
return
path_startswith ( path , " /dev/ " ) | |
path_startswith ( path , " /sys/ " ) ;
}
2010-05-24 07:25:33 +04:00
int dir_is_empty ( const char * path ) {
DIR * d ;
int r ;
struct dirent buf , * de ;
if ( ! ( d = opendir ( path ) ) )
return - errno ;
for ( ; ; ) {
if ( ( r = readdir_r ( d , & buf , & de ) ) > 0 ) {
r = - r ;
break ;
}
if ( ! de ) {
r = 1 ;
break ;
}
if ( ! ignore_file ( de - > d_name ) ) {
r = 0 ;
break ;
}
}
closedir ( d ) ;
return r ;
}
2010-06-16 07:05:36 +04:00
unsigned long long random_ull ( void ) {
int fd ;
uint64_t ull ;
ssize_t r ;
if ( ( fd = open ( " /dev/urandom " , O_RDONLY | O_CLOEXEC | O_NOCTTY ) ) < 0 )
goto fallback ;
2010-06-18 06:44:53 +04:00
r = loop_read ( fd , & ull , sizeof ( ull ) , true ) ;
2010-06-16 07:05:36 +04:00
close_nointr_nofail ( fd ) ;
if ( r ! = sizeof ( ull ) )
goto fallback ;
return ull ;
fallback :
return random ( ) * RAND_MAX + random ( ) ;
}
2010-06-16 23:54:17 +04:00
void rename_process ( const char name [ 8 ] ) {
assert ( name ) ;
2012-02-02 01:33:15 +04:00
/* This is a like a poor man's setproctitle(). It changes the
* comm field , argv [ 0 ] , and also the glibc ' s internally used
* name of the process . For the first one a limit of 16 chars
* applies , to the second one usually one of 10 ( i . e . length
* of " /sbin/init " ) , to the third one one of 7 ( i . e . length of
* " systemd " ) . If you pass a longer string it will be
* truncated */
2010-06-16 23:54:17 +04:00
2012-02-02 01:33:15 +04:00
prctl ( PR_SET_NAME , name ) ;
2010-06-16 23:54:17 +04:00
if ( program_invocation_name )
strncpy ( program_invocation_name , name , strlen ( program_invocation_name ) ) ;
2011-06-30 06:16:10 +04:00
if ( saved_argc > 0 ) {
int i ;
if ( saved_argv [ 0 ] )
strncpy ( saved_argv [ 0 ] , name , strlen ( saved_argv [ 0 ] ) ) ;
for ( i = 1 ; i < saved_argc ; i + + ) {
if ( ! saved_argv [ i ] )
break ;
memset ( saved_argv [ i ] , 0 , strlen ( saved_argv [ i ] ) ) ;
}
}
2010-06-16 23:54:17 +04:00
}
2010-06-18 01:22:56 +04:00
void sigset_add_many ( sigset_t * ss , . . . ) {
va_list ap ;
int sig ;
assert ( ss ) ;
va_start ( ap , ss ) ;
while ( ( sig = va_arg ( ap , int ) ) > 0 )
assert_se ( sigaddset ( ss , sig ) = = 0 ) ;
va_end ( ap ) ;
}
2010-06-18 04:28:35 +04:00
char * gethostname_malloc ( void ) {
struct utsname u ;
assert_se ( uname ( & u ) > = 0 ) ;
if ( u . nodename [ 0 ] )
return strdup ( u . nodename ) ;
return strdup ( u . sysname ) ;
}
char * getlogname_malloc ( void ) {
uid_t uid ;
long bufsize ;
char * buf , * name ;
struct passwd pwbuf , * pw = NULL ;
struct stat st ;
if ( isatty ( STDIN_FILENO ) & & fstat ( STDIN_FILENO , & st ) > = 0 )
uid = st . st_uid ;
else
uid = getuid ( ) ;
/* Shortcut things to avoid NSS lookups */
if ( uid = = 0 )
return strdup ( " root " ) ;
if ( ( bufsize = sysconf ( _SC_GETPW_R_SIZE_MAX ) ) < = 0 )
bufsize = 4096 ;
if ( ! ( buf = malloc ( bufsize ) ) )
return NULL ;
if ( getpwuid_r ( uid , & pwbuf , buf , bufsize , & pw ) = = 0 & & pw ) {
name = strdup ( pw - > pw_name ) ;
free ( buf ) ;
return name ;
}
free ( buf ) ;
if ( asprintf ( & name , " %lu " , ( unsigned long ) uid ) < 0 )
return NULL ;
return name ;
}
2011-02-17 18:29:04 +03:00
int getttyname_malloc ( int fd , char * * r ) {
char path [ PATH_MAX ] , * c ;
2010-08-16 23:25:09 +04:00
int k ;
2010-06-22 01:27:18 +04:00
assert ( r ) ;
2010-06-18 04:28:35 +04:00
2011-02-17 18:29:04 +03:00
if ( ( k = ttyname_r ( fd , path , sizeof ( path ) ) ) ! = 0 )
2010-08-16 23:25:09 +04:00
return - k ;
2010-06-18 04:28:35 +04:00
char_array_0 ( path ) ;
2011-02-17 18:29:04 +03:00
if ( ! ( c = strdup ( startswith ( path , " /dev/ " ) ? path + 5 : path ) ) )
2010-06-22 01:27:18 +04:00
return - ENOMEM ;
* r = c ;
return 0 ;
}
2011-02-17 18:29:04 +03:00
int getttyname_harder ( int fd , char * * r ) {
int k ;
char * s ;
if ( ( k = getttyname_malloc ( fd , & s ) ) < 0 )
return k ;
if ( streq ( s , " tty " ) ) {
free ( s ) ;
2011-06-28 00:44:12 +04:00
return get_ctty ( 0 , NULL , r ) ;
2011-02-17 18:29:04 +03:00
}
* r = s ;
return 0 ;
}
2011-06-28 00:44:12 +04:00
int get_ctty_devnr ( pid_t pid , dev_t * d ) {
2011-02-17 18:29:04 +03:00
int k ;
2011-06-28 00:44:12 +04:00
char line [ LINE_MAX ] , * p , * fn ;
2011-02-17 18:29:04 +03:00
unsigned long ttynr ;
FILE * f ;
2011-06-28 00:44:12 +04:00
if ( asprintf ( & fn , " /proc/%lu/stat " , ( unsigned long ) ( pid < = 0 ? getpid ( ) : pid ) ) < 0 )
return - ENOMEM ;
f = fopen ( fn , " re " ) ;
free ( fn ) ;
if ( ! f )
2011-02-17 18:29:04 +03:00
return - errno ;
2011-06-28 00:44:12 +04:00
if ( ! fgets ( line , sizeof ( line ) , f ) ) {
2011-12-03 03:41:34 +04:00
k = feof ( f ) ? - EIO : - errno ;
2011-02-17 18:29:04 +03:00
fclose ( f ) ;
return k ;
}
fclose ( f ) ;
2011-06-28 00:44:12 +04:00
p = strrchr ( line , ' ) ' ) ;
if ( ! p )
2011-02-17 18:29:04 +03:00
return - EIO ;
p + + ;
if ( sscanf ( p , " "
" %*c " /* state */
" %*d " /* ppid */
" %*d " /* pgrp */
" %*d " /* session */
" %lu " , /* ttynr */
& ttynr ) ! = 1 )
return - EIO ;
* d = ( dev_t ) ttynr ;
return 0 ;
}
2011-06-28 00:44:12 +04:00
int get_ctty ( pid_t pid , dev_t * _devnr , char * * r ) {
2011-02-17 18:29:04 +03:00
int k ;
2011-04-07 20:48:50 +04:00
char fn [ PATH_MAX ] , * s , * b , * p ;
2011-02-17 18:29:04 +03:00
dev_t devnr ;
assert ( r ) ;
2011-06-28 00:44:12 +04:00
k = get_ctty_devnr ( pid , & devnr ) ;
if ( k < 0 )
2011-02-17 18:29:04 +03:00
return k ;
snprintf ( fn , sizeof ( fn ) , " /dev/char/%u:%u " , major ( devnr ) , minor ( devnr ) ) ;
char_array_0 ( fn ) ;
if ( ( k = readlink_malloc ( fn , & s ) ) < 0 ) {
if ( k ! = - ENOENT )
return k ;
2011-03-14 04:33:23 +03:00
/* This is an ugly hack */
if ( major ( devnr ) = = 136 ) {
if ( asprintf ( & b , " pts/%lu " , ( unsigned long ) minor ( devnr ) ) < 0 )
return - ENOMEM ;
* r = b ;
if ( _devnr )
* _devnr = devnr ;
return 0 ;
}
2011-02-17 18:29:04 +03:00
/* Probably something like the ptys which have no
* symlink in / dev / char . Let ' s return something
* vaguely useful . */
if ( ! ( b = strdup ( fn + 5 ) ) )
return - ENOMEM ;
* r = b ;
2011-03-14 04:33:23 +03:00
if ( _devnr )
* _devnr = devnr ;
2011-02-17 18:29:04 +03:00
return 0 ;
}
if ( startswith ( s , " /dev/ " ) )
p = s + 5 ;
else if ( startswith ( s , " ../ " ) )
p = s + 3 ;
else
p = s ;
b = strdup ( p ) ;
free ( s ) ;
if ( ! b )
return - ENOMEM ;
* r = b ;
2011-03-14 04:33:23 +03:00
if ( _devnr )
* _devnr = devnr ;
2011-02-17 18:29:04 +03:00
return 0 ;
}
2011-08-21 22:05:51 +04:00
static int rm_rf_children ( int fd , bool only_dirs , bool honour_sticky ) {
2010-06-22 01:27:18 +04:00
DIR * d ;
int ret = 0 ;
assert ( fd > = 0 ) ;
/* This returns the first error we run into, but nevertheless
* tries to go on */
if ( ! ( d = fdopendir ( fd ) ) ) {
close_nointr_nofail ( fd ) ;
2010-07-13 21:00:01 +04:00
return errno = = ENOENT ? 0 : - errno ;
2010-06-22 01:27:18 +04:00
}
for ( ; ; ) {
struct dirent buf , * de ;
2011-08-21 22:05:51 +04:00
bool is_dir , keep_around = false ;
2010-06-22 01:27:18 +04:00
int r ;
if ( ( r = readdir_r ( d , & buf , & de ) ) ! = 0 ) {
if ( ret = = 0 )
ret = - r ;
break ;
}
if ( ! de )
break ;
if ( streq ( de - > d_name , " . " ) | | streq ( de - > d_name , " .. " ) )
continue ;
if ( de - > d_type = = DT_UNKNOWN ) {
struct stat st ;
if ( fstatat ( fd , de - > d_name , & st , AT_SYMLINK_NOFOLLOW ) < 0 ) {
2010-07-13 21:00:01 +04:00
if ( ret = = 0 & & errno ! = ENOENT )
2010-06-22 01:27:18 +04:00
ret = - errno ;
continue ;
}
2011-08-21 22:05:51 +04:00
if ( honour_sticky )
2012-01-18 18:40:21 +04:00
keep_around =
( st . st_uid = = 0 | | st . st_uid = = getuid ( ) ) & &
( st . st_mode & S_ISVTX ) ;
2011-08-21 22:05:51 +04:00
2010-06-22 01:27:18 +04:00
is_dir = S_ISDIR ( st . st_mode ) ;
2011-08-21 22:05:51 +04:00
} else {
if ( honour_sticky ) {
struct stat st ;
if ( fstatat ( fd , de - > d_name , & st , AT_SYMLINK_NOFOLLOW ) < 0 ) {
if ( ret = = 0 & & errno ! = ENOENT )
ret = - errno ;
continue ;
}
2012-01-18 18:40:21 +04:00
keep_around =
( st . st_uid = = 0 | | st . st_uid = = getuid ( ) ) & &
( st . st_mode & S_ISVTX ) ;
2011-08-21 22:05:51 +04:00
}
2010-06-22 01:27:18 +04:00
is_dir = de - > d_type = = DT_DIR ;
2011-08-21 22:05:51 +04:00
}
2010-06-22 01:27:18 +04:00
if ( is_dir ) {
int subdir_fd ;
if ( ( subdir_fd = openat ( fd , de - > d_name , O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC ) ) < 0 ) {
2010-07-13 21:00:01 +04:00
if ( ret = = 0 & & errno ! = ENOENT )
2010-06-22 01:27:18 +04:00
ret = - errno ;
continue ;
}
2011-08-21 22:05:51 +04:00
if ( ( r = rm_rf_children ( subdir_fd , only_dirs , honour_sticky ) ) < 0 ) {
2010-06-22 01:27:18 +04:00
if ( ret = = 0 )
ret = r ;
}
2011-08-21 22:05:51 +04:00
if ( ! keep_around )
if ( unlinkat ( fd , de - > d_name , AT_REMOVEDIR ) < 0 ) {
if ( ret = = 0 & & errno ! = ENOENT )
ret = - errno ;
}
} else if ( ! only_dirs & & ! keep_around ) {
2010-06-22 01:27:18 +04:00
if ( unlinkat ( fd , de - > d_name , 0 ) < 0 ) {
2010-07-13 21:00:01 +04:00
if ( ret = = 0 & & errno ! = ENOENT )
2010-06-22 01:27:18 +04:00
ret = - errno ;
}
}
}
closedir ( d ) ;
return ret ;
}
2011-08-21 22:05:51 +04:00
int rm_rf ( const char * path , bool only_dirs , bool delete_root , bool honour_sticky ) {
2010-06-22 01:27:18 +04:00
int fd ;
int r ;
assert ( path ) ;
if ( ( fd = open ( path , O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC ) ) < 0 ) {
if ( errno ! = ENOTDIR )
return - errno ;
if ( delete_root & & ! only_dirs )
if ( unlink ( path ) < 0 )
return - errno ;
return 0 ;
}
2011-08-21 22:05:51 +04:00
r = rm_rf_children ( fd , only_dirs , honour_sticky ) ;
if ( delete_root ) {
2012-01-18 18:40:21 +04:00
if ( honour_sticky & & file_is_priv_sticky ( path ) > 0 )
2011-08-21 22:05:51 +04:00
return r ;
2010-06-22 01:27:18 +04:00
2011-08-21 23:00:41 +04:00
if ( rmdir ( path ) < 0 & & errno ! = ENOENT ) {
2010-06-22 01:27:18 +04:00
if ( r = = 0 )
r = - errno ;
}
2011-08-21 22:05:51 +04:00
}
2010-06-22 01:27:18 +04:00
return r ;
}
int chmod_and_chown ( const char * path , mode_t mode , uid_t uid , gid_t gid ) {
assert ( path ) ;
/* Under the assumption that we are running privileged we
* first change the access mode and only then hand out
* ownership to avoid a window where access is too open . */
2012-01-18 18:40:21 +04:00
if ( mode ! = ( mode_t ) - 1 )
if ( chmod ( path , mode ) < 0 )
return - errno ;
2010-06-22 01:27:18 +04:00
2012-01-18 18:40:21 +04:00
if ( uid ! = ( uid_t ) - 1 | | gid ! = ( gid_t ) - 1 )
if ( chown ( path , uid , gid ) < 0 )
return - errno ;
2010-06-22 01:27:18 +04:00
return 0 ;
2010-06-18 04:28:35 +04:00
}
2011-10-08 01:03:07 +04:00
int fchmod_and_fchown ( int fd , mode_t mode , uid_t uid , gid_t gid ) {
assert ( fd > = 0 ) ;
/* Under the assumption that we are running privileged we
* first change the access mode and only then hand out
* ownership to avoid a window where access is too open . */
if ( fchmod ( fd , mode ) < 0 )
return - errno ;
if ( fchown ( fd , uid , gid ) < 0 )
return - errno ;
return 0 ;
}
2010-07-04 18:44:58 +04:00
cpu_set_t * cpu_set_malloc ( unsigned * ncpus ) {
cpu_set_t * r ;
unsigned n = 1024 ;
/* Allocates the cpuset in the right size */
for ( ; ; ) {
if ( ! ( r = CPU_ALLOC ( n ) ) )
return NULL ;
if ( sched_getaffinity ( 0 , CPU_ALLOC_SIZE ( n ) , r ) > = 0 ) {
CPU_ZERO_S ( CPU_ALLOC_SIZE ( n ) , r ) ;
if ( ncpus )
* ncpus = n ;
return r ;
}
CPU_FREE ( r ) ;
if ( errno ! = EINVAL )
return NULL ;
n * = 2 ;
}
}
2012-01-05 18:35:16 +04:00
void status_vprintf ( const char * status , bool ellipse , const char * format , va_list ap ) {
2012-01-05 06:24:39 +04:00
char * s = NULL , * spaces = NULL , * e ;
int fd = - 1 , c ;
size_t emax , sl , left ;
struct iovec iovec [ 5 ] ;
int n = 0 ;
2010-07-07 02:00:59 +04:00
assert ( format ) ;
/* This independent of logging, as status messages are
* optional and go exclusively to the console . */
if ( vasprintf ( & s , format , ap ) < 0 )
goto finish ;
2012-01-05 18:35:16 +04:00
fd = open_terminal ( " /dev/console " , O_WRONLY | O_NOCTTY | O_CLOEXEC ) ;
2012-01-05 06:24:39 +04:00
if ( fd < 0 )
2010-07-07 02:00:59 +04:00
goto finish ;
2012-01-05 18:35:16 +04:00
if ( ellipse ) {
c = fd_columns ( fd ) ;
if ( c < = 0 )
c = 80 ;
2012-01-05 06:24:39 +04:00
2012-01-05 18:35:16 +04:00
if ( status ) {
sl = 2 + 6 + 1 ; /* " [" status "]" */
emax = ( size_t ) c > sl ? c - sl - 1 : 0 ;
} else
emax = c - 1 ;
2012-01-05 06:24:39 +04:00
2012-01-05 18:35:16 +04:00
e = ellipsize ( s , emax , 75 ) ;
if ( e ) {
free ( s ) ;
s = e ;
}
2012-01-05 06:24:39 +04:00
}
zero ( iovec ) ;
IOVEC_SET_STRING ( iovec [ n + + ] , s ) ;
2012-01-05 18:35:16 +04:00
if ( ellipse ) {
sl = strlen ( s ) ;
left = emax > sl ? emax - sl : 0 ;
if ( left > 0 ) {
spaces = malloc ( left ) ;
if ( spaces ) {
memset ( spaces , ' ' , left ) ;
iovec [ n ] . iov_base = spaces ;
iovec [ n ] . iov_len = left ;
n + + ;
}
2012-01-05 06:24:39 +04:00
}
}
if ( status ) {
IOVEC_SET_STRING ( iovec [ n + + ] , " [ " ) ;
IOVEC_SET_STRING ( iovec [ n + + ] , status ) ;
IOVEC_SET_STRING ( iovec [ n + + ] , " ] \n " ) ;
} else
IOVEC_SET_STRING ( iovec [ n + + ] , " \n " ) ;
writev ( fd , iovec , n ) ;
2010-07-07 02:00:59 +04:00
finish :
free ( s ) ;
2012-01-05 06:24:39 +04:00
free ( spaces ) ;
2010-07-07 02:00:59 +04:00
if ( fd > = 0 )
close_nointr_nofail ( fd ) ;
}
2012-01-05 18:35:16 +04:00
void status_printf ( const char * status , bool ellipse , const char * format , . . . ) {
2010-07-07 02:25:41 +04:00
va_list ap ;
assert ( format ) ;
va_start ( ap , format ) ;
2012-01-05 18:35:16 +04:00
status_vprintf ( status , ellipse , format , ap ) ;
2010-07-07 02:25:41 +04:00
va_end ( ap ) ;
}
void status_welcome ( void ) {
2010-11-18 06:46:28 +03:00
char * pretty_name = NULL , * ansi_color = NULL ;
const char * const_pretty = NULL , * const_color = NULL ;
int r ;
2010-07-07 02:25:41 +04:00
2010-11-18 06:46:28 +03:00
if ( ( r = parse_env_file ( " /etc/os-release " , NEWLINE ,
" PRETTY_NAME " , & pretty_name ,
" ANSI_COLOR " , & ansi_color ,
NULL ) ) < 0 ) {
2010-07-07 02:25:41 +04:00
2010-11-18 06:46:28 +03:00
if ( r ! = - ENOENT )
log_warning ( " Failed to read /etc/os-release: %s " , strerror ( - r ) ) ;
}
2010-07-07 02:25:41 +04:00
2010-11-18 06:46:28 +03:00
if ( ! pretty_name & & ! const_pretty )
const_pretty = " Linux " ;
if ( ! ansi_color & & ! const_color )
const_color = " 1 " ;
2012-01-05 06:24:39 +04:00
status_printf ( NULL ,
2012-01-05 18:35:16 +04:00
false ,
2012-01-05 06:24:39 +04:00
" \n Welcome to \x1B [%sm%s \x1B [0m! \n " ,
2010-11-18 06:46:28 +03:00
const_color ? const_color : ansi_color ,
const_pretty ? const_pretty : pretty_name ) ;
2011-01-07 01:52:17 +03:00
free ( ansi_color ) ;
free ( pretty_name ) ;
2010-07-07 02:25:41 +04:00
}
2010-07-08 06:09:59 +04:00
char * replace_env ( const char * format , char * * env ) {
enum {
WORD ,
2010-07-21 04:57:35 +04:00
CURLY ,
2010-07-08 06:09:59 +04:00
VARIABLE
} state = WORD ;
const char * e , * word = format ;
char * r = NULL , * k ;
assert ( format ) ;
for ( e = format ; * e ; e + + ) {
switch ( state ) {
case WORD :
if ( * e = = ' $ ' )
2010-07-21 04:57:35 +04:00
state = CURLY ;
2010-07-08 06:09:59 +04:00
break ;
2010-07-21 04:57:35 +04:00
case CURLY :
if ( * e = = ' { ' ) {
2010-07-08 06:09:59 +04:00
if ( ! ( k = strnappend ( r , word , e - word - 1 ) ) )
goto fail ;
free ( r ) ;
r = k ;
word = e - 1 ;
state = VARIABLE ;
} else if ( * e = = ' $ ' ) {
if ( ! ( k = strnappend ( r , word , e - word ) ) )
goto fail ;
free ( r ) ;
r = k ;
word = e + 1 ;
state = WORD ;
} else
state = WORD ;
break ;
case VARIABLE :
2010-07-21 04:57:35 +04:00
if ( * e = = ' } ' ) {
2010-08-10 23:05:19 +04:00
const char * t ;
2010-07-08 06:09:59 +04:00
2010-08-10 23:05:19 +04:00
if ( ! ( t = strv_env_get_with_length ( env , word + 2 , e - word - 2 ) ) )
t = " " ;
2010-07-08 06:09:59 +04:00
2010-08-10 23:05:19 +04:00
if ( ! ( k = strappend ( r , t ) ) )
goto fail ;
2010-07-08 06:09:59 +04:00
2010-08-10 23:05:19 +04:00
free ( r ) ;
r = k ;
2010-07-08 06:09:59 +04:00
2010-08-10 23:05:19 +04:00
word = e + 1 ;
2010-07-08 06:09:59 +04:00
state = WORD ;
}
break ;
}
}
if ( ! ( k = strnappend ( r , word , e - word ) ) )
goto fail ;
free ( r ) ;
return k ;
fail :
free ( r ) ;
return NULL ;
}
char * * replace_env_argv ( char * * argv , char * * env ) {
char * * r , * * i ;
2010-07-21 04:57:35 +04:00
unsigned k = 0 , l = 0 ;
l = strv_length ( argv ) ;
2010-07-08 06:09:59 +04:00
2010-07-21 04:57:35 +04:00
if ( ! ( r = new ( char * , l + 1 ) ) )
2010-07-08 06:09:59 +04:00
return NULL ;
STRV_FOREACH ( i , argv ) {
2010-07-21 04:57:35 +04:00
/* If $FOO appears as single word, replace it by the split up variable */
2010-08-10 23:05:19 +04:00
if ( ( * i ) [ 0 ] = = ' $ ' & & ( * i ) [ 1 ] ! = ' { ' ) {
char * e ;
char * * w , * * m ;
unsigned q ;
2010-07-21 04:57:35 +04:00
2010-08-10 23:05:19 +04:00
if ( ( e = strv_env_get ( env , * i + 1 ) ) ) {
2010-07-21 04:57:35 +04:00
if ( ! ( m = strv_split_quoted ( e ) ) ) {
r [ k ] = NULL ;
strv_free ( r ) ;
return NULL ;
}
2010-08-10 23:05:19 +04:00
} else
m = NULL ;
2010-07-21 04:57:35 +04:00
2010-08-10 23:05:19 +04:00
q = strv_length ( m ) ;
l = l + q - 1 ;
2010-07-21 04:57:35 +04:00
2010-08-10 23:05:19 +04:00
if ( ! ( w = realloc ( r , sizeof ( char * ) * ( l + 1 ) ) ) ) {
r [ k ] = NULL ;
strv_free ( r ) ;
strv_free ( m ) ;
return NULL ;
}
2010-07-21 04:57:35 +04:00
2010-08-10 23:05:19 +04:00
r = w ;
if ( m ) {
2010-07-21 04:57:35 +04:00
memcpy ( r + k , m , q * sizeof ( char * ) ) ;
free ( m ) ;
}
2010-08-10 23:05:19 +04:00
k + = q ;
continue ;
2010-07-21 04:57:35 +04:00
}
/* If ${FOO} appears as part of a word, replace it by the variable as-is */
2010-07-08 06:09:59 +04:00
if ( ! ( r [ k + + ] = replace_env ( * i , env ) ) ) {
strv_free ( r ) ;
return NULL ;
}
}
r [ k ] = NULL ;
return r ;
}
2012-01-05 06:24:39 +04:00
int fd_columns ( int fd ) {
struct winsize ws ;
zero ( ws ) ;
if ( ioctl ( fd , TIOCGWINSZ , & ws ) < 0 )
return - errno ;
if ( ws . ws_col < = 0 )
return - EIO ;
return ws . ws_col ;
}
2011-12-21 21:17:22 +04:00
unsigned columns ( void ) {
2010-07-08 23:01:42 +04:00
static __thread int parsed_columns = 0 ;
const char * e ;
2011-08-01 07:05:59 +04:00
if ( _likely_ ( parsed_columns > 0 ) )
2010-07-08 23:01:42 +04:00
return parsed_columns ;
2012-01-05 06:24:39 +04:00
e = getenv ( " COLUMNS " ) ;
if ( e )
2010-07-08 23:01:42 +04:00
parsed_columns = atoi ( e ) ;
2012-01-05 06:24:39 +04:00
if ( parsed_columns < = 0 )
parsed_columns = fd_columns ( STDOUT_FILENO ) ;
2010-07-08 23:01:42 +04:00
if ( parsed_columns < = 0 )
parsed_columns = 80 ;
return parsed_columns ;
}
2012-01-22 21:21:15 +04:00
int fd_lines ( int fd ) {
struct winsize ws ;
zero ( ws ) ;
if ( ioctl ( fd , TIOCGWINSZ , & ws ) < 0 )
return - errno ;
if ( ws . ws_row < = 0 )
return - EIO ;
return ws . ws_row ;
}
unsigned lines ( void ) {
static __thread int parsed_lines = 0 ;
const char * e ;
if ( _likely_ ( parsed_lines > 0 ) )
return parsed_lines ;
e = getenv ( " LINES " ) ;
if ( e )
parsed_lines = atoi ( e ) ;
if ( parsed_lines < = 0 )
parsed_lines = fd_lines ( STDOUT_FILENO ) ;
if ( parsed_lines < = 0 )
parsed_lines = 25 ;
return parsed_lines ;
}
2010-07-08 23:34:51 +04:00
int running_in_chroot ( void ) {
struct stat a , b ;
zero ( a ) ;
zero ( b ) ;
/* Only works as root */
if ( stat ( " /proc/1/root " , & a ) < 0 )
return - errno ;
if ( stat ( " / " , & b ) < 0 )
return - errno ;
return
a . st_dev ! = b . st_dev | |
a . st_ino ! = b . st_ino ;
}
2011-12-21 21:17:22 +04:00
char * ellipsize_mem ( const char * s , size_t old_length , size_t new_length , unsigned percent ) {
size_t x ;
2010-07-20 22:33:19 +04:00
char * r ;
assert ( s ) ;
assert ( percent < = 100 ) ;
2011-12-21 21:17:22 +04:00
assert ( new_length > = 3 ) ;
2010-07-20 22:33:19 +04:00
2011-12-21 21:17:22 +04:00
if ( old_length < = 3 | | old_length < = new_length )
return strndup ( s , old_length ) ;
2010-07-20 22:33:19 +04:00
2011-12-21 21:17:22 +04:00
r = new0 ( char , new_length + 1 ) ;
if ( ! r )
2010-07-20 22:33:19 +04:00
return r ;
2011-12-21 21:17:22 +04:00
x = ( new_length * percent ) / 100 ;
2010-07-20 22:33:19 +04:00
2011-12-21 21:17:22 +04:00
if ( x > new_length - 3 )
x = new_length - 3 ;
2010-07-20 22:33:19 +04:00
memcpy ( r , s , x ) ;
r [ x ] = ' . ' ;
r [ x + 1 ] = ' . ' ;
r [ x + 2 ] = ' . ' ;
memcpy ( r + x + 3 ,
2011-12-21 21:17:22 +04:00
s + old_length - ( new_length - x - 3 ) ,
new_length - x - 3 ) ;
2010-07-20 22:33:19 +04:00
return r ;
}
2011-12-21 21:17:22 +04:00
char * ellipsize ( const char * s , size_t length , unsigned percent ) {
return ellipsize_mem ( s , strlen ( s ) , length , percent ) ;
}
2010-08-16 17:37:52 +04:00
int touch ( const char * path ) {
int fd ;
assert ( path ) ;
2011-03-16 04:58:05 +03:00
if ( ( fd = open ( path , O_WRONLY | O_CREAT | O_CLOEXEC | O_NOCTTY , 0644 ) ) < 0 )
2010-08-16 17:37:52 +04:00
return - errno ;
close_nointr_nofail ( fd ) ;
return 0 ;
}
2010-08-12 01:31:07 +04:00
2010-09-16 02:36:41 +04:00
char * unquote ( const char * s , const char * quotes ) {
2010-08-20 04:46:15 +04:00
size_t l ;
assert ( s ) ;
2012-01-18 19:39:04 +04:00
l = strlen ( s ) ;
if ( l < 2 )
2010-08-20 04:46:15 +04:00
return strdup ( s ) ;
2010-09-16 02:36:41 +04:00
if ( strchr ( quotes , s [ 0 ] ) & & s [ l - 1 ] = = s [ 0 ] )
2010-08-20 04:46:15 +04:00
return strndup ( s + 1 , l - 2 ) ;
return strdup ( s ) ;
}
2011-01-05 18:06:35 +03:00
char * normalize_env_assignment ( const char * s ) {
char * name , * value , * p , * r ;
p = strchr ( s , ' = ' ) ;
if ( ! p ) {
if ( ! ( r = strdup ( s ) ) )
return NULL ;
return strstrip ( r ) ;
}
if ( ! ( name = strndup ( s , p - s ) ) )
return NULL ;
if ( ! ( p = strdup ( p + 1 ) ) ) {
free ( name ) ;
return NULL ;
}
value = unquote ( strstrip ( p ) , QUOTES ) ;
free ( p ) ;
if ( ! value ) {
free ( name ) ;
return NULL ;
}
if ( asprintf ( & r , " %s=%s " , name , value ) < 0 )
r = NULL ;
free ( value ) ;
free ( name ) ;
return r ;
}
2010-09-15 16:48:59 +04:00
int wait_for_terminate ( pid_t pid , siginfo_t * status ) {
2011-07-07 04:34:35 +04:00
siginfo_t dummy ;
2010-09-15 16:37:16 +04:00
assert ( pid > = 1 ) ;
2011-07-07 04:34:35 +04:00
if ( ! status )
status = & dummy ;
2010-09-15 16:37:16 +04:00
for ( ; ; ) {
2010-09-15 16:48:59 +04:00
zero ( * status ) ;
if ( waitid ( P_PID , pid , status , WEXITED ) < 0 ) {
2010-09-15 16:37:16 +04:00
if ( errno = = EINTR )
continue ;
return - errno ;
}
return 0 ;
}
}
2010-09-16 02:36:41 +04:00
int wait_for_terminate_and_warn ( const char * name , pid_t pid ) {
int r ;
siginfo_t status ;
assert ( name ) ;
assert ( pid > 1 ) ;
if ( ( r = wait_for_terminate ( pid , & status ) ) < 0 ) {
log_warning ( " Failed to wait for %s: %s " , name , strerror ( - r ) ) ;
return r ;
}
if ( status . si_code = = CLD_EXITED ) {
if ( status . si_status ! = 0 ) {
log_warning ( " %s failed with error code %i. " , name , status . si_status ) ;
2011-03-14 04:33:51 +03:00
return status . si_status ;
2010-09-16 02:36:41 +04:00
}
log_debug ( " %s succeeded. " , name ) ;
return 0 ;
} else if ( status . si_code = = CLD_KILLED | |
status . si_code = = CLD_DUMPED ) {
log_warning ( " %s terminated by signal %s. " , name , signal_to_string ( status . si_status ) ) ;
return - EPROTO ;
}
log_warning ( " %s failed due to unknown reason. " , name ) ;
return - EPROTO ;
}
2012-02-29 17:42:49 +04:00
_noreturn_ void freeze ( void ) {
2011-03-11 02:52:13 +03:00
/* Make sure nobody waits for us on a socket anymore */
close_all_fds ( NULL , 0 ) ;
2011-01-01 21:50:32 +03:00
sync ( ) ;
2010-10-07 21:34:56 +04:00
for ( ; ; )
pause ( ) ;
}
2010-10-08 04:31:36 +04:00
bool null_or_empty ( struct stat * st ) {
assert ( st ) ;
if ( S_ISREG ( st - > st_mode ) & & st - > st_size < = 0 )
return true ;
2010-10-08 20:22:28 +04:00
if ( S_ISCHR ( st - > st_mode ) | | S_ISBLK ( st - > st_mode ) )
2010-10-08 04:31:36 +04:00
return true ;
return false ;
}
2011-07-22 06:21:18 +04:00
int null_or_empty_path ( const char * fn ) {
struct stat st ;
assert ( fn ) ;
if ( stat ( fn , & st ) < 0 )
return - errno ;
return null_or_empty ( & st ) ;
}
2010-12-28 16:20:21 +03:00
DIR * xopendirat ( int fd , const char * name , int flags ) {
2011-01-05 18:17:26 +03:00
int nfd ;
DIR * d ;
if ( ( nfd = openat ( fd , name , O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | flags ) ) < 0 )
return NULL ;
if ( ! ( d = fdopendir ( nfd ) ) ) {
close_nointr_nofail ( nfd ) ;
return NULL ;
}
return d ;
2010-10-19 00:38:41 +04:00
}
2010-10-22 18:11:50 +04:00
int signal_from_string_try_harder ( const char * s ) {
int signo ;
assert ( s ) ;
if ( ( signo = signal_from_string ( s ) ) < = 0 )
if ( startswith ( s , " SIG " ) )
return signal_from_string ( s + 3 ) ;
return signo ;
}
2010-10-27 02:01:12 +04:00
void dual_timestamp_serialize ( FILE * f , const char * name , dual_timestamp * t ) {
assert ( f ) ;
assert ( name ) ;
assert ( t ) ;
if ( ! dual_timestamp_is_set ( t ) )
return ;
fprintf ( f , " %s=%llu %llu \n " ,
name ,
( unsigned long long ) t - > realtime ,
( unsigned long long ) t - > monotonic ) ;
}
2010-10-28 05:16:03 +04:00
void dual_timestamp_deserialize ( const char * value , dual_timestamp * t ) {
2010-10-27 02:01:12 +04:00
unsigned long long a , b ;
assert ( value ) ;
assert ( t ) ;
if ( sscanf ( value , " %lli %llu " , & a , & b ) ! = 2 )
log_debug ( " Failed to parse finish timestamp value %s " , value ) ;
else {
t - > realtime = a ;
t - > monotonic = b ;
}
}
2010-11-08 07:02:45 +03:00
char * fstab_node_to_udev_node ( const char * p ) {
char * dn , * t , * u ;
int r ;
/* FIXME: to follow udev's logic 100% we need to leave valid
* UTF8 chars unescaped */
if ( startswith ( p , " LABEL= " ) ) {
if ( ! ( u = unquote ( p + 6 , " \" \' " ) ) )
return NULL ;
t = xescape ( u , " / " ) ;
free ( u ) ;
if ( ! t )
return NULL ;
r = asprintf ( & dn , " /dev/disk/by-label/%s " , t ) ;
free ( t ) ;
if ( r < 0 )
return NULL ;
return dn ;
}
if ( startswith ( p , " UUID= " ) ) {
if ( ! ( u = unquote ( p + 5 , " \" \' " ) ) )
return NULL ;
t = xescape ( u , " / " ) ;
free ( u ) ;
if ( ! t )
return NULL ;
2011-01-19 00:32:15 +03:00
r = asprintf ( & dn , " /dev/disk/by-uuid/%s " , t ) ;
2010-11-08 07:02:45 +03:00
free ( t ) ;
if ( r < 0 )
return NULL ;
return dn ;
}
return strdup ( p ) ;
}
2010-11-08 08:31:09 +03:00
void filter_environ ( const char * prefix ) {
int i , j ;
assert ( prefix ) ;
if ( ! environ )
return ;
for ( i = 0 , j = 0 ; environ [ i ] ; i + + ) {
if ( startswith ( environ [ i ] , prefix ) )
continue ;
environ [ j + + ] = environ [ i ] ;
}
environ [ j ] = NULL ;
}
2011-02-14 20:56:51 +03:00
bool tty_is_vc ( const char * tty ) {
assert ( tty ) ;
if ( startswith ( tty , " /dev/ " ) )
tty + = 5 ;
2011-06-24 20:50:50 +04:00
return vtnr_from_tty ( tty ) > = 0 ;
}
int vtnr_from_tty ( const char * tty ) {
int i , r ;
assert ( tty ) ;
if ( startswith ( tty , " /dev/ " ) )
tty + = 5 ;
if ( ! startswith ( tty , " tty " ) )
return - EINVAL ;
if ( tty [ 3 ] < ' 0 ' | | tty [ 3 ] > ' 9 ' )
return - EINVAL ;
r = safe_atoi ( tty + 3 , & i ) ;
if ( r < 0 )
return r ;
if ( i < 0 | | i > 63 )
return - EINVAL ;
return i ;
2011-02-14 20:56:51 +03:00
}
2012-01-14 00:56:28 +04:00
bool tty_is_vc_resolve ( const char * tty ) {
2011-02-13 21:01:47 +03:00
char * active = NULL ;
2012-01-14 00:56:28 +04:00
bool b ;
2011-02-13 21:01:47 +03:00
2010-11-16 01:49:02 +03:00
assert ( tty ) ;
if ( startswith ( tty , " /dev/ " ) )
tty + = 5 ;
2012-01-14 00:56:28 +04:00
/* Resolve where /dev/console is pointing to */
2011-02-13 21:01:47 +03:00
if ( streq ( tty , " console " ) )
if ( read_one_line_file ( " /sys/class/tty/console/active " , & active ) > = 0 ) {
2011-02-14 21:54:15 +03:00
/* If multiple log outputs are configured the
* last one is what / dev / console points to */
2012-01-14 00:56:28 +04:00
tty = strrchr ( active , ' ' ) ;
if ( tty )
2011-02-14 21:54:15 +03:00
tty + + ;
else
tty = active ;
2011-02-13 21:01:47 +03:00
}
2012-01-14 00:56:28 +04:00
b = tty_is_vc ( tty ) ;
2011-02-13 21:01:47 +03:00
free ( active ) ;
2010-11-16 01:49:02 +03:00
2012-01-14 00:56:28 +04:00
return b ;
}
const char * default_term_for_tty ( const char * tty ) {
assert ( tty ) ;
return tty_is_vc_resolve ( tty ) ? " TERM=linux " : " TERM=vt100 " ;
2010-11-16 01:49:02 +03:00
}
2011-10-07 23:06:39 +04:00
bool dirent_is_file ( const struct dirent * de ) {
2011-05-23 23:39:15 +04:00
assert ( de ) ;
if ( ignore_file ( de - > d_name ) )
return false ;
if ( de - > d_type ! = DT_REG & &
de - > d_type ! = DT_LNK & &
de - > d_type ! = DT_UNKNOWN )
return false ;
return true ;
}
2011-10-07 23:06:39 +04:00
bool dirent_is_file_with_suffix ( const struct dirent * de , const char * suffix ) {
assert ( de ) ;
if ( ! dirent_is_file ( de ) )
return false ;
return endswith ( de - > d_name , suffix ) ;
}
2011-02-15 02:30:11 +03:00
void execute_directory ( const char * directory , DIR * d , char * argv [ ] ) {
DIR * _d = NULL ;
struct dirent * de ;
Hashmap * pids = NULL ;
assert ( directory ) ;
/* Executes all binaries in a directory in parallel and waits
* until all they all finished . */
if ( ! d ) {
if ( ! ( _d = opendir ( directory ) ) ) {
if ( errno = = ENOENT )
return ;
log_error ( " Failed to enumerate directory %s: %m " , directory ) ;
return ;
}
d = _d ;
}
if ( ! ( pids = hashmap_new ( trivial_hash_func , trivial_compare_func ) ) ) {
log_error ( " Failed to allocate set. " ) ;
goto finish ;
}
while ( ( de = readdir ( d ) ) ) {
char * path ;
pid_t pid ;
int k ;
2011-05-23 23:39:15 +04:00
if ( ! dirent_is_file ( de ) )
2011-02-15 02:30:11 +03:00
continue ;
if ( asprintf ( & path , " %s/%s " , directory , de - > d_name ) < 0 ) {
log_error ( " Out of memory " ) ;
continue ;
}
if ( ( pid = fork ( ) ) < 0 ) {
log_error ( " Failed to fork: %m " ) ;
free ( path ) ;
continue ;
}
if ( pid = = 0 ) {
char * _argv [ 2 ] ;
/* Child */
if ( ! argv ) {
_argv [ 0 ] = path ;
_argv [ 1 ] = NULL ;
argv = _argv ;
} else
if ( ! argv [ 0 ] )
argv [ 0 ] = path ;
execv ( path , argv ) ;
log_error ( " Failed to execute %s: %m " , path ) ;
_exit ( EXIT_FAILURE ) ;
}
log_debug ( " Spawned %s as %lu " , path , ( unsigned long ) pid ) ;
if ( ( k = hashmap_put ( pids , UINT_TO_PTR ( pid ) , path ) ) < 0 ) {
log_error ( " Failed to add PID to set: %s " , strerror ( - k ) ) ;
free ( path ) ;
}
}
while ( ! hashmap_isempty ( pids ) ) {
2012-02-02 21:32:05 +04:00
pid_t pid = PTR_TO_UINT ( hashmap_first_key ( pids ) ) ;
2011-02-15 02:30:11 +03:00
siginfo_t si ;
char * path ;
zero ( si ) ;
2012-02-02 21:32:05 +04:00
if ( waitid ( P_PID , pid , & si , WEXITED ) < 0 ) {
2011-02-15 02:30:11 +03:00
if ( errno = = EINTR )
continue ;
log_error ( " waitid() failed: %m " ) ;
goto finish ;
}
if ( ( path = hashmap_remove ( pids , UINT_TO_PTR ( si . si_pid ) ) ) ) {
if ( ! is_clean_exit ( si . si_code , si . si_status ) ) {
if ( si . si_code = = CLD_EXITED )
log_error ( " %s exited with exit status %i. " , path , si . si_status ) ;
else
log_error ( " %s terminated by signal %s. " , path , signal_to_string ( si . si_status ) ) ;
} else
log_debug ( " %s exited successfully. " , path ) ;
free ( path ) ;
}
}
finish :
if ( _d )
closedir ( _d ) ;
if ( pids )
hashmap_free_free ( pids ) ;
}
2011-03-04 01:55:30 +03:00
int kill_and_sigcont ( pid_t pid , int sig ) {
int r ;
r = kill ( pid , sig ) < 0 ? - errno : 0 ;
if ( r > = 0 )
kill ( pid , SIGCONT ) ;
return r ;
}
2011-03-09 22:01:53 +03:00
bool nulstr_contains ( const char * nulstr , const char * needle ) {
const char * i ;
if ( ! nulstr )
return false ;
NULSTR_FOREACH ( i , nulstr )
if ( streq ( i , needle ) )
return true ;
return false ;
}
2011-03-30 04:21:48 +04:00
bool plymouth_running ( void ) {
2011-03-31 06:26:40 +04:00
return access ( " /run/plymouth/pid " , F_OK ) > = 0 ;
2011-03-30 04:21:48 +04:00
}
2011-04-04 00:14:34 +04:00
void parse_syslog_priority ( char * * p , int * priority ) {
int a = 0 , b = 0 , c = 0 ;
int k ;
assert ( p ) ;
assert ( * p ) ;
assert ( priority ) ;
if ( ( * p ) [ 0 ] ! = ' < ' )
return ;
if ( ! strchr ( * p , ' > ' ) )
return ;
if ( ( * p ) [ 2 ] = = ' > ' ) {
c = undecchar ( ( * p ) [ 1 ] ) ;
k = 3 ;
} else if ( ( * p ) [ 3 ] = = ' > ' ) {
b = undecchar ( ( * p ) [ 1 ] ) ;
c = undecchar ( ( * p ) [ 2 ] ) ;
k = 4 ;
} else if ( ( * p ) [ 4 ] = = ' > ' ) {
a = undecchar ( ( * p ) [ 1 ] ) ;
b = undecchar ( ( * p ) [ 2 ] ) ;
c = undecchar ( ( * p ) [ 3 ] ) ;
k = 5 ;
} else
return ;
if ( a < 0 | | b < 0 | | c < 0 )
return ;
* priority = a * 100 + b * 10 + c ;
* p + = k ;
}
2011-10-07 23:06:39 +04:00
void skip_syslog_pid ( char * * buf ) {
char * p ;
assert ( buf ) ;
assert ( * buf ) ;
p = * buf ;
if ( * p ! = ' [ ' )
return ;
p + + ;
p + = strspn ( p , " 0123456789 " ) ;
if ( * p ! = ' ] ' )
return ;
p + + ;
* buf = p ;
}
void skip_syslog_date ( char * * buf ) {
enum {
LETTER ,
SPACE ,
NUMBER ,
SPACE_OR_NUMBER ,
COLON
} sequence [ ] = {
LETTER , LETTER , LETTER ,
SPACE ,
SPACE_OR_NUMBER , NUMBER ,
SPACE ,
SPACE_OR_NUMBER , NUMBER ,
COLON ,
SPACE_OR_NUMBER , NUMBER ,
COLON ,
SPACE_OR_NUMBER , NUMBER ,
SPACE
} ;
char * p ;
unsigned i ;
assert ( buf ) ;
assert ( * buf ) ;
p = * buf ;
for ( i = 0 ; i < ELEMENTSOF ( sequence ) ; i + + , p + + ) {
if ( ! * p )
return ;
switch ( sequence [ i ] ) {
case SPACE :
if ( * p ! = ' ' )
return ;
break ;
case SPACE_OR_NUMBER :
if ( * p = = ' ' )
break ;
/* fall through */
case NUMBER :
if ( * p < ' 0 ' | | * p > ' 9 ' )
return ;
break ;
case LETTER :
if ( ! ( * p > = ' A ' & & * p < = ' Z ' ) & &
! ( * p > = ' a ' & & * p < = ' z ' ) )
return ;
break ;
case COLON :
if ( * p ! = ' : ' )
return ;
break ;
}
}
* buf = p ;
}
2011-04-12 23:08:44 +04:00
int have_effective_cap ( int value ) {
cap_t cap ;
cap_flag_value_t fv ;
int r ;
if ( ! ( cap = cap_get_proc ( ) ) )
return - errno ;
if ( cap_get_flag ( cap , value , CAP_EFFECTIVE , & fv ) < 0 )
r = - errno ;
else
r = fv = = CAP_SET ;
cap_free ( cap ) ;
return r ;
}
2011-04-16 03:57:23 +04:00
char * strshorten ( char * s , size_t l ) {
assert ( s ) ;
if ( l < strlen ( s ) )
s [ l ] = 0 ;
return s ;
}
static bool hostname_valid_char ( char c ) {
return
( c > = ' a ' & & c < = ' z ' ) | |
( c > = ' A ' & & c < = ' Z ' ) | |
( c > = ' 0 ' & & c < = ' 9 ' ) | |
c = = ' - ' | |
c = = ' _ ' | |
c = = ' . ' ;
}
bool hostname_is_valid ( const char * s ) {
const char * p ;
if ( isempty ( s ) )
return false ;
for ( p = s ; * p ; p + + )
if ( ! hostname_valid_char ( * p ) )
return false ;
if ( p - s > HOST_NAME_MAX )
return false ;
return true ;
}
char * hostname_cleanup ( char * s ) {
char * p , * d ;
for ( p = s , d = s ; * p ; p + + )
if ( ( * p > = ' a ' & & * p < = ' z ' ) | |
( * p > = ' A ' & & * p < = ' Z ' ) | |
( * p > = ' 0 ' & & * p < = ' 9 ' ) | |
* p = = ' - ' | |
* p = = ' _ ' | |
* p = = ' . ' )
* ( d + + ) = * p ;
* d = 0 ;
strshorten ( s , HOST_NAME_MAX ) ;
return s ;
}
2011-05-24 01:54:00 +04:00
int pipe_eof ( int fd ) {
struct pollfd pollfd ;
int r ;
zero ( pollfd ) ;
pollfd . fd = fd ;
pollfd . events = POLLIN | POLLHUP ;
r = poll ( & pollfd , 1 , 0 ) ;
if ( r < 0 )
return - errno ;
if ( r = = 0 )
return 0 ;
return pollfd . revents & POLLHUP ;
}
2012-01-22 21:21:15 +04:00
int fd_wait_for_event ( int fd , int event , usec_t t ) {
2012-01-04 21:33:36 +04:00
struct pollfd pollfd ;
int r ;
zero ( pollfd ) ;
pollfd . fd = fd ;
pollfd . events = event ;
2012-01-22 21:21:15 +04:00
r = poll ( & pollfd , 1 , t = = ( usec_t ) - 1 ? - 1 : ( int ) ( t / USEC_PER_MSEC ) ) ;
2012-01-04 21:33:36 +04:00
if ( r < 0 )
return - errno ;
if ( r = = 0 )
return 0 ;
return pollfd . revents ;
}
2011-05-25 02:54:32 +04:00
int fopen_temporary ( const char * path , FILE * * _f , char * * _temp_path ) {
FILE * f ;
char * t ;
const char * fn ;
size_t k ;
int fd ;
assert ( path ) ;
assert ( _f ) ;
assert ( _temp_path ) ;
t = new ( char , strlen ( path ) + 1 + 6 + 1 ) ;
if ( ! t )
return - ENOMEM ;
fn = file_name_from_path ( path ) ;
k = fn - path ;
memcpy ( t , path , k ) ;
t [ k ] = ' . ' ;
stpcpy ( stpcpy ( t + k + 1 , fn ) , " XXXXXX " ) ;
fd = mkostemp ( t , O_WRONLY | O_CLOEXEC ) ;
if ( fd < 0 ) {
free ( t ) ;
return - errno ;
}
f = fdopen ( fd , " we " ) ;
if ( ! f ) {
unlink ( t ) ;
free ( t ) ;
return - errno ;
}
* _f = f ;
* _temp_path = t ;
return 0 ;
}
2011-05-18 03:07:31 +04:00
int terminal_vhangup_fd ( int fd ) {
2011-05-25 02:54:32 +04:00
assert ( fd > = 0 ) ;
2011-05-18 03:07:31 +04:00
if ( ioctl ( fd , TIOCVHANGUP ) < 0 )
return - errno ;
return 0 ;
}
int terminal_vhangup ( const char * name ) {
int fd , r ;
fd = open_terminal ( name , O_RDWR | O_NOCTTY | O_CLOEXEC ) ;
if ( fd < 0 )
return fd ;
r = terminal_vhangup_fd ( fd ) ;
close_nointr_nofail ( fd ) ;
return r ;
}
int vt_disallocate ( const char * name ) {
int fd , r ;
unsigned u ;
/* Deallocate the VT if possible. If not possible
* ( i . e . because it is the active one ) , at least clear it
* entirely ( including the scrollback buffer ) */
2011-05-20 16:37:14 +04:00
if ( ! startswith ( name , " /dev/ " ) )
return - EINVAL ;
if ( ! tty_is_vc ( name ) ) {
/* So this is not a VT. I guess we cannot deallocate
* it then . But let ' s at least clear the screen */
fd = open_terminal ( name , O_RDWR | O_NOCTTY | O_CLOEXEC ) ;
if ( fd < 0 )
return fd ;
2011-06-29 23:17:31 +04:00
loop_write ( fd ,
" \033 [r " /* clear scrolling region */
" \033 [H " /* move home */
" \033 [2J " , /* clear screen */
10 , false ) ;
2011-05-20 16:37:14 +04:00
close_nointr_nofail ( fd ) ;
return 0 ;
}
2011-05-18 03:07:31 +04:00
if ( ! startswith ( name , " /dev/tty " ) )
return - EINVAL ;
r = safe_atou ( name + 8 , & u ) ;
if ( r < 0 )
return r ;
if ( u < = 0 )
2011-05-20 16:37:14 +04:00
return - EINVAL ;
2011-05-18 03:07:31 +04:00
2011-05-20 16:37:14 +04:00
/* Try to deallocate */
2011-05-18 03:07:31 +04:00
fd = open_terminal ( " /dev/tty0 " , O_RDWR | O_NOCTTY | O_CLOEXEC ) ;
if ( fd < 0 )
return fd ;
r = ioctl ( fd , VT_DISALLOCATE , u ) ;
2011-05-20 16:37:14 +04:00
close_nointr_nofail ( fd ) ;
2011-05-18 03:07:31 +04:00
2011-05-20 16:37:14 +04:00
if ( r > = 0 )
return 0 ;
2011-05-18 03:07:31 +04:00
2011-05-20 16:37:14 +04:00
if ( errno ! = EBUSY )
2011-05-18 03:07:31 +04:00
return - errno ;
2011-05-20 16:37:14 +04:00
/* Couldn't deallocate, so let's clear it fully with
* scrollback */
fd = open_terminal ( name , O_RDWR | O_NOCTTY | O_CLOEXEC ) ;
2011-05-18 03:07:31 +04:00
if ( fd < 0 )
2011-05-20 16:37:14 +04:00
return fd ;
2011-05-18 03:07:31 +04:00
2011-06-29 23:17:31 +04:00
loop_write ( fd ,
" \033 [r " /* clear scrolling region */
" \033 [H " /* move home */
" \033 [3J " , /* clear screen including scrollback, requires Linux 2.6.40 */
10 , false ) ;
2011-05-20 16:37:14 +04:00
close_nointr_nofail ( fd ) ;
2011-05-18 03:07:31 +04:00
2011-05-20 16:37:14 +04:00
return 0 ;
2011-05-18 03:07:31 +04:00
}
2011-04-25 22:41:47 +04:00
static int files_add ( Hashmap * h , const char * path , const char * suffix ) {
DIR * dir ;
2011-07-22 06:25:25 +04:00
struct dirent buffer , * de ;
2011-04-25 22:41:47 +04:00
int r = 0 ;
dir = opendir ( path ) ;
if ( ! dir ) {
if ( errno = = ENOENT )
return 0 ;
return - errno ;
}
2011-07-22 06:25:25 +04:00
for ( ; ; ) {
int k ;
2011-04-30 22:31:33 +04:00
char * p , * f ;
2011-07-22 06:25:25 +04:00
k = readdir_r ( dir , & buffer , & de ) ;
if ( k ! = 0 ) {
r = - k ;
goto finish ;
}
if ( ! de )
break ;
2011-04-25 22:41:47 +04:00
2011-10-07 23:06:39 +04:00
if ( ! dirent_is_file_with_suffix ( de , suffix ) )
2011-04-25 22:41:47 +04:00
continue ;
2011-04-30 22:31:33 +04:00
if ( asprintf ( & p , " %s/%s " , path , de - > d_name ) < 0 ) {
2011-04-25 22:41:47 +04:00
r = - ENOMEM ;
goto finish ;
}
2011-04-30 22:31:33 +04:00
f = canonicalize_file_name ( p ) ;
if ( ! f ) {
log_error ( " Failed to canonicalize file name '%s': %m " , p ) ;
free ( p ) ;
continue ;
}
free ( p ) ;
2011-04-25 22:41:47 +04:00
log_debug ( " found: %s \n " , f ) ;
2011-07-22 06:25:25 +04:00
if ( hashmap_put ( h , file_name_from_path ( f ) , f ) < = 0 )
2011-04-25 22:41:47 +04:00
free ( f ) ;
}
finish :
closedir ( dir ) ;
return r ;
}
static int base_cmp ( const void * a , const void * b ) {
const char * s1 , * s2 ;
s1 = * ( char * const * ) a ;
s2 = * ( char * const * ) b ;
return strcmp ( file_name_from_path ( s1 ) , file_name_from_path ( s2 ) ) ;
}
2011-04-29 01:51:24 +04:00
int conf_files_list ( char * * * strv , const char * suffix , const char * dir , . . . ) {
2011-04-30 22:31:33 +04:00
Hashmap * fh = NULL ;
char * * dirs = NULL ;
2011-04-25 22:41:47 +04:00
char * * files = NULL ;
2011-04-30 22:31:33 +04:00
char * * p ;
2011-04-25 22:41:47 +04:00
va_list ap ;
2011-04-29 01:51:24 +04:00
int r = 0 ;
2011-04-25 22:41:47 +04:00
2011-04-30 22:31:33 +04:00
va_start ( ap , dir ) ;
dirs = strv_new_ap ( dir , ap ) ;
va_end ( ap ) ;
if ( ! dirs ) {
r = - ENOMEM ;
goto finish ;
}
if ( ! strv_path_canonicalize ( dirs ) ) {
r = - ENOMEM ;
goto finish ;
}
if ( ! strv_uniq ( dirs ) ) {
r = - ENOMEM ;
goto finish ;
}
2011-04-25 22:41:47 +04:00
fh = hashmap_new ( string_hash_func , string_compare_func ) ;
if ( ! fh ) {
2011-04-29 01:51:24 +04:00
r = - ENOMEM ;
2011-04-25 22:41:47 +04:00
goto finish ;
}
2011-04-30 22:31:33 +04:00
STRV_FOREACH ( p , dirs ) {
if ( files_add ( fh , * p , suffix ) < 0 ) {
2011-04-25 22:41:47 +04:00
log_error ( " Failed to search for files. " ) ;
2011-04-29 01:51:24 +04:00
r = - EINVAL ;
2011-04-25 22:41:47 +04:00
goto finish ;
}
}
files = hashmap_get_strv ( fh ) ;
if ( files = = NULL ) {
log_error ( " Failed to compose list of files. " ) ;
2011-04-29 01:51:24 +04:00
r = - ENOMEM ;
2011-04-25 22:41:47 +04:00
goto finish ;
}
qsort ( files , hashmap_size ( fh ) , sizeof ( char * ) , base_cmp ) ;
2011-06-15 17:31:54 +04:00
2011-04-25 22:41:47 +04:00
finish :
2011-04-30 22:31:33 +04:00
strv_free ( dirs ) ;
2011-04-25 22:41:47 +04:00
hashmap_free ( fh ) ;
2011-04-29 01:51:24 +04:00
* strv = files ;
return r ;
2011-04-25 22:41:47 +04:00
}
2011-05-24 22:23:07 +04:00
2011-06-16 23:52:11 +04:00
int hwclock_is_localtime ( void ) {
2011-05-24 22:23:07 +04:00
FILE * f ;
bool local = false ;
/*
* The third line of adjtime is " UTC " or " LOCAL " or nothing .
* # / etc / adjtime
2011-06-16 23:52:11 +04:00
* 0.0 0 0
2011-05-24 22:23:07 +04:00
* 0
* UTC
*/
f = fopen ( " /etc/adjtime " , " re " ) ;
if ( f ) {
2011-06-16 23:52:11 +04:00
char line [ LINE_MAX ] ;
bool b ;
b = fgets ( line , sizeof ( line ) , f ) & &
fgets ( line , sizeof ( line ) , f ) & &
fgets ( line , sizeof ( line ) , f ) ;
2011-05-24 22:23:07 +04:00
fclose ( f ) ;
2011-06-16 23:52:11 +04:00
if ( ! b )
return - EIO ;
truncate_nl ( line ) ;
local = streq ( line , " LOCAL " ) ;
} else if ( errno ! = - ENOENT )
return - errno ;
2011-05-24 22:23:07 +04:00
return local ;
}
2011-07-21 22:28:27 +04:00
int hwclock_apply_localtime_delta ( int * min ) {
2011-05-24 22:23:07 +04:00
const struct timeval * tv_null = NULL ;
2011-06-16 23:52:11 +04:00
struct timespec ts ;
2011-05-24 22:23:07 +04:00
struct tm * tm ;
int minuteswest ;
struct timezone tz ;
2011-06-16 23:52:11 +04:00
assert_se ( clock_gettime ( CLOCK_REALTIME , & ts ) = = 0 ) ;
assert_se ( tm = localtime ( & ts . tv_sec ) ) ;
2011-05-24 22:23:07 +04:00
minuteswest = tm - > tm_gmtoff / 60 ;
tz . tz_minuteswest = - minuteswest ;
tz . tz_dsttime = 0 ; /* DST_NONE*/
/*
* If the hardware clock does not run in UTC , but in local time :
* The very first time we set the kernel ' s timezone , it will warp
* the clock so that it runs in UTC instead of local time .
*/
if ( settimeofday ( tv_null , & tz ) < 0 )
return - errno ;
2011-07-21 22:28:27 +04:00
if ( min )
* min = minuteswest ;
return 0 ;
2011-06-16 23:52:11 +04:00
}
int hwclock_reset_localtime_delta ( void ) {
const struct timeval * tv_null = NULL ;
struct timezone tz ;
tz . tz_minuteswest = 0 ;
tz . tz_dsttime = 0 ; /* DST_NONE*/
if ( settimeofday ( tv_null , & tz ) < 0 )
return - errno ;
return 0 ;
2011-05-24 22:23:07 +04:00
}
2012-01-21 06:15:54 +04:00
int rtc_open ( int flags ) {
int fd ;
DIR * d ;
2012-01-24 00:56:55 +04:00
/* First, we try to make use of the /dev/rtc symlink. If that
* doesn ' t exist , we open the first RTC which has hctosys = 1
* set . If we don ' t find any we just take the first RTC that
* exists at all . */
fd = open ( " /dev/rtc " , flags ) ;
if ( fd > = 0 )
return fd ;
2012-01-21 06:15:54 +04:00
d = opendir ( " /sys/class/rtc " ) ;
if ( ! d )
goto fallback ;
for ( ; ; ) {
char * p , * v ;
struct dirent buf , * de ;
int r ;
r = readdir_r ( d , & buf , & de ) ;
if ( r ! = 0 )
goto fallback ;
if ( ! de )
goto fallback ;
if ( ignore_file ( de - > d_name ) )
continue ;
p = join ( " /sys/class/rtc/ " , de - > d_name , " /hctosys " , NULL ) ;
if ( ! p ) {
closedir ( d ) ;
return - ENOMEM ;
}
r = read_one_line_file ( p , & v ) ;
free ( p ) ;
if ( r < 0 )
continue ;
r = parse_boolean ( v ) ;
free ( v ) ;
if ( r < = 0 )
continue ;
p = strappend ( " /dev/ " , de - > d_name ) ;
fd = open ( p , flags ) ;
free ( p ) ;
if ( fd > = 0 ) {
closedir ( d ) ;
return fd ;
}
}
fallback :
if ( d )
closedir ( d ) ;
fd = open ( " /dev/rtc0 " , flags ) ;
if ( fd < 0 )
return - errno ;
return fd ;
}
2011-05-24 22:23:07 +04:00
int hwclock_get_time ( struct tm * tm ) {
int fd ;
int err = 0 ;
2011-06-16 23:52:11 +04:00
assert ( tm ) ;
2012-01-21 06:15:54 +04:00
fd = rtc_open ( O_RDONLY | O_CLOEXEC ) ;
2011-05-24 22:23:07 +04:00
if ( fd < 0 )
return - errno ;
2011-06-16 23:52:11 +04:00
/* This leaves the timezone fields of struct tm
* uninitialized ! */
2011-05-24 22:23:07 +04:00
if ( ioctl ( fd , RTC_RD_TIME , tm ) < 0 )
err = - errno ;
2011-06-16 23:52:11 +04:00
/* We don't now daylight saving, so we reset this in order not
* to confused mktime ( ) . */
tm - > tm_isdst = - 1 ;
close_nointr_nofail ( fd ) ;
2011-05-24 22:23:07 +04:00
return err ;
}
int hwclock_set_time ( const struct tm * tm ) {
int fd ;
int err = 0 ;
2011-06-16 23:52:11 +04:00
assert ( tm ) ;
2012-01-21 06:15:54 +04:00
fd = rtc_open ( O_RDONLY | O_CLOEXEC ) ;
2011-05-24 22:23:07 +04:00
if ( fd < 0 )
return - errno ;
2011-06-16 23:52:11 +04:00
2011-05-24 22:23:07 +04:00
if ( ioctl ( fd , RTC_SET_TIME , tm ) < 0 )
err = - errno ;
2011-06-16 23:52:11 +04:00
close_nointr_nofail ( fd ) ;
2011-05-24 22:23:07 +04:00
return err ;
}
2011-05-24 01:54:22 +04:00
2011-06-15 17:35:23 +04:00
int copy_file ( const char * from , const char * to ) {
int r , fdf , fdt ;
assert ( from ) ;
assert ( to ) ;
fdf = open ( from , O_RDONLY | O_CLOEXEC | O_NOCTTY ) ;
if ( fdf < 0 )
return - errno ;
fdt = open ( to , O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC | O_NOCTTY , 0644 ) ;
if ( fdt < 0 ) {
close_nointr_nofail ( fdf ) ;
return - errno ;
}
for ( ; ; ) {
char buf [ PIPE_BUF ] ;
ssize_t n , k ;
n = read ( fdf , buf , sizeof ( buf ) ) ;
if ( n < 0 ) {
r = - errno ;
close_nointr_nofail ( fdf ) ;
close_nointr ( fdt ) ;
unlink ( to ) ;
return r ;
}
if ( n = = 0 )
break ;
errno = 0 ;
k = loop_write ( fdt , buf , n , false ) ;
if ( n ! = k ) {
r = k < 0 ? k : ( errno ? - errno : - EIO ) ;
close_nointr_nofail ( fdf ) ;
close_nointr ( fdt ) ;
unlink ( to ) ;
return r ;
}
}
close_nointr_nofail ( fdf ) ;
r = close_nointr ( fdt ) ;
if ( r < 0 ) {
unlink ( to ) ;
return r ;
}
return 0 ;
}
int symlink_or_copy ( const char * from , const char * to ) {
char * pf = NULL , * pt = NULL ;
struct stat a , b ;
int r ;
assert ( from ) ;
assert ( to ) ;
if ( parent_of_path ( from , & pf ) < 0 | |
parent_of_path ( to , & pt ) < 0 ) {
r = - ENOMEM ;
goto finish ;
}
if ( stat ( pf , & a ) < 0 | |
stat ( pt , & b ) < 0 ) {
r = - errno ;
goto finish ;
}
if ( a . st_dev ! = b . st_dev ) {
free ( pf ) ;
free ( pt ) ;
return copy_file ( from , to ) ;
}
if ( symlink ( from , to ) < 0 ) {
r = - errno ;
goto finish ;
}
r = 0 ;
finish :
free ( pf ) ;
free ( pt ) ;
return r ;
}
int symlink_or_copy_atomic ( const char * from , const char * to ) {
char * t , * x ;
const char * fn ;
size_t k ;
unsigned long long ull ;
unsigned i ;
int r ;
assert ( from ) ;
assert ( to ) ;
t = new ( char , strlen ( to ) + 1 + 16 + 1 ) ;
if ( ! t )
return - ENOMEM ;
fn = file_name_from_path ( to ) ;
k = fn - to ;
memcpy ( t , to , k ) ;
t [ k ] = ' . ' ;
x = stpcpy ( t + k + 1 , fn ) ;
ull = random_ull ( ) ;
for ( i = 0 ; i < 16 ; i + + ) {
* ( x + + ) = hexchar ( ull & 0xF ) ;
ull > > = 4 ;
}
* x = 0 ;
r = symlink_or_copy ( from , t ) ;
if ( r < 0 ) {
unlink ( t ) ;
free ( t ) ;
return r ;
}
if ( rename ( t , to ) < 0 ) {
r = - errno ;
unlink ( t ) ;
free ( t ) ;
return r ;
}
free ( t ) ;
return r ;
}
2011-06-24 20:50:50 +04:00
int audit_session_from_pid ( pid_t pid , uint32_t * id ) {
2011-10-07 23:06:39 +04:00
char * s ;
2011-06-24 20:50:50 +04:00
uint32_t u ;
int r ;
assert ( id ) ;
if ( have_effective_cap ( CAP_AUDIT_CONTROL ) < = 0 )
return - ENOENT ;
2011-10-07 23:06:39 +04:00
if ( pid = = 0 )
r = read_one_line_file ( " /proc/self/sessionid " , & s ) ;
else {
char * p ;
if ( asprintf ( & p , " /proc/%lu/sessionid " , ( unsigned long ) pid ) < 0 )
return - ENOMEM ;
r = read_one_line_file ( p , & s ) ;
free ( p ) ;
}
2011-06-24 20:50:50 +04:00
if ( r < 0 )
return r ;
r = safe_atou32 ( s , & u ) ;
free ( s ) ;
if ( r < 0 )
return r ;
if ( u = = ( uint32_t ) - 1 | | u < = 0 )
return - ENOENT ;
* id = u ;
return 0 ;
}
2011-10-07 23:06:39 +04:00
int audit_loginuid_from_pid ( pid_t pid , uid_t * uid ) {
char * s ;
uid_t u ;
int r ;
assert ( uid ) ;
/* Only use audit login uid if we are executed with sufficient
* capabilities so that pam_loginuid could do its job . If we
* are lacking the CAP_AUDIT_CONTROL capabality we most likely
* are being run in a container and / proc / self / loginuid is
* useless since it probably contains a uid of the host
* system . */
if ( have_effective_cap ( CAP_AUDIT_CONTROL ) < = 0 )
return - ENOENT ;
if ( pid = = 0 )
r = read_one_line_file ( " /proc/self/loginuid " , & s ) ;
else {
char * p ;
if ( asprintf ( & p , " /proc/%lu/loginuid " , ( unsigned long ) pid ) < 0 )
return - ENOMEM ;
r = read_one_line_file ( p , & s ) ;
free ( p ) ;
}
if ( r < 0 )
return r ;
r = parse_uid ( s , & u ) ;
free ( s ) ;
if ( r < 0 )
return r ;
if ( u = = ( uid_t ) - 1 )
return - ENOENT ;
* uid = ( uid_t ) u ;
return 0 ;
}
2011-06-28 00:44:12 +04:00
bool display_is_local ( const char * display ) {
assert ( display ) ;
return
display [ 0 ] = = ' : ' & &
display [ 1 ] > = ' 0 ' & &
display [ 1 ] < = ' 9 ' ;
}
int socket_from_display ( const char * display , char * * path ) {
size_t k ;
char * f , * c ;
assert ( display ) ;
assert ( path ) ;
if ( ! display_is_local ( display ) )
return - EINVAL ;
k = strspn ( display + 1 , " 0123456789 " ) ;
f = new ( char , sizeof ( " /tmp/.X11-unix/X " ) + k ) ;
if ( ! f )
return - ENOMEM ;
c = stpcpy ( f , " /tmp/.X11-unix/X " ) ;
memcpy ( c , display + 1 , k ) ;
c [ k ] = 0 ;
* path = f ;
return 0 ;
}
2011-07-02 01:49:56 +04:00
int get_user_creds ( const char * * username , uid_t * uid , gid_t * gid , const char * * home ) {
struct passwd * p ;
2011-07-23 02:47:17 +04:00
uid_t u ;
2011-07-02 01:49:56 +04:00
assert ( username ) ;
assert ( * username ) ;
/* We enforce some special rules for uid=0: in order to avoid
* NSS lookups for root we hardcode its data . */
if ( streq ( * username , " root " ) | | streq ( * username , " 0 " ) ) {
* username = " root " ;
2011-07-23 03:17:59 +04:00
if ( uid )
* uid = 0 ;
if ( gid )
* gid = 0 ;
if ( home )
* home = " /root " ;
2011-07-02 01:49:56 +04:00
return 0 ;
}
2011-07-23 02:47:17 +04:00
if ( parse_uid ( * username , & u ) > = 0 ) {
2011-07-02 01:49:56 +04:00
errno = 0 ;
2011-07-23 02:47:17 +04:00
p = getpwuid ( u ) ;
2011-07-02 01:49:56 +04:00
/* If there are multiple users with the same id, make
* sure to leave $ USER to the configured value instead
* of the first occurrence in the database . However if
* the uid was configured by a numeric uid , then let ' s
* pick the real username from / etc / passwd . */
if ( p )
* username = p - > pw_name ;
} else {
errno = 0 ;
p = getpwnam ( * username ) ;
}
if ( ! p )
return errno ! = 0 ? - errno : - ESRCH ;
2011-07-23 03:17:59 +04:00
if ( uid )
* uid = p - > pw_uid ;
if ( gid )
* gid = p - > pw_gid ;
if ( home )
* home = p - > pw_dir ;
return 0 ;
}
int get_group_creds ( const char * * groupname , gid_t * gid ) {
struct group * g ;
gid_t id ;
assert ( groupname ) ;
/* We enforce some special rules for gid=0: in order to avoid
* NSS lookups for root we hardcode its data . */
if ( streq ( * groupname , " root " ) | | streq ( * groupname , " 0 " ) ) {
* groupname = " root " ;
if ( gid )
* gid = 0 ;
return 0 ;
}
if ( parse_gid ( * groupname , & id ) > = 0 ) {
errno = 0 ;
g = getgrgid ( id ) ;
if ( g )
* groupname = g - > gr_name ;
} else {
errno = 0 ;
g = getgrnam ( * groupname ) ;
}
if ( ! g )
return errno ! = 0 ? - errno : - ESRCH ;
if ( gid )
* gid = g - > gr_gid ;
2011-07-02 01:49:56 +04:00
return 0 ;
}
2011-07-07 04:07:39 +04:00
int glob_exists ( const char * path ) {
glob_t g ;
int r , k ;
assert ( path ) ;
zero ( g ) ;
errno = 0 ;
k = glob ( path , GLOB_NOSORT | GLOB_BRACE , NULL , & g ) ;
if ( k = = GLOB_NOMATCH )
r = 0 ;
else if ( k = = GLOB_NOSPACE )
r = - ENOMEM ;
else if ( k = = 0 )
r = ! strv_isempty ( g . gl_pathv ) ;
else
r = errno ? - errno : - EIO ;
globfree ( & g ) ;
return r ;
}
2011-07-22 06:21:18 +04:00
int dirent_ensure_type ( DIR * d , struct dirent * de ) {
struct stat st ;
assert ( d ) ;
assert ( de ) ;
if ( de - > d_type ! = DT_UNKNOWN )
return 0 ;
if ( fstatat ( dirfd ( d ) , de - > d_name , & st , AT_SYMLINK_NOFOLLOW ) < 0 )
return - errno ;
de - > d_type =
S_ISREG ( st . st_mode ) ? DT_REG :
S_ISDIR ( st . st_mode ) ? DT_DIR :
S_ISLNK ( st . st_mode ) ? DT_LNK :
S_ISFIFO ( st . st_mode ) ? DT_FIFO :
S_ISSOCK ( st . st_mode ) ? DT_SOCK :
S_ISCHR ( st . st_mode ) ? DT_CHR :
S_ISBLK ( st . st_mode ) ? DT_BLK :
DT_UNKNOWN ;
return 0 ;
}
int in_search_path ( const char * path , char * * search ) {
char * * i , * parent ;
int r ;
r = parent_of_path ( path , & parent ) ;
if ( r < 0 )
return r ;
r = 0 ;
STRV_FOREACH ( i , search ) {
if ( path_equal ( parent , * i ) ) {
r = 1 ;
break ;
}
}
free ( parent ) ;
return r ;
}
2011-07-22 23:01:15 +04:00
int get_files_in_directory ( const char * path , char * * * list ) {
DIR * d ;
int r = 0 ;
unsigned n = 0 ;
char * * l = NULL ;
assert ( path ) ;
2011-07-29 05:08:49 +04:00
/* Returns all files in a directory in *list, and the number
* of files as return value . If list is NULL returns only the
* number */
2011-07-22 23:01:15 +04:00
d = opendir ( path ) ;
2011-09-23 03:43:28 +04:00
if ( ! d )
return - errno ;
2011-07-22 23:01:15 +04:00
for ( ; ; ) {
struct dirent buffer , * de ;
int k ;
k = readdir_r ( d , & buffer , & de ) ;
if ( k ! = 0 ) {
r = - k ;
goto finish ;
}
if ( ! de )
break ;
dirent_ensure_type ( d , de ) ;
if ( ! dirent_is_file ( de ) )
continue ;
2011-07-29 05:08:49 +04:00
if ( list ) {
if ( ( unsigned ) r > = n ) {
char * * t ;
2011-07-22 23:01:15 +04:00
2011-07-29 05:08:49 +04:00
n = MAX ( 16 , 2 * r ) ;
t = realloc ( l , sizeof ( char * ) * n ) ;
if ( ! t ) {
r = - ENOMEM ;
goto finish ;
}
2011-07-22 23:01:15 +04:00
2011-07-29 05:08:49 +04:00
l = t ;
}
2011-07-22 23:01:15 +04:00
2011-07-29 05:08:49 +04:00
assert ( ( unsigned ) r < n ) ;
2011-07-22 23:01:15 +04:00
2011-07-29 05:08:49 +04:00
l [ r ] = strdup ( de - > d_name ) ;
if ( ! l [ r ] ) {
r = - ENOMEM ;
goto finish ;
}
2011-07-22 23:01:15 +04:00
2011-07-29 05:08:49 +04:00
l [ + + r ] = NULL ;
} else
r + + ;
2011-07-22 23:01:15 +04:00
}
finish :
if ( d )
closedir ( d ) ;
2011-07-29 05:08:49 +04:00
if ( r > = 0 ) {
if ( list )
* list = l ;
} else
2011-07-22 23:01:15 +04:00
strv_free ( l ) ;
return r ;
}
2011-08-01 03:28:01 +04:00
char * join ( 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 ;
t = va_arg ( ap , const char * ) ;
if ( ! t )
break ;
l + = strlen ( t ) ;
}
} 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 ) ;
}
2011-09-23 03:43:28 +04:00
va_end ( ap ) ;
2011-08-01 03:28:01 +04:00
} else
r [ 0 ] = 0 ;
return r ;
}
2011-08-01 07:05:12 +04:00
bool is_main_thread ( void ) {
static __thread int cached = 0 ;
if ( _unlikely_ ( cached = = 0 ) )
cached = getpid ( ) = = gettid ( ) ? 1 : - 1 ;
return cached > 0 ;
}
2011-08-21 02:28:30 +04:00
int block_get_whole_disk ( dev_t d , dev_t * ret ) {
char * p , * s ;
int r ;
unsigned n , m ;
assert ( ret ) ;
/* If it has a queue this is good enough for us */
if ( asprintf ( & p , " /sys/dev/block/%u:%u/queue " , major ( d ) , minor ( d ) ) < 0 )
return - ENOMEM ;
r = access ( p , F_OK ) ;
free ( p ) ;
if ( r > = 0 ) {
* ret = d ;
return 0 ;
}
/* If it is a partition find the originating device */
if ( asprintf ( & p , " /sys/dev/block/%u:%u/partition " , major ( d ) , minor ( d ) ) < 0 )
return - ENOMEM ;
r = access ( p , F_OK ) ;
free ( p ) ;
if ( r < 0 )
return - ENOENT ;
/* Get parent dev_t */
if ( asprintf ( & p , " /sys/dev/block/%u:%u/../dev " , major ( d ) , minor ( d ) ) < 0 )
return - ENOMEM ;
r = read_one_line_file ( p , & s ) ;
free ( p ) ;
if ( r < 0 )
return r ;
r = sscanf ( s , " %u:%u " , & m , & n ) ;
free ( s ) ;
if ( r ! = 2 )
return - EINVAL ;
/* Only return this if it is really good enough for us. */
if ( asprintf ( & p , " /sys/dev/block/%u:%u/queue " , m , n ) < 0 )
return - ENOMEM ;
r = access ( p , F_OK ) ;
free ( p ) ;
if ( r > = 0 ) {
* ret = makedev ( m , n ) ;
return 0 ;
}
return - ENOENT ;
}
2012-01-18 18:40:21 +04:00
int file_is_priv_sticky ( const char * p ) {
2011-08-21 22:05:51 +04:00
struct stat st ;
assert ( p ) ;
if ( lstat ( p , & st ) < 0 )
return - errno ;
return
2012-01-18 18:40:21 +04:00
( st . st_uid = = 0 | | st . st_uid = = getuid ( ) ) & &
2011-08-21 22:05:51 +04:00
( st . st_mode & S_ISVTX ) ;
}
2011-08-21 02:28:30 +04:00
2011-05-24 01:54:22 +04: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_unshifted_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_unshifted , 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 ) ;
static const char * const ip_tos_table [ ] = {
[ IPTOS_LOWDELAY ] = " low-delay " ,
[ IPTOS_THROUGHPUT ] = " throughput " ,
[ IPTOS_RELIABILITY ] = " reliability " ,
[ IPTOS_LOWCOST ] = " low-cost " ,
} ;
DEFINE_STRING_TABLE_LOOKUP ( ip_tos , int ) ;
2011-09-23 11:39:40 +04:00
static const char * const __signal_table [ ] = {
2011-05-24 01:54:22 +04:00
[ SIGHUP ] = " HUP " ,
[ SIGINT ] = " INT " ,
[ SIGQUIT ] = " QUIT " ,
[ SIGILL ] = " ILL " ,
[ SIGTRAP ] = " TRAP " ,
[ SIGABRT ] = " ABRT " ,
[ SIGBUS ] = " BUS " ,
[ SIGFPE ] = " FPE " ,
[ SIGKILL ] = " KILL " ,
[ SIGUSR1 ] = " USR1 " ,
[ SIGSEGV ] = " SEGV " ,
[ SIGUSR2 ] = " USR2 " ,
[ SIGPIPE ] = " PIPE " ,
[ SIGALRM ] = " ALRM " ,
[ SIGTERM ] = " TERM " ,
# ifdef SIGSTKFLT
[ SIGSTKFLT ] = " STKFLT " , /* Linux on SPARC doesn't know SIGSTKFLT */
# endif
[ SIGCHLD ] = " CHLD " ,
[ SIGCONT ] = " CONT " ,
[ SIGSTOP ] = " STOP " ,
[ SIGTSTP ] = " TSTP " ,
[ SIGTTIN ] = " TTIN " ,
[ SIGTTOU ] = " TTOU " ,
[ SIGURG ] = " URG " ,
[ SIGXCPU ] = " XCPU " ,
[ SIGXFSZ ] = " XFSZ " ,
[ SIGVTALRM ] = " VTALRM " ,
[ SIGPROF ] = " PROF " ,
[ SIGWINCH ] = " WINCH " ,
[ SIGIO ] = " IO " ,
[ SIGPWR ] = " PWR " ,
[ SIGSYS ] = " SYS "
} ;
2011-09-23 11:39:40 +04:00
DEFINE_PRIVATE_STRING_TABLE_LOOKUP ( __signal , int ) ;
const char * signal_to_string ( int signo ) {
static __thread char buf [ 12 ] ;
const char * name ;
name = __signal_to_string ( signo ) ;
if ( name )
return name ;
if ( signo > = SIGRTMIN & & signo < = SIGRTMAX )
snprintf ( buf , sizeof ( buf ) - 1 , " RTMIN+%d " , signo - SIGRTMIN ) ;
else
snprintf ( buf , sizeof ( buf ) - 1 , " %d " , signo ) ;
char_array_0 ( buf ) ;
return buf ;
}
int signal_from_string ( const char * s ) {
int signo ;
int offset = 0 ;
unsigned u ;
signo = __signal_from_string ( s ) ;
if ( signo > 0 )
return signo ;
if ( startswith ( s , " RTMIN+ " ) ) {
s + = 6 ;
offset = SIGRTMIN ;
}
if ( safe_atou ( s , & u ) > = 0 ) {
signo = ( int ) u + offset ;
if ( signo > 0 & & signo < _NSIG )
return signo ;
}
return - 1 ;
}
2011-08-22 16:58:50 +04:00
bool kexec_loaded ( void ) {
bool loaded = false ;
char * s ;
if ( read_one_line_file ( " /sys/kernel/kexec_loaded " , & s ) > = 0 ) {
if ( s [ 0 ] = = ' 1 ' )
loaded = true ;
free ( s ) ;
}
return loaded ;
}
2011-09-28 06:25:13 +04:00
int strdup_or_null ( const char * a , char * * b ) {
char * c ;
assert ( b ) ;
if ( ! a ) {
* b = NULL ;
return 0 ;
}
c = strdup ( a ) ;
if ( ! c )
return - ENOMEM ;
* b = c ;
return 0 ;
}
2011-10-12 00:30:31 +04:00
2011-10-07 23:06:39 +04:00
int prot_from_flags ( int flags ) {
switch ( flags & O_ACCMODE ) {
case O_RDONLY :
return PROT_READ ;
case O_WRONLY :
return PROT_WRITE ;
case O_RDWR :
return PROT_READ | PROT_WRITE ;
default :
return - EINVAL ;
}
2011-10-12 06:42:38 +04:00
}
2011-10-12 06:29:11 +04:00
2011-10-12 00:30:31 +04:00
unsigned long cap_last_cap ( void ) {
static __thread unsigned long saved ;
static __thread bool valid = false ;
unsigned long p ;
if ( valid )
return saved ;
p = ( unsigned long ) CAP_LAST_CAP ;
if ( prctl ( PR_CAPBSET_READ , p ) < 0 ) {
/* Hmm, look downwards, until we find one that
* works */
for ( p - - ; p > 0 ; p - - )
if ( prctl ( PR_CAPBSET_READ , p ) > = 0 )
break ;
} else {
/* Hmm, look upwards, until we find one that doesn't
* work */
for ( ; ; p + + )
if ( prctl ( PR_CAPBSET_READ , p + 1 ) < 0 )
break ;
}
saved = p ;
valid = true ;
return p ;
}
2011-12-31 05:31:54 +04:00
char * format_bytes ( char * buf , size_t l , off_t t ) {
2011-12-31 06:35:45 +04:00
unsigned i ;
2011-12-31 05:31:54 +04:00
static const struct {
const char * suffix ;
off_t factor ;
} table [ ] = {
2012-01-14 06:07:29 +04:00
{ " E " , 1024ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL } ,
{ " P " , 1024ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL } ,
2011-12-31 05:31:54 +04:00
{ " T " , 1024ULL * 1024ULL * 1024ULL * 1024ULL } ,
{ " G " , 1024ULL * 1024ULL * 1024ULL } ,
{ " M " , 1024ULL * 1024ULL } ,
{ " K " , 1024ULL } ,
} ;
for ( i = 0 ; i < ELEMENTSOF ( table ) ; i + + ) {
if ( t > = table [ i ] . factor ) {
snprintf ( buf , l ,
" %llu.%llu%s " ,
( unsigned long long ) ( t / table [ i ] . factor ) ,
( unsigned long long ) ( ( ( t * 10ULL ) / table [ i ] . factor ) % 10ULL ) ,
table [ i ] . suffix ) ;
goto finish ;
}
}
snprintf ( buf , l , " %lluB " , ( unsigned long long ) t ) ;
finish :
buf [ l - 1 ] = 0 ;
return buf ;
}
2012-01-05 23:11:47 +04:00
void * memdup ( const void * p , size_t l ) {
void * r ;
assert ( p ) ;
r = malloc ( l ) ;
if ( ! r )
return NULL ;
memcpy ( r , p , l ) ;
return r ;
}
2012-01-27 21:57:37 +04:00
int fd_inc_sndbuf ( int fd , size_t n ) {
int r , value ;
socklen_t l = sizeof ( value ) ;
r = getsockopt ( fd , SOL_SOCKET , SO_SNDBUF , & value , & l ) ;
if ( r > = 0 & &
l = = sizeof ( value ) & &
( size_t ) value > = n * 2 )
return 0 ;
value = ( int ) n ;
r = setsockopt ( fd , SOL_SOCKET , SO_SNDBUF , & value , sizeof ( value ) ) ;
if ( r < 0 )
return - errno ;
return 1 ;
}
int fd_inc_rcvbuf ( int fd , size_t n ) {
int r , value ;
socklen_t l = sizeof ( value ) ;
r = getsockopt ( fd , SOL_SOCKET , SO_RCVBUF , & value , & l ) ;
if ( r > = 0 & &
l = = sizeof ( value ) & &
( size_t ) value > = n * 2 )
return 0 ;
value = ( int ) n ;
r = setsockopt ( fd , SOL_SOCKET , SO_RCVBUF , & value , sizeof ( value ) ) ;
if ( r < 0 )
return - errno ;
return 1 ;
}