fixes init script for non ipv6 enabled systems #472755
[packages/xinetd.git] / xinetd / util.c
1 /*
2  * (c) Copyright 1992 by Panagiotis Tsirigotis
3  * (c) Sections Copyright 1998-2001 by Rob Braun
4  * All rights reserved.  The file named COPYRIGHT specifies the terms 
5  * and conditions for redistribution.
6  */
7
8
9 #include "config.h"
10 #include <sys/types.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <ctype.h>
14 #if defined (HAVE_SYS_SOCKET_H)
15 #include <sys/socket.h>
16 #endif
17 /*
18  * The following ifdef is for TIOCNOTTY
19  */
20 #ifndef NO_TERMIOS
21 #ifdef HAVE_SYS_TERMIOS_H
22 #include <sys/termios.h>
23 #endif
24 #ifdef HAVE_TERMIOS_H
25 #include <termios.h>
26 #endif
27 #else
28 #include <sys/ioctl.h>
29 #endif
30 #include <fcntl.h>
31 #ifdef HAVE_SYS_FILE_H
32 #include <sys/file.h>
33 #endif
34
35 #ifdef HAVE_SYS_IOCTL_H
36 #include <sys/ioctl.h>
37 #endif
38
39 #include <memory.h>
40 #include <syslog.h>
41 #include <errno.h>
42
43 #include "sio.h"
44 #include "str.h"
45 #include "util.h"
46 #include "msg.h"
47
48 void out_of_memory( const char *func )
49 {
50    msg( LOG_CRIT, func, ES_NOMEM ) ;
51 }
52
53
54 const struct name_value *nv_find_value( const struct name_value nv_array[], const char *name )
55 {
56    const struct name_value *nvp ;
57
58    for ( nvp = nv_array ; nvp->name ; nvp++ )
59    {
60       if ( EQ( name, nvp->name ) )
61          return( nvp ) ;
62    }
63    return( NULL ) ;
64 }
65
66
67 const struct name_value *nv_find_name( const struct name_value nv_array[], int value )
68 {
69    const struct name_value *nvp ;
70
71    for ( nvp = nv_array ; nvp->name ; nvp++ )
72    {
73       if ( value == nvp->value )
74          return( nvp ) ;
75    }
76    return( NULL ) ;
77 }
78
79
80 /*
81  * A name-value list is exactly what its name says.
82  * The functions nv_get_name() and nv_get_value() return a pointer to
83  * the entry with the specified value or name respectively.
84  *
85  * The list ends when an antry with a NULL name is encountered.
86  * The value field of that entry is treated in a special manner: if it
87  * is non-zero, it is assumed that there exists one more entry whose
88  * name field will be returned by the nv_get_name function if it can't
89  * find an entry whose value field is equal to its 2nd parameter.
90  * If the value field of the NULL entry is 0, then nv_get_name() will
91  * return NULL.
92  */
93 const char *nv_get_name( const struct name_value nv_array[], int value )
94 {
95    const struct name_value *nvp ;
96
97    for ( nvp = nv_array ; nvp->name ; nvp++ )
98    {
99       if ( value == nvp->value )
100          return( nvp->name ) ;
101    }
102    return( nvp->value ? (nvp+1)->name : NULL ) ;
103 }
104
105
106
107 char **argv_alloc( unsigned count )
108 {
109    unsigned argv_size = (count + 1) * sizeof( char *) ;
110    char **argv ;
111    const char *func = "new_argv" ;
112
113    argv = (char **) malloc( argv_size ) ;
114    if ( argv == NULL )
115    {
116       out_of_memory( func ) ;
117       return( NULL ) ;
118    }
119    (void) memset( (char *)argv, 0, argv_size ) ;
120    return( argv ) ;
121 }
122
123
124 /*
125  * If size is 0, the pset holds strings
126  */
127 status_e copy_pset( const pset_h from, pset_h *to, unsigned size )
128 {
129    unsigned u ;
130    const char *func = "copy_pset" ;
131
132    if ( *to == NULL )
133    {
134       *to = pset_create( pset_count( from ), 0 ) ;
135       if ( *to == NULL )
136       {
137          out_of_memory( func ) ;
138          return( FAILED ) ;
139       }
140    }
141
142    for ( u = 0 ; u < pset_count( from ) ; u++ )
143    {
144       char *p = (char *) pset_pointer( from, u ) ;
145       char *new_s ;
146       
147       if ( size == 0 )
148          new_s = new_string( p ) ;
149       else
150          new_s = (char *)malloc( size ) ;
151
152       if ( new_s == NULL )
153       {
154          out_of_memory( func ) ;
155          return( FAILED ) ;
156       }
157
158       if ( size != 0 )
159          (void) memcpy( new_s, p, size ) ;
160
161       if ( pset_add( *to, new_s ) == NULL )
162       {
163          free( new_s ) ;
164          out_of_memory( func ) ;
165          return( FAILED ) ;
166       }
167    }
168    return( OK ) ;
169 }
170
171
172 /*
173  * Disassociate from controlling terminal
174  */
175 void no_control_tty(void)
176 {
177 #if !defined(HAVE_SETSID)
178    int fd ;
179    const char *func = "no_control_tty" ;
180
181    if ( ( fd = open( "/dev/tty", O_RDWR ) ) == -1 )
182       msg( LOG_WARNING, func, "open of /dev/tty failed: %m" ) ;
183    else
184    {
185       if ( ioctl( fd, TIOCNOTTY, (caddr_t)0 ) == -1 )
186          msg( LOG_WARNING, func, "ioctl on /dev/tty failed: %m" ) ;
187       (void) Sclose( fd ) ;
188    }
189    (void) setpgrp( getpid(), 0 ) ;
190 #else
191    (void) setsid() ;
192 #endif
193 }
194
195
196 /*
197  * Write the whole buffer to the given file descriptor ignoring interrupts
198  */
199 status_e write_buf( int fd, const char *buf, int len )
200 {
201    int cc, i ;
202
203    for ( i = 0 ; len > 0 ; i += cc, len -= cc )
204    {
205       cc = write( fd, buf+i, len ) ;
206       if ( cc == -1 )
207       {
208          if ( errno != EINTR )
209             return( FAILED ) ;
210          cc = 0 ;
211       }
212    }
213    return( OK ) ;
214 }
215
216
217 void tabprint( int fd, int tab_level, const char *fmt, ...)
218 {
219    va_list ap ;
220    int i ;
221
222    for ( i = 0 ; i < tab_level ; i++ )
223       Sputchar( fd, '\t' ) ;
224
225    va_start( ap, fmt ) ;
226    Sprintv( fd, fmt, ap ) ;
227    va_end( ap ) ;
228 }
229
230
231 /*
232  * Empty the socket receive buffers of all data.
233  */
234 void drain( int sd )
235 {
236    char buf[ 256 ] ; /* This size is arbitrarily chosen */
237    int ret ;
238    int old_val ;
239
240    /* Put in non-blocking mode so we don't hang. */
241    old_val = fcntl( sd, F_GETFL, FNDELAY );
242    if ( fcntl( sd, F_SETFL, FNDELAY ) < 0 )
243    {
244       if ( debug.on )
245          msg( LOG_DEBUG, "drain",
246               "UDP socket could not be made non-blocking: %m" ) ;
247       return;
248    }
249
250    do {
251       ret = recv( sd, buf, sizeof( buf ), 0 ) ;
252    } while (ret > 0);
253
254    /* Restore the value since the connection will be freed, not closed. */
255    if (old_val >= 0)
256       fcntl( sd, F_SETFL, old_val );
257
258    if ( debug.on )
259       msg( LOG_DEBUG, "drain", "UDP socket should be empty" ) ;
260 }
261
262 /*
263  * Convert string to an int detecting errors.
264  */
265 int parse_int(const char *str, int base, int term, int *res)
266 {
267         char *endptr;
268         long strtol_res;
269
270 /* SUSv2 says:
271  * "Because 0, LONG_MIN and LONG_MAX are returned on error and are also
272  * valid returns on success, an application wishing to check for error
273  * situations should set errno to 0, then call strtol(), then check errno." */
274         errno = 0;
275         strtol_res = strtol(str, (char **)&endptr, base);
276
277         if (errno == 0 && *str != NUL) {
278                 /* Special case: -1 means allow trailing whitespace */
279                 if (term == -1) {
280                         while (*endptr != NUL && isspace(*endptr))
281                                 endptr++;
282                         term = NUL;
283                 }
284
285                 if (*endptr == term) {
286                         *res = strtol_res;
287                         return 0;
288                 }
289         }
290
291         *res = 0;
292         return -1;
293 }
294
295 int parse_uint(const char *str, int base, int term, unsigned int *res)
296 {
297         unsigned long long tmp;
298         int ret;
299         ret = parse_ull(str, base, term, &tmp);
300         *res = (unsigned int)tmp;
301         return ret;
302 }
303
304 int parse_ull(const char *str, int base, int term, unsigned long long *res)
305 {
306         char *endptr;
307         unsigned long long strtol_res;
308
309 /* SUSv2 says:
310  * "Because 0, LONG_MIN and LONG_MAX are returned on error and are also
311  * valid returns on success, an application wishing to check for error
312  * situations should set errno to 0, then call strtol(), then check errno." */
313         errno = 0;
314         strtol_res = strtoull(str, (char **)&endptr, base);
315
316         if (errno == 0 && *str != NUL) {
317                 /* Special case: -1 means allow trailing whitespace */
318                 if (term == -1) {
319                         while (*endptr != NUL && isspace(*endptr))
320                                 endptr++;
321                         term = NUL;
322                 }
323
324                 if (*endptr == term) {
325                         *res = strtol_res;
326                         return 0;
327                 }
328         }
329
330         *res = 0;
331         return -1;
332 }
333
334 int parse_ubase10(const char *str, unsigned int *res)
335 {
336         return parse_uint(str, 10, -1, res);
337 }
338
339 int parse_base10(const char *str, int *res)
340 {
341         return parse_int(str, 10, -1, res);
342 }
343
344 bool_int parse_all_digits(const char *ptr)
345 {
346         size_t num=0, len = strlen(ptr);
347
348         while (isdigit(*ptr++))
349                 num++;
350         if (num == len)
351                 return TRUE;
352         else
353                 return FALSE;
354 }