17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*b493790cSbasabi * Common Development and Distribution License (the "License"). 6*b493790cSbasabi * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*b493790cSbasabi * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*b493790cSbasabi * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate * 257c478bd9Sstevel@tonic-gate * logadm/err.c -- some basic error routines 267c478bd9Sstevel@tonic-gate * 277c478bd9Sstevel@tonic-gate */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #include <stdio.h> 327c478bd9Sstevel@tonic-gate #include <unistd.h> 337c478bd9Sstevel@tonic-gate #include <libintl.h> 347c478bd9Sstevel@tonic-gate #include <stdlib.h> 357c478bd9Sstevel@tonic-gate #include <stdarg.h> 367c478bd9Sstevel@tonic-gate #include <string.h> 377c478bd9Sstevel@tonic-gate #include <errno.h> 387c478bd9Sstevel@tonic-gate #include "err.h" 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate static const char *Myname; 417c478bd9Sstevel@tonic-gate static int Exitcode; 427c478bd9Sstevel@tonic-gate static FILE *Errorfile; 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate /* 457c478bd9Sstevel@tonic-gate * err_init -- initialize the error handling routine 467c478bd9Sstevel@tonic-gate * 477c478bd9Sstevel@tonic-gate */ 487c478bd9Sstevel@tonic-gate void 497c478bd9Sstevel@tonic-gate err_init(const char *myname) 507c478bd9Sstevel@tonic-gate { 517c478bd9Sstevel@tonic-gate char *ptr; 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate if ((ptr = strrchr(myname, '/')) == NULL) 547c478bd9Sstevel@tonic-gate Myname = myname; 557c478bd9Sstevel@tonic-gate else 567c478bd9Sstevel@tonic-gate Myname = ptr + 1; 577c478bd9Sstevel@tonic-gate } 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate static const char *File; 607c478bd9Sstevel@tonic-gate static int Line; 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate /* 637c478bd9Sstevel@tonic-gate * err_fileline -- record the filename/line number for err(EF_FILE, ...) 647c478bd9Sstevel@tonic-gate */ 657c478bd9Sstevel@tonic-gate void 667c478bd9Sstevel@tonic-gate err_fileline(const char *file, int line) 677c478bd9Sstevel@tonic-gate { 687c478bd9Sstevel@tonic-gate File = file; 697c478bd9Sstevel@tonic-gate Line = line; 707c478bd9Sstevel@tonic-gate } 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate /* 737c478bd9Sstevel@tonic-gate * err -- print an error message and return, exit or longjmp based on flags 747c478bd9Sstevel@tonic-gate * 757c478bd9Sstevel@tonic-gate * this routine calls gettext() to translate the fmt string. 767c478bd9Sstevel@tonic-gate */ 777c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/ 787c478bd9Sstevel@tonic-gate void 797c478bd9Sstevel@tonic-gate err(int flags, const char *fmt, ...) 807c478bd9Sstevel@tonic-gate { 817c478bd9Sstevel@tonic-gate va_list ap; 827c478bd9Sstevel@tonic-gate int safe_errno = errno; 837c478bd9Sstevel@tonic-gate char *errno_msg = NULL; 847c478bd9Sstevel@tonic-gate int as_is = 0; 857c478bd9Sstevel@tonic-gate int jump = 0; 867c478bd9Sstevel@tonic-gate int warning = 0; 877c478bd9Sstevel@tonic-gate int fileline = 0; 887c478bd9Sstevel@tonic-gate char *prefix = "Error: "; 897c478bd9Sstevel@tonic-gate const char *intlfmt; 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate va_start(ap, fmt); 927c478bd9Sstevel@tonic-gate intlfmt = gettext(fmt); 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate if (flags & EF_WARN) { 957c478bd9Sstevel@tonic-gate warning = 1; 967c478bd9Sstevel@tonic-gate prefix = "Warning: "; 977c478bd9Sstevel@tonic-gate } 987c478bd9Sstevel@tonic-gate if (flags & EF_FILE) { 997c478bd9Sstevel@tonic-gate fileline = 1; 1007c478bd9Sstevel@tonic-gate Exitcode++; 1017c478bd9Sstevel@tonic-gate } 1027c478bd9Sstevel@tonic-gate if (flags & EF_SYS) 1037c478bd9Sstevel@tonic-gate errno_msg = strerror(safe_errno); 1047c478bd9Sstevel@tonic-gate if (flags & EF_JMP) 1057c478bd9Sstevel@tonic-gate jump = 1; 1067c478bd9Sstevel@tonic-gate if (flags & EF_RAW) 1077c478bd9Sstevel@tonic-gate as_is = 1; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate /* print a copy to stderr */ 1107c478bd9Sstevel@tonic-gate if (!as_is) { 111*b493790cSbasabi if (Myname != NULL) { 1127c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", Myname); 1137c478bd9Sstevel@tonic-gate if (Errorfile) 1147c478bd9Sstevel@tonic-gate (void) fprintf(Errorfile, "%s: ", Myname); 1157c478bd9Sstevel@tonic-gate } 1167c478bd9Sstevel@tonic-gate if (fileline && File) { 1177c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s line %d: ", File, Line); 1187c478bd9Sstevel@tonic-gate if (Errorfile) 1197c478bd9Sstevel@tonic-gate (void) fprintf(Errorfile, 1207c478bd9Sstevel@tonic-gate "%s line %d: ", File, Line); 1217c478bd9Sstevel@tonic-gate } 1227c478bd9Sstevel@tonic-gate (void) fputs(gettext(prefix), stderr); 1237c478bd9Sstevel@tonic-gate if (Errorfile) 1247c478bd9Sstevel@tonic-gate (void) fputs(gettext(prefix), Errorfile); 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, intlfmt, ap); 1277c478bd9Sstevel@tonic-gate if (Errorfile) 1287c478bd9Sstevel@tonic-gate (void) vfprintf(Errorfile, intlfmt, ap); 129*b493790cSbasabi if (errno_msg != NULL) { 1307c478bd9Sstevel@tonic-gate (void) fprintf(stderr, ": %s", errno_msg); 1317c478bd9Sstevel@tonic-gate if (Errorfile) 1327c478bd9Sstevel@tonic-gate (void) fprintf(Errorfile, ": %s", errno_msg); 1337c478bd9Sstevel@tonic-gate } 1347c478bd9Sstevel@tonic-gate if (!as_is) { 1357c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 1367c478bd9Sstevel@tonic-gate if (Errorfile) 1377c478bd9Sstevel@tonic-gate (void) fprintf(Errorfile, "\n"); 1387c478bd9Sstevel@tonic-gate } 1397c478bd9Sstevel@tonic-gate (void) fflush(stderr); 1407c478bd9Sstevel@tonic-gate if (Errorfile) 1417c478bd9Sstevel@tonic-gate (void) fflush(Errorfile); 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate va_end(ap); 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate if (jump) 1467c478bd9Sstevel@tonic-gate longjmp(Err_env, 1); 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate if (!warning && !fileline) { 1497c478bd9Sstevel@tonic-gate err_done(1); 1507c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 1517c478bd9Sstevel@tonic-gate } 1527c478bd9Sstevel@tonic-gate } 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate /* 1557c478bd9Sstevel@tonic-gate * out -- print a message and return 1567c478bd9Sstevel@tonic-gate * 1577c478bd9Sstevel@tonic-gate * this routine calls gettext() to translate the fmt string. 1587c478bd9Sstevel@tonic-gate */ 1597c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 1607c478bd9Sstevel@tonic-gate void 1617c478bd9Sstevel@tonic-gate out(const char *fmt, ...) 1627c478bd9Sstevel@tonic-gate { 1637c478bd9Sstevel@tonic-gate va_list ap; 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate va_start(ap, fmt); 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate (void) vfprintf(stdout, gettext(fmt), ap); 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate va_end(ap); 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate #define CHUNKSIZE 8192 /* for copying stderr */ 1737c478bd9Sstevel@tonic-gate /* 1747c478bd9Sstevel@tonic-gate * err_fromfd -- copy data from fd to stderr 1757c478bd9Sstevel@tonic-gate */ 1767c478bd9Sstevel@tonic-gate void 1777c478bd9Sstevel@tonic-gate err_fromfd(int fd) 1787c478bd9Sstevel@tonic-gate { 1797c478bd9Sstevel@tonic-gate char buf[CHUNKSIZE]; 1807c478bd9Sstevel@tonic-gate int count; 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate while ((count = read(fd, buf, CHUNKSIZE)) > 0) { 1837c478bd9Sstevel@tonic-gate (void) fwrite(buf, 1, count, stderr); 1847c478bd9Sstevel@tonic-gate if (Errorfile) 1857c478bd9Sstevel@tonic-gate (void) fwrite(buf, 1, count, Errorfile); 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate (void) fflush(stderr); 1887c478bd9Sstevel@tonic-gate if (Errorfile) 1897c478bd9Sstevel@tonic-gate (void) fflush(Errorfile); 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate /* 1937c478bd9Sstevel@tonic-gate * err_done -- exit the program 1947c478bd9Sstevel@tonic-gate */ 1957c478bd9Sstevel@tonic-gate void 1967c478bd9Sstevel@tonic-gate err_done(int exitcode) 1977c478bd9Sstevel@tonic-gate { 1987c478bd9Sstevel@tonic-gate /* send error mail if applicable */ 1997c478bd9Sstevel@tonic-gate err_mailto(NULL); 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate if (exitcode) 2027c478bd9Sstevel@tonic-gate exit(exitcode); 2037c478bd9Sstevel@tonic-gate else 2047c478bd9Sstevel@tonic-gate exit(Exitcode); 2057c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate #define MAXLINE 8192 /* for tmp file line buffer */ 2097c478bd9Sstevel@tonic-gate /* 2107c478bd9Sstevel@tonic-gate * err_mailto -- arrange for error output to be mailed to someone 2117c478bd9Sstevel@tonic-gate */ 2127c478bd9Sstevel@tonic-gate void 2137c478bd9Sstevel@tonic-gate err_mailto(const char *recipient) 2147c478bd9Sstevel@tonic-gate { 2157c478bd9Sstevel@tonic-gate static const char *lastrecipient; 2167c478bd9Sstevel@tonic-gate static char mailcmd[] = "/bin/mailx -s 'logadm error output'"; 2177c478bd9Sstevel@tonic-gate char *cmd; 2187c478bd9Sstevel@tonic-gate int len; 2197c478bd9Sstevel@tonic-gate FILE *pfp; 2207c478bd9Sstevel@tonic-gate char line[MAXLINE]; 2217c478bd9Sstevel@tonic-gate 222*b493790cSbasabi if (lastrecipient != NULL) { 223*b493790cSbasabi if (recipient != NULL && 224*b493790cSbasabi strcmp(recipient, lastrecipient) == 0) 2257c478bd9Sstevel@tonic-gate return; /* keep going, same recipient */ 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate /* stop saving output for lastrecipient and send message */ 2287c478bd9Sstevel@tonic-gate if (ftell(Errorfile)) { 2297c478bd9Sstevel@tonic-gate rewind(Errorfile); 2307c478bd9Sstevel@tonic-gate len = strlen(lastrecipient) + strlen(mailcmd) + 2; 2317c478bd9Sstevel@tonic-gate cmd = MALLOC(len); 2327c478bd9Sstevel@tonic-gate (void) snprintf(cmd, len, "%s %s", 2337c478bd9Sstevel@tonic-gate mailcmd, lastrecipient); 2347c478bd9Sstevel@tonic-gate if ((pfp = popen(cmd, "w")) == NULL) 2357c478bd9Sstevel@tonic-gate err(EF_SYS, "popen to mailx"); 2367c478bd9Sstevel@tonic-gate while (fgets(line, MAXLINE, Errorfile) != NULL) 2377c478bd9Sstevel@tonic-gate (void) fputs(line, pfp); 2387c478bd9Sstevel@tonic-gate (void) pclose(pfp); 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate (void) fclose(Errorfile); 2417c478bd9Sstevel@tonic-gate Errorfile = NULL; 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate 244*b493790cSbasabi if (recipient != NULL) { 2457c478bd9Sstevel@tonic-gate /* start saving error output for this recipient */ 2467c478bd9Sstevel@tonic-gate if ((Errorfile = tmpfile()) == NULL) 2477c478bd9Sstevel@tonic-gate err(EF_SYS, "tmpfile"); 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate lastrecipient = recipient; 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate /* 2537c478bd9Sstevel@tonic-gate * err_malloc -- a malloc() with checks 2547c478bd9Sstevel@tonic-gate * 2557c478bd9Sstevel@tonic-gate * this routine is typically called via the MALLOC() macro in err.h 2567c478bd9Sstevel@tonic-gate */ 2577c478bd9Sstevel@tonic-gate void * 2587c478bd9Sstevel@tonic-gate err_malloc(int nbytes, const char *fname, int line) 2597c478bd9Sstevel@tonic-gate { 2607c478bd9Sstevel@tonic-gate void *retval = malloc(nbytes); 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate if (retval == NULL) 2637c478bd9Sstevel@tonic-gate err(0, "%s:%d: out of memory", fname, line); 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate return (retval); 2667c478bd9Sstevel@tonic-gate } 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate /* 2697c478bd9Sstevel@tonic-gate * err_realloc -- a realloc() with checks 2707c478bd9Sstevel@tonic-gate * 2717c478bd9Sstevel@tonic-gate * this routine is typically called via the REALLOC() macro in err.h 2727c478bd9Sstevel@tonic-gate */ 2737c478bd9Sstevel@tonic-gate void * 2747c478bd9Sstevel@tonic-gate err_realloc(void *ptr, int nbytes, const char *fname, int line) 2757c478bd9Sstevel@tonic-gate { 2767c478bd9Sstevel@tonic-gate void *retval = realloc(ptr, nbytes); 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate if (retval == NULL) 2797c478bd9Sstevel@tonic-gate err(0, "%s:%d: out of memory", fname, line); 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate return (retval); 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate /* 2857c478bd9Sstevel@tonic-gate * err_strdup -- a strdup() with checks 2867c478bd9Sstevel@tonic-gate * 2877c478bd9Sstevel@tonic-gate * this routine is typically called via the STRDUP() macro in err.h 2887c478bd9Sstevel@tonic-gate */ 2897c478bd9Sstevel@tonic-gate char * 2907c478bd9Sstevel@tonic-gate err_strdup(const char *ptr, const char *fname, int line) 2917c478bd9Sstevel@tonic-gate { 292*b493790cSbasabi char *retval = NULL; 2937c478bd9Sstevel@tonic-gate 294*b493790cSbasabi if (ptr != NULL) { 295*b493790cSbasabi retval = strdup(ptr); 2967c478bd9Sstevel@tonic-gate if (retval == NULL) 2977c478bd9Sstevel@tonic-gate err(0, "%s:%d: out of memory", fname, line); 298*b493790cSbasabi } else 299*b493790cSbasabi err(0, "%s:%d: could not strdup", fname, line); 300*b493790cSbasabi 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate return (retval); 303*b493790cSbasabi 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate /* 3077c478bd9Sstevel@tonic-gate * err_free -- a free() with checks 3087c478bd9Sstevel@tonic-gate * 3097c478bd9Sstevel@tonic-gate * this routine is typically called via the FREE() macro in err.h 3107c478bd9Sstevel@tonic-gate */ 3117c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 3127c478bd9Sstevel@tonic-gate void 3137c478bd9Sstevel@tonic-gate err_free(void *ptr, const char *fname, int line) 3147c478bd9Sstevel@tonic-gate { 3157c478bd9Sstevel@tonic-gate /* nothing to check in this version */ 3167c478bd9Sstevel@tonic-gate free(ptr); 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate /* 3207c478bd9Sstevel@tonic-gate * err_exitcode -- set an error exit code for when done(0) is called 3217c478bd9Sstevel@tonic-gate */ 3227c478bd9Sstevel@tonic-gate void 3237c478bd9Sstevel@tonic-gate err_exitcode(int exitcode) 3247c478bd9Sstevel@tonic-gate { 3257c478bd9Sstevel@tonic-gate Exitcode = exitcode; 3267c478bd9Sstevel@tonic-gate } 327