X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lib%2Fet%2Ferror_message.c;h=1b08c16600c3fb70750d2cb79b3286b8ebc7ae2f;hb=bf0449b1a6547a566975cb32c18a2ba5972deace;hp=90d63c417f1a6ada35bc568b48314f5f1fd3564d;hpb=d51b819e549d635c5b0293427fba59d097ad8df2;p=tools%2Fe2fsprogs.git diff --git a/lib/et/error_message.c b/lib/et/error_message.c index 90d63c4..1b08c16 100644 --- a/lib/et/error_message.c +++ b/lib/et/error_message.c @@ -20,15 +20,82 @@ #include #include #include +#ifdef HAVE_SYS_PRCTL_H +#include +#else +#define PR_GET_DUMPABLE 3 +#endif +#if (!defined(HAVE_PRCTL) && defined(linux)) +#include +#endif +#ifdef HAVE_SEMAPHORE_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#include +#if HAVE_SYS_TYPES_H +#include +#endif #include "com_err.h" #include "error_table.h" #include "internal.h" -static char buffer[25]; +#ifdef TLS +#define THREAD_LOCAL static TLS +#else +#define THREAD_LOCAL static +#endif + +THREAD_LOCAL char buffer[25]; struct et_list * _et_list = (struct et_list *) NULL; struct et_list * _et_dynamic_list = (struct et_list *) NULL; +#ifdef __GNUC__ +#define COMERR_ATTR(x) __attribute__(x) +#else +#define COMERR_ATTR(x) +#endif + +#ifdef HAVE_SEM_INIT +static sem_t _et_lock; +static int _et_lock_initialized; + +static void COMERR_ATTR((constructor)) setup_et_lock(void) +{ + sem_init(&_et_lock, 0, 1); + _et_lock_initialized = 1; +} + +static void COMERR_ATTR((destructor)) fini_et_lock(void) +{ + sem_destroy(&_et_lock); + _et_lock_initialized = 0; +} +#endif + + +int et_list_lock(void) +{ +#ifdef HAVE_SEM_INIT + if (!_et_lock_initialized) + setup_et_lock(); + return sem_wait(&_et_lock); +#else + return 0; +#endif +} + +int et_list_unlock(void) +{ +#ifdef HAVE_SEM_INIT + if (_et_lock_initialized) + return sem_post(&_et_lock); +#endif + return 0; +} const char * error_message (errcode_t code) { @@ -54,22 +121,32 @@ const char * error_message (errcode_t code) goto oops; #endif } + et_list_lock(); for (et = _et_list; et; et = et->next) { - if (et->table->base == table_num) { + if ((et->table->base & 0xffffffL) == (table_num & 0xffffffL)) { /* This is the right table */ - if (et->table->n_msgs <= offset) - goto oops; - return(et->table->msgs[offset]); + if (et->table->n_msgs <= offset) { + break; + } else { + const char *msg = et->table->msgs[offset]; + et_list_unlock(); + return msg; + } } } for (et = _et_dynamic_list; et; et = et->next) { - if (et->table->base == table_num) { + if ((et->table->base & 0xffffffL) == (table_num & 0xffffffL)) { /* This is the right table */ - if (et->table->n_msgs <= offset) - goto oops; - return(et->table->msgs[offset]); + if (et->table->n_msgs <= offset) { + break; + } else { + const char *msg = et->table->msgs[offset]; + et_list_unlock(); + return msg; + } } } + et_list_unlock(); oops: strcpy (buffer, "Unknown code "); if (table_num) { @@ -93,6 +170,73 @@ oops: } /* + * This routine will only return a value if the we are not running as + * a privileged process. + */ +static char *safe_getenv(const char *arg) +{ + if ((getuid() != geteuid()) || (getgid() != getegid())) + return NULL; +#if HAVE_PRCTL + if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) + return NULL; +#else +#if (defined(linux) && defined(SYS_prctl)) + if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) + return NULL; +#endif +#endif + +#ifdef HAVE___SECURE_GETENV + return __secure_getenv(arg); +#else + return getenv(arg); +#endif +} + +#define DEBUG_INIT 0x8000 +#define DEBUG_ADDREMOVE 0x0001 + +static int debug_mask = 0; +static FILE *debug_f = 0; + +static void init_debug(void) +{ + char *dstr, *fn, *tmp; + int fd, flags; + + if (debug_mask & DEBUG_INIT) + return; + + dstr = getenv("COMERR_DEBUG"); + if (dstr) { + debug_mask = strtoul(dstr, &tmp, 0); + if (*tmp || errno) + debug_mask = 0; + } + + debug_mask |= DEBUG_INIT; + if (debug_mask == DEBUG_INIT) + return; + + fn = safe_getenv("COMERR_DEBUG_FILE"); + if (fn) + debug_f = fopen(fn, "a"); + if (!debug_f) + debug_f = fopen("/dev/tty", "a"); + if (debug_f) { + fd = fileno(debug_f); + if (fd >= 0) { + flags = fcntl(fd, F_GETFD); + if (flags >= 0) + fcntl(fd, F_SETFD, flags | FD_CLOEXEC); + } + } else + debug_mask = DEBUG_INIT; + +} + +/* * New interface provided by krb5's com_err library */ errcode_t add_error_table(const struct error_table * et) @@ -102,10 +246,22 @@ errcode_t add_error_table(const struct error_table * et) if (!(el = (struct et_list *) malloc(sizeof(struct et_list)))) return ENOMEM; + if (et_list_lock() != 0) { + free(el); + return errno; + } + el->table = et; el->next = _et_dynamic_list; _et_dynamic_list = el; + init_debug(); + if (debug_mask & DEBUG_ADDREMOVE) + fprintf(debug_f, "add_error_table: %s (0x%p)\n", + error_table_name(et->base), + (const void *) et); + + et_list_unlock(); return 0; } @@ -114,9 +270,14 @@ errcode_t add_error_table(const struct error_table * et) */ errcode_t remove_error_table(const struct error_table * et) { - struct et_list *el = _et_dynamic_list; + struct et_list *el; struct et_list *el2 = 0; + if (et_list_lock() != 0) + return ENOENT; + + el = _et_dynamic_list; + init_debug(); while (el) { if (el->table->base == et->base) { if (el2) /* Not the beginning of the list */ @@ -124,11 +285,22 @@ errcode_t remove_error_table(const struct error_table * et) else _et_dynamic_list = el->next; (void) free(el); + if (debug_mask & DEBUG_ADDREMOVE) + fprintf(debug_f, + "remove_error_table: %s (0x%p)\n", + error_table_name(et->base), + (const void *) et); + et_list_unlock(); return 0; } el2 = el; el = el->next; } + if (debug_mask & DEBUG_ADDREMOVE) + fprintf(debug_f, "remove_error_table FAILED: %s (0x%p)\n", + error_table_name(et->base), + (const void *) et); + et_list_unlock(); return ENOENT; }