1/* ========================================================================== 2 * errno.c.m4 - Lua Continuation Queues 3 * -------------------------------------------------------------------------- 4 * Copyright (c) 2012, 2015 William Ahern 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sublicense, and/or sell copies of the Software, and to permit 11 * persons to whom the Software is furnished to do so, subject to the 12 * following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 20 * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 * USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * ========================================================================== 25 */ 26#include "config.h" 27 28#include <string.h> /* memcpy(3) strcmp(3) strerror_r(3) strnlen(3) */ 29#include <errno.h> 30 31#include <lua.h> 32#include <lauxlib.h> 33 34#include "lib/dns.h" 35#include "lib/socket.h" 36 37#include "cqueues.h" 38 39 40#ifndef STRERROR_R_CHAR_P 41#define STRERROR_R_CHAR_P ((GLIBC_PREREQ(0,0) || UCLIBC_PREREQ(0,0,0)) && (_GNU_SOURCE || !(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600))) 42#endif 43 44cqs_error_t cqs_strerror_r(cqs_error_t error, char *dst, size_t lim) { 45 const char *src; 46 47 if (error >= DNS_EBASE && error < DNS_ELAST) { 48 src = dns_strerror(error); 49 } else if (error >= SO_EBASE && error < SO_ELAST) { 50 src = so_strerror(error); 51 } else { 52#if STRERROR_R_CHAR_P 53 if (!(src = strerror_r(error, dst, lim))) 54 return EINVAL; 55#else 56 /* glibc between 2.3.4 and 2.13 returns -1 on error */ 57 if (-1 == (error = strerror_r(error, dst, lim))) 58 return errno; 59 60 return error; 61#endif 62 } 63 64 if (src != dst && lim > 0) { 65 size_t n = strnlen(src, lim - 1); 66 memcpy(dst, src, n); 67 dst[n] = '\0'; 68 } 69 70 return 0; 71} /* cqs_strerror_r() */ 72 73 74const char *(cqs_strerror)(int error, void *dst, size_t lim) { 75 char *p, *pe, *unknown; 76 char e10[((sizeof error * CHAR_BIT) / 3) + 1], *ep; 77 int n; 78 79 if (!lim) 80 return dst; 81 82 if (0 == cqs_strerror_r(error, dst, lim) && *(char *)dst) 83 return dst; 84 85 p = dst; 86 pe = p + lim; 87 88 unknown = "Unknown error: "; 89 while (*unknown && p < pe) 90 *p++ = *unknown++; 91 92 if (error < 0 && p < pe) 93 *p++ = '-'; 94 95 /* translate integer to string in LSB order */ 96 for (ep = e10, n = error; n; ep++, n /= 10) 97 *ep = "0123456789"[abs(n % 10)]; 98 if (ep == e10) 99 *ep++ = '0'; 100 101 /* copy string, flipping from LSB to MSB */ 102 while (ep > e10 && p < pe) 103 *p++ = *--ep; 104 105 p[-1] = '\0'; 106 107 return dst; 108} /* cqs_strerror() */ 109 110 111static const struct { 112 const char *name; 113 int value; 114} errlist[] = { 115changequote(<<<,>>>)dnl 116ifdef(<<<esyscmd>>>,<<<esyscmd>>>,<<<syscmd>>>)(<<< 117../mk/errno.ls | awk '{ print "#ifdef "$1"\n\t{ \""$1"\", "$1" },\n#endif" }' 118>>>)dnl 119}; 120 121 122static int le_strerror(lua_State *L) { 123 lua_pushstring(L, cqs_strerror(luaL_checkint(L, 1))); 124 125 return 1; 126} /* le_strerror() */ 127 128 129static const luaL_Reg le_globals[] = { 130 { "strerror", &le_strerror }, 131 { NULL, NULL } 132}; 133 134 135int luaopen__cqueues_errno(lua_State *L) { 136 unsigned i; 137 138 luaL_newlib(L, le_globals); 139 140 for (i = 0; i < sizeof errlist / sizeof *errlist; i++) { 141 lua_pushstring(L, errlist[i].name); 142 lua_pushinteger(L, errlist[i].value); 143 lua_settable(L, -3); 144 145#if EAGAIN == EWOULDBLOCK 146 if (!strcmp(errlist[i].name, "EWOULDBLOCK")) 147 continue; 148#endif 149 150 lua_pushinteger(L, errlist[i].value); 151 lua_pushstring(L, errlist[i].name); 152 lua_settable(L, -3); 153 } 154 155 return 1; 156} /* luaopen__cqueues_errno() */ 157