L4Re/departure

libext2fs/lib/libet/error_message.c

618:7123a7307a82
8 months ago Paul Boddie Introduced some debugging output control.
     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 "config.h"    20 #include <stdio.h>    21 #include <stdlib.h>    22 #include <string.h>    23 #include <errno.h>    24 #ifdef HAVE_SYS_PRCTL_H    25 #include <sys/prctl.h>    26 #else    27 #define PR_GET_DUMPABLE 3    28 #endif    29 #if (!defined(HAVE_PRCTL) && defined(linux))    30 #include <sys/syscall.h>    31 #endif    32 #ifdef HAVE_SEMAPHORE_H    33 #include <semaphore.h>    34 #endif    35 #if HAVE_UNISTD_H    36 #include <unistd.h>    37 #endif    38 #if HAVE_FCNTL    39 #include <fcntl.h>    40 #endif    41 #if HAVE_SYS_TYPES_H    42 #include <sys/types.h>    43 #endif    44 #include "com_err.h"    45 #include "error_table.h"    46 #include "internal.h"    47     48 #ifdef TLS    49 #define THREAD_LOCAL static TLS    50 #else    51 #define THREAD_LOCAL static    52 #endif    53     54 THREAD_LOCAL char buffer[25];    55     56 struct et_list * _et_list = (struct et_list *) NULL;    57 struct et_list * _et_dynamic_list = (struct et_list *) NULL;    58     59 #ifdef __GNUC__    60 #define COMERR_ATTR(x) __attribute__(x)    61 #else    62 #define COMERR_ATTR(x)    63 #endif    64     65 #ifdef HAVE_SEM_INIT    66 static sem_t _et_lock;    67 static int _et_lock_initialized;    68     69 static void COMERR_ATTR((constructor)) setup_et_lock(void)    70 {    71 	sem_init(&_et_lock, 0, 1);    72 	_et_lock_initialized = 1;    73 }    74     75 static void COMERR_ATTR((destructor)) fini_et_lock(void)    76 {    77 	sem_destroy(&_et_lock);    78 	_et_lock_initialized = 0;    79 }    80 #endif    81     82     83 int et_list_lock(void)    84 {    85 #ifdef HAVE_SEM_INIT    86 	if (!_et_lock_initialized)    87 		setup_et_lock();    88 	return sem_wait(&_et_lock);    89 #else    90 	return 0;    91 #endif    92 }    93     94 int et_list_unlock(void)    95 {    96 #ifdef HAVE_SEM_INIT    97 	if (_et_lock_initialized)    98 		return sem_post(&_et_lock);    99 #endif   100 	return 0;   101 }   102    103 typedef char *(*gettextf) (const char *);   104    105 static gettextf com_err_gettext = NULL;   106    107 gettextf set_com_err_gettext(gettextf new_proc)   108 {   109     gettextf x = com_err_gettext;   110    111     com_err_gettext = new_proc;   112    113     return x;   114 }   115    116 #ifdef __GNU__   117 #define SYS_ERR_BASE 0x40000000   118 #else   119 #define SYS_ERR_BASE 0   120 #endif   121    122 const char * error_message (errcode_t code)   123 {   124     int offset;   125     struct et_list *et;   126     errcode_t table_num;   127     int started = 0;   128     char *cp;   129    130     offset = (int) (code & ((1<<ERRCODE_RANGE)-1));   131     table_num = code - offset;   132     if (table_num == SYS_ERR_BASE) {   133 #ifdef HAS_SYS_ERRLIST   134 	if (code < sys_nerr)   135 	    return(sys_errlist[code]);   136 	else   137 	    goto oops;   138 #else   139 	cp = strerror(code);   140 	if (cp)   141 	    return(cp);   142 	else   143 	    goto oops;   144 #endif   145     }   146     et_list_lock();   147     for (et = _et_list; et; et = et->next) {   148 	if ((et->table->base & 0xffffffL) == (table_num & 0xffffffL)) {   149 	    /* This is the right table */   150 	    if (et->table->n_msgs <= offset) {   151 		break;   152 	    } else {   153 		const char *msg = et->table->msgs[offset];   154 		et_list_unlock();   155 		if (com_err_gettext)   156 		    return (*com_err_gettext)(msg);   157 		else   158 		    return msg;   159 	    }   160 	}   161     }   162     for (et = _et_dynamic_list; et; et = et->next) {   163 	if ((et->table->base & 0xffffffL) == (table_num & 0xffffffL)) {   164 	    /* This is the right table */   165 	    if (et->table->n_msgs <= offset) {   166 		break;   167 	    } else {   168 		const char *msg = et->table->msgs[offset];   169 		et_list_unlock();   170 		if (com_err_gettext)   171 		    return (*com_err_gettext)(msg);   172 		else   173 		    return msg;   174 	    }   175 	}   176     }   177     et_list_unlock();   178 oops:   179     strcpy (buffer, "Unknown code ");   180     if (table_num) {   181 	strcat (buffer, error_table_name (table_num));   182 	strcat (buffer, " ");   183     }   184     for (cp = buffer; *cp; cp++)   185 	;   186     if (offset >= 100) {   187 	*cp++ = '0' + offset / 100;   188 	offset %= 100;   189 	started++;   190     }   191     if (started || offset >= 10) {   192 	*cp++ = '0' + offset / 10;   193 	offset %= 10;   194     }   195     *cp++ = '0' + offset;   196     *cp = '\0';   197     return(buffer);   198 }   199    200 /*   201  * This routine will only return a value if the we are not running as   202  * a privileged process.   203  */   204 static char *safe_getenv(const char *arg)   205 {   206 #if !defined(_WIN32)   207 	if ((getuid() != geteuid()) || (getgid() != getegid()))   208 		return NULL;   209 #endif   210 #if HAVE_PRCTL   211 	if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)   212 		return NULL;   213 #else   214 #if (defined(linux) && defined(SYS_prctl))   215 	if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)   216 		return NULL;   217 #endif   218 #endif   219    220 #if defined(HAVE_SECURE_GETENV)   221 	return secure_getenv(arg);   222 #elif defined(HAVE___SECURE_GETENV)   223 	return __secure_getenv(arg);   224 #else   225 	return getenv(arg);   226 #endif   227 }   228    229 #define DEBUG_INIT	0x8000   230 #define DEBUG_ADDREMOVE 0x0001   231    232 static int debug_mask = 0;   233 static FILE *debug_f = 0;   234    235 static void init_debug(void)   236 {   237 	char	*dstr, *fn, *tmp;   238 	int	fd, flags;   239    240 	if (debug_mask & DEBUG_INIT)   241 		return;   242    243 	dstr = getenv("COMERR_DEBUG");   244 	if (dstr) {   245 		debug_mask = strtoul(dstr, &tmp, 0);   246 		if (*tmp || errno)   247 			debug_mask = 0;   248 	}   249    250 	debug_mask |= DEBUG_INIT;   251 	if (debug_mask == DEBUG_INIT)   252 		return;   253    254 	fn = safe_getenv("COMERR_DEBUG_FILE");   255 	if (fn)   256 		debug_f = fopen(fn, "a");   257 	if (!debug_f)   258 		debug_f = fopen("/dev/tty", "a");   259 	if (debug_f) {   260 		fd = fileno(debug_f);   261 #if defined(HAVE_FCNTL)   262 		if (fd >= 0) {   263 			flags = fcntl(fd, F_GETFD);   264 			if (flags >= 0)   265 				flags = fcntl(fd, F_SETFD, flags | FD_CLOEXEC);   266 			if (flags < 0) {   267 				fprintf(debug_f, "Couldn't set FD_CLOEXEC "   268 					"on debug FILE: %s\n", strerror(errno));   269 				fclose(debug_f);   270 				debug_f = NULL;   271 				debug_mask = DEBUG_INIT;   272 			}   273 		}   274 #endif   275 	} else   276 		debug_mask = DEBUG_INIT;   277    278 }   279    280 /*   281  * New interface provided by krb5's com_err library   282  */   283 errcode_t add_error_table(const struct error_table * et)   284 {   285 	struct et_list *el;   286    287 	if (!(el = (struct et_list *) malloc(sizeof(struct et_list))))   288 		return ENOMEM;   289    290 	if (et_list_lock() != 0) {   291 		free(el);   292 		return errno;   293 	}   294    295 	el->table = et;   296 	el->next = _et_dynamic_list;   297 	_et_dynamic_list = el;   298    299 	init_debug();   300 	if (debug_mask & DEBUG_ADDREMOVE)   301 		fprintf(debug_f, "add_error_table: %s (0x%p)\n",   302 			error_table_name(et->base),   303 			(const void *) et);   304    305 	et_list_unlock();   306 	return 0;   307 }   308    309 /*   310  * New interface provided by krb5's com_err library   311  */   312 errcode_t remove_error_table(const struct error_table * et)   313 {   314 	struct et_list *el;   315 	struct et_list *el2 = 0;   316    317 	if (et_list_lock() != 0)   318 		return ENOENT;   319    320 	el = _et_dynamic_list;   321 	init_debug();   322 	while (el) {   323 		if (el->table->base == et->base) {   324 			if (el2)	/* Not the beginning of the list */   325 				el2->next = el->next;   326 			else   327 				_et_dynamic_list = el->next;   328 			(void) free(el);   329 			if (debug_mask & DEBUG_ADDREMOVE)   330 				fprintf(debug_f,   331 					"remove_error_table: %s (0x%p)\n",   332 					error_table_name(et->base),   333 					(const void *) et);   334 			et_list_unlock();   335 			return 0;   336 		}   337 		el2 = el;   338 		el = el->next;   339 	}   340 	if (debug_mask & DEBUG_ADDREMOVE)   341 		fprintf(debug_f, "remove_error_table FAILED: %s (0x%p)\n",   342 			error_table_name(et->base),   343 			(const void *) et);   344 	et_list_unlock();   345 	return ENOENT;   346 }   347    348 /*   349  * Variant of the interface provided by Heimdal's com_err library   350  */   351 void   352 add_to_error_table(struct et_list *new_table)   353 {   354 	add_error_table(new_table->table);   355 }