error_message.c revision de8f3a76218255e443ba57dec5d74850180fa75d
1/* 2 * $Header$ 3 * $Source$ 4 * $Locker$ 5 * 6 * Copyright 1987 by the Student Information Processing Board 7 * of the Massachusetts Institute of Technology 8 * 9 * Permission to use, copy, modify, and distribute this software and 10 * its documentation for any purpose is hereby granted, provided that 11 * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in 12 * advertising or publicity pertaining to distribution of the software 13 * without specific, written prior permission. M.I.T. and the 14 * M.I.T. S.I.P.B. make no representations about the suitability of 15 * this software for any purpose. It is provided "as is" without 16 * express or implied warranty. 17 */ 18 19#include <stdio.h> 20#include <stdlib.h> 21#include <string.h> 22#include <errno.h> 23#ifdef HAVE_SYS_PRCTL_H 24#include <sys/prctl.h> 25#else 26#define PR_GET_DUMPABLE 3 27#endif 28#if (!defined(HAVE_PRCTL) && defined(linux)) 29#include <sys/syscall.h> 30#endif 31#if HAVE_UNISTD_H 32#include <unistd.h> 33#endif 34#if HAVE_SYS_TYPES_H 35#include <sys/types.h> 36#endif 37#include "com_err.h" 38#include "error_table.h" 39#include "internal.h" 40 41static char buffer[25]; 42 43struct et_list * _et_list = (struct et_list *) NULL; 44struct et_list * _et_dynamic_list = (struct et_list *) NULL; 45 46 47const char * error_message (errcode_t code) 48{ 49 int offset; 50 struct et_list *et; 51 errcode_t table_num; 52 int started = 0; 53 char *cp; 54 55 offset = (int) (code & ((1<<ERRCODE_RANGE)-1)); 56 table_num = code - offset; 57 if (!table_num) { 58#ifdef HAS_SYS_ERRLIST 59 if (offset < sys_nerr) 60 return(sys_errlist[offset]); 61 else 62 goto oops; 63#else 64 cp = strerror(offset); 65 if (cp) 66 return(cp); 67 else 68 goto oops; 69#endif 70 } 71 for (et = _et_list; et; et = et->next) { 72 if (et->table->base == table_num) { 73 /* This is the right table */ 74 if (et->table->n_msgs <= offset) 75 goto oops; 76 return(et->table->msgs[offset]); 77 } 78 } 79 for (et = _et_dynamic_list; et; et = et->next) { 80 if (et->table->base == table_num) { 81 /* This is the right table */ 82 if (et->table->n_msgs <= offset) 83 goto oops; 84 return(et->table->msgs[offset]); 85 } 86 } 87oops: 88 strcpy (buffer, "Unknown code "); 89 if (table_num) { 90 strcat (buffer, error_table_name (table_num)); 91 strcat (buffer, " "); 92 } 93 for (cp = buffer; *cp; cp++) 94 ; 95 if (offset >= 100) { 96 *cp++ = '0' + offset / 100; 97 offset %= 100; 98 started++; 99 } 100 if (started || offset >= 10) { 101 *cp++ = '0' + offset / 10; 102 offset %= 10; 103 } 104 *cp++ = '0' + offset; 105 *cp = '\0'; 106 return(buffer); 107} 108 109/* 110 * This routine will only return a value if the we are not running as 111 * a privileged process. 112 */ 113static char *safe_getenv(const char *arg) 114{ 115 if ((getuid() != geteuid()) || (getgid() != getegid())) 116 return NULL; 117#if HAVE_PRCTL 118 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) 119 return NULL; 120#else 121#if (defined(linux) && defined(SYS_prctl)) 122 if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) 123 return NULL; 124#endif 125#endif 126 127#ifdef HAVE___SECURE_GETENV 128 return __secure_getenv(arg); 129#else 130 return getenv(arg); 131#endif 132} 133 134#define DEBUG_INIT 0x8000 135#define DEBUG_ADDREMOVE 0x0001 136 137static int debug_mask = 0; 138static FILE *debug_f = 0; 139 140static void init_debug(void) 141{ 142 char *dstr; 143 char *fn; 144 145 if (debug_mask & DEBUG_INIT) 146 return; 147 148 dstr = getenv("COMERR_DEBUG"); 149 if (dstr) 150 debug_mask = strtoul(dstr, 0, 0); 151 152 fn = safe_getenv("COMERR_DEBUG_FILE"); 153 if (fn) 154 debug_f = fopen(fn, "a"); 155 if (!debug_f) 156 debug_f = fopen("/dev/tty", "a"); 157 if (!debug_f) 158 debug_mask = 0; 159 160 debug_mask |= DEBUG_INIT; 161} 162 163/* 164 * New interface provided by krb5's com_err library 165 */ 166errcode_t add_error_table(const struct error_table * et) 167{ 168 struct et_list *el; 169 170 if (!(el = (struct et_list *) malloc(sizeof(struct et_list)))) 171 return ENOMEM; 172 173 el->table = et; 174 el->next = _et_dynamic_list; 175 _et_dynamic_list = el; 176 177 init_debug(); 178 if (debug_mask & DEBUG_ADDREMOVE) 179 fprintf(debug_f, "add_error_table: %s (0x%p)\n", 180 error_table_name(et->base), 181 (const void *) et); 182 183 return 0; 184} 185 186/* 187 * New interface provided by krb5's com_err library 188 */ 189errcode_t remove_error_table(const struct error_table * et) 190{ 191 struct et_list *el = _et_dynamic_list; 192 struct et_list *el2 = 0; 193 194 init_debug(); 195 while (el) { 196 if (el->table->base == et->base) { 197 if (el2) /* Not the beginning of the list */ 198 el2->next = el->next; 199 else 200 _et_dynamic_list = el->next; 201 (void) free(el); 202 if (debug_mask & DEBUG_ADDREMOVE) 203 fprintf(debug_f, 204 "remove_error_table: %s (0x%p)\n", 205 error_table_name(et->base), 206 (const void *) et); 207 return 0; 208 } 209 el2 = el; 210 el = el->next; 211 } 212 if (debug_mask & DEBUG_ADDREMOVE) 213 fprintf(debug_f, "remove_error_table FAILED: %s (0x%p)\n", 214 error_table_name(et->base), 215 (const void *) et); 216 return ENOENT; 217} 218 219/* 220 * Variant of the interface provided by Heimdal's com_err library 221 */ 222void 223add_to_error_table(struct et_list *new_table) 224{ 225 add_error_table(new_table->table); 226} 227