summaryrefslogtreecommitdiff
path: root/luxio.c
diff options
context:
space:
mode:
authorRob Kendrick (humdrum) <rjek@rjek.com>2012-05-04 15:36:14 +0100
committerRob Kendrick (humdrum) <rjek@rjek.com>2012-05-04 15:36:14 +0100
commit2e5e55bfd3f66afab5bc9fee18a242c9f9eb88c4 (patch)
tree72aaf514a4c298160d08d617088009d38db962b0 /luxio.c
parentb1dffec3cdc4c1c1d1b84f142ac5dba170f407e4 (diff)
downloadluxio-2e5e55bfd3f66afab5bc9fee18a242c9f9eb88c4.tar.gz
Reorganise luxio source to order functions roughly in the order that they appear in POSIX 1996, and include references to sections where appropriate. Also include sections and functions that are not implemented as comments.
Diffstat (limited to 'luxio.c')
-rw-r--r--luxio.c1374
1 files changed, 755 insertions, 619 deletions
diff --git a/luxio.c b/luxio.c
index 7298926..418f009 100644
--- a/luxio.c
+++ b/luxio.c
@@ -40,305 +40,481 @@
# define lua_rawlen(L, idx) lua_objlen((L), (idx))
#endif
-#define INVALID_MODE ((mode_t) -1)
+/* 3.1: Process creation and execution ***************************************/
+
static int
-luxio_open(lua_State *L)
+luxio_fork(lua_State *L) /* 3.1.1 */
{
- const char *pathname = luaL_checkstring(L, 1);
- int flags = luaL_checkint(L, 2);
- mode_t mode = luaL_optinteger(L, 3, INVALID_MODE);
- int result;
+ int ret = fork();
- if ((flags & O_CREAT) && mode == INVALID_MODE) {
- lua_pushstring(L, "open with O_CREAT called with no mode");
- lua_error(L);
+ lua_pushinteger(L, ret);
+
+ if (ret == -1) {
+ lua_pushinteger(L, errno);
+ return 2;
}
+
+ return 1;
+}
+
+static int
+luxio__exec(lua_State *L, bool usep)
+{
+ const char *path = luaL_checkstring(L, 1);
+ int params = lua_gettop(L) - 1;
+ char **args;
+ int c, ret;
+
+ /* we probably at least need them to fill in arg[0] ... */
+ luaL_checkstring(L, 2);
+
+ args = calloc(params + 1, sizeof(*args));
+
+ for (c = 0; c < params; c++) {
+ /* gah! constness */
+ args[c] = (char *)luaL_checkstring(L, c + 2);
+ }
+
+ args[c] = NULL;
- if (mode == INVALID_MODE)
- result = open(pathname, flags);
+ if (usep)
+ ret = execvp(path, args);
else
- result = open(pathname, flags, mode);
-
- lua_pushinteger(L, result);
+ ret = execv(path, args);
+
+ /* if we got here, there's an error. */
+ free(args);
+ lua_pushinteger(L, ret);
lua_pushinteger(L, errno);
return 2;
}
static int
-luxio_close(lua_State *L)
+luxio_exec(lua_State *L) /* 3.1.2 */
{
- lua_pushinteger(L, close(luaL_checkint(L, 1)));
- lua_pushinteger(L, errno);
- return 2;
+ return luxio__exec(L, false);
}
static int
-luxio_read(lua_State *L)
+luxio_execp(lua_State *L) /* 3.1.2 */
{
- int fd = luaL_checkint(L, 1);
- int count = luaL_checkint(L, 2);
- ssize_t result;
- char *buf = malloc(count);
-
- if (buf == NULL) {
- lua_pushstring(L, "unable to allocate read buffer: memory exhausted");
- lua_error(L);
- }
-
- result = read(fd, buf, count);
-
- if (result == -1) {
- lua_pushinteger(L, result);
- lua_pushinteger(L, errno);
- } else {
- /* sadly there appears to be no way to avoid this copy.
- * luaL_Buffer actually builds things on the C stack bytes at a time,
- * and there is no way to pre-allocate a Lua type other than a
- * userdatum. Additionally, should Lua call its panic function because
- * it can't allocate memory to copy this into, our buf will be leaked.
- * We could perhaps fix this with a lot of faff, involving creating
- * a userdatum for our buffer, and setting a __gc metamethod.
- */
- lua_pushlstring(L, buf, result);
- lua_pushinteger(L, errno);
- }
-
- free(buf);
- return 2;
+ return luxio__exec(L, true);
}
+/* TODO: pthread_atfork() 3.1.3 */
+
+/* 3.2: Process termination **************************************************/
+
static int
-luxio_write(lua_State *L)
+luxio_waitpid(lua_State *L) /* 3.2.1 */
{
- int fd = luaL_checkint(L, 1);
- size_t count;
- const char *buf = luaL_checklstring(L, 2, &count);
- size_t offset = luaL_optinteger(L, 3, 0);
+ pid_t pid = luaL_checkinteger(L, 1);
+ int options = luaL_checkinteger(L, 2);
+ int status;
+ pid_t proc;
- if (offset > count) offset = count;
+ proc = waitpid(pid, &status, options);
+ lua_pushinteger(L, proc);
+ if (proc == -1) {
+ lua_pushinteger(L, errno);
+ } else {
+ lua_pushinteger(L, status);
+ }
+
+ return 2;
+}
+
+#define WAITPID_STATUS(x) static int luxio_##x(lua_State *L) { \
+ int status = luaL_checkinteger(L, 1); \
+ lua_pushinteger(L, x(status)); \
+ return 1; \
+ }
+
+WAITPID_STATUS(WIFEXITED)
+WAITPID_STATUS(WEXITSTATUS)
+WAITPID_STATUS(WIFSIGNALED)
+WAITPID_STATUS(WTERMSIG)
+#ifdef WCOREDUMP
+WAITPID_STATUS(WCOREDUMP)
+#endif
+WAITPID_STATUS(WIFSTOPPED)
+WAITPID_STATUS(WSTOPSIG)
+#ifdef WIFCONTINUED
+WAITPID_STATUS(WIFCONTINUED)
+#endif
+
+#undef WAITPID_STATUS
+
+static int
+luxio__exit(lua_State *L) /* 3.2.2 */
+{
+ int ret = luaL_optinteger(L, 1, 0);
- lua_pushinteger(L, write(fd, buf + offset, count - offset));
+ _exit(ret);
+
+ return 0;
+}
+
+/* 3.3: Signals */
+
+static int
+luxio_kill(lua_State *L) /* 3.3.2 */
+{
+ pid_t pid = luaL_checkinteger(L, 1);
+ int sig = luaL_checkinteger(L, 2);
+
+ lua_pushinteger(L, kill(pid, sig));
lua_pushinteger(L, errno);
+
return 2;
}
+/* TODO: Manipulate Signal Sets 3.3.3 */
+/* TODO: sigaction() 3.3.4 */
+/* TODO: pthread_sigmask(), sigprocmask() 3.3.5 */
+/* TODO: sigpending() 3.3.6 */
+/* TODO: sigsuspend() 3.3.7 */
+/* TODO: sigwait(), sigwaitinfo(), sigtimedwait() 3.3.8 */
+/* TODO: sigqueue() 3.3.9 */
+/* TODO: pthread_kill() 3.3.10 */
+
+/* 3.4 Timer operations */
+
+/* TODO: alarm() 3.4.1 */
+/* TODO: pause() 3.4.2 */
+/* TODO: sleep() 3.4.3 */
+
+/* 4.1 Process identification ************************************************/
+
+/* TODO: getpid(), getppid() 4.1.1 */
+
+/* 4.2 User identification ***************************************************/
+
+/* TODO: getuid(), geteuid(), getgid(), getegid() 4.2.1 */
+/* TODO: setuid(), setgit() 4.2.2 */
+/* TODO: getgroups() 4.2.3 */
+/* TODO: getlogin(), getlogin_r() 4.2.4 */
+
+/* 4.3 Process groups ********************************************************/
+
+/* TODO: getpgrp() 4.3.1 */
+/* TODO: setsid() 4.3.2 */
+/* TODO: setpgid() 4.3.3 */
+
+/* 4.4 System identification *************************************************/
+
+/* TODO: uname() 4.4.1 */
+
+/* 4.5 Time ******************************************************************/
+
+/* TODO: time() 4.5.1 */
+/* TODO: times() 4.5.2 */
+
+/* 4.6 Environment variables *************************************************/
+
static int
-luxio_writev(lua_State *L)
+luxio_getenv(lua_State *L) /* 4.6.1 */
{
- int fd = luaL_checkint(L, 1);
- int blks = lua_gettop(L) - 1;
- int c;
- struct iovec *iov;
+ const char *envvar = luaL_checkstring(L, 1);
- /* check there is at least one string to write */
- luaL_checkstring(L, 2);
+ char *envval = getenv(envvar);
- iov = malloc(blks * sizeof(*iov));
+ if (envval == NULL)
+ return 0;
- for (c = 0; c < blks; c++) {
- iov[c].iov_base = (void *)luaL_checkstring(L, c + 2);
- iov[c].iov_len = lua_rawlen(L, c + 2);
- }
+ lua_pushstring(L, envval);
- lua_pushinteger(L, writev(fd, iov, blks));
- lua_pushinteger(L, errno);
+ return 1;
+}
+
+static int
+luxio_setenv(lua_State *L) /* POSIX.1-2001 */
+{
+ const char *envvar = luaL_checkstring(L, 1);
+ const char *envval = luaL_checkstring(L, 2);
+ int overwrite = luaL_optint(L, 3, 1);
- free(iov);
+ lua_pushinteger(L, setenv(envvar, envval, overwrite));
+ lua_pushinteger(L, errno);
return 2;
}
-#ifdef _LARGEFILE64_SOURCE
static int
-luxio_lseek(lua_State *L)
+luxio_unsetenv(lua_State *L) /* POSIX.1-2001 */
{
- int fd = luaL_checkint(L, 1);
- off64_t offset = (off64_t)luaL_checknumber(L, 2); /* 56b is enough! */
- int whence = luaL_checkint(L, 3);
+ const char *envvar = luaL_checkstring(L, 1);
- lua_pushinteger(L, (lua_Number)lseek64(fd, offset, whence));
+ lua_pushinteger(L, unsetenv(envvar));
lua_pushinteger(L, errno);
+
return 2;
}
-#else
+
+/* 4.7 Terminal identification ***********************************************/
+
+/* TODO: ctermid() 4.7.1 */
+/* TODO: ttyname(), ttyname_r(), isatty() 4.7.2 */
+
+/* 4.8 Configurable system variables *****************************************/
+
+/* TODO: sysconf() 4.8.1 */
+
+/* 5.1 Directories ***********************************************************/
+
+/* readdir is a hideous API. We need to be reasonably high-level here,
+ * otherwise everything is just too painful.
+ */
+
+#define LUXIO_READDIR_METATABLE "luxio.readdir"
+
+typedef struct {
+ DIR *dirp;
+ struct dirent *buf, *ent;
+} luxio_readdir_state;
+
static int
-luxio_lseek(lua_State *L)
+luxio_readdir_gc(lua_State *L)
{
- int fd = luaL_checkint(L, 1);
- off_t offset = luaL_checkinteger(L, 2);
- int whence = luaL_checkint(L, 3);
+ luxio_readdir_state *s = luaL_checkudata(L, 1, LUXIO_READDIR_METATABLE);
- lua_pushinteger(L, lseek(fd, offset, whence));
- lua_pushinteger(L, errno);
- return 2;
+ closedir(s->dirp);
+ free(s->buf);
+
+ return 0;
}
-#endif
static int
-luxio_ftruncate(lua_State *L)
+luxio_readdir_tostring(lua_State *L)
{
- int fildes = luaL_checkinteger(L, 1);
- off_t length = luaL_checkinteger(L, 2);
+ luxio_readdir_state *s = luaL_checkudata(L, 1, LUXIO_READDIR_METATABLE);
+ char buf[sizeof("dirent: 0xffffffffffffffff")];
- lua_pushinteger(L, ftruncate(fildes, length));
- lua_pushinteger(L, errno);
- return 2;
+ snprintf(buf, sizeof(buf), "dirent: %p", s);
+ lua_pushstring(L, buf);
+ return 1;
}
-static int
-luxio_fsync(lua_State *L)
+static void
+luxio__bless_readdir(lua_State *L)
{
- int fildes = luaL_checkinteger(L, 1);
-
- lua_pushinteger(L, fsync(fildes));
- lua_pushinteger(L, errno);
- return 2;
+ int create = luaL_newmetatable(L, LUXIO_READDIR_METATABLE);
+
+ if (create != 0) {
+ lua_pushcfunction(L, luxio_readdir_gc);
+ lua_setfield(L, -2, "__gc");
+ lua_pushcfunction(L, luxio_readdir_tostring);
+ lua_setfield(L, -2, "__tostring");
+ }
+
+ lua_setmetatable(L, -2);
}
static int
-luxio_fdatasync(lua_State *L)
+luxio_opendir(lua_State *L) /* 5.1.2 */
{
- int fildes = luaL_checkinteger(L, 2);
-
- lua_pushinteger(L, fdatasync(fildes));
- lua_pushinteger(L, errno);
- return 2;
+ const char *path = luaL_checkstring(L, 1);
+ DIR *d = opendir(path);
+ size_t bufz;
+ luxio_readdir_state *s;
+
+ if (d == NULL) {
+ lua_pushnil(L);
+ lua_pushinteger(L, errno);
+ return 2;
+ }
+
+ s = lua_newuserdata(L, sizeof(*s));
+
+ s->dirp = d;
+ /* + 256 because it'd always be +1 if it weren't for the horrors
+ * of Solaris. If we were using autoconf, we could use Ben
+ * Hutchings' function mentioned in the article above.
+ */
+ bufz = sizeof(struct dirent) + pathconf(path, _PC_NAME_MAX) + 256;
+ s->buf = malloc(bufz);
+
+ luxio__bless_readdir(L);
+
+ return 1;
}
-#ifdef HAVE_SENDFILE
static int
-luxio_sendfile(lua_State *L)
+luxio_fdopendir(lua_State *L) /* POSIX.1-2008 */
{
- int out_fd = luaL_checkint(L, 1);
- int in_fd = luaL_checkint(L, 2);
- off_t offset;
- size_t count = luaL_checkint(L, 4);
- ssize_t r;
+ int fd = luaL_checkinteger(L, 1);
+ DIR *d = fdopendir(fd);
+ size_t bufz;
+ luxio_readdir_state *s;
- if (lua_isnil(L, 3)) {
- r = sendfile(out_fd, in_fd, NULL, count);
- lua_pushinteger(L, r);
+ if (d == NULL) {
+ lua_pushnil(L);
lua_pushinteger(L, errno);
return 2;
}
-
- offset = luaL_checkint(L, 3);
- r = sendfile(out_fd, in_fd, &offset, count);
- lua_pushinteger(L, r);
- lua_pushinteger(L, errno);
- lua_pushinteger(L, offset);
- return 3;
+ s = lua_newuserdata(L, sizeof(*s));
+
+ s->dirp = d;
+ /* + 256 because it'd always be +1 if it weren't for the horrors
+ * of Solaris. If we were using autoconf, we could use Ben
+ * Hutchings' function mentioned in the article above.
+ */
+ bufz = sizeof(struct dirent) + fpathconf(fd, _PC_NAME_MAX) + 256;
+ s->buf = malloc(bufz);
+
+ luxio__bless_readdir(L);
+
+ return 1;
}
-#endif /* HAVE_SENDFILE */
static int
-luxio_dup(lua_State *L)
+luxio_closedir(lua_State *L) /* 5.1.2 */
{
- int oldfd = luaL_checkint(L, 1);
+ luxio_readdir_state *s = luaL_checkudata(L, 1, LUXIO_READDIR_METATABLE);
+
+ if (s->dirp != NULL) {
+ closedir(s->dirp);
+ s->dirp = NULL;
+ }
+
+ free(s->buf);
+ s->buf = NULL;
- lua_pushinteger(L, dup(oldfd));
- lua_pushinteger(L, errno);
- return 2;
+ return 0;
}
static int
-luxio_dup2(lua_State *L)
+luxio_readdir(lua_State *L) /* 5.1.2 */
{
- int oldfd = luaL_checkint(L, 1);
- int newfd = luaL_checkint(L, 2);
+ luxio_readdir_state *s = luaL_checkudata(L, 1, LUXIO_READDIR_METATABLE);
+ int err;
- lua_pushinteger(L, dup2(oldfd, newfd));
- lua_pushinteger(L, errno);
- return 2;
+ err = readdir_r(s->dirp, s->buf, &s->ent);
+
+ if (err == 0 && s->ent != NULL) {
+ lua_pushinteger(L, 0);
+ lua_newtable(L);
+ lua_pushinteger(L, s->ent->d_ino);
+ lua_setfield(L, -2, "d_ino");
+ lua_pushstring(L, s->ent->d_name);
+ lua_setfield(L, -2, "d_name");
+#ifdef HAVE_D_TYPE
+ lua_pushinteger(L, s->ent->d_type);
+ lua_setfield(L, -2, "d_type");
+#endif
+ return 2;
+ }
+
+ if (s->ent == NULL) {
+ /* end of directory */
+ lua_pushnil(L);
+ return 1;
+ }
+
+ lua_pushinteger(L, err);
+ return 1;
}
-#ifdef _GNU_SOURCE
static int
-luxio_dup3(lua_State *L)
+luxio_rewinddir(lua_State *L) /* 5.1.2 */
{
- int oldfd = luaL_checkint(L, 1);
- int newfd = luaL_checkint(L, 2);
- int flags = luaL_checkint(L, 3);
-
- lua_pushinteger(L, dup3(oldfd, newfd, flags));
+ luxio_readdir_state *s = luaL_checkudata(L, 1, LUXIO_READDIR_METATABLE);
+ rewinddir(s->dirp);
+
+ return 0;
+}
+
+/* 5.2 Working directory *****************************************************/
+
+static int
+luxio_chdir(lua_State *L) /* 5.2.1 */
+{
+ const char *path = luaL_checkstring(L, 1);
+ lua_pushinteger(L, chdir(path));
lua_pushinteger(L, errno);
return 2;
}
-#endif
static int
-luxio_pipe(lua_State *L)
+luxio_getcwd(lua_State *L) /* 5.2.2 */
{
- int res, pipefd[2];
- luaL_checktype(L, 1, LUA_TTABLE);
-
- res = pipe(pipefd);
- if (res == 0) {
- lua_pushinteger(L, pipefd[0]);
- lua_rawseti(L, 1, 1);
- lua_pushinteger(L, pipefd[1]);
- lua_rawseti(L, 1, 2);
+ char buf[PATH_MAX];
+
+ if (getcwd(buf, PATH_MAX) == NULL) {
+ lua_pushnil(L);
+ } else {
+ lua_pushstring(L, buf);
}
-
- lua_pushinteger(L, res);
+
lua_pushinteger(L, errno);
-
+
return 2;
}
-#ifdef _GNU_SOURCE
+/* 5.3 General file creation *************************************************/
+
+#define INVALID_MODE ((mode_t) -1)
static int
-luxio_pipe2(lua_State *L)
+luxio_open(lua_State *L) /* 5.3.1 */
{
- int res, pipefd[2];
- int flags;
-
- luaL_checktype(L, 1, LUA_TTABLE);
- flags = luaL_checkinteger(L, 2);
-
- res = pipe2(pipefd, flags);
- if (res == 0) {
- lua_pushinteger(L, pipefd[0]);
- lua_rawseti(L, 1, 1);
- lua_pushinteger(L, pipefd[1]);
- lua_rawseti(L, 1, 2);
+ const char *pathname = luaL_checkstring(L, 1);
+ int flags = luaL_checkint(L, 2);
+ mode_t mode = luaL_optinteger(L, 3, INVALID_MODE);
+ int result;
+
+ if ((flags & O_CREAT) && mode == INVALID_MODE) {
+ lua_pushstring(L, "open with O_CREAT called with no mode");
+ lua_error(L);
}
- lua_pushinteger(L, res);
- lua_pushinteger(L, errno);
+ if (mode == INVALID_MODE)
+ result = open(pathname, flags);
+ else
+ result = open(pathname, flags, mode);
+ lua_pushinteger(L, result);
+ lua_pushinteger(L, errno);
return 2;
}
-#endif
+/* TODO: creat() 5.3.2 */
static int
-luxio_socketpair(lua_State *L)
+luxio_umask(lua_State *L) /* 5.3.3 */
{
- int domain = luaL_checkinteger(L, 1);
- int type = luaL_checkinteger(L, 2);
- int protocol = luaL_checkinteger(L, 3);
- int sv[2];
- int res;
- luaL_checktype(L, 4, LUA_TTABLE);
-
- res = socketpair(domain, type, protocol, sv);
- if (res == 0) {
- lua_pushinteger(L, sv[0]);
- lua_rawseti(L, 4, 1);
- lua_pushinteger(L, sv[1]);
- lua_rawseti(L, 4, 2);
- }
+ mode_t mask = luaL_checkinteger(L, 1);
+ lua_pushinteger(L, umask(mask));
+ return 1;
+}
- lua_pushinteger(L, res);
+static int
+luxio_link(lua_State *L) /* 5.3.4 */
+{
+ const char *existing = luaL_checkstring(L, 1);
+ const char *new = luaL_checkstring(L, 2);
+
+ lua_pushinteger(L, link(existing, new));
lua_pushinteger(L, errno);
+ return 2;
+}
- return 2;
+/* 5.4 Special file creation *************************************************/
+
+static int
+luxio_mkdir(lua_State *L) /* 5.4.1 */
+{
+ const char *pathname = luaL_checkstring(L, 1);
+ mode_t mode = luaL_checkinteger(L, 2);
+
+ lua_pushinteger(L, mkdir(pathname, mode));
+ lua_pushinteger(L, errno);
+
+ return 2;
}
static int
-luxio_mkfifo(lua_State *L)
+luxio_mkfifo(lua_State *L) /* 5.4.2 */
{
const char *pathname = luaL_checkstring(L, 1);
mode_t mode = luaL_checkinteger(L, 2);
@@ -349,20 +525,20 @@ luxio_mkfifo(lua_State *L)
return 2;
}
+/* 5.5 File removal **********************************************************/
+
static int
-luxio_mkdir(lua_State *L)
+luxio_unlink(lua_State *L) /* 5.5.1 */
{
- const char *pathname = luaL_checkstring(L, 1);
- mode_t mode = luaL_checkinteger(L, 2);
-
- lua_pushinteger(L, mkdir(pathname, mode));
+ const char *s = luaL_checkstring(L, 1);
+
+ lua_pushinteger(L, unlink(s));
lua_pushinteger(L, errno);
-
return 2;
}
static int
-luxio_rmdir(lua_State *L)
+luxio_rmdir(lua_State *L) /* 5.5.2 */
{
const char *pathname = luaL_checkstring(L, 1);
@@ -372,7 +548,7 @@ luxio_rmdir(lua_State *L)
}
static int
-luxio_rename(lua_State *L)
+luxio_rename(lua_State *L) /* 5.5.3 */
{
const char *old = luaL_checkstring(L, 1);
const char *new = luaL_checkstring(L, 2);
@@ -382,6 +558,8 @@ luxio_rename(lua_State *L)
return 2;
}
+/* 5.6 File characteristics **************************************************/
+
static int
luxio_push_stat_table(lua_State *L, struct stat *s)
{
@@ -411,7 +589,7 @@ luxio_push_stat_table(lua_State *L, struct stat *s)
}
static int
-luxio_stat(lua_State *L)
+luxio_stat(lua_State *L) /* 5.6.2 */
{
const char *pathname = luaL_checkstring(L, 1);
struct stat s;
@@ -430,18 +608,18 @@ luxio_stat(lua_State *L)
}
static int
-luxio_lstat(lua_State *L)
+luxio_fstat(lua_State *L) /* 5.6.2 */
{
- const char *pathname = luaL_checkstring(L, 1);
+ int fd = luaL_checkinteger(L, 1);
struct stat s;
- int r = lstat(pathname, &s);
+ int r = fstat(fd, &s);
if (r < 0) {
lua_pushinteger(L, r);
lua_pushinteger(L, errno);
return 2;
}
-
+
lua_pushnumber(L, r);
luxio_push_stat_table(L, &s);
@@ -449,33 +627,307 @@ luxio_lstat(lua_State *L)
}
static int
-luxio_fstat(lua_State *L)
+luxio_lstat(lua_State *L) /* POSIX.1-2001 */
{
- int fd = luaL_checkinteger(L, 1);
+ const char *pathname = luaL_checkstring(L, 1);
struct stat s;
- int r = fstat(fd, &s);
+ int r = lstat(pathname, &s);
if (r < 0) {
lua_pushinteger(L, r);
lua_pushinteger(L, errno);
return 2;
}
-
+
lua_pushnumber(L, r);
luxio_push_stat_table(L, &s);
return 2;
}
+
+/* TODO: access() 5.6.3 */
+
+static int
+luxio_chmod(lua_State *L) /* 5.6.4 */
+{
+ const char *path = luaL_checkstring(L, 1);
+ mode_t mode = luaL_checkinteger(L, 2);
+
+ lua_pushinteger(L, chmod(path, mode));
+ lua_pushinteger(L, errno);
+
+ return 2;
+}
+
static int
-luxio_strerror(lua_State *L)
+luxio_fchmod(lua_State *L) /* 5.6.4 */
{
- lua_pushstring(L, strerror(luaL_checkint(L, 1)));
- return 1;
+ int fd = luaL_checkinteger(L, 1);
+ mode_t mode = luaL_checkinteger(L, 2);
+
+ lua_pushinteger(L, fchmod(fd, mode));
+ lua_pushinteger(L, errno);
+
+ return 2;
}
static int
-luxio_fcntl(lua_State *L)
+luxio_chown(lua_State *L) /* 5.6.5 */
+{
+ const char *path = luaL_checkstring(L, 1);
+ uid_t owner = luaL_checkinteger(L, 2);
+ gid_t group = luaL_checkinteger(L, 3);
+
+ lua_pushinteger(L, chown(path, owner, group));
+ lua_pushinteger(L, errno);
+ return 2;
+}
+
+/* TODO: utime() 5.6.6 */
+
+static int
+luxio_ftruncate(lua_State *L) /* 5.6.7 */
+{
+ int fildes = luaL_checkinteger(L, 1);
+ off_t length = luaL_checkinteger(L, 2);
+
+ lua_pushinteger(L, ftruncate(fildes, length));
+ lua_pushinteger(L, errno);
+ return 2;
+}
+
+/* 5.7 Configurable pathname variables ***************************************/
+
+/* TODO: pathconf(), fpathconf() 5.7.1 */
+
+/* 6.1 Pipes *****************************************************************/
+
+static int
+luxio_pipe(lua_State *L) /* 6.1.1 */
+{
+ int res, pipefd[2];
+ luaL_checktype(L, 1, LUA_TTABLE);
+
+ res = pipe(pipefd);
+ if (res == 0) {
+ lua_pushinteger(L, pipefd[0]);
+ lua_rawseti(L, 1, 1);
+ lua_pushinteger(L, pipefd[1]);
+ lua_rawseti(L, 1, 2);
+ }
+
+ lua_pushinteger(L, res);
+ lua_pushinteger(L, errno);
+
+ return 2;
+}
+
+#ifdef _GNU_SOURCE
+static int
+luxio_pipe2(lua_State *L) /* GNU extension */
+{
+ int res, pipefd[2];
+ int flags;
+
+ luaL_checktype(L, 1, LUA_TTABLE);
+ flags = luaL_checkinteger(L, 2);
+
+ res = pipe2(pipefd, flags);
+ if (res == 0) {
+ lua_pushinteger(L, pipefd[0]);
+ lua_rawseti(L, 1, 1);
+ lua_pushinteger(L, pipefd[1]);
+ lua_rawseti(L, 1, 2);
+ }
+
+ lua_pushinteger(L, res);
+ lua_pushinteger(L, errno);
+
+ return 2;
+}
+#endif
+
+static int
+luxio_socketpair(lua_State *L) /* POSIX.1-2001 */
+{
+ int domain = luaL_checkinteger(L, 1);
+ int type = luaL_checkinteger(L, 2);
+ int protocol = luaL_checkinteger(L, 3);
+ int sv[2];
+ int res;
+ luaL_checktype(L, 4, LUA_TTABLE);
+
+ res = socketpair(domain, type, protocol, sv);
+ if (res == 0) {
+ lua_pushinteger(L, sv[0]);
+ lua_rawseti(L, 4, 1);
+ lua_pushinteger(L, sv[1]);
+ lua_rawseti(L, 4, 2);
+ }
+
+ lua_pushinteger(L, res);
+ lua_pushinteger(L, errno);
+
+ return 2;
+}
+
+/* 6.2 File descriptor manipulation ******************************************/
+
+static int
+luxio_dup(lua_State *L) /* 6.2.1 */
+{
+ int oldfd = luaL_checkint(L, 1);
+
+ lua_pushinteger(L, dup(oldfd));
+ lua_pushinteger(L, errno);
+ return 2;
+}
+
+static int
+luxio_dup2(lua_State *L) /* 6.2.1 */
+{
+ int oldfd = luaL_checkint(L, 1);
+ int newfd = luaL_checkint(L, 2);
+
+ lua_pushinteger(L, dup2(oldfd, newfd));
+ lua_pushinteger(L, errno);
+ return 2;
+}
+
+#ifdef _GNU_SOURCE
+static int
+luxio_dup3(lua_State *L) /* GNU extension */
+{
+ int oldfd = luaL_checkint(L, 1);
+ int newfd = luaL_checkint(L, 2);
+ int flags = luaL_checkint(L, 3);
+
+ lua_pushinteger(L, dup3(oldfd, newfd, flags));
+ lua_pushinteger(L, errno);
+ return 2;
+}
+#endif
+
+/* 6.3 File descriptor deassignment ******************************************/
+
+static int
+luxio_close(lua_State *L) /* 6.3.1 */
+{
+ lua_pushinteger(L, close(luaL_checkint(L, 1)));
+ lua_pushinteger(L, errno);
+ return 2;
+}
+
+/* 6.4 Input and output ******************************************************/
+
+static int
+luxio_read(lua_State *L) /* 6.4.1 */
+{
+ int fd = luaL_checkint(L, 1);
+ int count = luaL_checkint(L, 2);
+ ssize_t result;
+ char *buf = malloc(count);
+
+ if (buf == NULL) {
+ lua_pushstring(L, "unable to allocate read buffer: memory exhausted");
+ lua_error(L);
+ }
+
+ result = read(fd, buf, count);
+
+ if (result == -1) {
+ lua_pushinteger(L, result);
+ lua_pushinteger(L, errno);
+ } else {
+ /* sadly there appears to be no way to avoid this copy.
+ * luaL_Buffer actually builds things on the C stack bytes at a time,
+ * and there is no way to pre-allocate a Lua type other than a
+ * userdatum. Additionally, should Lua call its panic function because
+ * it can't allocate memory to copy this into, our buf will be leaked.
+ * We could perhaps fix this with a lot of faff, involving creating
+ * a userdatum for our buffer, and setting a __gc metamethod.
+ */
+ lua_pushlstring(L, buf, result);
+ lua_pushinteger(L, errno);
+ }
+
+ free(buf);
+ return 2;
+}
+
+static int
+luxio_write(lua_State *L) /* 6.4.2 */
+{
+ int fd = luaL_checkint(L, 1);
+ size_t count;
+ const char *buf = luaL_checklstring(L, 2, &count);
+ size_t offset = luaL_optinteger(L, 3, 0);
+
+ if (offset > count) offset = count;
+
+ lua_pushinteger(L, write(fd, buf + offset, count - offset));
+ lua_pushinteger(L, errno);
+ return 2;
+}
+
+static int
+luxio_writev(lua_State *L) /* POSIX.1-2001 */
+{
+ int fd = luaL_checkint(L, 1);
+ int blks = lua_gettop(L) - 1;
+ int c;
+ struct iovec *iov;
+
+ /* check there is at least one string to write */
+ luaL_checkstring(L, 2);
+
+ iov = malloc(blks * sizeof(*iov));
+
+ for (c = 0; c < blks; c++) {
+ iov[c].iov_base = (void *)luaL_checkstring(L, c + 2);
+ iov[c].iov_len = lua_rawlen(L, c + 2);
+ }
+
+ lua_pushinteger(L, writev(fd, iov, blks));
+ lua_pushinteger(L, errno);
+
+ free(iov);
+
+ return 2;
+}
+
+#ifdef HAVE_SENDFILE
+static int
+luxio_sendfile(lua_State *L) /* Linux-specific */
+{
+ int out_fd = luaL_checkint(L, 1);
+ int in_fd = luaL_checkint(L, 2);
+ off_t offset;
+ size_t count = luaL_checkint(L, 4);
+ ssize_t r;
+
+ if (lua_isnil(L, 3)) {
+ r = sendfile(out_fd, in_fd, NULL, count);
+ lua_pushinteger(L, r);
+ lua_pushinteger(L, errno);
+ return 2;
+ }
+
+ offset = luaL_checkint(L, 3);
+ r = sendfile(out_fd, in_fd, &offset, count);
+ lua_pushinteger(L, r);
+ lua_pushinteger(L, errno);
+ lua_pushinteger(L, offset);
+
+ return 3;
+}
+#endif /* HAVE_SENDFILE */
+
+/* 6.5 Control operationson files ********************************************/
+
+static int
+luxio_fcntl(lua_State *L) /* 6.5.2 */
{
int fd = luaL_checkint(L, 1);
int cmd = luaL_checkint(L, 2);
@@ -515,50 +967,112 @@ luxio_fcntl(lua_State *L)
return 0; /* never get here, but keep compiler happy */
}
+#ifdef _LARGEFILE64_SOURCE
static int
-luxio_umask(lua_State *L)
+luxio_lseek(lua_State *L) /* 6.5.3 */
{
- mode_t mask = luaL_checkinteger(L, 1);
- lua_pushinteger(L, umask(mask));
- return 1;
+ int fd = luaL_checkint(L, 1);
+ off64_t offset = (off64_t)luaL_checknumber(L, 2); /* 56b is enough! */
+ int whence = luaL_checkint(L, 3);
+
+ lua_pushinteger(L, (lua_Number)lseek64(fd, offset, whence));
+ lua_pushinteger(L, errno);
+ return 2;
}
-
+#else
static int
-luxio_chmod(lua_State *L)
+luxio_lseek(lua_State *L) /* 6.5.3 */
{
- const char *path = luaL_checkstring(L, 1);
- mode_t mode = luaL_checkinteger(L, 2);
-
- lua_pushinteger(L, chmod(path, mode));
+ int fd = luaL_checkint(L, 1);
+ off_t offset = luaL_checkinteger(L, 2);
+ int whence = luaL_checkint(L, 3);
+
+ lua_pushinteger(L, lseek(fd, offset, whence));
lua_pushinteger(L, errno);
-
return 2;
}
+#endif
+
+/* 6.6 File synchronisation */
static int
-luxio_fchmod(lua_State *L)
+luxio_fsync(lua_State *L) /* 6.6.1 */
{
- int fd = luaL_checkinteger(L, 1);
- mode_t mode = luaL_checkinteger(L, 2);
-
- lua_pushinteger(L, fchmod(fd, mode));
+ int fildes = luaL_checkinteger(L, 1);
+
+ lua_pushinteger(L, fsync(fildes));
lua_pushinteger(L, errno);
-
return 2;
}
static int
-luxio_chown(lua_State *L)
+luxio_fdatasync(lua_State *L) /* 6.6.2 */
{
- const char *path = luaL_checkstring(L, 1);
- uid_t owner = luaL_checkinteger(L, 2);
- gid_t group = luaL_checkinteger(L, 3);
-
- lua_pushinteger(L, chown(path, owner, group));
+ int fildes = luaL_checkinteger(L, 2);
+
+ lua_pushinteger(L, fdatasync(fildes));
lua_pushinteger(L, errno);
return 2;
}
+/* 6.7 Asynchronous input and output */
+
+/* TODO: aio_read() 6.7.2 */
+/* TODO: aio_write() 6.7.3 */
+/* TODO: lio_listio() 6.7.4 */
+/* TODO: aio_error() 6.7.5 */
+/* TODO: aio_return() 6.7.6 */
+/* TODO: aio_cancel() 6.7.7 */
+/* TODO: aio_suspend() 6.7.8 */
+/* TODO: aio_fsync() 6.7.9 */
+
+/* 7.1 General Terminal Interface ********************************************/
+
+/* TODO: all of this. */
+
+/* 8.1 Referenced C Language Routines ****************************************/
+
+/* These are ANSI C functions POSIX imports. TODO any Lua doesn't already */
+
+/* 9.1 Database access *******************************************************/
+
+/* TODO: getgrgid(), getgrgid_r(), getgrnam(), getgrnam_r() 9.2.1 */
+/* TODO: getpwuid(), getpwuid_r(), getpwnam(), getpwnam_r() 9.2.2 */
+
+/* 10 Data interchange format ************************************************/
+
+/* This is just related to data structures and file formats, not functions */
+
+/* 11 Synchronisation ********************************************************/
+
+/* Semaphores, mutexes, etc should be handled by a dedicated threading lib */
+
+/* 12 Memory management ******************************************************/
+
+/* While it might be interesting to bind mmap and mlock etc, it's difficult to
+ * see how this might work in Lua. Perhaps emulate a string?
+ */
+
+/* 13 Execution scheduling ***************************************************/
+
+/* TODO: all of this. */
+
+/* 14.2 Clock and timer functions ********************************************/
+
+/* TODO: clock_settime(), clock_gettime(), clock_getres() 14.2.1 */
+/* Timer functions excluded, based on signals */
+/* TODO: nanosleep() 14.2.5 */
+
+/* 15 Message passing ********************************************************/
+
+/* TODO: all of this. message queues and such would be cool to have. */
+
+/* 16 Thread management ******************************************************/
+
+/* Nope: use a threading library. */
+
+/* Socket-handling ***********************************************************/
+
#define LUXIO_SOCKADDR_METATABLE_NAME "luxio.sockaddr"
#ifndef UNIX_PATH_MAX
/* From man 7 unix */
@@ -1023,21 +1537,7 @@ luxio_getaddrinfo(lua_State *L)
return 2;
}
-/*
- * Plan of action for poll() support
- *
- * 1. Bind a pollfd array
- * 2. Devise useful API for the pollfds
- * 3. implement poll()
- *
- * Optional:
- *
- * 4. Implement epoll()
- *
- * Optional Optional:
- *
- * 5. Implement cute Lua-based epoll/poll wrapper.
- */
+/* Poll-binding functions ****************************************************/
#define LUXIO_POLLFD_METATABLE "luxio.pollfdarray"
@@ -1166,6 +1666,8 @@ luxio_poll(lua_State *L)
return 2;
}
+/* Bit/flag operation functions **********************************************/
+
static int
luxio_bitop_or(lua_State *L)
{
@@ -1239,8 +1741,7 @@ luxio_bitop_test(lua_State *L)
return 1;
}
-/*
- */
+/* Time-related functions ****************************************************/
#define LUXIO_TIMEVAL_METATABLE "luxio.timeval"
@@ -1426,380 +1927,15 @@ luxio_gettimeofday(lua_State *L)
return 1;
}
-static int
-luxio_fork(lua_State *L)
-{
- int ret = fork();
-
- lua_pushinteger(L, ret);
-
- if (ret == -1) {
- lua_pushinteger(L, errno);
- return 2;
- }
-
- return 1;
-}
-
-static int
-luxio__exec(lua_State *L, bool usep)
-{
- const char *path = luaL_checkstring(L, 1);
- int params = lua_gettop(L) - 1;
- char **args;
- int c, ret;
-
- /* we probably at least need them to fill in arg[0] ... */
- luaL_checkstring(L, 2);
-
- args = calloc(params + 1, sizeof(*args));
-
- for (c = 0; c < params; c++) {
- /* gah! constness */
- args[c] = (char *)luaL_checkstring(L, c + 2);
- }
-
- args[c] = NULL;
-
- if (usep)
- ret = execvp(path, args);
- else
- ret = execv(path, args);
-
- /* if we got here, there's an error. */
- free(args);
- lua_pushinteger(L, ret);
- lua_pushinteger(L, errno);
- return 2;
-}
-
-static int
-luxio_exec(lua_State *L)
-{
- return luxio__exec(L, false);
-}
-
-static int
-luxio_execp(lua_State *L)
-{
- return luxio__exec(L, true);
-}
-
-static int
-luxio_waitpid(lua_State *L)
-{
- pid_t pid = luaL_checkinteger(L, 1);
- int options = luaL_checkinteger(L, 2);
- int status;
- pid_t proc;
-
- proc = waitpid(pid, &status, options);
- lua_pushinteger(L, proc);
- if (proc == -1) {
- lua_pushinteger(L, errno);
- } else {
- lua_pushinteger(L, status);
- }
-
- return 2;
-}
-
-#define WAITPID_STATUS(x) static int luxio_##x(lua_State *L) { \
- int status = luaL_checkinteger(L, 1); \
- lua_pushinteger(L, x(status)); \
- return 1; \
- }
-
-WAITPID_STATUS(WIFEXITED)
-WAITPID_STATUS(WEXITSTATUS)
-WAITPID_STATUS(WIFSIGNALED)
-WAITPID_STATUS(WTERMSIG)
-#ifdef WCOREDUMP
-WAITPID_STATUS(WCOREDUMP)
-#endif
-WAITPID_STATUS(WIFSTOPPED)
-WAITPID_STATUS(WSTOPSIG)
-#ifdef WIFCONTINUED
-WAITPID_STATUS(WIFCONTINUED)
-#endif
-
-#undef WAITPID_STATUS
-
-static int
-luxio_kill(lua_State *L)
-{
- pid_t pid = luaL_checkinteger(L, 1);
- int sig = luaL_checkinteger(L, 2);
-
- lua_pushinteger(L, kill(pid, sig));
- lua_pushinteger(L, errno);
-
- return 2;
-}
-
-static int
-luxio__exit(lua_State *L)
-{
- int ret = luaL_optinteger(L, 1, 0);
-
- _exit(ret);
-
- return 0;
-}
-
-static int
-luxio_setenv(lua_State *L)
-{
- const char *envvar = luaL_checkstring(L, 1);
- const char *envval = luaL_checkstring(L, 2);
- int overwrite = luaL_optint(L, 3, 1);
-
- lua_pushinteger(L, setenv(envvar, envval, overwrite));
- lua_pushinteger(L, errno);
-
- return 2;
-}
-
-static int
-luxio_unsetenv(lua_State *L)
-{
- const char *envvar = luaL_checkstring(L, 1);
-
- lua_pushinteger(L, unsetenv(envvar));
- lua_pushinteger(L, errno);
-
- return 2;
-}
-
-static int
-luxio_getenv(lua_State *L)
-{
- const char *envvar = luaL_checkstring(L, 1);
-
- char *envval = getenv(envvar);
-
- if (envval == NULL)
- return 0;
-
- lua_pushstring(L, envval);
-
- return 1;
-}
-
-/* readdir is a hideous API. We need to be reasonably high-level here,
- * otherwise everything is just too painful.
- */
-
-#define LUXIO_READDIR_METATABLE "luxio.readdir"
-
-typedef struct {
- DIR *dirp;
- struct dirent *buf, *ent;
-} luxio_readdir_state;
+/* Misc utility functions ****************************************************/
static int
-luxio_readdir_gc(lua_State *L)
-{
- luxio_readdir_state *s = luaL_checkudata(L, 1, LUXIO_READDIR_METATABLE);
-
- closedir(s->dirp);
- free(s->buf);
-
- return 0;
-}
-
-static int
-luxio_readdir_tostring(lua_State *L)
-{
- luxio_readdir_state *s = luaL_checkudata(L, 1, LUXIO_READDIR_METATABLE);
- char buf[sizeof("dirent: 0xffffffffffffffff")];
-
- snprintf(buf, sizeof(buf), "dirent: %p", s);
- lua_pushstring(L, buf);
- return 1;
-}
-
-static void
-luxio__bless_readdir(lua_State *L)
-{
- int create = luaL_newmetatable(L, LUXIO_READDIR_METATABLE);
-
- if (create != 0) {
- lua_pushcfunction(L, luxio_readdir_gc);
- lua_setfield(L, -2, "__gc");
- lua_pushcfunction(L, luxio_readdir_tostring);
- lua_setfield(L, -2, "__tostring");
- }
-
- lua_setmetatable(L, -2);
-}
-
-static int
-luxio_opendir(lua_State *L)
-{
- const char *path = luaL_checkstring(L, 1);
- DIR *d = opendir(path);
- size_t bufz;
- luxio_readdir_state *s;
-
- if (d == NULL) {
- lua_pushnil(L);
- lua_pushinteger(L, errno);
- return 2;
- }
-
- s = lua_newuserdata(L, sizeof(*s));
-
- s->dirp = d;
- /* + 256 because it'd always be +1 if it weren't for the horrors
- * of Solaris. If we were using autoconf, we could use Ben
- * Hutchings' function mentioned in the article above.
- */
- bufz = sizeof(struct dirent) + pathconf(path, _PC_NAME_MAX) + 256;
- s->buf = malloc(bufz);
-
- luxio__bless_readdir(L);
-
- return 1;
-}
-
-static int
-luxio_fdopendir(lua_State *L)
-{
- int fd = luaL_checkinteger(L, 1);
- DIR *d = fdopendir(fd);
- size_t bufz;
- luxio_readdir_state *s;
-
- if (d == NULL) {
- lua_pushnil(L);
- lua_pushinteger(L, errno);
- return 2;
- }
-
- s = lua_newuserdata(L, sizeof(*s));
-
- s->dirp = d;
- /* + 256 because it'd always be +1 if it weren't for the horrors
- * of Solaris. If we were using autoconf, we could use Ben
- * Hutchings' function mentioned in the article above.
- */
- bufz = sizeof(struct dirent) + fpathconf(fd, _PC_NAME_MAX) + 256;
- s->buf = malloc(bufz);
-
- luxio__bless_readdir(L);
-
- return 1;
-}
-
-static int
-luxio_closedir(lua_State *L)
-{
- luxio_readdir_state *s = luaL_checkudata(L, 1, LUXIO_READDIR_METATABLE);
-
- if (s->dirp != NULL) {
- closedir(s->dirp);
- s->dirp = NULL;
- }
-
- free(s->buf);
- s->buf = NULL;
-
- return 0;
-}
-
-static int
-luxio_readdir(lua_State *L)
+luxio_strerror(lua_State *L)
{
- luxio_readdir_state *s = luaL_checkudata(L, 1, LUXIO_READDIR_METATABLE);
- int err;
-
- err = readdir_r(s->dirp, s->buf, &s->ent);
-
- if (err == 0 && s->ent != NULL) {
- lua_pushinteger(L, 0);
- lua_newtable(L);
- lua_pushinteger(L, s->ent->d_ino);
- lua_setfield(L, -2, "d_ino");
- lua_pushstring(L, s->ent->d_name);
- lua_setfield(L, -2, "d_name");
-#ifdef HAVE_D_TYPE
- lua_pushinteger(L, s->ent->d_type);
- lua_setfield(L, -2, "d_type");
-#endif
- return 2;
- }
-
- if (s->ent == NULL) {
- /* end of directory */
- lua_pushnil(L);
- return 1;
- }
-
- lua_pushinteger(L, err);
+ lua_pushstring(L, strerror(luaL_checkint(L, 1)));
return 1;
}
-static int
-luxio_rewinddir(lua_State *L)
-{
- luxio_readdir_state *s = luaL_checkudata(L, 1, LUXIO_READDIR_METATABLE);
- rewinddir(s->dirp);
-
- return 0;
-}
-
-static int
-luxio_chdir(lua_State *L)
-{
- const char *path = luaL_checkstring(L, 1);
- lua_pushinteger(L, chdir(path));
- lua_pushinteger(L, errno);
- return 2;
-}
-
-static int
-luxio_getcwd(lua_State *L)
-{
- char buf[PATH_MAX];
-
- if (getcwd(buf, PATH_MAX) == NULL) {
- lua_pushnil(L);
- } else {
- lua_pushstring(L, buf);
- }
-
- lua_pushinteger(L, errno);
-
- return 2;
-}
-
-static int
-luxio_link(lua_State *L)
-{
- const char *existing = luaL_checkstring(L, 1);
- const char *new = luaL_checkstring(L, 2);
-
- lua_pushinteger(L, link(existing, new));
- lua_pushinteger(L, errno);
- return 2;
-}
-
-static int
-luxio_unlink(lua_State *L)
-{
- const char *s = luaL_checkstring(L, 1);
- int ret, err;
-
- ret = unlink(s);
- err = errno;
-
- lua_pushinteger(L, ret);
- lua_pushinteger(L, err);
-
- return 2;
-}
-
static const struct luaL_Reg
luxio_functions[] = {
{ "open", luxio_open },