Home | History | Annotate | Download | only in sed
      1 /*  Functions from hack's utils library.
      2     Copyright (C) 1989, 1990, 1991, 1998, 1999, 2003, 2008, 2009
      3     Free Software Foundation, Inc.
      4 
      5     This program is free software; you can redistribute it and/or modify
      6     it under the terms of the GNU General Public License as published by
      7     the Free Software Foundation; either version 3, or (at your option)
      8     any later version.
      9 
     10     This program is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13     GNU General Public License for more details.
     14 
     15     You should have received a copy of the GNU General Public License
     16     along with this program; if not, write to the Free Software
     17     Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
     18 
     19 #include "config.h"
     20 
     21 #include <stdio.h>
     22 #include <stdarg.h>
     23 #include <errno.h>
     24 #ifndef errno
     25   extern int errno;
     26 #endif
     27 
     28 #ifdef HAVE_STRINGS_H
     29 # include <strings.h>
     30 #else
     31 # include <string.h>
     32 #endif /* HAVE_STRINGS_H */
     33 
     34 #ifdef HAVE_STDLIB_H
     35 # include <stdlib.h>
     36 #endif /* HAVE_STDLIB_H */
     37 
     38 #include <sys/types.h>
     39 #include <sys/stat.h>
     40 #include <unistd.h>
     41 #include <limits.h>
     42 
     43 #include "utils.h"
     44 #include "pathmax.h"
     45 
     46 const char *myname;
     47 
     48 /* Store information about files opened with ck_fopen
     49    so that error messages from ck_fread, ck_fwrite, etc. can print the
     50    name of the file that had the error */
     51 
     52 struct open_file
     53   {
     54     FILE *fp;
     55     char *name;
     56     struct open_file *link;
     57     unsigned temp : 1;
     58   };
     59 
     60 static struct open_file *open_files = NULL;
     61 static void do_ck_fclose P_((FILE *fp));
     62 
     63 /* Print an error message and exit */
     64 
     65 void
     66 panic(const char *str, ...)
     67 {
     68   va_list ap;
     69 
     70   fprintf(stderr, "%s: ", myname);
     71   va_start(ap, str);
     72 #ifndef HAVE_VPRINTF
     73 # ifndef HAVE_DOPRNT
     74   fputs(str, stderr);	/* not great, but perhaps better than nothing... */
     75 # else /* HAVE_DOPRNT */
     76   _doprnt(str, &ap, stderr);
     77 # endif /* HAVE_DOPRNT */
     78 #else /* HAVE_VFPRINTF */
     79   vfprintf(stderr, str, ap);
     80 #endif /* HAVE_VFPRINTF */
     81   va_end(ap);
     82   putc('\n', stderr);
     83 
     84   /* Unlink the temporary files.  */
     85   while (open_files)
     86     {
     87       if (open_files->temp)
     88 	{
     89 	  fclose (open_files->fp);
     90 	  errno = 0;
     91 	  unlink (open_files->name);
     92           if (errno != 0)
     93             fprintf (stderr, _("cannot remove %s: %s"), open_files->name, strerror (errno));
     94 	}
     95 
     96       open_files = open_files->link;
     97     }
     98 
     99   exit(4);
    100 }
    101 
    102 
    103 /* Internal routine to get a filename from open_files */
    105 static const char *utils_fp_name P_((FILE *fp));
    106 static const char *
    107 utils_fp_name(fp)
    108   FILE *fp;
    109 {
    110   struct open_file *p;
    111 
    112   for (p=open_files; p; p=p->link)
    113     if (p->fp == fp)
    114       return p->name;
    115   if (fp == stdin)
    116     return "stdin";
    117   else if (fp == stdout)
    118     return "stdout";
    119   else if (fp == stderr)
    120     return "stderr";
    121 
    122   return "<unknown>";
    123 }
    124 
    125 static void
    126 register_open_file (fp, name, temp)
    127   FILE *fp;
    128   const char *name;
    129   int temp;
    130 {
    131   struct open_file *p;
    132   for (p=open_files; p; p=p->link)
    133     {
    134       if (fp == p->fp)
    135 	{
    136 	  FREE(p->name);
    137 	  break;
    138 	}
    139     }
    140   if (!p)
    141     {
    142       p = MALLOC(1, struct open_file);
    143       p->link = open_files;
    144       open_files = p;
    145     }
    146   p->name = ck_strdup(name);
    147   p->fp = fp;
    148   p->temp = false;
    149 }
    150 
    151 /* Panic on failing fopen */
    152 FILE *
    153 ck_fopen(name, mode, fail)
    154   const char *name;
    155   const char *mode;
    156   int fail;
    157 {
    158   FILE *fp;
    159 
    160   fp = fopen (name, mode);
    161   if (!fp)
    162     {
    163       if (fail)
    164         panic(_("couldn't open file %s: %s"), name, strerror(errno));
    165 
    166       return NULL;
    167     }
    168 
    169   register_open_file (fp, name, false);
    170   return fp;
    171 }
    172 
    173 /* Panic on failing fdopen */
    174 FILE *
    175 ck_fdopen(fd, name, mode, fail)
    176   int fd;
    177   const char *name;
    178   const char *mode;
    179   int fail;
    180 {
    181   FILE *fp;
    182 
    183   fp = fdopen (fd, mode);
    184   if (!fp)
    185     {
    186       if (fail)
    187         panic(_("couldn't attach to %s: %s"), name, strerror(errno));
    188 
    189       return NULL;
    190     }
    191 
    192   register_open_file (fp, name, false);
    193   return fp;
    194 }
    195 
    196 FILE *
    197 ck_mkstemp (p_filename, tmpdir, base)
    198   char **p_filename;
    199   char *base, *tmpdir;
    200 {
    201   char *template;
    202   FILE *fp;
    203   int fd;
    204   int save_umask;
    205 
    206   if (tmpdir == NULL)
    207     tmpdir = getenv("TMPDIR");
    208   if (tmpdir == NULL)
    209     {
    210       tmpdir = getenv("TMP");
    211       if (tmpdir == NULL)
    212 #ifdef P_tmpdir
    213 	tmpdir = P_tmpdir;
    214 #else
    215 	tmpdir = "/tmp";
    216 #endif
    217     }
    218 
    219   template = xmalloc (strlen (tmpdir) + strlen (base) + 8);
    220   sprintf (template, "%s/%sXXXXXX", tmpdir, base);
    221 
    222    /* The ownership might change, so omit some permissions at first
    223       so unauthorized users cannot nip in before the file is ready.  */
    224   save_umask = umask (0700);
    225   fd = mkstemp (template);
    226   umask (save_umask);
    227   if (fd == -1)
    228     panic(_("couldn't open temporary file %s: %s"), template, strerror(errno));
    229 
    230   *p_filename = template;
    231   fp = fdopen (fd, "w");
    232   register_open_file (fp, template, true);
    233   return fp;
    234 }
    235 
    236 /* Panic on failing fwrite */
    237 void
    238 ck_fwrite(ptr, size, nmemb, stream)
    239   const VOID *ptr;
    240   size_t size;
    241   size_t nmemb;
    242   FILE *stream;
    243 {
    244   clearerr(stream);
    245   if (size && fwrite(ptr, size, nmemb, stream) != nmemb)
    246     panic(ngettext("couldn't write %d item to %s: %s",
    247 		   "couldn't write %d items to %s: %s", nmemb),
    248 		nmemb, utils_fp_name(stream), strerror(errno));
    249 }
    250 
    251 /* Panic on failing fread */
    252 size_t
    253 ck_fread(ptr, size, nmemb, stream)
    254   VOID *ptr;
    255   size_t size;
    256   size_t nmemb;
    257   FILE *stream;
    258 {
    259   clearerr(stream);
    260   if (size && (nmemb=fread(ptr, size, nmemb, stream)) <= 0 && ferror(stream))
    261     panic(_("read error on %s: %s"), utils_fp_name(stream), strerror(errno));
    262 
    263   return nmemb;
    264 }
    265 
    266 size_t
    267 ck_getline(text, buflen, stream)
    268   char **text;
    269   size_t *buflen;
    270   FILE *stream;
    271 {
    272   int result;
    273   if (!ferror (stream))
    274     result = getline (text, buflen, stream);
    275 
    276   if (ferror (stream))
    277     panic (_("read error on %s: %s"), utils_fp_name(stream), strerror(errno));
    278 
    279   return result;
    280 }
    281 
    282 /* Panic on failing fflush */
    283 void
    284 ck_fflush(stream)
    285   FILE *stream;
    286 {
    287   clearerr(stream);
    288   if (fflush(stream) == EOF && errno != EBADF)
    289     panic("couldn't flush %s: %s", utils_fp_name(stream), strerror(errno));
    290 }
    291 
    292 /* Panic on failing fclose */
    293 void
    294 ck_fclose(stream)
    295   FILE *stream;
    296 {
    297   struct open_file r;
    298   struct open_file *prev;
    299   struct open_file *cur;
    300 
    301   /* a NULL stream means to close all files */
    302   r.link = open_files;
    303   prev = &r;
    304   while ( (cur = prev->link) )
    305     {
    306       if (!stream || stream == cur->fp)
    307 	{
    308 	  do_ck_fclose (cur->fp);
    309 	  prev->link = cur->link;
    310 	  FREE(cur->name);
    311 	  FREE(cur);
    312 	}
    313       else
    314 	prev = cur;
    315     }
    316 
    317   open_files = r.link;
    318 
    319   /* Also care about stdout, because if it is redirected the
    320      last output operations might fail and it is important
    321      to signal this as an error (perhaps to make). */
    322   if (!stream)
    323     {
    324       do_ck_fclose (stdout);
    325       do_ck_fclose (stderr);
    326     }
    327 }
    328 
    329 /* Close a single file. */
    330 void
    331 do_ck_fclose(fp)
    332   FILE *fp;
    333 {
    334   ck_fflush(fp);
    335   clearerr(fp);
    336 
    337   if (fclose(fp) == EOF)
    338     panic("couldn't close %s: %s", utils_fp_name(fp), strerror(errno));
    339 }
    340 
    341 
    343 /* Follow symlink and panic if something fails.  Return the ultimate
    344    symlink target, stored in a temporary buffer that the caller should
    345    not free.  */
    346 const char *
    347 follow_symlink(const char *fname)
    348 {
    349 #ifdef ENABLE_FOLLOW_SYMLINKS
    350   static char *buf1, *buf2;
    351   static int buf_size;
    352 
    353   struct stat statbuf;
    354   const char *buf = fname, *c;
    355   int rc;
    356 
    357   if (buf_size == 0)
    358     {
    359       buf1 = ck_malloc (PATH_MAX + 1);
    360       buf2 = ck_malloc (PATH_MAX + 1);
    361       buf_size = PATH_MAX + 1;
    362     }
    363 
    364   while ((rc = lstat (buf, &statbuf)) == 0
    365          && (statbuf.st_mode & S_IFLNK) == S_IFLNK)
    366     {
    367       if (buf == buf2)
    368         {
    369           strcpy (buf1, buf2);
    370           buf = buf1;
    371         }
    372 
    373       while ((rc = readlink (buf, buf2, buf_size)) == buf_size)
    374         {
    375           buf_size *= 2;
    376           buf1 = ck_realloc (buf1, buf_size);
    377           buf2 = ck_realloc (buf2, buf_size);
    378         }
    379       if (rc < 0)
    380 	panic (_("couldn't follow symlink %s: %s"), buf, strerror(errno));
    381       else
    382 	buf2 [rc] = '\0';
    383 
    384       if (buf2[0] != '/' && (c = strrchr (buf, '/')) != NULL)
    385 	{
    386 	  /* Need to handle relative paths with care.  Reallocate buf1 and
    387 	     buf2 to be big enough.  */
    388 	  int len = c - buf + 1;
    389 	  if (len + rc + 1 > buf_size)
    390 	    {
    391 	      buf_size = len + rc + 1;
    392 	      buf1 = ck_realloc (buf1, buf_size);
    393 	      buf2 = ck_realloc (buf2, buf_size);
    394 	    }
    395 
    396 	  /* Always store the new path in buf1.  */
    397 	  if (buf != buf1)
    398             memcpy (buf1, buf, len);
    399 
    400           /* Tack the relative symlink at the end of buf1.  */
    401           memcpy (buf1 + len, buf2, rc + 1);
    402 	  buf = buf1;
    403 	}
    404       else
    405 	{
    406 	  /* Use buf2 as the buffer, it saves a strcpy if it is not pointing to
    407 	     another link.  It works for absolute symlinks, and as long as
    408 	     symlinks do not leave the current directory.  */
    409 	   buf = buf2;
    410 	}
    411     }
    412 
    413   if (rc < 0)
    414     panic (_("cannot stat %s: %s"), buf, strerror(errno));
    415 
    416   return buf;
    417 #else
    418   return fname;
    419 #endif /* ENABLE_FOLLOW_SYMLINKS */
    420 }
    421 
    422 /* Panic on failing rename */
    423 void
    424 ck_rename (from, to, unlink_if_fail)
    425   const char *from, *to;
    426   const char *unlink_if_fail;
    427 {
    428   int rd = rename (from, to);
    429   if (rd != -1)
    430     return;
    431 
    432   if (unlink_if_fail)
    433     {
    434       int save_errno = errno;
    435       errno = 0;
    436       unlink (unlink_if_fail);
    437 
    438       /* Failure to remove the temporary file is more severe, so trigger it first.  */
    439       if (errno != 0)
    440         panic (_("cannot remove %s: %s"), unlink_if_fail, strerror (errno));
    441 
    442       errno = save_errno;
    443     }
    444 
    445   panic (_("cannot rename %s: %s"), from, strerror (errno));
    446 }
    447 
    448 
    449 
    450 
    451 /* Panic on failing malloc */
    453 VOID *
    454 ck_malloc(size)
    455   size_t size;
    456 {
    457   VOID *ret = calloc(1, size ? size : 1);
    458   if (!ret)
    459     panic("couldn't allocate memory");
    460   return ret;
    461 }
    462 
    463 /* Panic on failing realloc */
    464 VOID *
    465 ck_realloc(ptr, size)
    466   VOID *ptr;
    467   size_t size;
    468 {
    469   VOID *ret;
    470 
    471   if (size == 0)
    472     {
    473       FREE(ptr);
    474       return NULL;
    475     }
    476   if (!ptr)
    477     return ck_malloc(size);
    478   ret = realloc(ptr, size);
    479   if (!ret)
    480     panic("couldn't re-allocate memory");
    481   return ret;
    482 }
    483 
    484 /* Return a malloc()'d copy of a string */
    485 char *
    486 ck_strdup(str)
    487   const char *str;
    488 {
    489   char *ret = MALLOC(strlen(str)+1, char);
    490   return strcpy(ret, str);
    491 }
    492 
    493 /* Return a malloc()'d copy of a block of memory */
    494 VOID *
    495 ck_memdup(buf, len)
    496   const VOID *buf;
    497   size_t len;
    498 {
    499   VOID *ret = ck_malloc(len);
    500   return memcpy(ret, buf, len);
    501 }
    502 
    503 /* Release a malloc'd block of memory */
    504 void
    505 ck_free(ptr)
    506   VOID *ptr;
    507 {
    508   if (ptr)
    509     free(ptr);
    510 }
    511 
    512 
    513 /* Implement a variable sized buffer of `stuff'.  We don't know what it is,
    515 nor do we care, as long as it doesn't mind being aligned by malloc. */
    516 
    517 struct buffer
    518   {
    519     size_t allocated;
    520     size_t length;
    521     char *b;
    522   };
    523 
    524 #define MIN_ALLOCATE 50
    525 
    526 struct buffer *
    527 init_buffer()
    528 {
    529   struct buffer *b = MALLOC(1, struct buffer);
    530   b->b = MALLOC(MIN_ALLOCATE, char);
    531   b->allocated = MIN_ALLOCATE;
    532   b->length = 0;
    533   return b;
    534 }
    535 
    536 char *
    537 get_buffer(b)
    538   struct buffer *b;
    539 {
    540   return b->b;
    541 }
    542 
    543 size_t
    544 size_buffer(b)
    545   struct buffer *b;
    546 {
    547   return b->length;
    548 }
    549 
    550 static void resize_buffer P_((struct buffer *b, size_t newlen));
    551 static void
    552 resize_buffer(b, newlen)
    553   struct buffer *b;
    554   size_t newlen;
    555 {
    556   char *try = NULL;
    557   size_t alen = b->allocated;
    558 
    559   if (newlen <= alen)
    560     return;
    561   alen *= 2;
    562   if (newlen < alen)
    563     try = realloc(b->b, alen);	/* Note: *not* the REALLOC() macro! */
    564   if (!try)
    565     {
    566       alen = newlen;
    567       try = REALLOC(b->b, alen, char);
    568     }
    569   b->allocated = alen;
    570   b->b = try;
    571 }
    572 
    573 char *
    574 add_buffer(b, p, n)
    575   struct buffer *b;
    576   const char *p;
    577   size_t n;
    578 {
    579   char *result;
    580   if (b->allocated - b->length < n)
    581     resize_buffer(b, b->length+n);
    582   result = memcpy(b->b + b->length, p, n);
    583   b->length += n;
    584   return result;
    585 }
    586 
    587 char *
    588 add1_buffer(b, c)
    589   struct buffer *b;
    590   int c;
    591 {
    592   /* This special case should be kept cheap;
    593    *  don't make it just a mere convenience
    594    *  wrapper for add_buffer() -- even "builtin"
    595    *  versions of memcpy(a, b, 1) can become
    596    *  expensive when called too often.
    597    */
    598   if (c != EOF)
    599     {
    600       char *result;
    601       if (b->allocated - b->length < 1)
    602 	resize_buffer(b, b->length+1);
    603       result = b->b + b->length++;
    604       *result = c;
    605       return result;
    606     }
    607 
    608   return NULL;
    609 }
    610 
    611 void
    612 free_buffer(b)
    613   struct buffer *b;
    614 {
    615   if (b)
    616     FREE(b->b);
    617   FREE(b);
    618 }
    619