Correct PPTP server firewall rules chain.
[tomato/davidwu.git] / release / src / router / udpxy / util.c
blobd9f2da06dac9cc60bc30c0563d9fab54c79165a0
1 /* @(#) implementation of utility functions for udpxy
3 * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com)
5 * This file is part of udpxy.
7 * udpxy is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * udpxy is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with udpxy. If not, see <http://www.gnu.org/licenses/>.
21 #include <sys/stat.h>
22 #include <sys/utsname.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include <assert.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <signal.h>
31 #include <stdlib.h>
32 #include <syslog.h>
33 #include <string.h>
34 #include <stdarg.h>
35 #include <sys/time.h>
36 #include <time.h>
37 #include <ctype.h>
38 #include <limits.h>
40 #include "util.h"
41 #include "uopt.h"
42 #include "mtrace.h"
43 #include "osdef.h"
45 extern const char COMPILE_MODE[];
46 extern const char VERSION[];
47 extern const int BUILDNUM;
48 extern const char BUILD_TYPE[];
49 extern const int PATCH;
51 static char s_sysinfo [80] = "\0";
53 extern struct udpxy_opt g_uopt;
55 /* write buffer to a file
58 ssize_t
59 save_buffer( const void* buf, size_t len, const char* filename )
61 int fd, rc;
62 ssize_t nw, left;
63 const char* p;
65 assert( buf && len && filename );
67 rc = 0;
68 fd = creat( filename,
69 (mode_t)(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) );
70 if( -1 == fd ) {
71 perror("creat");
72 return 1;
75 for( p = (const char*)buf, nw = 0, left = len; left > 0; ) {
76 nw = write( fd, p, left );
77 if( nw <= 0 ) {
78 nw = 0;
79 if( EINTR != errno) {
80 perror("write");
81 rc = -1;
82 break;
86 left -= nw;
87 p += nw;
90 (void)close(fd);
91 return (rc ? -1 : ((ssize_t)len - left));
95 /* read text file into a buffer
98 ssize_t
99 txtf_read (const char* fpath, char* dst, size_t maxlen, FILE* log)
101 int rc = 0, fd = -1;
102 ssize_t n = 0;
103 ssize_t left = maxlen - 1;
104 char *p = dst;
106 assert (fpath && dst && maxlen);
107 fd = open (fpath, O_RDONLY, 0);
108 if (-1 == fd) {
109 mperror (log, errno, "%s open %s", __func__, fpath);
110 return -1;
113 while (left > 0) {
114 n = read (fd, p, maxlen - 1);
115 if (!n) break;
116 if (n < 0) {
117 n = 0; rc = errno;
118 if (EINTR != rc) {
119 mperror (log, errno, "%s read %s", __func__, fpath);
120 break;
122 rc = 0;
124 left -= (size_t)n;
125 p += n;
127 if (!rc) *p = '\0';
129 if (-1 == close (fd)) {
130 mperror (log, errno, "%s close %s", __func__, fpath);
132 return (rc ? -1 : ((ssize_t)maxlen - left - 1));
136 /* make current process run as a daemon
139 daemonize(int options, FILE* log)
141 pid_t pid;
142 int rc = 0, fh = -1;
144 assert( log );
146 if( (pid = fork()) < 0 ) {
147 mperror( log, errno,
148 "%s: fork", __func__);
149 return -1;
151 else if( 0 != pid ) {
152 exit(0);
155 do {
156 if( -1 == (rc = setsid()) ) {
157 mperror( log, errno,
158 "%s: setsid", __func__);
159 break;
162 if( -1 == (rc = chdir("/")) ) {
163 mperror( log, errno, "%s: chdir", __func__ );
164 break;
167 (void) umask(0);
169 if( !(options & DZ_STDIO_OPEN) ) {
170 for( fh = 0; fh < 3; ++fh )
171 if( -1 == (rc = close(fh)) ) {
172 mperror( log, errno, "%s: close", __func__);
173 break;
177 if( SIG_ERR == signal(SIGHUP, SIG_IGN) ) {
178 mperror( log, errno, "%s: signal", __func__ );
179 rc = 2;
180 break;
183 } while(0);
185 if( 0 != rc ) return rc;
187 /* child exits to avoid session leader's re-acquiring
188 * control terminal */
189 if( (pid = fork()) < 0 ) {
190 mperror( log, errno, "%s: fork", __func__);
191 return -1;
193 else if( 0 != pid )
194 exit(0);
196 return 0;
200 /* multiplex error output to custom log
201 * and syslog
203 void
204 mperror( FILE* fp, int err, const char* format, ... )
206 char buf[ 256 ] = { '\0' };
207 va_list ap;
208 int n = 0;
210 assert(format);
212 va_start( ap, format );
213 n = vsnprintf( buf, sizeof(buf) - 1, format, ap );
214 va_end( ap );
216 if( n <= 0 || n >= ((int)sizeof(buf) - 1) ) return;
218 snprintf( buf + n, sizeof(buf) - n - 1, ": %s",
219 strerror(err) );
221 syslog( LOG_ERR | LOG_LOCAL0, "%s", buf );
222 if( fp ) (void) tmfprintf( fp, "%s\n", buf );
224 return;
228 /* write-lock on a file handle
230 static int
231 wlock_file( int fd )
233 struct flock lck;
235 lck.l_type = F_WRLCK;
236 lck.l_start = 0;
237 lck.l_whence = SEEK_SET;
238 lck.l_len = 0;
240 return fcntl( fd, F_SETLK, &lck );
243 /* create and lock file with process's ID
246 make_pidfile( const char* fpath, pid_t pid, FILE* log )
248 int fd = -1, rc = 0, n = -1;
249 ssize_t nwr = -1;
251 #define LLONG_MAX_DIGITS 21
252 char buf[ LLONG_MAX_DIGITS + 1 ];
254 mode_t fmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
256 assert( (NULL != fpath) && pid );
258 errno = 0;
259 do {
260 fd = open( fpath, O_CREAT | O_WRONLY | O_NOCTTY, fmode );
261 if( -1 == fd ) {
262 mperror(log, errno, "make_pidfile - open");
263 rc = EXIT_FAILURE;
264 break;
267 rc = wlock_file( fd );
268 if( 0 != rc ) {
269 if( (EACCES == errno) || (EAGAIN == errno) ) {
270 (void) fprintf( stderr, "File [%s] is locked "
271 "(another instance of daemon must be running)\n",
272 fpath );
273 exit(EXIT_FAILURE);
276 mperror(log, errno, "wlock_file");
277 break;
280 rc = ftruncate( fd, 0 );
281 if( 0 != rc ) {
282 mperror(log, errno, "make_pidfile - ftruncate");
283 break;
286 n = snprintf( buf, sizeof(buf) - 1, "%d", pid );
287 if( n < 0 ) {
288 mperror(log, errno, "make_pidfile - snprintf");
289 rc = EXIT_FAILURE;
290 break;
293 nwr = write( fd, buf, n );
294 if( (ssize_t)n != nwr ) {
295 mperror( log, errno, "make_pidfile - write");
296 rc = EXIT_FAILURE;
297 break;
300 } while(0);
302 if( (0 != rc) && (fd > 0) ) {
303 (void)close( fd );
306 return rc;
310 /* write path to application's pidfile into the the buffer
311 * (fail if destination directory is not writable)
314 set_pidfile( const char* appname, int port, char* buf, size_t len )
316 int n = -1;
318 assert( appname && buf && len );
320 if( -1 == access(PIDFILE_DIR, W_OK ) )
321 return -1;
323 n = snprintf( buf, len, "%s/%s%d.pid", PIDFILE_DIR, appname, port );
324 if( n < 0 ) return EXIT_FAILURE;
326 buf[ len - 1 ] = '\0';
328 return 0;
333 would_block(int err)
335 return (EAGAIN == err) || (EWOULDBLOCK == err);
340 no_fault(int err)
342 return (EPIPE == err) || (ECONNRESET == err) || would_block(err);
346 /* write buffer to designated socket/file
348 ssize_t
349 write_buf( int fd, const char* data, const ssize_t len, FILE* log )
351 ssize_t n = 0, nwr = 0, error = IO_ERR;
352 int err = 0;
354 for( n = 0; errno = 0, n < len ; ) {
355 nwr = write( fd, &(data[n]), len - n );
356 if( nwr <= 0 ) {
357 err = errno;
358 if( EINTR == err ) {
359 TRACE( (void)tmfprintf( log,
360 "%s interrupted\n", __func__ ) );
361 continue;
363 else {
364 if( would_block(err) )
365 error = IO_BLK;
367 break;
371 n += nwr;
373 if( nwr != len ) {
374 if( NULL != log ) {
375 TRACE( (void)tmfprintf( log,
376 "Fragment written %s[%ld:%ld]/[%ld] bytes\n",
377 (len > n ? "P" : "F"), (long)nwr, (long)n, (long)len ) );
383 if( nwr <= 0 ) {
384 if( log ) {
385 if (IO_BLK == error)
386 (void)tmfprintf( log, "%s: socket time-out on write", __func__);
387 else if( !no_fault(err) || g_uopt.is_verbose )
388 mperror( log, errno, "%s: write", __func__ );
391 return error;
394 return n;
398 /* read data chunk of designated size (or less) into buffer
399 * (will *NOT* attempt to re-read if read less than expected
400 * w/o interruption)
402 ssize_t
403 read_buf( int fd, char* data, const ssize_t len, FILE* log )
405 ssize_t n = 0, nrd = 0, err = 0;
407 for( n = 0; errno = 0, n < len ; ) {
408 nrd = read( fd, &(data[n]), len - n );
409 if( nrd <= 0 ) {
410 err = errno;
411 if( EINTR == err ) {
412 TRACE( (void)tmfprintf( log,
413 "%s interrupted\n", __func__ ) );
414 errno = 0;
415 continue;
417 else {
418 break;
422 n += nrd;
424 if( nrd != len ) {
425 if( NULL != log ) {
426 TRACE( (void)tmfprintf( log,
427 "Fragment read [%ld]/[%ld] bytes\n",
428 (long)nrd, (long)len ) );
433 /* we only read as much as we can read at once (uninterrupted) */
434 break;
437 if( nrd < 0 ) {
438 if( log ) {
439 if( would_block(err) )
440 (void)tmfprintf( log, "%s: socket time-out on read", __func__);
441 else if( !no_fault(err) || g_uopt.is_verbose )
442 mperror( log, errno, "%s: read", __func__ );
446 return n;
450 /* output hex dump of a memory fragment
452 void
453 hex_dump( const char* msg, const char* data, size_t len, FILE* log )
455 u_int i = 0;
457 assert( data && (len > (size_t)0) && log );
459 if( msg ) (void)fprintf( log, "%s: ", msg );
461 for( i = 0; i < len; ++i )
462 (void)fprintf( log, "%02x ", data[i] & 0xFF );
464 (void) fputs("\n", log);
465 return;
469 /* check for expected size, complain if not matched
472 sizecheck( const char* msg, ssize_t expct, ssize_t len,
473 FILE* log, const char* func )
475 assert( msg && log && func );
476 if( expct == len ) return 0;
478 (void) (msg && log && func); /* NOP to eliminate warnings */
480 TRACE( (void)tmfprintf( log, "%s: %s - read only [%ld] "
481 "bytes out of [%ld]\n",
482 func, msg, (long)len, (long)expct ) );
484 return 1;
488 /* check for a potential buffer overrun by
489 * evaluating target buffer and the portion
490 * of that buffer to be accessed
493 buf_overrun( const char* buf, size_t buflen,
494 size_t offset, size_t dlen,
495 FILE* log )
497 const char* tgt = buf + offset + dlen;
498 if( tgt > (buf + buflen) ) {
499 if( NULL != log ) {
500 TRACE( (void)tmfprintf( log, "+++ BUFFER OVERRUN at: "
501 "buf=[%p], size=[%lu] - intending to access [%p]: "
502 "offset=[%lu], data_length=[%lu]\n",
503 buf, (u_long)buflen, tgt, (u_long)offset,
504 (u_long)dlen) );
506 return 1;
509 return 0;
513 /* create timestamp string in YYYY-mm-dd HH24:MI:SS.MSEC from struct timeval
516 mk_tvstamp( const struct timeval* tv, char* buf, size_t* len,
517 int32_t flags )
519 const char tmfmt_TZ[] = "%Y-%m-%d %H:%M:%S.%%06ld %Z";
521 char tfmt_ms[ 80 ] = { '\0' };
522 int n = 0;
523 struct tm src_tm, *p_tm;
524 time_t clock;
526 assert( tv && buf && len );
529 clock = tv->tv_sec;
530 p_tm = (flags & TVSTAMP_GMT)
531 ? gmtime_r( &clock, &src_tm )
532 : localtime_r( &clock, &src_tm );
533 if( NULL == p_tm ) {
534 perror("gmtime_r/localtime_r");
535 return errno;
538 n = strftime( tfmt_ms, sizeof(tfmt_ms) - 1, tmfmt_TZ, &src_tm );
539 if( 0 == n ) {
540 perror( "strftime" );
541 return errno;
544 n = snprintf( buf, *len, tfmt_ms, (long)tv->tv_usec );
545 if( 0 == n ) {
546 perror( "snprintf" );
547 return errno;
550 *len = (size_t)n;
551 return 0;
556 /* write timestamp-prepended formatted message to file
559 tmfprintf( FILE* stream, const char* format, ... )
561 va_list ap;
562 int n = -1, total = 0, rc = 0, NO_RESET = 0;
563 char tstamp[ 80 ] = {'\0'};
564 size_t ts_len = sizeof(tstamp) - 1;
565 struct timeval tv_now;
566 const char* pidstr = get_pidstr( NO_RESET, NULL );
568 (void)gettimeofday( &tv_now, NULL );
570 errno = 0;
571 do {
572 rc = mk_tvstamp( &tv_now, tstamp, &ts_len, 0 );
573 if( 0 != rc ) break;
575 n = fprintf( stream, "%s\t%s\t", tstamp, pidstr );
576 if( n <= 0 ) break;
577 total += n;
579 va_start( ap, format );
580 n = vfprintf( stream, format, ap );
581 va_end( ap );
583 if( n <= 0 ) break;
584 total += n;
586 } while(0);
588 if( n <= 0 ) {
589 perror( "fprintf/vfprintf" );
590 return -1;
593 return (0 != rc) ? -1 : total;
597 /* write timestamp-prepended message to file
600 tmfputs( const char* s, FILE* stream )
602 int n = -1, rc = 0, NO_RESET = 0;
603 char tstamp[ 80 ] = {'\0'};
604 size_t ts_len = sizeof(tstamp) - 1;
605 struct timeval tv_now;
606 const char* pidstr = get_pidstr( NO_RESET, NULL );
608 (void)gettimeofday( &tv_now, NULL );
610 errno = 0;
611 do {
612 rc = mk_tvstamp( &tv_now, tstamp, &ts_len, 0 );
613 if( 0 != rc ) break;
615 if( (n = fputs( tstamp, stream )) < 0 ||
616 (n = fputs( "\t", stream )) < 0 ||
617 (n = fputs( pidstr, stream )) < 0 ||
618 (n = fputs( "\t", stream )) < 0 )
619 break;
621 if( (n = fputs( s, stream )) < 0 )
622 break;
623 } while(0);
625 if( n < 0 && errno ) {
626 perror( "fputs" );
629 return (0 != rc) ? -1 : n;
633 /* print out command-line
635 void
636 printcmdln( FILE* stream, const char* msg,
637 int argc, char* const argv[] )
639 int i = 0;
641 assert( stream );
643 if( msg )
644 (void)tmfprintf( stream, "%s: ", msg );
645 else
646 (void)tmfputs( "", stream );
648 for( i = 0; i < argc; ++i )
649 (void)fprintf( stream, "%s ", argv[i] );
650 (void)fputc( '\n', stream );
654 /* convert timespec to time_t
655 * where
656 * timespec format: [+|-]dd:hh24:mi.ss
658 * @return 0 if success, n>0 if errno > 0,
659 * n < 0 otherwise (see ERR_ codes)
662 a2time( const char* str, time_t* t, time_t from )
664 int field[ 4 ] = {0};
665 const size_t field_LEN = sizeof(field)/sizeof(field[0]);
667 int is_offset = 0;
668 int i_sec, i_min, i_hour, i_day;
669 int n = 0, fi = 0, i = 0, new_field = 0, has_seconds = 0;
670 struct tm stm;
671 time_t tgt_time = (time_t)-1, offset_tm = (time_t)0;
672 time_t now = from;
674 static const int ERR_HSEC = -2;
675 static const int ERR_FIELDLEN = -3;
676 static const int ERR_NONDIGIT = -4;
678 assert( str );
680 /* check if timespec is an offset (to current time) */
681 n = 0;
682 if( ('-' == str[n]) || ('+' == str[n]) ) {
683 is_offset = ('-' == str[n]) ? -1 : 1;
684 ++n;
687 /* read every field into an array element
689 for( fi = 0; (size_t)fi < field_LEN; ++n ) {
690 if( '\0' == str[n] ) break;
692 /* seconds has to be the last field in timespec
693 * if seconds field has already been processed
694 * it an error */
695 if( (':' == str[n]) && has_seconds ) return ERR_HSEC;
697 /* delimiter - move on to the next timespec field */
698 if( ':' == str[n] || ('.' == str[n]) ) {
699 new_field = 1;
700 if( '.' == str[n] ) has_seconds = 1;
701 continue;
704 if( !isdigit( str[n] ) ) return ERR_NONDIGIT;
706 if( new_field ) {
707 new_field = 0;
708 ++fi;
711 field[ fi ] *= 10;
712 field[ fi ] += (str[n] - '0');
714 if( (fi <= 0) || (size_t)fi >= field_LEN ) return ERR_FIELDLEN;
716 /* last field is seconds, the one before is hours, etc. */
717 i = fi;
718 i_sec = has_seconds ? i-- : -1;
719 i_min = i--;
720 i_hour = i--;
721 i_day = i--;
723 if( NULL == localtime_r( &now, &stm ) ) {
724 return errno;
728 (void) fprintf( stderr, "sec[%d], min[%d], hour[%d], day[%d]\n",
729 stm.tm_sec, stm.tm_min, stm.tm_hour, stm.tm_mday );
730 (void) fprintf( stderr, "i_sec[%d], i_min[%d], i_hour[%d], i_day[%d]\n",
731 i_sec, i_min, i_hour, i_day );
734 if( !is_offset ) {
735 /* hours and days default to current value */
736 if( i_hour >= 0 )
737 stm.tm_hour = field[ i_hour ];
739 if( i_day >= 0 )
740 stm.tm_mday = field[ i_day ];
742 stm.tm_sec = (i_sec < 0) ? 0 : field[ i_sec ];
743 stm.tm_min = (i_min < 0) ? 0 : field[ i_min ];
746 (void) fprintf( stderr, "sec[%d], min[%d], hour[%d], day[%d]\n",
747 stm.tm_sec, stm.tm_min, stm.tm_hour, stm.tm_mday );
750 tgt_time = mktime( &stm );
752 else {
754 (void) fprintf( stderr, "sec[%d], min[%d], hour[%d], day[%d]\n",
755 (i_sec < 0 ? 0 : field[i_sec]), (i_min < 0 ? 0 : field[i_min]),
756 (i_hour < 0 ? 0 : field[i_hour]),(i_day < 0 ? 0 : field[i_day]) );
759 offset_tm = ( (i_sec < 0 ? 0 : field[ i_sec ]) +
760 60 * (i_min < 0 ? 0 : field[ i_min ]) +
761 3600 * (i_hour < 0 ? 0 : field[ i_hour ]) +
762 (3600*24) * (i_day < 0 ? 0 : field[ i_day ])
764 tgt_time = now + is_offset * offset_tm;
767 if( NULL != t )
768 *t = tgt_time;
770 return ((time_t)-1 == tgt_time) ? -1 : 0;
776 /* convert ASCII size spec (positive) into numeric value
777 * size spec format:
778 * num[modifier], where num is an ASCII representation of
779 * any positive integer and
780 * modifier ::= [Kb|K|Mb|M|Gb|G]
782 static int
783 a2double( const char* str, double* pval )
785 int64_t mult = 1;
786 const char* p = NULL;
787 double dval = 0.0;
788 size_t numsz = 0;
790 static const int ERR_OVERRUN = -3;
791 static const int ERR_NUMFMT = -4;
792 static const int ERR_BADMULT = -5;
794 #define MAX_SZLEN 64
795 char buf[ MAX_SZLEN ] = {0};
797 assert( str );
799 /* skip to the first */
800 for( p = str; *p && !isalpha(*p); ++p );
802 if( '\0' != *p ) {
803 /* there is a modifier, calculate multiplication
804 * factor */
805 if( 0 == strncasecmp( p, "Kb", MAX_SZLEN ) ||
806 0 == strncasecmp( p, "K", MAX_SZLEN ))
807 mult = 1024;
808 else if( 0 == strncasecmp( p, "Mb", MAX_SZLEN ) ||
809 0 == strncasecmp( p, "M", MAX_SZLEN ) )
810 mult = (1024 * 1024);
811 else if( 0 == strncasecmp( p, "Gb", MAX_SZLEN ) ||
812 0 == strncasecmp( p, "G", MAX_SZLEN ) )
813 mult = (1024 * 1024 * 1024);
814 else
815 return ERR_BADMULT;
818 numsz = p - str;
819 if( numsz >= (size_t)MAX_SZLEN ) return ERR_OVERRUN;
820 (void) memcpy( buf, str, numsz );
822 /*(void)fprintf( stderr, "buf=[%s]\n", buf);*/
824 errno = 0;
825 dval = strtod( buf, (char**)NULL );
826 if( errno ) return ERR_NUMFMT;
828 /* apply the modifier-induced multiplication factor */
829 dval *= mult;
831 else {
832 errno = 0;
833 dval = strtod( str, (char**)NULL );
834 if( errno ) return ERR_NUMFMT;
838 /*fprintf( stderr, "dval = [%f]\n", dval );*/
840 if( NULL != pval )
841 *pval = dval;
843 return 0;
848 a2size( const char* str, ssize_t* pval )
850 double dval = 0.0;
851 int rc = 0;
852 static const int ERR_OVFLW = -2;
854 if( 0 != (rc = a2double( str, &dval )) )
855 return rc;
857 if( dval > LONG_MAX || dval < LONG_MIN )
858 return ERR_OVFLW;
860 if( NULL != pval ) {
861 *pval = (ssize_t)dval;
864 return rc;
868 a2int64( const char* str, int64_t* pval )
870 /* NB: use LLONG_MAX and LLONG_MIN recommended when
871 * compiling with C99 compliance;
873 * we still (yet) complie under C89, so LLONGMAX64,
874 * LLONGMIN64 are introduced instead to avoid C99-related
875 * warnings
878 # define LLONGMAX64 9223372036854775807.0
879 # define LLONGMIN64 (-LLONGMAX64 - 1.0)
881 double dval = 0.0;
882 int rc = 0;
883 static const int ERR_OVFLW = -2;
885 if( 0 != (rc = a2double( str, &dval )) )
886 return rc;
888 if( dval > LLONGMAX64 || dval < LLONGMIN64 )
889 return ERR_OVFLW;
891 if( NULL != pval ) {
892 *pval = (int64_t)dval;
895 return rc;
898 /* returns asctime w/o CR character at the end
900 const char*
901 Zasctime( const struct tm* tm )
903 size_t n = 0;
905 #define ASCBUF_SZ 64
906 static char buf[ ASCBUF_SZ ], *p = NULL;
908 buf[0] = '\0';
909 p = asctime_r( tm, buf );
910 if( NULL == p ) return p;
912 buf[ ASCBUF_SZ - 1 ] = '\0';
913 n = strlen( buf );
914 if( (n > (size_t)1) && ('\n' == buf[ n - 1 ]) ) {
915 buf[ n - 1 ] = '\0';
918 return buf;
922 /* adjust nice value if needed
925 set_nice( int val, FILE* log )
927 int newval = 0;
928 assert( log );
930 if( 0 != val ) {
931 errno = 0;
932 newval = nice( val );
933 if( (-1 == newval) && (0 != errno) ) {
934 mperror( log, errno, "%s: nice", __func__ );
935 return -1;
937 else {
938 TRACE( (void)tmfprintf( log, "Nice value incremented by %d\n",
939 val) );
943 return 0;
947 /* check and report a deviation in values: n_was and n_is are not supposed
948 * to differ more than by delta
950 void
951 check_fragments( const char* action, ssize_t total, ssize_t n_was, ssize_t n_is,
952 ssize_t delta, FILE* log )
954 if( NULL == action ) return;
956 if( (n_is < (n_was - delta)) || (n_is > (n_was + delta)) ) {
957 (void)tmfprintf( log,
958 "%s [%ld] bytes out of [%ld], last=[%ld]\n",
959 action, (long)n_is, (long)total, (long)n_was);
964 /* retrieve UNIX time value from given environment
965 * variable, otherwise return default */
966 time_t
967 get_timeval( const char* envar, const time_t deflt )
969 char *str = NULL, *eptr = NULL;
970 time_t tval = -1;
972 assert( envar );
973 if( NULL == (str = getenv( envar )) )
974 return deflt;
976 errno = 0;
977 tval = (time_t) strtol( str, &eptr, 10 );
978 if( errno ) return deflt;
980 if ( eptr && (0 == *eptr) ) return tval;
982 return deflt;
986 /* retrieve flag value as 1 = true, 0 = false
987 * from an environment variable set in the form
988 * of 0|1|'true'|'false'|'yes'|'no'
991 get_flagval( const char* envar, const int deflt )
993 long lval = (long)deflt;
994 char *str = NULL, *eptr = NULL;
995 size_t i = 0;
997 static char* ON_sym[] = { "true", "yes", "on" };
998 static char* OFF_sym[] = { "false", "no", "off" };
1000 assert( envar );
1001 str = getenv( envar );
1002 if ( NULL == str )
1003 return deflt;
1005 errno = 0;
1006 lval = strtol( str, &eptr, 10 );
1007 if( errno ) return deflt;
1009 if ( eptr && (0 == *eptr) ) return lval;
1011 for( i = 0; i < sizeof(ON_sym)/sizeof(ON_sym[0]); ++i )
1012 if( 0 == strcasecmp(str, ON_sym[i]) ) return 1;
1014 for( i = 0; i < sizeof(OFF_sym)/sizeof(OFF_sym[0]); ++i )
1015 if( 0 == strcasecmp(str, OFF_sym[i]) ) return 0;
1017 return deflt;
1021 /* retrieve SSIZE value from given environment
1022 * variable, otherwise return default */
1023 ssize_t
1024 get_sizeval( const char* envar, const ssize_t deflt )
1026 char *str = NULL, *eptr = NULL;
1027 long lval = -1;
1029 assert( envar );
1030 if( NULL == (str = getenv( envar )) )
1031 return deflt;
1033 errno = 0;
1034 lval = strtol( str, &eptr, 10 );
1035 if( errno ) return deflt;
1037 if ( eptr && (0 == *eptr) ) return lval;
1039 return deflt;
1044 /* retrieve/reset string representation of pid
1046 const char*
1047 get_pidstr( int reset, const char* pfx )
1049 static char pidstr[ 24 ];
1050 static pid_t pid = 0;
1052 if( 1 == reset || (0 == pid) ) {
1053 pid = getpid();
1054 if (pfx) {
1055 (void) snprintf (pidstr, sizeof(pidstr)-1, "%s(%d)", pfx, pid);
1056 } else {
1057 (void) snprintf (pidstr, sizeof(pidstr)-1, "%d", pid );
1059 pidstr [sizeof(pidstr)-1] = '\0';
1062 return pidstr;
1066 /* retrieve system info string
1068 const char*
1069 get_sysinfo (int* perr)
1071 struct utsname uts;
1072 int rc = 0;
1074 if (s_sysinfo[0]) return s_sysinfo;
1076 (void) memset (&uts, 0, sizeof(uts));
1077 errno = 0; rc = uname (&uts);
1078 if (perr) *perr = errno;
1080 if (0 == rc) {
1081 s_sysinfo [sizeof(s_sysinfo)-1] = '\0';
1082 (void) snprintf (s_sysinfo, sizeof(s_sysinfo)-1, "%s %s %s",
1083 uts.sysname, uts.release, uts.machine);
1085 return s_sysinfo;
1089 void
1090 mk_app_info(const char *appname, char *info, size_t infolen)
1092 assert(info);
1093 if ('\0' == *info) {
1094 (void) snprintf(info, infolen,
1095 "%s %s-%d.%d (%s) %s [%s]", appname, VERSION,
1096 BUILDNUM, PATCH, BUILD_TYPE,
1097 COMPILE_MODE, get_sysinfo(NULL) );
1102 /* __EOF__ */