diff --git a/lprocess.c b/lprocess.c index f862bb9..2b56c38 100644 --- a/lprocess.c +++ b/lprocess.c @@ -9,9 +9,6 @@ #include #include #include -#ifdef __OpenBSD__ -# include -#endif #include #include @@ -22,9 +19,61 @@ #define PID_MAX 8 /* rounded to the nearest even number */ #define PROCESS_MAX 256 -/* signals and signal count */ -#define SIGC 36 -static const char *signals[] = { +/* signals */ +static const int signals[] = { + SIGHUP, + SIGINT, + SIGQUIT, + SIGILL, + SIGTRAP, + SIGABRT, + SIGIOT, + SIGFPE, + SIGKILL, + SIGBUS, + SIGSEGV, + SIGSYS, + SIGPIPE, + SIGALRM, + SIGTERM, + SIGURG, + SIGSTOP, + SIGTSTP, + SIGCONT, + SIGCHLD, + SIGTTIN, + SIGTTOU, +#ifdef SIGSTKFL + SIGSTKFL, +#endif + SIGIO, + SIGXCPU, + SIGXFSZ, +#ifdef SIGVTALR + SIGVTALR, +#elif defined(SIGVTALRM) + SIGVTALRM, +#endif + SIGPROF, +#ifdef SIGWINC + SIGWINC, +#elif defined(SIGWINCH) + SIGWINCH, +#endif +#ifdef SIGINFO + SIGINFO, +#endif +#ifdef SIGPOLL + SIGPOLL, +#endif +#ifdef SIGPWR + SIGPWR, +#endif + SIGUSR1, + SIGUSR2, + -1 /* end */ +}; +static const char *sigstrs[] = { [SIGHUP] = "SIGHUP", [SIGINT] = "SIGINT", [SIGQUIT] = "SIGQUIT", @@ -91,9 +140,13 @@ process_pid(lua_State *L) } /*** - * Returns the PID (process ID) of the given process. + * Returns the PID (process ID) of the given process, + * or nil if the process could not be found. * - * Returns nil if the process was not found. + * Depends on the nonportable userspace utility `pgrep`. + * Can be found in the procps-ng package on Linux usually + * included in most distributions, or as part of the base + * system on OpenBSD, NetBSD and FreeBSD. * * @function pidof * @usage process.pidof("init") @@ -102,61 +155,89 @@ process_pid(lua_State *L) static int process_pidof(lua_State *L) { - const char *process; /* parameter 1 (string) */ - char *command; /* pidof command buffer */ - char *buffer; /* pidof reading buffer */ - int pexit; /* pidof exit code */ - long pid; /* pid to return to Lua */ - size_t pidmax; /* length passed to getline */ - ssize_t ret; /* getline return value */ - FILE *p; /* pidof stream */ + const char *process; /* parameter 1 (string) */ + char command[PROCESS_MAX]; /* pgrep command buffer */ + char *buffer; /* pgrep reading buffer */ + int pexit; /* pgrep exit code */ + long pid; /* pid to return to Lua */ + size_t pidmax; /* length passed to getline */ + ssize_t ret; /* getline return value */ + FILE *p; /* pgrep reading stream */ process = luaL_checkstring(L, 1); - command = calloc(1, PROCESS_MAX * sizeof(char *)); - /* construct pidof command */ - strlcat(command, "pidof -s '", (size_t)PROCESS_MAX); - strlcat(command, process, (size_t)PROCESS_MAX); - strlcat(command, "'", (size_t)PROCESS_MAX); + /* construct pgrep command */ + memset(command, 0, PROCESS_MAX * sizeof(char)); + strlcat(command, "pgrep '", PROCESS_MAX); + strlcat(command, process, PROCESS_MAX); + strlcat(command, "' | sed 1q", PROCESS_MAX); p = popen(command, "r"); buffer = malloc(PID_MAX * sizeof(char *)); - pidmax = (size_t)PID_MAX; + pidmax = PID_MAX; - /* read line from pidof */ + /* read line from pgrep */ ret = getline(&buffer, &pidmax, p); pexit = pclose(p); - if (ret == -1 || pexit != 0) { /* did getline or pidof fail? */ - luaL_pushfail(L); + if (ret == -1 || pexit != 0) { /* did getline or pgrep fail? */ + lua_pushnil(L); return 1; } /* convert it to an integer and push */ pid = strtol(buffer, NULL, 10); lua_pushinteger(L, pid); - free(command); free(buffer); return 1; } -static int -strtosig(const char *sig) -{ - int i; +#define REG_SIGC "callisto!process:sigc" - for (i = 1; i <= SIGC; i++) { - if (strcmp(signals[i], sig) == 0) - return i; /* valid signal found */ +static int +initsignals(lua_State *L) +{ + int sigc; + + /* get the registry entry containing the sig count */ + lua_getfield(L, LUA_REGISTRYINDEX, REG_SIGC); + /* if the registry entry isn't a number greater than 0... */ + if (!lua_isnoneornil(L, -1)) { + if (lua_type(L, -1) != LUA_TNUMBER || lua_tointeger(L, -1) <= 0) { + luaL_error(L, "registry index for signal count is invalid"); + return 0; + } + } + + sigc = 0; + while (signals[sigc] != -1) + sigc++; + + lua_pushinteger(L, sigc + 1); + lua_setfield(L, LUA_REGISTRYINDEX, REG_SIGC); + + return 1; +} + +static int +strtosig(const char *sig, int sigc) +{ + int i, j; + + j = 0; + for (i = signals[j]; i < sigc; j++) { + i = signals[j]; + if (strcasecmp(sigstrs[i], sig) == 0) + return i; /* signal found */ } return -1; /* invalid signal */ } /*** * Returns the given signal as an integer. - * This function may return different values - * across different operating systems, as - * signal constants vary across different Unixes. + * + * This signal value is a platform-dependent value; + * do not attempt to use it portably across different platforms. * * @function signum * @usage local sigkill = process.signum("SIGKILL") @@ -165,26 +246,43 @@ strtosig(const char *sig) static int process_signum(lua_State *L) { - int sig; + char *sigstr; + int sig, sigc; - if ((sig = strtosig(luaL_checkstring(L, 1))) != -1) /* valid signal? */ + sigstr = strdup(luaL_checkstring(L, 1)); + + if (!initsignals(L)) + return 0; + + lua_getfield(L, LUA_REGISTRYINDEX, REG_SIGC); + sigc = lua_tointeger(L, -1); + sig = strtosig(sigstr, sigc); + free(sigstr); + + if (sig != -1) { /* valid signal? */ lua_pushinteger(L, sig); /* return signal */ - else - return lfailm(L, "no such signal"); + return 1; + } - return 1; + return luaL_error(L, "no such signal"); } static int sigsend(lua_State *L, pid_t pid, const char *sigstr) { - int ret, sig; + int ret, sig, sigc; - sig = strtosig(sigstr); + if (!initsignals(L)) + return 0; + + lua_getfield(L, LUA_REGISTRYINDEX, REG_SIGC); + sigc = lua_tointeger(L, -1); + + sig = strtosig(sigstr, sigc); if (sig != -1) /* valid signal? */ ret = kill(pid, sig); else - return lfailm(L, "no such signal"); + return luaL_error(L, "no such signal"); if (ret == 0) { /* check for success */ lua_pushboolean(L, 1); @@ -194,13 +292,13 @@ sigsend(lua_State *L, pid_t pid, const char *sigstr) return lfail(L); } +#undef REG_SIGC + /*** - * Sends the given signal to the - * process with the given PID. + * Sends the given signal to the process with the given PID. * - * The *signal* parameter is a string - * containing the name of the desired - * signal to send.. + * The *signal* parameter is a string containing the name + * of the desired signal to send (e.g. SIGKILL). * * @function send * @usage