• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
panic(const char * str,...)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 */
104 static const char *utils_fp_name P_((FILE *fp));
105 static const char *
utils_fp_name(fp)106 utils_fp_name(fp)
107   FILE *fp;
108 {
109   struct open_file *p;
110 
111   for (p=open_files; p; p=p->link)
112     if (p->fp == fp)
113       return p->name;
114   if (fp == stdin)
115     return "stdin";
116   else if (fp == stdout)
117     return "stdout";
118   else if (fp == stderr)
119     return "stderr";
120 
121   return "<unknown>";
122 }
123 
124 static void
register_open_file(fp,name,temp)125 register_open_file (fp, name, temp)
126   FILE *fp;
127   const char *name;
128   int temp;
129 {
130   struct open_file *p;
131   for (p=open_files; p; p=p->link)
132     {
133       if (fp == p->fp)
134 	{
135 	  FREE(p->name);
136 	  break;
137 	}
138     }
139   if (!p)
140     {
141       p = MALLOC(1, struct open_file);
142       p->link = open_files;
143       open_files = p;
144     }
145   p->name = ck_strdup(name);
146   p->fp = fp;
147   p->temp = false;
148 }
149 
150 /* Panic on failing fopen */
151 FILE *
ck_fopen(name,mode,fail)152 ck_fopen(name, mode, fail)
153   const char *name;
154   const char *mode;
155   int fail;
156 {
157   FILE *fp;
158 
159   fp = fopen (name, mode);
160   if (!fp)
161     {
162       if (fail)
163         panic(_("couldn't open file %s: %s"), name, strerror(errno));
164 
165       return NULL;
166     }
167 
168   register_open_file (fp, name, false);
169   return fp;
170 }
171 
172 /* Panic on failing fdopen */
173 FILE *
ck_fdopen(fd,name,mode,fail)174 ck_fdopen(fd, name, mode, fail)
175   int fd;
176   const char *name;
177   const char *mode;
178   int fail;
179 {
180   FILE *fp;
181 
182   fp = fdopen (fd, mode);
183   if (!fp)
184     {
185       if (fail)
186         panic(_("couldn't attach to %s: %s"), name, strerror(errno));
187 
188       return NULL;
189     }
190 
191   register_open_file (fp, name, false);
192   return fp;
193 }
194 
195 FILE *
ck_mkstemp(p_filename,tmpdir,base)196 ck_mkstemp (p_filename, tmpdir, base)
197   char **p_filename;
198   char *base, *tmpdir;
199 {
200   char *template;
201   FILE *fp;
202   int fd;
203   int save_umask;
204 
205   if (tmpdir == NULL)
206     tmpdir = getenv("TMPDIR");
207   if (tmpdir == NULL)
208     {
209       tmpdir = getenv("TMP");
210       if (tmpdir == NULL)
211 #ifdef P_tmpdir
212 	tmpdir = P_tmpdir;
213 #else
214 	tmpdir = "/tmp";
215 #endif
216     }
217 
218   template = xmalloc (strlen (tmpdir) + strlen (base) + 8);
219   sprintf (template, "%s/%sXXXXXX", tmpdir, base);
220 
221    /* The ownership might change, so omit some permissions at first
222       so unauthorized users cannot nip in before the file is ready.  */
223   save_umask = umask (0700);
224   fd = mkstemp (template);
225   umask (save_umask);
226   if (fd == -1)
227     panic(_("couldn't open temporary file %s: %s"), template, strerror(errno));
228 
229   *p_filename = template;
230   fp = fdopen (fd, "w");
231   register_open_file (fp, template, true);
232   return fp;
233 }
234 
235 /* Panic on failing fwrite */
236 void
ck_fwrite(ptr,size,nmemb,stream)237 ck_fwrite(ptr, size, nmemb, stream)
238   const VOID *ptr;
239   size_t size;
240   size_t nmemb;
241   FILE *stream;
242 {
243   clearerr(stream);
244   if (size && fwrite(ptr, size, nmemb, stream) != nmemb)
245     panic(ngettext("couldn't write %d item to %s: %s",
246 		   "couldn't write %d items to %s: %s", nmemb),
247 		nmemb, utils_fp_name(stream), strerror(errno));
248 }
249 
250 /* Panic on failing fread */
251 size_t
ck_fread(ptr,size,nmemb,stream)252 ck_fread(ptr, size, nmemb, stream)
253   VOID *ptr;
254   size_t size;
255   size_t nmemb;
256   FILE *stream;
257 {
258   clearerr(stream);
259   if (size && (nmemb=fread(ptr, size, nmemb, stream)) <= 0 && ferror(stream))
260     panic(_("read error on %s: %s"), utils_fp_name(stream), strerror(errno));
261 
262   return nmemb;
263 }
264 
265 size_t
ck_getline(text,buflen,stream)266 ck_getline(text, buflen, stream)
267   char **text;
268   size_t *buflen;
269   FILE *stream;
270 {
271   int result;
272   if (!ferror (stream))
273     result = getline (text, buflen, stream);
274 
275   if (ferror (stream))
276     panic (_("read error on %s: %s"), utils_fp_name(stream), strerror(errno));
277 
278   return result;
279 }
280 
281 /* Panic on failing fflush */
282 void
ck_fflush(stream)283 ck_fflush(stream)
284   FILE *stream;
285 {
286   clearerr(stream);
287   if (fflush(stream) == EOF && errno != EBADF)
288     panic("couldn't flush %s: %s", utils_fp_name(stream), strerror(errno));
289 }
290 
291 /* Panic on failing fclose */
292 void
ck_fclose(stream)293 ck_fclose(stream)
294   FILE *stream;
295 {
296   struct open_file r;
297   struct open_file *prev;
298   struct open_file *cur;
299 
300   /* a NULL stream means to close all files */
301   r.link = open_files;
302   prev = &r;
303   while ( (cur = prev->link) )
304     {
305       if (!stream || stream == cur->fp)
306 	{
307 	  do_ck_fclose (cur->fp);
308 	  prev->link = cur->link;
309 	  FREE(cur->name);
310 	  FREE(cur);
311 	}
312       else
313 	prev = cur;
314     }
315 
316   open_files = r.link;
317 
318   /* Also care about stdout, because if it is redirected the
319      last output operations might fail and it is important
320      to signal this as an error (perhaps to make). */
321   if (!stream)
322     {
323       do_ck_fclose (stdout);
324       do_ck_fclose (stderr);
325     }
326 }
327 
328 /* Close a single file. */
329 void
do_ck_fclose(fp)330 do_ck_fclose(fp)
331   FILE *fp;
332 {
333   ck_fflush(fp);
334   clearerr(fp);
335 
336   if (fclose(fp) == EOF)
337     panic("couldn't close %s: %s", utils_fp_name(fp), strerror(errno));
338 }
339 
340 
341 /* Follow symlink and panic if something fails.  Return the ultimate
342    symlink target, stored in a temporary buffer that the caller should
343    not free.  */
344 const char *
follow_symlink(const char * fname)345 follow_symlink(const char *fname)
346 {
347 #ifdef ENABLE_FOLLOW_SYMLINKS
348   static char *buf1, *buf2;
349   static int buf_size;
350 
351   struct stat statbuf;
352   const char *buf = fname, *c;
353   int rc;
354 
355   if (buf_size == 0)
356     {
357       buf1 = ck_malloc (PATH_MAX + 1);
358       buf2 = ck_malloc (PATH_MAX + 1);
359       buf_size = PATH_MAX + 1;
360     }
361 
362   while ((rc = lstat (buf, &statbuf)) == 0
363          && (statbuf.st_mode & S_IFLNK) == S_IFLNK)
364     {
365       if (buf == buf2)
366         {
367           strcpy (buf1, buf2);
368           buf = buf1;
369         }
370 
371       while ((rc = readlink (buf, buf2, buf_size)) == buf_size)
372         {
373           buf_size *= 2;
374           buf1 = ck_realloc (buf1, buf_size);
375           buf2 = ck_realloc (buf2, buf_size);
376         }
377       if (rc < 0)
378 	panic (_("couldn't follow symlink %s: %s"), buf, strerror(errno));
379       else
380 	buf2 [rc] = '\0';
381 
382       if (buf2[0] != '/' && (c = strrchr (buf, '/')) != NULL)
383 	{
384 	  /* Need to handle relative paths with care.  Reallocate buf1 and
385 	     buf2 to be big enough.  */
386 	  int len = c - buf + 1;
387 	  if (len + rc + 1 > buf_size)
388 	    {
389 	      buf_size = len + rc + 1;
390 	      buf1 = ck_realloc (buf1, buf_size);
391 	      buf2 = ck_realloc (buf2, buf_size);
392 	    }
393 
394 	  /* Always store the new path in buf1.  */
395 	  if (buf != buf1)
396             memcpy (buf1, buf, len);
397 
398           /* Tack the relative symlink at the end of buf1.  */
399           memcpy (buf1 + len, buf2, rc + 1);
400 	  buf = buf1;
401 	}
402       else
403 	{
404 	  /* Use buf2 as the buffer, it saves a strcpy if it is not pointing to
405 	     another link.  It works for absolute symlinks, and as long as
406 	     symlinks do not leave the current directory.  */
407 	   buf = buf2;
408 	}
409     }
410 
411   if (rc < 0)
412     panic (_("cannot stat %s: %s"), buf, strerror(errno));
413 
414   return buf;
415 #else
416   return fname;
417 #endif /* ENABLE_FOLLOW_SYMLINKS */
418 }
419 
420 /* Panic on failing rename */
421 void
ck_rename(from,to,unlink_if_fail)422 ck_rename (from, to, unlink_if_fail)
423   const char *from, *to;
424   const char *unlink_if_fail;
425 {
426   int rd = rename (from, to);
427   if (rd != -1)
428     return;
429 
430   if (unlink_if_fail)
431     {
432       int save_errno = errno;
433       errno = 0;
434       unlink (unlink_if_fail);
435 
436       /* Failure to remove the temporary file is more severe, so trigger it first.  */
437       if (errno != 0)
438         panic (_("cannot remove %s: %s"), unlink_if_fail, strerror (errno));
439 
440       errno = save_errno;
441     }
442 
443   panic (_("cannot rename %s: %s"), from, strerror (errno));
444 }
445 
446 
447 
448 
449 /* Panic on failing malloc */
450 VOID *
ck_malloc(size)451 ck_malloc(size)
452   size_t size;
453 {
454   VOID *ret = calloc(1, size ? size : 1);
455   if (!ret)
456     panic("couldn't allocate memory");
457   return ret;
458 }
459 
460 /* Panic on failing realloc */
461 VOID *
ck_realloc(ptr,size)462 ck_realloc(ptr, size)
463   VOID *ptr;
464   size_t size;
465 {
466   VOID *ret;
467 
468   if (size == 0)
469     {
470       FREE(ptr);
471       return NULL;
472     }
473   if (!ptr)
474     return ck_malloc(size);
475   ret = realloc(ptr, size);
476   if (!ret)
477     panic("couldn't re-allocate memory");
478   return ret;
479 }
480 
481 /* Return a malloc()'d copy of a string */
482 char *
ck_strdup(str)483 ck_strdup(str)
484   const char *str;
485 {
486   char *ret = MALLOC(strlen(str)+1, char);
487   return strcpy(ret, str);
488 }
489 
490 /* Return a malloc()'d copy of a block of memory */
491 VOID *
ck_memdup(buf,len)492 ck_memdup(buf, len)
493   const VOID *buf;
494   size_t len;
495 {
496   VOID *ret = ck_malloc(len);
497   return memcpy(ret, buf, len);
498 }
499 
500 /* Release a malloc'd block of memory */
501 void
ck_free(ptr)502 ck_free(ptr)
503   VOID *ptr;
504 {
505   if (ptr)
506     free(ptr);
507 }
508 
509 
510 /* Implement a variable sized buffer of `stuff'.  We don't know what it is,
511 nor do we care, as long as it doesn't mind being aligned by malloc. */
512 
513 struct buffer
514   {
515     size_t allocated;
516     size_t length;
517     char *b;
518   };
519 
520 #define MIN_ALLOCATE 50
521 
522 struct buffer *
init_buffer()523 init_buffer()
524 {
525   struct buffer *b = MALLOC(1, struct buffer);
526   b->b = MALLOC(MIN_ALLOCATE, char);
527   b->allocated = MIN_ALLOCATE;
528   b->length = 0;
529   return b;
530 }
531 
532 char *
get_buffer(b)533 get_buffer(b)
534   struct buffer *b;
535 {
536   return b->b;
537 }
538 
539 size_t
size_buffer(b)540 size_buffer(b)
541   struct buffer *b;
542 {
543   return b->length;
544 }
545 
546 static void resize_buffer P_((struct buffer *b, size_t newlen));
547 static void
resize_buffer(b,newlen)548 resize_buffer(b, newlen)
549   struct buffer *b;
550   size_t newlen;
551 {
552   char *try = NULL;
553   size_t alen = b->allocated;
554 
555   if (newlen <= alen)
556     return;
557   alen *= 2;
558   if (newlen < alen)
559     try = realloc(b->b, alen);	/* Note: *not* the REALLOC() macro! */
560   if (!try)
561     {
562       alen = newlen;
563       try = REALLOC(b->b, alen, char);
564     }
565   b->allocated = alen;
566   b->b = try;
567 }
568 
569 char *
add_buffer(b,p,n)570 add_buffer(b, p, n)
571   struct buffer *b;
572   const char *p;
573   size_t n;
574 {
575   char *result;
576   if (b->allocated - b->length < n)
577     resize_buffer(b, b->length+n);
578   result = memcpy(b->b + b->length, p, n);
579   b->length += n;
580   return result;
581 }
582 
583 char *
add1_buffer(b,c)584 add1_buffer(b, c)
585   struct buffer *b;
586   int c;
587 {
588   /* This special case should be kept cheap;
589    *  don't make it just a mere convenience
590    *  wrapper for add_buffer() -- even "builtin"
591    *  versions of memcpy(a, b, 1) can become
592    *  expensive when called too often.
593    */
594   if (c != EOF)
595     {
596       char *result;
597       if (b->allocated - b->length < 1)
598 	resize_buffer(b, b->length+1);
599       result = b->b + b->length++;
600       *result = c;
601       return result;
602     }
603 
604   return NULL;
605 }
606 
607 void
free_buffer(b)608 free_buffer(b)
609   struct buffer *b;
610 {
611   if (b)
612     FREE(b->b);
613   FREE(b);
614 }
615