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