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