L4Re/departure

libext2fs/lib/libet/error_message.c

617:2733e5770ee9
9 months ago Paul Boddie Made the run command wait for completion, introducing the spawn command to run programs in the background. Introduced conveniences for waiting for the last job to be initiated and for piping from the last job, also subscribing to signals from pipe-supplying jobs so that they may be transparently removed from the job list upon completion. Augmented the job listing with the "+" notation familiar from Unix. Prevented new jobs from being started when no job slots are available.
     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 }