1 /**********************************************************
2  * Misc stuff.
3  **********************************************************/
4 /*
5  * $Id: tools.c,v 1.12 2005/08/10 19:45:50 mitry Exp $
6  *
7  * $Log: tools.c,v $
8  * Revision 1.12  2005/08/10 19:45:50  mitry
9  * Added param to qscandir() to return full path with file name
10  *
11  * Revision 1.11  2005/05/17 18:17:42  mitry
12  * Removed system basename() usage.
13  * Added qbasename() implementation.
14  *
15  * Revision 1.10  2005/05/16 14:40:59  mitry
16  * Added check for NULL fname in lunlink()
17  *
18  * Revision 1.9  2005/05/16 11:20:13  mitry
19  * Updated function prototypes. Changed code a bit.
20  *
21  * Revision 1.8  2005/05/06 20:48:55  mitry
22  * Misc code cleanup
23  *
24  * Revision 1.7  2005/04/14 18:04:26  mitry
25  * Changed scandir() to qscandir()
26  *
27  * Revision 1.6  2005/04/08 18:11:12  mitry
28  * Insignificant changes
29  *
30  * Revision 1.5  2005/03/28 17:02:53  mitry
31  * Pre non-blocking i/o update. Mostly non working.
32  *
33  * Revision 1.4  2005/02/12 19:38:05  mitry
34  * Remove superfluous log message.
35  *
36  * Revision 1.3  2005/02/08 19:45:55  mitry
37  * islocked() is rewritten to reflect zero-sized .csy/.bsy files
38  *
39  */
40 
41 #include "headers.h"
42 /*
43 #ifdef HAVE_SYS_MOUNT_H
44 #include <sys/mount.h>
45 #endif
46 */
47 #ifdef HAVE_SYS_STATFS_H
48 #include <sys/statfs.h>
49 #endif
50 #ifdef HAVE_SYS_STATVFS_H
51 #include <sys/statvfs.h>
52 #endif
53 #ifdef HAVE_SYS_VFS_H
54 #include <sys/vfs.h>
55 #endif
56 #include "charset.h"
57 #include "crc.h"
58 
59 static unsigned long seq = 0xFFFFFFFFUL;
60 static char _qfmc[MAX_PATH + 5];
61 
62 char *sigs[] = {
63 	"","HUP","INT","QUIT","ILL","TRAP","IOT","BUS","FPE",
64 	"KILL","USR1","SEGV","USR2","PIPE","ALRM","TERM"
65 };
66 
67 
initcharset(char * name,unsigned char * tab)68 static int initcharset(char *name,unsigned char *tab)
69 {
70     FILE *f;
71     int rev=0,n;
72     unsigned i,c;
73     char buf[MAX_STRING];
74     if(!name||!strcasecmp(name,"none"))return -1;
75     if(!strcasecmp(name,"internal"))return 1;
76     if(!strncasecmp(name,"revert",6)) {
77         rev=1;name+=6;
78         while(*name==' '||*name=='\t')name++;
79         if(!*name)return -1;
80     }
81     if(!(f=fopen(name,"r"))) {
82         write_log("can't open recode file '%s': %s",name,strerror(errno));
83         return -1;
84     }
85     memset(tab,0,128);
86     while(fgets(buf,MAX_STRING,f)) {
87         if(!isdigit(*buf))continue;
88         if(*buf=='0'&&buf[1]=='x') {
89             if(sscanf(buf,"0x%x 0x%x",&i,&c)!=2)continue;
90         } else {
91             if(sscanf(buf,"%u %u",&i,&c)!=2)continue;
92         }
93         if(rev) { n=i;i=c;c=n; }
94         if(c>255||i<128||i>255)continue;
95         tab[i-128]=c;
96     }
97     for(n=0;n<128;n++)if(!tab[n])tab[n]=n+128;
98     fclose(f);
99     return 1;
100 }
101 
102 
recode_to_remote(char * s)103 void recode_to_remote(char *s)
104 {
105     static int loaded=0;
106     register unsigned char c;
107     if(!loaded||!s)loaded=initcharset(cfgs(CFG_REMOTECP),ctab_remote);
108     if(loaded==1&&s) {
109         while(*s) {
110             c=*(unsigned char*)s;
111             if(c>=128)*(unsigned char*)s=ctab_remote[c-128];
112             s++;
113         }
114     }
115 }
116 
117 
recode_to_local(char * s)118 void recode_to_local(char *s)
119 {
120     static int loaded=0;
121     register unsigned char c;
122     if(!loaded||!s)loaded=initcharset(cfgs(CFG_LOCALCP),ctab_local);
123     if(loaded==1&&s) {
124         while(*s) {
125             c=*(unsigned char*)s;
126             if(c>=128)*(unsigned char*)s=ctab_local[c-128];
127             s++;
128         }
129     }
130 }
131 
132 
mappath(const char * fname)133 char *mappath(const char *fname)
134 {
135 	static char	newfn[MAX_PATH+5];
136 	char		*mapfrom, *mapto, *mapout = cfgs( CFG_MAPOUT );
137 	slist_t		*mappath;
138 
139 	DEBUG(('S',5,"mappath: '%s'",fname));
140 	memset( newfn, 0, MAX_PATH );
141 
142 	for( mappath = cfgsl( CFG_MAPPATH ); mappath; mappath = mappath->next ) {
143 		for( mapfrom = mappath->str; *mapfrom && *mapfrom != ' '; mapfrom++ );
144 
145 		for( mapto = mapfrom; *mapto == ' '; mapto++ );
146 
147 		if ( !*mapfrom || !*mapto)
148 			write_log( "bad mapping '%s'", mappath->str );
149 		else {
150 			size_t lenf = mapfrom - mappath->str;
151 
152 			if ( !strncasecmp( mappath->str, fname, lenf )) {
153 				size_t lent = strlen( mapto );
154 
155 				memcpy( newfn, mapto, lent );
156 				memcpy( newfn + lent, fname + lenf,
157 					MAX_PATH - lent - strlen( fname + lenf ));
158 				break;
159 			}
160 		}
161 	}
162 
163 	if ( mapout && strchr( mapout, 'S' ))
164 		strtr( newfn, '\\', '/' );
165 
166 	DEBUG(('S',5,"mappath: out '%s'",newfn));
167 
168 	return newfn;
169 }
170 
171 
mapname(char * fn,char * map,size_t size)172 char *mapname(char *fn, char *map, size_t size)
173 {
174 	int	t;
175 	char	*l;
176 
177 	if ( !map )
178 		return fn;
179 
180 	DEBUG(('S',5,"mapname: '%s', fn: '%s'",map,fn));
181 
182 	if ( strchr( map, 'c' ))
183 		recode_to_remote( fn );
184 	if ( strchr( map, 'k' ))
185 		recode_to_local( fn );
186 	if ( strchr( map, 'd' )) {
187 		if (( l = strrchr( fn, '.' ))) {
188 			strtr( fn, '.', '_' );
189 			*l = '.';
190 		}
191 	}
192 	t = whattype( fn );
193 
194 	if ( strchr( map, 'b' ) && t != IS_FILE ) {
195 		l = strrchr( fn, '.' );
196 		snprintf( fn, 14, "%08lx%s", crc32s( fn ), l );
197 	}
198 
199 	if ( strchr( map, 'u' ))
200 		strupr( fn );
201 	if ( strchr( map, 'l' ))
202 		strlwr( fn );
203 	if ( strchr( map, 'f' ))
204 		xstrcpy( fn, fnc( fn ), size );
205 
206 	switch( t ) {
207 	case IS_PKT:
208 		if ( strchr( map, 'p' ))
209 			strlwr( fn );
210 		else if ( strchr( map, 'P' ))
211 			strupr( fn );
212 		break;
213 
214 	case IS_ARC:
215 		if ( strchr( map, 'a' ))
216 			strlwr( fn );
217 		else if ( strchr( map, 'A' ))
218 			strupr( fn );
219 		break;
220 
221 	case IS_FILE:
222 		if ( istic( fn )) {
223 			if ( strchr( map, 't' ))
224 				strlwr( fn );
225 			else if ( strchr( map, 'T' ))
226 				strupr( fn );
227 		} else {
228 			if ( isdos83name( fn )) {
229 				if ( strchr( map, 'o' ))
230 					strlwr( fn );
231 				else if ( strchr( map, 'O' ))
232 					strupr( fn );
233 			}
234 		}
235 		break;
236 	}
237 
238 	if ( bink )
239 		strtr( fn, ' ', '_' );
240 
241 	DEBUG(('S',5,"mapname: out '%s'",fn));
242 
243 	return fn;
244 }
245 
246 
qbasename(const char * name)247 char *qbasename(const char *name)
248 {
249 	char *p = strrchr( name, '/' );
250 
251 	return p ? p + 1 : (char *) name;
252 }
253 
254 
hexdcd(char h,char l)255 int hexdcd(char h, char l)
256 {
257 	l = tolower( l );
258 	h = tolower( h );
259 	if ( l >= 'a' && l <= 'f' )
260 		l -= ( 'a' - 10 );
261         else
262         	l -= '0';
263 
264 	if ( h >= 'a' && h <= 'f' )
265 		h -= ( 'a' - 10 );
266         else
267         	h -= '0';
268 	return ( h * 16 + l );
269 }
270 
271 
qver(int w)272 char *qver(int w)
273 {
274 	cfgs( CFG_PROGNAME );
275 
276 	switch( w ) {
277 	case 0:
278 		if ( ccs && strncasecmp( ccs, progname, 4 ))
279 			return ccs;
280 		return progname;
281 
282 	case 1:
283 		if ( ccs && strncasecmp( ccs, progname, 4 ))
284 			if ( cfgs( CFG_VERSION ))
285 				return ccs;
286 		return version;
287 
288 	default:
289 		return ( cfgs( CFG_OSNAME ) ? ccs : osname );
290 	}
291 }
292 
293 
sequencer(void)294 unsigned long sequencer(void)
295 {
296 	if ( seq == 0xFFFFFFFFUL || time( NULL ) > seq )
297 		seq = time( NULL );
298         else
299         	seq++;
300 	return seq;
301 }
302 
303 
filesize(const char * fname)304 off_t filesize(const char *fname)
305 {
306 	struct stat sb;
307 
308 	if ( stat( fname, &sb ) == 0 )
309 		return sb.st_size;
310 
311 	return -1;
312 }
313 
314 
islocked(const char * pidfn)315 int islocked(const char *pidfn)
316 {
317 	FILE *f;
318 	long pid;
319 
320 	if (( f = fopen( pidfn, "rt" ))) {
321 		if ( filesize( pidfn ) == 0 )
322 			return 1; /* File exists with zero size */
323 
324 		fseeko( f, (off_t) 0, SEEK_SET );
325 		fscanf( f, "%ld", &pid );
326 		fclose( f );
327 		if ( kill( (pid_t) pid, 0) && ( errno == ESRCH ))
328 			lunlink( pidfn );
329 		else
330 			return ( (int) pid );
331 	}
332 	return 0;
333 }
334 
335 
lockpid(const char * pidfn)336 int lockpid(const char *pidfn)
337 {
338 	int	rc;
339 	char	tmpname[MAX_PATH+5], pidbuf[15];
340 #ifndef LOCKSTYLE_OPEN
341 	char	*p;
342 #endif
343 
344 	if ( islocked( pidfn ))
345 		return 0;
346 
347 	xstrcpy( tmpname, pidfn, MAX_PATH );
348 
349 #ifndef LOCKSTYLE_OPEN
350 	p = strrchr( tmpname, '/' );
351 	if ( !p )
352 		p = tmpname;
353 
354 	snprintf( tmpname + ( p - tmpname ), MAX_PATH - ( p - tmpname + 1 ),
355 		"/QTEMP.%ld", (long) getpid());
356 #endif
357 
358 	rc = open( tmpname, O_WRONLY | O_CREAT | O_EXCL, 0644 );
359 	if ( rc < 0 )
360 		return 0;
361 
362 	snprintf( pidbuf, 12, "%10d\n", getpid());
363 	write( rc, pidbuf, 11);
364 	close( rc );
365 
366 #ifndef LOCKSTYLE_OPEN
367 	rc = link( tmpname, pidfn );
368 	lunlink( tmpname );
369 	if ( rc )
370 		return 0;
371 #endif
372 	return 1;
373 }
374 
375 
touch(char * fn)376 static int touch(char *fn)
377 {
378 	FILE *f = fopen( fn, "a" );
379 
380 	if ( f ) {
381 		fclose( f );
382 		return 1;
383 	} else
384 		write_log( "can't touch '%s': %s", fn, strerror( errno ));
385 	return 0;
386 }
387 
388 
lunlink(const char * fname)389 int lunlink(const char *fname)
390 {
391 	int rc = 0;
392 
393 	if ( fname && *fname )
394 		unlink( fname );
395 
396 	if ( rc < 0 && errno != ENOENT )
397 		write_log("can't delete file %s: %s", fname, strerror( errno ));
398 	return rc;
399 }
400 
401 
mdfopen(char * fn,const char * pr)402 FILE *mdfopen(char *fn, const char *pr)
403 {
404 	FILE		*f;
405 	struct stat	sb;
406 	int		nf = ( stat( fn, &sb )) ? 1 : 0;
407 
408 	if (( f = fopen( fn, pr ))) {
409 		if ( nf )
410 			fchmod( fileno( f ), cfgi( CFG_DEFPERM ));
411 		return f;
412 	}
413 	if ( errno == ENOENT ) {
414 		mkdirs( fn );
415 		f = fopen( fn, pr );
416 		if ( f && nf)
417 			fchmod( fileno( f ), cfgi( CFG_DEFPERM ));
418 		return f;
419 	}
420 	return NULL;
421 }
422 
423 
fexist(const char * s)424 int fexist(const char *s)
425 {
426 	struct stat sb;
427 	return ( stat( s, &sb ) == 0 && S_ISREG( sb.st_mode ));
428 }
429 
430 
mkdirs(char * name)431 int mkdirs(char *name)
432 {
433 	int	rc = 0;
434 	char	*p = name + 1, *q;
435 
436 	while(( q = strchr( p, '/' )) && ( rc == 0 || errno == EEXIST )) {
437 		*q = 0;
438 		rc = mkdir( name, cfgi( CFG_DIRPERM ));
439 		*q = '/';
440 		p = q + 1;
441 	}
442 	return rc;
443 }
444 
445 
rmdirs(char * name)446 void rmdirs(char *name)
447 {
448 	int	rc = 0;
449 	char	*q = strrchr( name, '/' ), *t;
450 
451 	while( q && q != name && rc == 0 ) {
452 		*q = 0;
453 		rc = rmdir( name );
454 		t = strrchr( name,'/' );
455 		*q = '/';
456 		q = t;
457 	}
458 }
459 
460 
qalphasort(const void * a,const void * b)461 int qalphasort(const void *a, const void *b)
462 {
463 	return strcmp( qbasename((const char *) a ), qbasename((const char *) b ));
464 }
465 
466 
467 /*
468  * Scan the directory dirname calling select to make a list of selected
469  * directory entries then sort using qsort and compare routine dcomp.
470  * Returns the number of entries and a pointer to a list of pointers to
471  * struct dirent (through namelist). Returns -1 if there were any errors.
472  *
473  * Based on libc scandir code.
474  */
qscandir(const char * dirname,char *** namelist,int nodir,int (* nselect)(const char *),int (* ndcomp)(const void *,const void *))475 int qscandir(const char *dirname, char ***namelist, int nodir,
476 	int (*nselect)(const char *),
477 	int (*ndcomp)(const void *, const void *))
478 {
479 	register struct dirent	*d;
480 	register size_t		nitems = 0;
481 	register char		*p, **names = NULL;
482 	long			arraysz = 0;
483 	size_t			l, dlen = 1;
484 	DIR			*dirp;
485 	char			_dirname[MAX_PATH + 5] = {'\0'};
486 
487 	if ( dirname == NULL || *dirname == '\0' )
488 		return(-1);
489 
490 	if (( dirp = opendir( dirname )) == NULL )
491 		return(-1);
492 
493 	if ( !nodir ) {
494 		xstrcpy( _dirname, dirname, MAX_PATH );
495 		dlen = strlen( dirname );
496 		if ( _dirname[dlen++] != '/' ) {
497 			xstrcat( _dirname, "/", MAX_PATH );
498 			dlen++;
499 		}
500 	}
501 
502 	while(( d = readdir( dirp )) != NULL ) {
503 		DEBUG(('S',5,"qscandir: '%s'",d->d_name));
504 		if ( nselect != NULL && !(*nselect)( d->d_name ))
505 			continue;	/* just selected names */
506 		/*
507 		 * Make a minimum size copy of the data
508 		 */
509 		l = strlen( d->d_name ) + dlen;
510 		p = (char *) xmalloc( l );
511 		if ( p == NULL )
512 			goto fail;
513 		if ( !nodir )
514 			xstrcpy( p, _dirname, l );
515 		else
516 			*p = '\0';
517 
518 		xstrcat( p, d->d_name, l );
519 		/*
520 		 * Check to make sure the array has space left and
521 		 * realloc the maximum size.
522 		 */
523 		if ( nitems >= arraysz ) {
524 			const int inc = 4;	/* increase by this much */
525 			char **names2;
526 
527 			names2 = (char **) xrealloc((char *) names,
528 				(arraysz + inc) * sizeof(char *));
529 			if ( names2 == NULL ) {
530 				xfree( p );
531 				goto fail;
532 			}
533 			names = names2;
534 			arraysz += inc;
535 		}
536 		names[nitems++] = p;
537 	}
538 	closedir( dirp );
539 	if ( nitems && ndcomp != NULL )
540 		qsort( names, nitems, sizeof(char *), ndcomp );
541 	*namelist = names;
542 	return( nitems );
543 
544 fail:
545 	closedir( dirp );
546 	while( nitems > 0 )
547 		xfree( names[--nitems] );
548 	xfree( names );
549 	*namelist = NULL;
550 	return (-1);
551 }
552 
553 
qfmcselect(const char * d_name)554 static int qfmcselect(const char *d_name)
555 {
556 	if ( d_name == NULL || *d_name == '\0' )
557 		return 0;
558 	return ( strncasecmp( d_name, _qfmc, sizeof( _qfmc )) == 0 );
559 }
560 
561 
qfmcasesort(const void * a,const void * b)562 static int qfmcasesort(const void *a, const void *b)
563 {
564 	return strcasecmp( qbasename((const char *) a ), qbasename((const char *) b ));
565 }
566 
567 
fmatchcase(const char * fname,char *** namelist)568 int fmatchcase(const char *fname, char ***namelist)
569 {
570 	char	path[MAX_PATH + 5], *p;
571 	int	gotcha;
572 
573 	DEBUG(('S',5,"fmatchcase: '%s'",fname));
574 	if ( fname == NULL || *fname == '\0' )
575 		return 0;
576 
577 	xstrcpy( path, fname, MAX_PATH );
578 	p = qbasename( path );
579 
580 	if ( p == NULL || *p == '\0' )
581 		return (-1);
582 
583 	xstrcpy( _qfmc, p, MAX_PATH );
584 	if ( p == path )
585 		xstrcpy( path, "./", MAX_PATH );
586 	else
587 		*p = '\0';
588 
589 	DEBUG(('S',5,"fmatchcase: path '%s'",path));
590 	DEBUG(('S',5,"fmatchcase: _qfmc '%s'",_qfmc));
591 
592 	gotcha = qscandir( path, namelist, 0, qfmcselect, qfmcasesort );
593 
594 	_qfmc[0] = '\0';
595 
596 	return gotcha;
597 }
598 
599 
dosallowin83(int c)600 static int dosallowin83(int c)
601 {
602 	static char dos_allow[] = "!@#$%^&()~`'-_{}";
603 
604 	return (( c >= 'a' && c <= 'z') || ( c >='A' && c <= 'Z' )
605 		|| ( c >= '0' && c <= '9' ) || strchr( dos_allow, c ));
606 }
607 
608 
fnc(char * s)609 char *fnc(char *s)
610 {
611 #define LEN83	13
612 	static char	s8[LEN83+5];
613 	char		*p, *q;
614 	size_t		i = 0;
615 
616 	if ( !s )
617 		return NULL;
618 	if ( !( p = strrchr( s, '/' )))
619 		p = s;
620 	else
621 		s = p;
622 
623 	while( *p && *p != '.' && i < 8 ) {
624 		if ( dosallowin83( *p ))
625 			s8[i++] = tolower( *p );
626 		p++;
627 	}
628 	s8[i] = '\0';
629 
630 	if ( strstr( s, ".tar.gz" ))
631 		xstrcat( s8, ".tgz", LEN83 );
632 	else if ( strstr( s, ".tar.bz2" ))
633 		xstrcat( s8, ".tb2", LEN83 );
634 	else if ( strstr( s, ".html" ))
635 		xstrcat( s8, ".htm", LEN83 );
636 	else if ( strstr( s, ".jpeg" ))
637 		xstrcat( s8, ".jpg", LEN83 );
638 	else if ( strstr( s, ".desc" ))
639 		xstrcat( s8, ".dsc", LEN83 );
640 	else {
641 		if (( p = strrchr( s, '.' ))) {
642 			xstrcat( s8, ".", LEN83);
643 			q = p + 4;
644 			i = strlen( s8 );
645 			while( *p && q > p ) {
646 				if ( dosallowin83( *p ))
647 					s8[i++] = tolower( *p );
648 				p++;
649 			}
650 			s8[i] = '\0';
651 		}
652 	}
653 	return s8;
654 #undef LEN83
655 }
656 
657 
isdos83name(char * fn)658 int isdos83name(char *fn)
659 {
660 	int nl = 0, el = 0, ec = 0, uc = 0, lc = 0, f = 1;
661 
662 	while( *fn ) {
663 		if( !dosallowin83( *fn ) && ( *fn != '.' )) {
664 			f = 0;
665 			break;
666 		}
667 
668 		if ( *fn == '.' )
669 			ec++;
670 		else {
671 			if ( !ec )
672 				nl++;
673 			else
674 				el++;
675 			if ( isalpha((int) *fn )) {
676 				if ( isupper((int) *fn ))
677 					uc++;
678 				else lc++;
679 			}
680 		}
681 		fn++;
682 	}
683 
684 	return ( f && ec < 2 && el < 4 && nl < 9 && ( !lc || !uc ));
685 }
686 
687 
688 #if defined(HAVE_STATFS) && defined(STATFS_HAVE_F_BAVAIL)
689 #    define STAT_V_FS statfs
690 #else
691 #    if defined(HAVE_STATVFS) && defined(STATVFS_HAVE_F_BAVAIL)
692 #        define STAT_V_FS statvfs
693 #    else
694 #        undef STAT_V_FS
695 #    endif
696 #endif
697 
698 
getfreespace(const char * path)699 size_t getfreespace(const char *path)
700 {
701 #ifdef STAT_V_FS
702 	struct STAT_V_FS sfs;
703 
704 	if ( !STAT_V_FS( path, &sfs )) {
705 		if ( sfs.f_bsize >= 1024 )
706 			return(( sfs.f_bsize / 1024L ) * sfs.f_bavail );
707 		else
708 			return( sfs.f_bavail / ( 1024L / sfs.f_bsize ));
709 	} else
710 		write_log("can't statfs '%s': %s", path, strerror( errno ));
711 #endif
712 	return (~0UL);
713 }
714 
715 
to_dev_null(void)716 void to_dev_null(void)
717 {
718 	int fd;
719 
720 	close( STDIN_FILENO );
721 	close( STDOUT_FILENO );
722 	close( STDERR_FILENO );
723 
724 	fd = open( devnull, O_RDONLY );
725 	if ( dup2( fd, STDIN_FILENO ) != STDIN_FILENO ) {
726 		write_log("reopening of stdin is failed: %s", strerror( errno ));
727 		exit (-1);
728 	}
729 	if ( fd != STDIN_FILENO )
730 		close( fd );
731 
732 	fd = open( devnull, O_WRONLY | O_APPEND | O_CREAT, 0600 );
733 	if ( dup2( fd, STDOUT_FILENO ) != STDOUT_FILENO ) {
734 		write_log("reopening of stdout is failed: %s", strerror( errno ));
735 		exit (-1);
736 	}
737 	if ( fd != STDOUT_FILENO )
738 		close( fd );
739 
740 	fd = open( devnull, O_WRONLY | O_APPEND | O_CREAT, 0600 );
741 	if ( dup2( fd, STDERR_FILENO ) != STDERR_FILENO ) {
742 		write_log("reopening of stderr is failed: %s", strerror( errno ));
743 		exit (-1);
744 	}
745 	if ( fd != STDERR_FILENO )
746 		close( fd );
747 }
748 
749 
randper(int base,int diff)750 int randper(int base, int diff)
751 {
752     return (base - diff + (int)( diff * 2.0 * rand() / ( RAND_MAX + 1.0 )));
753 }
754 
755 
execsh(const char * cmd)756 int execsh(const char *cmd)
757 {
758 	int rc;
759 
760 	write_log( "executing '%s'", cmd );
761 	rc = system( cmd );
762 
763 	return rc;
764 }
765 
766 
execnowait(const char * cmd,const char * p1,const char * p2,const char * p3)767 int execnowait(const char *cmd, const char *p1, const char *p2, const char *p3)
768 {
769 	pid_t	pid;
770 	int	rc;
771 
772 	if (( pid = fork()) == 0 ) {
773 		to_dev_null();
774 		setsid();
775 		rc = execl( cmd, cmd, p1, p2, p3, NULL );
776 		if ( rc < 0 )
777 			write_log("can't exec %s: %s", cmd, strerror( errno ));
778 		exit (-1);
779 	}
780 
781 	if ( pid < 0 ) {
782 		write_log("can't fork(): %s", strerror( errno ));
783 		return -1;
784 	}
785 
786 	return 0;
787 }
788 
789 
qsleep(int waittime)790 void qsleep(int waittime)			/* wait waittime milliseconds */
791 {
792 	struct timeval s;
793 
794 	s.tv_sec = waittime / 1000;
795 	s.tv_usec = (waittime % 1000) * 1000;
796 	select( 0, (fd_set *) NULL, (fd_set *) NULL, (fd_set *) NULL, &s );
797 }
798