1 /* $Id: misc.c 7420 2005-10-09 04:40:13Z eagle $
3 ** Helper routines for the innfeed program.
5 ** Written by James Brister <brister@vix.com>
17 #include <netinet/in.h>
20 #include <sys/param.h>
24 /* FIXME: Default to a max length of 256 characters for path names if the
25 host headers doesn't give better information. Should be replaced by the
31 #include "inn/messages.h"
38 unsigned int openfds ;
40 unsigned int loggingLevel ;
41 char **PointersFreedOnExit ;
43 bool debuggingDump = true ;
44 extern void (*gPrintInfo) (void) ;
45 void (*gCleanUp) (void) = 0 ;
48 /* Log a message to stderr, called from warn or die. Mostly the same as the
49 standard message_log_stderr, but prepends the date to each line. */
51 error_log_stderr_date(int len UNUSED, const char *fmt, va_list args, int err)
59 strftime(timebuff, sizeof(timebuff), "%Y-%m-%d %H:%M:%S", tm);
60 fprintf(stderr, "%s %s: ", timebuff,
61 (message_program_name ? message_program_name : "UNKNOWN"));
62 vfprintf(stderr, fmt, args);
63 if (err) fprintf(stderr, ": %s", strerror(err));
64 fprintf(stderr, "\n");
67 /* If desired, print out the state of innfeed, call a cleanup function, and
68 then dump core. Used as an exit handler for die. */
73 if (debuggingDump && gPrintInfo != NULL)
80 if (CORE_DIRECTORY != NULL)
81 chdir(CORE_DIRECTORY);
83 chdir(getTapeDirectory());
92 /* An alternate version of die, used when we don't want to dump core. This
93 should somehow eventually be phased out to simplify things; it's
94 basically a copy of die() from lib/error.c that ignores the cleanup
95 handler and has innfeed's handlers hard-coded (ugh). */
97 logAndExit(int status, const char *format, ...)
102 va_start(args, format);
103 length = vsnprintf(NULL, 0, format, args);
105 va_start(args, format);
106 error_log_stderr_date(length, format, args, 0);
108 va_start(args, format);
109 message_log_syslog_err(length, format, args, 0);
116 void d_printf (unsigned int level, const char *fmt, ...)
119 char timeString [30] ;
126 if (loggingLevel < level)
130 /* strip off leading day name */
131 strlcpy (timeString, ctime (&now) + 4, sizeof (timeString)) ;
132 timeString [15] = '\0' ; /* strip off trailing year and newline */
135 fprintf (stderr, "%s %s[%ld]: ",timeString,
136 (message_program_name ? message_program_name : "UNKNOWN"),
138 vfprintf (stderr, fmt, ap) ;
142 void logOrPrint (int level, FILE *fp, const char *fmt, ...)
149 vfprintf (fp,fmt,ap) ;
154 char buffer [512] ; /* gag me */
156 vsnprintf (buffer,sizeof (buffer),fmt,ap) ;
157 syslog (level,"%s",buffer) ;
164 /* return true if the file exists and is a regular file. */
165 bool fileExistsP (const char *filename)
169 if (stat (filename,&buf) < 0)
172 return (S_ISREG (buf.st_mode) ? true : false) ;
176 bool isDirectory (const char *filename)
180 if (stat (filename,&buf) < 0)
183 return (S_ISDIR (buf.st_mode) ? true : false) ;
188 bool getNntpResponse (char *p, int *code, char **rest)
201 while (*p && CTYPE (isspace, *p))
204 while (*p && CTYPE (isdigit, *p))
207 cd = (cd * 10) + (*p - '0') ;
217 while (*p && CTYPE (isspace, *p))
230 /* Pull out a message id from a response on to a streaming command */
231 char *getMsgId (const char *p)
236 while (*p && CTYPE (isspace, *p)) p++ ;
237 while (*p && !CTYPE (isspace, *p)) p++ ; /* skip response code */
238 while (*p && CTYPE (isspace, *p)) p++ ;
244 while ( *q && !CTYPE (isspace, *q) )
247 rval = xstrndup (p, q - p) ;
255 char *findNonBlankString (char *ptr, char **tail)
259 for (p = ptr ; *p && CTYPE (isspace, *p) ; p++)
264 for (q = p ; *q && !CTYPE (isspace, *q) ; q++)
273 /* strtok can't handle zero length tokens. */
274 char *mystrtok (char *line, const char *sep)
276 static char *newPoint ;
279 if (line == NULL && newPoint == NULL)
285 while (*line != '\0' && strchr (sep,*line) == NULL)
292 newPoint = line + 1 ;
298 if (newPoint == NULL)
304 while (*line != '\0' && strchr (sep,*line) == NULL)
311 newPoint = line + 1 ;
321 void trim_ws (char *string)
326 assert (string != NULL) ;
328 len = strlen (string) ;
332 for (p = string + len - 1 ; p >= string && CTYPE (isspace, *p) ; p--)
339 /* Scribble on top of memory we're about to free. */
340 void deadBeef (void *base, size_t byteCount)
342 unsigned char *b = (unsigned char *) base ;
347 memset (base, 0, byteCount) ;
353 for (i = 0 ; i < ((int) byteCount) - 4 ; i += 4)
356 *((int *) (b + i)) = 0xdeadbeef ;
358 b [i + 0] = (unsigned char) 0xde ;
359 b [i + 1] = (unsigned char) 0xad ;
360 b [i + 2] = (unsigned char) 0xbe ;
361 b [i + 3] = (unsigned char) 0xef ;
365 switch (byteCount % 4)
368 *(b + i + 3) = (unsigned char) 0xef ;
371 *(b + i + 2) = (unsigned char) 0xbe ;
374 *(b + i + 1) = (unsigned char) 0xad ;
377 *b = (unsigned char) 0xde ;
384 /* Not using plain flock or lockf 'cause I don't want to waste file
385 descriptors. This routine is based on the file shlock.c from INN. */
386 bool lockFile (const char *fileName)
389 char tmpName [PATH_MAX], realName [PATH_MAX] ;
392 pid_t pid = getpid () ;
394 strlcpy (realName,fileName,sizeof (realName)) ;
395 if ((p = strrchr (realName, '/')) != NULL)
398 snprintf (tmpName, sizeof(tmpName), "%s/lockf%ld", realName,
403 snprintf (tmpName, sizeof(tmpName), "lockf%ld", (long) pid) ;
405 /* Create the temporary name for the lock file. */
406 while ((fd = open (tmpName, O_RDWR | O_CREAT | O_EXCL, 0644)) < 0)
412 syswarn ("ME lock file open: %s", tmpName) ;
416 if (unlink (tmpName) < 0)
418 syswarn ("ME lock file unlink: %s", tmpName) ;
425 /* stick our pid in the temp file. */
426 snprintf (buff,sizeof(buff),"%ld\n",(long) pid) ;
427 if (write (fd,buff,(size_t) strlen (buff)) != (int) strlen (buff))
429 syswarn ("ME lock file pid-write") ;
436 /* now link the real name to the temp file. */
437 while (link (tmpName,realName) < 0)
441 default: /* opps. bailing out. */
442 syswarn ("ME lock file link: %s", realName) ;
447 /* the real lock file exists. So pull out the pid in there and
448 see if that process is still alive. */
449 if ((fd = open (realName,O_RDONLY)) < 0)
451 syswarn ("ME lock file open: %s", realName) ;
456 if ((i = read (fd,buff,sizeof (buff) - 1)) <= 0)
465 pid = (pid_t) atol (buff) ;
468 warn ("ME lock bad-pid info in %s: %s", realName, buff) ;
473 /* now send a null signal to the process named inside to see if
475 if (kill (pid,0) == 0)
477 warn ("ME lock in-use already: %s by pid %ld", realName,
478 (unsigned long) pid);
480 return false ; /* process is still alive */
483 /* process that took out the lock is gone */
484 if (unlink (realName) < 0)
486 syswarn ("ME lock file unlink: %s", realName) ;
499 void unlockFile (const char *lockfile)
505 bool endsIn (const char *string, const char *tail)
507 size_t len = strlen (tail) ;
508 size_t slen = strlen (string) ;
512 else if (strcmp (string + slen - len, tail) == 0)
519 /* append the contents of src to dest. src is removed if append if
521 bool appendFile (const char *dest, const char *src)
523 FILE *inTmp, *outTmp ;
527 /* append the outputFilename file to the inputFilename file */
528 if ((outTmp = fopen (dest, "a")) == NULL)
529 die ("fopen (%s): %s",dest, strerror (errno)) ;
530 if ((inTmp = fopen (src, "r")) == NULL)
531 die ("fopen (%s): %s",src, strerror (errno)) ;
533 while ((rval = fread (buff,sizeof (char),BUFSIZ,inTmp)) > 0)
535 if (fwrite (buff,sizeof (char), rval, outTmp) != rval)
536 die ("fwrite: %s", strerror (errno)) ;
540 die ("Error on inTmp in newTape") ;
542 die ("Error on outTmp in newTape") ;
544 if (fclose (inTmp) != 0)
545 die ("fclose (inTmp): appendFile (%s,%s): %s",dest,src,strerror (errno)) ;
547 if (fclose (outTmp) != 0)
548 die ("fclose (outTmp): appendFile (%s,%s): %s",dest,src,strerror (errno)) ;
550 if (unlink (src) != 0)
551 die ("unlink (%s): %s", src, strerror (errno)) ;
557 /* return true if file1 is older than file2 */
558 bool isOlder (const char *file1, const char *file2)
563 if (stat (file1,&buf1) < 0)
566 if (stat (file2,&buf2) < 0)
569 return ((buf1.st_mtime < buf2.st_mtime) ? true : false) ;
573 void freeCharP (char *charp)
579 /* return the length of the file reference by the given file descriptor */
580 long fileLength (int fd)
584 if (fstat (fd,&buf) < 0)
587 return ((long) buf.st_size) ;
592 const char *boolToString (bool val)
594 return val ? "true" : "false" ;
597 void addPointerFreedOnExit (char *pointerToFree)
599 static int totalPointers = 0 ;
600 static int nextPointer = 0 ;
602 if (nextPointer == 0 || nextPointer == totalPointers - 1)
606 totalPointers += 16 ;
607 if (PointersFreedOnExit == NULL)
608 PointersFreedOnExit = xmalloc (sizeof(char *) * totalPointers) ;
610 PointersFreedOnExit =
611 xrealloc (PointersFreedOnExit, sizeof(char *) * totalPointers) ;
613 for (i = nextPointer; i < totalPointers; i++)
614 PointersFreedOnExit [i] = NULL;
616 PointersFreedOnExit [nextPointer++] = pointerToFree ;
619 /* malloc a buffer and build the filename in it. */
620 char *buildFilename (const char *directory, const char *fname)
628 if (directory == NULL)
631 len = strlen (directory) + strlen (fname) + 2 + 1 ;
633 if (len < pathMax(directory) - 2)
637 if (fname [0] != '/')
639 strlcat (p,directory,len) ;
640 if (p [strlen(p) - 1] != '/')
641 strlcat (p,"/",len) ;
643 strlcat (p,fname,len) ;
651 /* borrows heavily from the shrinkfile program by chongo. */
652 bool shrinkfile (FILE *fp, long size, char *name, const char *mode)
654 long currlen = ftello (fp) ;
656 char buffer [BUFSIZ] ;
664 d_printf (1,"No need to shrink file (%s %ld vs %ld\n",
669 /* create a temp file. */
670 tmpname = concat (name,".XXXXXX",(char *)0) ;
671 fd = mkstemp (tmpname) ;
675 syswarn ("ME error creating temp shrink file for %s", name) ;
680 if ((tmpFp = fdopen (fd,"w")) == NULL)
682 syswarn ("ME error opening temp shrink file %s", tmpname) ;
687 if (fseeko (fp,currlen - size,SEEK_SET) != 0)
690 warn ("ME error seeking to point %ld in %s", currlen - size, name) ;
695 /* find the end of the next line in the shrinking file. */
696 while ((c = fgetc (fp)) != '\n')
699 warn ("ME no newline in shrinking file %s", name) ;
701 fseeko (fp,currlen,SEEK_SET) ;
706 /* copy the tail of the shrinking file to the temp file. */
707 while ((i = fread (buffer,1,sizeof (buffer),fp)) > 0)
709 if (fwrite (buffer,1,i,tmpFp) != (size_t) i)
712 syswarn ("ME fwrite failed to temp shrink file %s", tmpname) ;
713 fseeko (fp,currlen, SEEK_SET) ;
720 logAndExit (1,"ME fread failed on file %s: %s",name, strerror (errno)) ;
724 if (unlink (name) != 0)
725 logAndExit (1,"ME oserr unlink %s: %s",name, strerror (errno)) ;
727 /* we're in the same directory so this is ok. */
728 if (rename (tmpname,name) != 0)
729 logAndExit (1,"ME oserr rename %s, %s: %s", tmpname, name,
732 if (freopen (name,mode,fp) != fp)
733 logAndExit (1,"ME freopen on shrink file failed %s: %s", name,
736 fseeko (fp,0,SEEK_END) ;
739 notice ("ME file %s shrunk from %ld to %ld", name, currlen, size) ;
748 long pathMax (const char *pathname UNUSED)
750 static long rval = 0 ;
755 #if defined (PATH_MAX)
759 #elif defined (_POSIX_PATH_MAX)
761 rval = _POSIX_PATH_MAX ;
763 #elif defined (DO_HAVE_PATHCONF) && defined (_PC_PATH_MAX)
765 if (pathname == NULL)
768 rval = pathconf (pathname,_PC_PATH_MAX) ;
775 syslog (LOG_ERR,NO_PATH_MAX,rval) ;