xref: /freebsd/libexec/flua/modules/lposix.c (revision f35ccf46c7c6cb7d26994ec5dc5926ea53be0116)
1506f3640SKyle Evans /*-
2c2caf3b3SKyle Evans  * Copyright (c) 2019, 2023 Kyle Evans <kevans@FreeBSD.org>
3506f3640SKyle Evans  *
4c2caf3b3SKyle Evans  * SPDX-License-Identifier: BSD-2-Clause
5506f3640SKyle Evans  */
6506f3640SKyle Evans 
7405e3338SEd Maste #include <sys/stat.h>
81726db7aSMark Johnston #include <sys/utsname.h>
9c2caf3b3SKyle Evans #include <sys/wait.h>
10405e3338SEd Maste 
11405e3338SEd Maste #include <errno.h>
12*f35ccf46SStefan Eßer #include <fnmatch.h>
13a1ab15abSBaptiste Daroussin #include <grp.h>
14c2caf3b3SKyle Evans #include <libgen.h>
15a1ab15abSBaptiste Daroussin #include <pwd.h>
16c2caf3b3SKyle Evans #include <stdlib.h>
17405e3338SEd Maste #include <string.h>
18506f3640SKyle Evans #include <unistd.h>
19506f3640SKyle Evans 
20506f3640SKyle Evans #include <lua.h>
21506f3640SKyle Evans #include "lauxlib.h"
22506f3640SKyle Evans #include "lposix.h"
23506f3640SKyle Evans 
24506f3640SKyle Evans /*
25506f3640SKyle Evans  * Minimal implementation of luaposix needed for internal FreeBSD bits.
26506f3640SKyle Evans  */
27c2caf3b3SKyle Evans static int
28c2caf3b3SKyle Evans lua__exit(lua_State *L)
29c2caf3b3SKyle Evans {
30c2caf3b3SKyle Evans 	int code, narg;
31c2caf3b3SKyle Evans 
32c2caf3b3SKyle Evans 	narg = lua_gettop(L);
33c2caf3b3SKyle Evans 	luaL_argcheck(L, narg == 1, 1, "_exit takes exactly one argument");
34c2caf3b3SKyle Evans 
35c2caf3b3SKyle Evans 	code = luaL_checkinteger(L, 1);
36c2caf3b3SKyle Evans 	_exit(code);
37c2caf3b3SKyle Evans }
38c2caf3b3SKyle Evans 
39c2caf3b3SKyle Evans static int
40c2caf3b3SKyle Evans lua_basename(lua_State *L)
41c2caf3b3SKyle Evans {
42c2caf3b3SKyle Evans 	char *inpath, *outpath;
43c2caf3b3SKyle Evans 	int narg;
44c2caf3b3SKyle Evans 
45c2caf3b3SKyle Evans 	narg = lua_gettop(L);
46c2caf3b3SKyle Evans 	luaL_argcheck(L, narg > 0, 1, "at least one argument required");
47c2caf3b3SKyle Evans 	inpath = strdup(luaL_checkstring(L, 1));
48c2caf3b3SKyle Evans 	if (inpath == NULL) {
49c2caf3b3SKyle Evans 		lua_pushnil(L);
50c2caf3b3SKyle Evans 		lua_pushstring(L, strerror(ENOMEM));
51c2caf3b3SKyle Evans 		lua_pushinteger(L, ENOMEM);
52c2caf3b3SKyle Evans 		return (3);
53c2caf3b3SKyle Evans 	}
54c2caf3b3SKyle Evans 
55c2caf3b3SKyle Evans 	outpath = basename(inpath);
56c2caf3b3SKyle Evans 	lua_pushstring(L, outpath);
57c2caf3b3SKyle Evans 	free(inpath);
58c2caf3b3SKyle Evans 	return (1);
59c2caf3b3SKyle Evans }
60506f3640SKyle Evans 
61506f3640SKyle Evans static int
62405e3338SEd Maste lua_chmod(lua_State *L)
63405e3338SEd Maste {
64405e3338SEd Maste 	int n;
65405e3338SEd Maste 	const char *path;
66405e3338SEd Maste 	mode_t mode;
67405e3338SEd Maste 
68405e3338SEd Maste 	n = lua_gettop(L);
69405e3338SEd Maste 	luaL_argcheck(L, n == 2, n > 2 ? 3 : n,
70405e3338SEd Maste 	    "chmod takes exactly two arguments");
71405e3338SEd Maste 	path = luaL_checkstring(L, 1);
72405e3338SEd Maste 	mode = (mode_t)luaL_checkinteger(L, 2);
73405e3338SEd Maste 	if (chmod(path, mode) == -1) {
74405e3338SEd Maste 		lua_pushnil(L);
75405e3338SEd Maste 		lua_pushstring(L, strerror(errno));
76405e3338SEd Maste 		lua_pushinteger(L, errno);
77c2caf3b3SKyle Evans 		return (3);
78405e3338SEd Maste 	}
79405e3338SEd Maste 	lua_pushinteger(L, 0);
80c2caf3b3SKyle Evans 	return (1);
81405e3338SEd Maste }
82405e3338SEd Maste 
83405e3338SEd Maste static int
84a1ab15abSBaptiste Daroussin lua_chown(lua_State *L)
85a1ab15abSBaptiste Daroussin {
86a1ab15abSBaptiste Daroussin 	int n;
87a1ab15abSBaptiste Daroussin 	const char *path;
88a1ab15abSBaptiste Daroussin 	uid_t owner = (uid_t) -1;
89a1ab15abSBaptiste Daroussin 	gid_t group = (gid_t) -1;
90a1ab15abSBaptiste Daroussin 
91a1ab15abSBaptiste Daroussin 	n = lua_gettop(L);
92a1ab15abSBaptiste Daroussin 	luaL_argcheck(L, n > 1, n,
93a1ab15abSBaptiste Daroussin 	   "chown takes at least two arguments");
94a1ab15abSBaptiste Daroussin 	path = luaL_checkstring(L, 1);
95a1ab15abSBaptiste Daroussin 	if (lua_isinteger(L, 2))
96a1ab15abSBaptiste Daroussin 		owner = (uid_t) lua_tointeger(L, 2);
97a1ab15abSBaptiste Daroussin 	else if (lua_isstring(L, 2)) {
98a1ab15abSBaptiste Daroussin 		struct passwd *p = getpwnam(lua_tostring(L, 2));
99a1ab15abSBaptiste Daroussin 		if (p != NULL)
100a1ab15abSBaptiste Daroussin 			owner = p->pw_uid;
101a1ab15abSBaptiste Daroussin 		else
102a1ab15abSBaptiste Daroussin 			return (luaL_argerror(L, 2,
103a1ab15abSBaptiste Daroussin 			    lua_pushfstring(L, "unknown user %s",
104a1ab15abSBaptiste Daroussin 			    lua_tostring(L, 2))));
105a1ab15abSBaptiste Daroussin 	} else if (!lua_isnoneornil(L, 2)) {
106a1ab15abSBaptiste Daroussin 		const char *type = luaL_typename(L, 2);
107a1ab15abSBaptiste Daroussin 		return (luaL_argerror(L, 2,
108a1ab15abSBaptiste Daroussin 		    lua_pushfstring(L, "integer or string expected, got %s",
109a1ab15abSBaptiste Daroussin 		    type)));
110a1ab15abSBaptiste Daroussin 	}
111a1ab15abSBaptiste Daroussin 
112a1ab15abSBaptiste Daroussin 	if (lua_isinteger(L, 3))
113a1ab15abSBaptiste Daroussin 		group = (gid_t) lua_tointeger(L, 3);
114a1ab15abSBaptiste Daroussin 	else if (lua_isstring(L, 3)) {
115a1ab15abSBaptiste Daroussin 		struct group *g = getgrnam(lua_tostring(L, 3));
116a1ab15abSBaptiste Daroussin 		if (g != NULL)
117a1ab15abSBaptiste Daroussin 			group = g->gr_gid;
118a1ab15abSBaptiste Daroussin 		else
119a1ab15abSBaptiste Daroussin 			return (luaL_argerror(L, 3,
120280f11f1SBaptiste Daroussin 			    lua_pushfstring(L, "unknown group %s",
121a1ab15abSBaptiste Daroussin 			    lua_tostring(L, 3))));
122a1ab15abSBaptiste Daroussin 	} else if (!lua_isnoneornil(L, 3)) {
123a1ab15abSBaptiste Daroussin 		const char *type = luaL_typename(L, 3);
124a1ab15abSBaptiste Daroussin 		return (luaL_argerror(L, 3,
125a1ab15abSBaptiste Daroussin 		    lua_pushfstring(L, "integer or string expected, got %s",
126a1ab15abSBaptiste Daroussin 		    type)));
127a1ab15abSBaptiste Daroussin 	}
128a1ab15abSBaptiste Daroussin 
129a1ab15abSBaptiste Daroussin 	if (chown(path, owner, group) == -1) {
130a1ab15abSBaptiste Daroussin 		lua_pushnil(L);
131a1ab15abSBaptiste Daroussin 		lua_pushstring(L, strerror(errno));
132a1ab15abSBaptiste Daroussin 		lua_pushinteger(L, errno);
133a1ab15abSBaptiste Daroussin 		return (3);
134a1ab15abSBaptiste Daroussin 	}
135a1ab15abSBaptiste Daroussin 	lua_pushinteger(L, 0);
136a1ab15abSBaptiste Daroussin 	return (1);
137a1ab15abSBaptiste Daroussin }
138a1ab15abSBaptiste Daroussin 
139a1ab15abSBaptiste Daroussin static int
140c2caf3b3SKyle Evans lua_pclose(lua_State *L)
141506f3640SKyle Evans {
142c2caf3b3SKyle Evans 	int error, fd, n;
143506f3640SKyle Evans 
144506f3640SKyle Evans 	n = lua_gettop(L);
145c2caf3b3SKyle Evans 	luaL_argcheck(L, n == 1, 1,
146c2caf3b3SKyle Evans 	    "close takes exactly one argument (fd)");
147c2caf3b3SKyle Evans 
148c2caf3b3SKyle Evans 	fd = luaL_checkinteger(L, 1);
149c2caf3b3SKyle Evans 	if (fd < 0) {
150c2caf3b3SKyle Evans 		error = EBADF;
151c2caf3b3SKyle Evans 		goto err;
152c2caf3b3SKyle Evans 	}
153c2caf3b3SKyle Evans 
154c2caf3b3SKyle Evans 	if (close(fd) == 0) {
155c2caf3b3SKyle Evans 		lua_pushinteger(L, 0);
156c2caf3b3SKyle Evans 		return (1);
157c2caf3b3SKyle Evans 	}
158c2caf3b3SKyle Evans 
159c2caf3b3SKyle Evans 	error = errno;
160c2caf3b3SKyle Evans err:
161c2caf3b3SKyle Evans 	lua_pushnil(L);
162c2caf3b3SKyle Evans 	lua_pushstring(L, strerror(error));
163c2caf3b3SKyle Evans 	lua_pushinteger(L, error);
164c2caf3b3SKyle Evans 	return (3);
165c2caf3b3SKyle Evans 
166506f3640SKyle Evans }
167506f3640SKyle Evans 
1681726db7aSMark Johnston static int
169*f35ccf46SStefan Eßer lua_fnmatch(lua_State *L)
170*f35ccf46SStefan Eßer {
171*f35ccf46SStefan Eßer 	const char *pattern, *string;
172*f35ccf46SStefan Eßer 	int flags, n;
173*f35ccf46SStefan Eßer 
174*f35ccf46SStefan Eßer 	n = lua_gettop(L);
175*f35ccf46SStefan Eßer 	luaL_argcheck(L, n == 2 || n == 3, 4, "need 2 or 3 arguments");
176*f35ccf46SStefan Eßer 
177*f35ccf46SStefan Eßer 	pattern = luaL_checkstring(L, 1);
178*f35ccf46SStefan Eßer 	string = luaL_checkstring(L, 2);
179*f35ccf46SStefan Eßer 	flags = luaL_optinteger(L, 3, 0);
180*f35ccf46SStefan Eßer 	lua_pushinteger(L, fnmatch(pattern, string, flags));
181*f35ccf46SStefan Eßer 
182*f35ccf46SStefan Eßer 	return (1);
183*f35ccf46SStefan Eßer }
184*f35ccf46SStefan Eßer 
185*f35ccf46SStefan Eßer static int
1861726db7aSMark Johnston lua_uname(lua_State *L)
1871726db7aSMark Johnston {
1881726db7aSMark Johnston 	struct utsname name;
1891726db7aSMark Johnston 	int error, n;
1901726db7aSMark Johnston 
1911726db7aSMark Johnston 	n = lua_gettop(L);
1921726db7aSMark Johnston 	luaL_argcheck(L, n == 0, 1, "too many arguments");
1931726db7aSMark Johnston 
1941726db7aSMark Johnston 	error = uname(&name);
1951726db7aSMark Johnston 	if (error != 0) {
1961726db7aSMark Johnston 		error = errno;
1971726db7aSMark Johnston 		lua_pushnil(L);
1981726db7aSMark Johnston 		lua_pushstring(L, strerror(error));
1991726db7aSMark Johnston 		lua_pushinteger(L, error);
2001726db7aSMark Johnston 		return (3);
2011726db7aSMark Johnston 	}
2021726db7aSMark Johnston 
2031726db7aSMark Johnston 	lua_newtable(L);
2041726db7aSMark Johnston #define	setkv(f) do {			\
2051726db7aSMark Johnston 	lua_pushstring(L, name.f);	\
2061726db7aSMark Johnston 	lua_setfield(L, -2, #f);	\
2071726db7aSMark Johnston } while (0)
2081726db7aSMark Johnston 	setkv(sysname);
2091726db7aSMark Johnston 	setkv(nodename);
2101726db7aSMark Johnston 	setkv(release);
2111726db7aSMark Johnston 	setkv(version);
2121726db7aSMark Johnston 	setkv(machine);
2131726db7aSMark Johnston #undef setkv
2141726db7aSMark Johnston 
2151726db7aSMark Johnston 	return (1);
2161726db7aSMark Johnston }
2171726db7aSMark Johnston 
218c2caf3b3SKyle Evans static int
219c2caf3b3SKyle Evans lua_dirname(lua_State *L)
220c2caf3b3SKyle Evans {
221c2caf3b3SKyle Evans 	char *inpath, *outpath;
222c2caf3b3SKyle Evans 	int narg;
223c2caf3b3SKyle Evans 
224c2caf3b3SKyle Evans 	narg = lua_gettop(L);
225c2caf3b3SKyle Evans 	luaL_argcheck(L, narg > 0, 1,
226c2caf3b3SKyle Evans 	    "dirname takes at least one argument (path)");
227c2caf3b3SKyle Evans 	inpath = strdup(luaL_checkstring(L, 1));
228c2caf3b3SKyle Evans 	if (inpath == NULL) {
229c2caf3b3SKyle Evans 		lua_pushnil(L);
230c2caf3b3SKyle Evans 		lua_pushstring(L, strerror(ENOMEM));
231c2caf3b3SKyle Evans 		lua_pushinteger(L, ENOMEM);
232c2caf3b3SKyle Evans 		return (3);
233c2caf3b3SKyle Evans 	}
234c2caf3b3SKyle Evans 
235c2caf3b3SKyle Evans 	outpath = dirname(inpath);
236c2caf3b3SKyle Evans 	lua_pushstring(L, outpath);
237c2caf3b3SKyle Evans 	free(inpath);
238c2caf3b3SKyle Evans 	return (1);
239c2caf3b3SKyle Evans }
240c2caf3b3SKyle Evans 
241c2caf3b3SKyle Evans static int
242c2caf3b3SKyle Evans lua_fork(lua_State *L)
243c2caf3b3SKyle Evans {
244c2caf3b3SKyle Evans 	pid_t pid;
245c2caf3b3SKyle Evans 	int narg;
246c2caf3b3SKyle Evans 
247c2caf3b3SKyle Evans 	narg = lua_gettop(L);
248c2caf3b3SKyle Evans 	luaL_argcheck(L, narg == 0, 1, "too many arguments");
249c2caf3b3SKyle Evans 
250c2caf3b3SKyle Evans 	pid = fork();
251c2caf3b3SKyle Evans 	if (pid < 0) {
252c2caf3b3SKyle Evans 		lua_pushnil(L);
253c2caf3b3SKyle Evans 		lua_pushstring(L, strerror(errno));
254c2caf3b3SKyle Evans 		lua_pushinteger(L, errno);
255c2caf3b3SKyle Evans 		return (3);
256c2caf3b3SKyle Evans 	}
257c2caf3b3SKyle Evans 
258c2caf3b3SKyle Evans 	lua_pushinteger(L, pid);
259c2caf3b3SKyle Evans 	return (1);
260c2caf3b3SKyle Evans }
261c2caf3b3SKyle Evans 
262c2caf3b3SKyle Evans static int
263c2caf3b3SKyle Evans lua_getpid(lua_State *L)
264c2caf3b3SKyle Evans {
265c2caf3b3SKyle Evans 	int narg;
266c2caf3b3SKyle Evans 
267c2caf3b3SKyle Evans 	narg = lua_gettop(L);
268c2caf3b3SKyle Evans 	luaL_argcheck(L, narg == 0, 1, "too many arguments");
269c2caf3b3SKyle Evans 	lua_pushinteger(L, getpid());
270c2caf3b3SKyle Evans 	return (1);
271c2caf3b3SKyle Evans }
272c2caf3b3SKyle Evans 
273c2caf3b3SKyle Evans static int
274c2caf3b3SKyle Evans lua_pipe(lua_State *L)
275c2caf3b3SKyle Evans {
276c2caf3b3SKyle Evans 	int error, fd[2], narg;
277c2caf3b3SKyle Evans 
278c2caf3b3SKyle Evans 	narg = lua_gettop(L);
279c2caf3b3SKyle Evans 	luaL_argcheck(L, narg == 0, 1, "too many arguments");
280c2caf3b3SKyle Evans 
281c2caf3b3SKyle Evans 	error = pipe(fd);
282c2caf3b3SKyle Evans 	if (error != 0) {
283c2caf3b3SKyle Evans 		lua_pushnil(L);
284c2caf3b3SKyle Evans 		lua_pushstring(L, strerror(errno));
285c2caf3b3SKyle Evans 		lua_pushinteger(L, errno);
286c2caf3b3SKyle Evans 		return (1);
287c2caf3b3SKyle Evans 	}
288c2caf3b3SKyle Evans 
289c2caf3b3SKyle Evans 	lua_pushinteger(L, fd[0]);
290c2caf3b3SKyle Evans 	lua_pushinteger(L, fd[1]);
291c2caf3b3SKyle Evans 	return (2);
292c2caf3b3SKyle Evans }
293c2caf3b3SKyle Evans 
294c2caf3b3SKyle Evans static int
295c2caf3b3SKyle Evans lua_read(lua_State *L)
296c2caf3b3SKyle Evans {
297c2caf3b3SKyle Evans 	char *buf;
298c2caf3b3SKyle Evans 	ssize_t ret;
299c2caf3b3SKyle Evans 	size_t sz;
300c2caf3b3SKyle Evans 	int error, fd, narg;
301c2caf3b3SKyle Evans 
302c2caf3b3SKyle Evans 	narg = lua_gettop(L);
303c2caf3b3SKyle Evans 	luaL_argcheck(L, narg == 2, 1,
304c2caf3b3SKyle Evans 	    "read takes exactly two arguments (fd, size)");
305c2caf3b3SKyle Evans 
306c2caf3b3SKyle Evans 	fd = luaL_checkinteger(L, 1);
307c2caf3b3SKyle Evans 	sz = luaL_checkinteger(L, 2);
308c2caf3b3SKyle Evans 
309c2caf3b3SKyle Evans 	if (fd < 0) {
310c2caf3b3SKyle Evans 		error = EBADF;
311c2caf3b3SKyle Evans 		goto err;
312c2caf3b3SKyle Evans 	}
313c2caf3b3SKyle Evans 
314c2caf3b3SKyle Evans 	buf = malloc(sz);
315c2caf3b3SKyle Evans 	if (buf == NULL)
316c2caf3b3SKyle Evans 		goto err;
317c2caf3b3SKyle Evans 
318c2caf3b3SKyle Evans 	/*
319c2caf3b3SKyle Evans 	 * For 0-byte reads, we'll still push the empty string and let the
320c2caf3b3SKyle Evans 	 * caller deal with EOF to match lposix semantics.
321c2caf3b3SKyle Evans 	 */
322c2caf3b3SKyle Evans 	ret = read(fd, buf, sz);
323c2caf3b3SKyle Evans 	if (ret >= 0)
324c2caf3b3SKyle Evans 		lua_pushlstring(L, buf, ret);
325c2caf3b3SKyle Evans 	else if (ret < 0)
326c2caf3b3SKyle Evans 		error = errno; /* Save to avoid clobber by free() */
327c2caf3b3SKyle Evans 
328c2caf3b3SKyle Evans 	free(buf);
329c2caf3b3SKyle Evans 	if (error != 0)
330c2caf3b3SKyle Evans 		goto err;
331c2caf3b3SKyle Evans 
332c2caf3b3SKyle Evans 	/* Just the string pushed. */
333c2caf3b3SKyle Evans 	return (1);
334c2caf3b3SKyle Evans err:
335c2caf3b3SKyle Evans 	lua_pushnil(L);
336c2caf3b3SKyle Evans 	lua_pushstring(L, strerror(error));
337c2caf3b3SKyle Evans 	lua_pushinteger(L, error);
338c2caf3b3SKyle Evans 	return (3);
339c2caf3b3SKyle Evans }
340c2caf3b3SKyle Evans 
341c2caf3b3SKyle Evans static int
342c2caf3b3SKyle Evans lua_realpath(lua_State *L)
343c2caf3b3SKyle Evans {
344c2caf3b3SKyle Evans 	const char *inpath;
345c2caf3b3SKyle Evans 	char *outpath;
346c2caf3b3SKyle Evans 	int narg;
347c2caf3b3SKyle Evans 
348c2caf3b3SKyle Evans 	narg = lua_gettop(L);
349c2caf3b3SKyle Evans 	luaL_argcheck(L, narg > 0, 1, "at least one argument required");
350c2caf3b3SKyle Evans 	inpath = luaL_checkstring(L, 1);
351c2caf3b3SKyle Evans 
352c2caf3b3SKyle Evans 	outpath = realpath(inpath, NULL);
353c2caf3b3SKyle Evans 	if (outpath == NULL) {
354c2caf3b3SKyle Evans 		lua_pushnil(L);
355c2caf3b3SKyle Evans 		lua_pushstring(L, strerror(errno));
356c2caf3b3SKyle Evans 		lua_pushinteger(L, errno);
357c2caf3b3SKyle Evans 		return (3);
358c2caf3b3SKyle Evans 	}
359c2caf3b3SKyle Evans 
360c2caf3b3SKyle Evans 	lua_pushstring(L, outpath);
361c2caf3b3SKyle Evans 	free(outpath);
362c2caf3b3SKyle Evans 	return (1);
363c2caf3b3SKyle Evans }
364c2caf3b3SKyle Evans 
365c2caf3b3SKyle Evans static int
366c2caf3b3SKyle Evans lua_wait(lua_State *L)
367c2caf3b3SKyle Evans {
368c2caf3b3SKyle Evans 	pid_t pid;
369c2caf3b3SKyle Evans 	int options, status;
370c2caf3b3SKyle Evans 	int narg;
371c2caf3b3SKyle Evans 
372c2caf3b3SKyle Evans 	narg = lua_gettop(L);
373c2caf3b3SKyle Evans 
374c2caf3b3SKyle Evans 	pid = -1;
375c2caf3b3SKyle Evans 	status = options = 0;
376c2caf3b3SKyle Evans 	if (narg >= 1 && !lua_isnil(L, 1))
377c2caf3b3SKyle Evans 		pid = luaL_checkinteger(L, 1);
378c2caf3b3SKyle Evans 	if (narg >= 2 && !lua_isnil(L, 2))
379c2caf3b3SKyle Evans 		options = luaL_checkinteger(L, 2);
380c2caf3b3SKyle Evans 
381c2caf3b3SKyle Evans 	pid = waitpid(pid, &status, options);
382c2caf3b3SKyle Evans 	if (pid < 0) {
383c2caf3b3SKyle Evans 		lua_pushnil(L);
384c2caf3b3SKyle Evans 		lua_pushstring(L, strerror(errno));
385c2caf3b3SKyle Evans 		lua_pushinteger(L, errno);
386c2caf3b3SKyle Evans 		return (3);
387c2caf3b3SKyle Evans 	}
388c2caf3b3SKyle Evans 
389c2caf3b3SKyle Evans 	lua_pushinteger(L, pid);
390c2caf3b3SKyle Evans 	if (pid == 0) {
391c2caf3b3SKyle Evans 		lua_pushliteral(L, "running");
392c2caf3b3SKyle Evans 		return (2);
393c2caf3b3SKyle Evans 	}
394c2caf3b3SKyle Evans 
395c2caf3b3SKyle Evans 	if (WIFCONTINUED(status)) {
396c2caf3b3SKyle Evans 		lua_pushliteral(L, "continued");
397c2caf3b3SKyle Evans 		return (2);
398c2caf3b3SKyle Evans 	} else if(WIFSTOPPED(status)) {
399c2caf3b3SKyle Evans 		lua_pushliteral(L, "stopped");
400c2caf3b3SKyle Evans 		lua_pushinteger(L, WSTOPSIG(status));
401c2caf3b3SKyle Evans 		return (3);
402c2caf3b3SKyle Evans 	} else if (WIFEXITED(status)) {
403c2caf3b3SKyle Evans 		lua_pushliteral(L, "exited");
404c2caf3b3SKyle Evans 		lua_pushinteger(L, WEXITSTATUS(status));
405c2caf3b3SKyle Evans 		return (3);
406c2caf3b3SKyle Evans 	} else if (WIFSIGNALED(status)) {
407c2caf3b3SKyle Evans 		lua_pushliteral(L, "killed");
408c2caf3b3SKyle Evans 		lua_pushinteger(L, WTERMSIG(status));
409c2caf3b3SKyle Evans 		return (3);
410c2caf3b3SKyle Evans 	}
411c2caf3b3SKyle Evans 
412c2caf3b3SKyle Evans 	return (1);
413c2caf3b3SKyle Evans }
414c2caf3b3SKyle Evans 
415c2caf3b3SKyle Evans static int
416c2caf3b3SKyle Evans lua_write(lua_State *L)
417c2caf3b3SKyle Evans {
418c2caf3b3SKyle Evans 	const char *buf;
419c2caf3b3SKyle Evans 	size_t bufsz, sz;
420c2caf3b3SKyle Evans 	ssize_t ret;
421c2caf3b3SKyle Evans 	off_t offset;
422c2caf3b3SKyle Evans 	int error, fd, narg;
423c2caf3b3SKyle Evans 
424c2caf3b3SKyle Evans 	narg = lua_gettop(L);
425c2caf3b3SKyle Evans 	luaL_argcheck(L, narg >= 2, 1,
426c2caf3b3SKyle Evans 	    "write takes at least two arguments (fd, buf, sz, off)");
427c2caf3b3SKyle Evans 	luaL_argcheck(L, narg <= 4, 5,
428c2caf3b3SKyle Evans 	    "write takes no more than four arguments (fd, buf, sz, off)");
429c2caf3b3SKyle Evans 
430c2caf3b3SKyle Evans 	fd = luaL_checkinteger(L, 1);
431c2caf3b3SKyle Evans 	if (fd < 0) {
432c2caf3b3SKyle Evans 		error = EBADF;
433c2caf3b3SKyle Evans 		goto err;
434c2caf3b3SKyle Evans 	}
435c2caf3b3SKyle Evans 
436c2caf3b3SKyle Evans 	buf = luaL_checkstring(L, 2);
437c2caf3b3SKyle Evans 
438c2caf3b3SKyle Evans 	bufsz = sz = lua_rawlen(L, 2);
439c2caf3b3SKyle Evans 	if (narg >= 3 && !lua_isnil(L, 3))
440c2caf3b3SKyle Evans 		sz = luaL_checkinteger(L, 3);
441c2caf3b3SKyle Evans 
442c2caf3b3SKyle Evans 	offset = 0;
443c2caf3b3SKyle Evans 	if (narg >= 4 && !lua_isnil(L, 4))
444c2caf3b3SKyle Evans 		offset = luaL_checkinteger(L, 4);
445c2caf3b3SKyle Evans 
446c2caf3b3SKyle Evans 	if ((size_t)offset > bufsz || offset + sz > bufsz) {
447c2caf3b3SKyle Evans 		lua_pushnil(L);
448c2caf3b3SKyle Evans 		lua_pushfstring(L,
449c2caf3b3SKyle Evans 		    "write: invalid access offset %zu, size %zu in a buffer size %zu",
450c2caf3b3SKyle Evans 		    offset, sz, bufsz);
451c2caf3b3SKyle Evans 		lua_pushinteger(L, EINVAL);
452c2caf3b3SKyle Evans 		return (3);
453c2caf3b3SKyle Evans 	}
454c2caf3b3SKyle Evans 
455c2caf3b3SKyle Evans 	ret = write(fd, buf + offset, sz);
456c2caf3b3SKyle Evans 	if (ret < 0) {
457c2caf3b3SKyle Evans 		error = errno;
458c2caf3b3SKyle Evans 		goto err;
459c2caf3b3SKyle Evans 	}
460c2caf3b3SKyle Evans 
461c2caf3b3SKyle Evans 	lua_pushinteger(L, ret);
462c2caf3b3SKyle Evans 	return (1);
463c2caf3b3SKyle Evans err:
464c2caf3b3SKyle Evans 	lua_pushnil(L);
465c2caf3b3SKyle Evans 	lua_pushstring(L, strerror(error));
466c2caf3b3SKyle Evans 	lua_pushinteger(L, error);
467c2caf3b3SKyle Evans 	return (3);
468c2caf3b3SKyle Evans }
469c2caf3b3SKyle Evans 
470c2caf3b3SKyle Evans #define	REG_DEF(n, func)	{ #n, func }
471c2caf3b3SKyle Evans #define REG_SIMPLE(n)		REG_DEF(n, lua_ ## n)
472c2caf3b3SKyle Evans static const struct luaL_Reg libgenlib[] = {
473c2caf3b3SKyle Evans 	REG_SIMPLE(basename),
474c2caf3b3SKyle Evans 	REG_SIMPLE(dirname),
475c2caf3b3SKyle Evans 	{ NULL, NULL },
476c2caf3b3SKyle Evans };
477c2caf3b3SKyle Evans 
478c2caf3b3SKyle Evans static const struct luaL_Reg stdliblib[] = {
479c2caf3b3SKyle Evans 	REG_SIMPLE(realpath),
480c2caf3b3SKyle Evans 	{ NULL, NULL },
481c2caf3b3SKyle Evans };
482c2caf3b3SKyle Evans 
483*f35ccf46SStefan Eßer static const struct luaL_Reg fnmatchlib[] = {
484*f35ccf46SStefan Eßer 	REG_SIMPLE(fnmatch),
485*f35ccf46SStefan Eßer 	{ NULL, NULL },
486*f35ccf46SStefan Eßer };
487*f35ccf46SStefan Eßer 
488405e3338SEd Maste static const struct luaL_Reg sys_statlib[] = {
489405e3338SEd Maste 	REG_SIMPLE(chmod),
490405e3338SEd Maste 	{ NULL, NULL },
491405e3338SEd Maste };
492405e3338SEd Maste 
4931726db7aSMark Johnston static const struct luaL_Reg sys_utsnamelib[] = {
4941726db7aSMark Johnston 	REG_SIMPLE(uname),
4951726db7aSMark Johnston 	{ NULL, NULL },
4961726db7aSMark Johnston };
4971726db7aSMark Johnston 
498c2caf3b3SKyle Evans static const struct luaL_Reg sys_waitlib[] = {
499c2caf3b3SKyle Evans 	REG_SIMPLE(wait),
500506f3640SKyle Evans 	{NULL, NULL},
501506f3640SKyle Evans };
502c2caf3b3SKyle Evans 
503c2caf3b3SKyle Evans static const struct luaL_Reg unistdlib[] = {
504c2caf3b3SKyle Evans 	REG_SIMPLE(_exit),
505c2caf3b3SKyle Evans 	REG_SIMPLE(chown),
506c2caf3b3SKyle Evans 	REG_DEF(close, lua_pclose),
507c2caf3b3SKyle Evans 	REG_SIMPLE(fork),
508c2caf3b3SKyle Evans 	REG_SIMPLE(getpid),
509c2caf3b3SKyle Evans 	REG_SIMPLE(pipe),
510c2caf3b3SKyle Evans 	REG_SIMPLE(read),
511c2caf3b3SKyle Evans 	REG_SIMPLE(write),
512c2caf3b3SKyle Evans 	{ NULL, NULL },
513c2caf3b3SKyle Evans };
514c2caf3b3SKyle Evans 
515506f3640SKyle Evans #undef REG_SIMPLE
516c2caf3b3SKyle Evans #undef REG_DEF
517c2caf3b3SKyle Evans 
518c2caf3b3SKyle Evans int
519c2caf3b3SKyle Evans luaopen_posix_libgen(lua_State *L)
520c2caf3b3SKyle Evans {
521c2caf3b3SKyle Evans 	luaL_newlib(L, libgenlib);
522c2caf3b3SKyle Evans 	return (1);
523c2caf3b3SKyle Evans }
524c2caf3b3SKyle Evans 
525c2caf3b3SKyle Evans int
526c2caf3b3SKyle Evans luaopen_posix_stdlib(lua_State *L)
527c2caf3b3SKyle Evans {
528c2caf3b3SKyle Evans 	luaL_newlib(L, stdliblib);
529c2caf3b3SKyle Evans 	return (1);
530c2caf3b3SKyle Evans }
531506f3640SKyle Evans 
532506f3640SKyle Evans int
533*f35ccf46SStefan Eßer luaopen_posix_fnmatch(lua_State *L)
534*f35ccf46SStefan Eßer {
535*f35ccf46SStefan Eßer 	luaL_newlib(L, fnmatchlib);
536*f35ccf46SStefan Eßer 
537*f35ccf46SStefan Eßer #define	setkv(f) do {			\
538*f35ccf46SStefan Eßer 	lua_pushinteger(L, f);		\
539*f35ccf46SStefan Eßer 	lua_setfield(L, -2, #f);	\
540*f35ccf46SStefan Eßer } while (0)
541*f35ccf46SStefan Eßer 	setkv(FNM_PATHNAME);
542*f35ccf46SStefan Eßer 	setkv(FNM_NOESCAPE);
543*f35ccf46SStefan Eßer 	setkv(FNM_NOMATCH);
544*f35ccf46SStefan Eßer 	setkv(FNM_PERIOD);
545*f35ccf46SStefan Eßer #undef setkv
546*f35ccf46SStefan Eßer 
547*f35ccf46SStefan Eßer 	return 1;
548*f35ccf46SStefan Eßer }
549*f35ccf46SStefan Eßer 
550*f35ccf46SStefan Eßer int
551405e3338SEd Maste luaopen_posix_sys_stat(lua_State *L)
552405e3338SEd Maste {
553405e3338SEd Maste 	luaL_newlib(L, sys_statlib);
554c2caf3b3SKyle Evans 	return (1);
555c2caf3b3SKyle Evans }
556c2caf3b3SKyle Evans 
557c2caf3b3SKyle Evans int
558c2caf3b3SKyle Evans luaopen_posix_sys_wait(lua_State *L)
559c2caf3b3SKyle Evans {
560c2caf3b3SKyle Evans 	luaL_newlib(L, sys_waitlib);
561c2caf3b3SKyle Evans 
562c2caf3b3SKyle Evans #define	lua_pushflag(L, flag) do {	\
563c2caf3b3SKyle Evans 	lua_pushinteger(L, flag);	\
564c2caf3b3SKyle Evans 	lua_setfield(L, -2, #flag);	\
565c2caf3b3SKyle Evans } while(0)
566c2caf3b3SKyle Evans 
567c2caf3b3SKyle Evans 	/* Only these two exported by lposix */
568c2caf3b3SKyle Evans 	lua_pushflag(L, WNOHANG);
569c2caf3b3SKyle Evans 	lua_pushflag(L, WUNTRACED);
570c2caf3b3SKyle Evans 
571c2caf3b3SKyle Evans 	lua_pushflag(L, WCONTINUED);
572c2caf3b3SKyle Evans 	lua_pushflag(L, WSTOPPED);
573aad50785SKyle Evans #ifdef WTRAPPED
574c2caf3b3SKyle Evans 	lua_pushflag(L, WTRAPPED);
575aad50785SKyle Evans #endif
576c2caf3b3SKyle Evans 	lua_pushflag(L, WEXITED);
577c2caf3b3SKyle Evans 	lua_pushflag(L, WNOWAIT);
578c2caf3b3SKyle Evans #undef lua_pushflag
579c2caf3b3SKyle Evans 
580c2caf3b3SKyle Evans 	return (1);
581405e3338SEd Maste }
582405e3338SEd Maste 
583405e3338SEd Maste int
5841726db7aSMark Johnston luaopen_posix_sys_utsname(lua_State *L)
5851726db7aSMark Johnston {
5861726db7aSMark Johnston 	luaL_newlib(L, sys_utsnamelib);
5871726db7aSMark Johnston 	return 1;
5881726db7aSMark Johnston }
5891726db7aSMark Johnston 
5901726db7aSMark Johnston int
591506f3640SKyle Evans luaopen_posix_unistd(lua_State *L)
592506f3640SKyle Evans {
593506f3640SKyle Evans 	luaL_newlib(L, unistdlib);
594c2caf3b3SKyle Evans 	return (1);
595506f3640SKyle Evans }
596