Created
June 14, 2014 14:57
-
-
Save katlogic/a989dfe1fc4062a9ad13 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #define DEF_ERR(_) \ | |
| _(EPERM)_(ENOENT)_(ESRCH)_(EINTR)_(EIO)_(ENXIO)_(E2BIG)_(ENOEXEC) \ | |
| _(EBADF)_(ECHILD)_(EAGAIN)_(ENOMEM)_(EACCESS)_(EFAULT)_(ENOTBLK) \ | |
| _(EBUSY)_(EEXIST)_(EXDEV)_(ENODEV)_(ENOTDIR)_(EISDIR)_(EINVAL) \ | |
| _(ENFILE)_(EMFILE)_(ENOTTY)_(ETXTBSY)_(EFBIG)_(ENOSPC)_(ESPIPE) \ | |
| _(EROFS)_(EMLINK)_(EPIPE)_(EDOM)_(ENAMETOOLONG)_(ENOSYS)_(ELOOP) \ | |
| _(EAGAIN) | |
| #define DEF_SYMS(_) \ | |
| _(SEEK_SET)_(SEEK_CUR)_(SEEK_END) \ | |
| _(F_OK)_(R_OK)_(W_OK)_(X_OK) \ | |
| _(S_IFMT)_(S_IFSOCK)_(S_IFLNK)_(S_IFREG) \ | |
| _(S_IFBLK)_(S_IFDIR)_(S_IFCHR)_(S_IFIFO) \ | |
| _(S_ISUID)_(S_ISGID)_(S_ISVTX)_(S_IRWXU) \ | |
| _(S_IRUSR)_(S_IWUSR)_(S_IXUSR)_(S_IRWXG) \ | |
| _(S_IRGRP)_(S_IWGRP)_(S_IXGRP)_(S_IRWXO) \ | |
| _(S_IROTH)_(S_IWOTH)_(S_IXOTH) \ | |
| _(AT_SYMLINK_NOFOLLOW)_(AT_REMOVEDIR) \ | |
| _(AT_SYMLINK_FOLLOW)_(AT_EACCESS) \ | |
| _(AT_NO_AUTOMOUNT)_(AT_EMPTY_PATH) \ | |
| _(O_SEARCH)_(O_EXEC)_(O_PATH) \ | |
| _(O_ACCMODE)_(O_RDONLY)_(O_WRONLY) \ | |
| _(O_RDWR)_(F_RDLCK)_(F_WRLCK)_(F_UNLCK) \ | |
| _(FD_CLOEXEC) \ | |
| _(POSIX_FADV_NORMAL)_(POSIX_FADV_RANDOM) \ | |
| _(POSIX_FADV_SEQUENTIAL)_(POSIX_FADV_WILLNEED) \ | |
| _(POSIX_FADV_DONTNEED)_(POSIX_FADV_NOREUSE) \ | |
| _(F_ULOCK)_(F_LOCK)_(F_TLOCK)_(F_TEST) \ | |
| _(F_SETLEASE)_(F_GETLEASE)_(F_NOTIFY) \ | |
| _(F_CANCELLK)_(F_SETPIPE_SZ)_(F_GETPIPE_SZ) \ | |
| _(DN_ACCESS)_(DN_MODIFY)_(DN_CREATE) \ | |
| _(DN_DELETE)_(DN_RENAME)_(DN_ATTRIB) \ | |
| _(DN_MULTISHOT) \ | |
| _(RLIMIT_CORE)_(RLIMIT_CPU)_(RLIMIT_DATA) \ | |
| _(RLIMIT_FSIZE)_(RLIMIT_NOFILE)_(RLIMIT_STACK) \ | |
| _(RLIMIT_AS) \ | |
| _(FNM_PATHNAME)_(FNM_NOESCAPE)_(FNM_PERIOD) \ | |
| _(FNM_LEADING_DIR)_(FNM_CASEFOLD)_(FNM_FILE_NAME) \ | |
| _(FNM_NOMATCH) | |
| /* Mini-libiberty */ | |
| #ifndef HAVE_LIBIBERTY | |
| static const char *strerrno(int err) | |
| { | |
| #define SWITCH_AND_RET(e) case e: return #e; | |
| static char buf[16]; | |
| switch (err) { | |
| DEF_ERR(SWITCH_AND_RET) | |
| default: | |
| sprintf(buf, "E%d", err); | |
| return buf; | |
| } | |
| } | |
| #endif | |
| /* Template for errors. */ | |
| #define PUSHERR \ | |
| lua_pushnil(L); \ | |
| lua_pushstring(L, strerror(err)); \ | |
| lua_pushinteger(err); \ | |
| lua_pushstring(strerrno(err)); \ | |
| return 4; | |
| #define DOERR { \ | |
| int err = errno; \ | |
| PUSHERR | |
| } | |
| /* Tamplate for most APIs. */ | |
| #define CHECK(fn, ...) \ | |
| int res = fn(__VA_ARGS__) \ | |
| if (res < 0) \ | |
| DOERR; | |
| #define API(n, ...) \ | |
| static int fs_##n(lua_State *L) { \ | |
| HEADER \ | |
| CHECK(n, __VA_ARGS__) \ | |
| FOOTER \ | |
| } | |
| /* | |
| * Functions returning result (if no error) | |
| */ | |
| #define HEADER | |
| #define FOOTER lua_puhsinteger(L, res); return 1; | |
| API(access, STR, OPTINT(F_OK)) | |
| API(alarm, INT) | |
| API(acct, STR) | |
| API(chdir, STR) | |
| API(chown, STR, INT, INT) | |
| API(close, INT) | |
| API(faccessat, INT, STR, INT, OPTINT(F_OK)) | |
| API(fchdir, INT) | |
| API(fchown, INT, INT, INT) | |
| API(fchownat, INT, STR, INT, INT, OPTINT(0)) | |
| API(fdatasync, INT) | |
| API(fsync, INT) | |
| API(ftruncate, INT, NUM) | |
| API(lchown, STR, INT, INT) | |
| API(link, STR, STR) | |
| API(linkat, INT, STR, INT, STR, OPTINT(0)) | |
| API(lseek, INT, NUM, OPTINT(SEEK_END)) | |
| API(rename, STR, STR) | |
| API(renameat, INT, STR, INT, STR) | |
| API(rmdir, STR) | |
| API(setegid, INT) | |
| API(seteuid, INT) | |
| API(setgid, INT) | |
| API(setpgid, INT, INT) | |
| API(setregid, INT, INT) | |
| API(setresgid, INT, INT, INT) | |
| API(setresuid, INT, INT, INT) | |
| API(setreuid, INT, INT) | |
| API(setuid, INT) | |
| API(sleep, INT) | |
| API(usleep, INT) | |
| API(symlink, STR, STR) | |
| API(symlinkat, STR, INT, STR) | |
| API(tcsetpgrp, INT, INT) | |
| API(truncate, STR, NUM) | |
| API(chmod, STR, INT) | |
| API(fchmod, INT, INT) | |
| API(fchmodat, INT, STR, INT, OPTINT(0)) | |
| API(lchmod, STR, INT) | |
| API(unlink, STR) | |
| API(mkdir, STR, OPTINT(0755)) | |
| API(mkdirat, INT, STR, OPTINT(0755)) | |
| API(mkfifo, STR, OPTINT(0644)) | |
| API(mkfifoat, INT, STR, OPTINT(0644)) | |
| API(mknod, STR, OPTINT(0644)|S_IFIFO, OPTINT(0)) | |
| API(mknodat, INT, STR, OPTINT(0644)|S_IFIFO, OPTINT(0)) | |
| API(grantpt, INT) | |
| API(unlockpt, INT) | |
| API(dup, INT) | |
| API(dup2, INT, INT) | |
| API(getpgid, INT) | |
| API(getsid, OPTINT(0)) | |
| API(isatty, OPTINT(0)) | |
| API(nice, OPINT(20)) | |
| API(open, STR, OPTINT(O_RDONLY), OPTINT(0755)) | |
| API(openat, INT, STR, OPTINT(O_RDONLY), OPTINT(0755)) | |
| API(posix_openpt, OPTINT(O_RDWR)) | |
| API(tcgetpgrp, INT) | |
| API(umask) | |
| API(getegid,) | |
| API(geteuid,) | |
| API(getpgrp,) | |
| API(getpid,) | |
| API(getppid,) | |
| API(getuid,) | |
| API(setpgrp,) | |
| API(setsid,) | |
| /* | |
| * Functions returning string (with buffer as input) | |
| */ | |
| #define HEADER char buf[PATH_MAX+1]; | |
| #define FOOTER buf[PATH_MAX] = 0; lua_pushstring(L, buf); return 1 | |
| #define CHECK(fn, realfn, ...) \ | |
| const char *res = realfn(__VA_ARGS__) \ | |
| if (!res) \ | |
| DOERR; | |
| API(getcwd, buf, PATH_MAX) | |
| API(basename, strcpy(buf, STR)) | |
| API(dirname, strcpy(buf, STR)) | |
| API(readlink, STR, buf, PATH_MAX) | |
| API(realpath, STR, buf) | |
| API(readlinkat, INT, STR, buf, PATH_MAX) | |
| API(mkstemp, strcpy(buf, STR)) | |
| API(mkdtemp, strcpy(buf, STR)) | |
| API(mkstemps, strcpy(buf, STR), INT) | |
| API(tmpnam, strcpy(buf, STR)) | |
| API(ctermid,) | |
| /* Slightly renamed */ | |
| #undef CHECK | |
| #define CHECK(fn, realfn, ...) \ | |
| const char *res = realfn(__VA_ARGS__) \ | |
| if (!res) \ | |
| DOERR; | |
| API(ttyname, ttyname_r, INT, buf, sizeof(buf)) | |
| API(ptsname, ptsname_r, INT, buf, sizeof(buf)) | |
| API(getlogin, getlogin_r, buf, sizeof(buf)) | |
| /* | |
| * Get file/fs status. | |
| */ | |
| #undef HEADER | |
| #undef FOOTER | |
| #define HEADER struct stat st; | |
| #define FOOTER return stat_convert(L, &st); | |
| #define PUSH lua_pushvalue(L, -1); \ | |
| lua_setfield(L, -3, #PUSHER_STRUCT "_" #n);lua_rawseti(L, -2, ++counter); | |
| #define PUSH_NUMS(n) lua_pushnumber(L, \ | |
| PUSHER_STRUCT->##PUSHER_STRUCT##_##n); PUSH | |
| #define PUSH_STRINGS(n) lua_pushstring(L, \ | |
| PUSHER_STRUCT->##PUSHER_STRUCT##_##n); PUSH | |
| #define ST_FIELDS(N) \ | |
| N(dev) N(ino) N(mode) N(nlink) N(uid) \ | |
| N(gid) N(rdev) N(size) N(blksize)N(blocks) \ | |
| N(atime)N(mtime)N(ctime) | |
| static int stat_convert(lua_State *L, const struct stat *st) | |
| { | |
| /* Poop. */ | |
| int counter = 0; | |
| lua_createtable(L, 14, 14) | |
| #define PUSHER_STRUCT st | |
| ST_FIELDS(PUSH_NUMS) | |
| #undef PUSHER_STRUCT | |
| return 1; | |
| } | |
| API(stat, STR) | |
| API(fstat, INT) | |
| API(lstat, INT) | |
| #define F_FIELDS(N) \ | |
| N(bsize)N(frsize) N(blocks) N(bfree)N(bavail) \ | |
| N(files)N(ffree) N(favail) N(fsid) N(flag) \ | |
| N(fnamemax) | |
| static int statvfs_convert(lua_State *L, const struct statvfs *f) | |
| { | |
| /* Poop. */ | |
| int counter = 0; | |
| lua_createtable(L, 13, 13) | |
| #define PUSHER_STRUCT f | |
| F_FIELDS(PUSH_NUMS) | |
| #undef PUSHER_STRUCT | |
| return 1; | |
| } | |
| #undef FOOTER | |
| #define FOOTER return statvfs_convert(L, &st); | |
| API(statvfs, STR) | |
| API(fstatvfs, INT) | |
| /* | |
| * Miscalleneous functions which don't fit the macro templates very well. | |
| */ | |
| #undef API | |
| #define API(n) \ | |
| static int fs_##n(lua_State *L) | |
| API(pause) { pause(); return 0; } | |
| API(sync) { sync(); return 0; } | |
| API(abort) { abort(); return 0; } | |
| /* | |
| * File IO. | |
| */ | |
| API(pipe) { | |
| int p[2]; | |
| CHECK(pipe, p); | |
| lua_pushinteger(p[0]); | |
| lua_pushinteger(p[1]); | |
| return 2; | |
| } | |
| API(pread) { | |
| int fd = luaL_checkint(L, 1); | |
| ssize_t got; | |
| size_t pfxsz = 0; | |
| const char *pfx = lua_tolstring(L, 2, &pfxsz); | |
| size_t nbyte = luaL_optint(L, 3, 4096); | |
| char buf[nbyte+pfxsz]; /* C99 */ | |
| lua_Number off = luaL_optnumber(L, 4, -1); | |
| if (pfx) | |
| memcpy(buf, pfx, pfxsz); | |
| if (off >= 0) { | |
| got = pread(fd, buf + pfxsz, nbyte, off); | |
| } else { | |
| got = read(fd, buf + pfxsz, nbyte); | |
| } | |
| if (got < 0) | |
| DOERR; | |
| lua_pushlstring(L, buf, pfxsz + got); | |
| lua_pushnumber(L, got); | |
| return 2; | |
| } | |
| API(read) { | |
| lua_settop(L, 3); | |
| return fs_pread(L); | |
| } | |
| API(pwrite) { | |
| int fd = luaL_checkint(L, 1); | |
| ssize_t got; | |
| size_t nbyte = 0; | |
| const char *buf = lua_checklstring(L, 2, &pfxsz); | |
| nbyte = luaL_optint(L, 3, nbyte); | |
| lua_Number off = luaL_optnumber(L, 4, -1); | |
| if (off >= 0) { | |
| got = pwrite(fd, buf, nbyte, off); | |
| } else { | |
| got = read(fd, buf, nbyte); | |
| } | |
| if (got < 0) | |
| DOERR; | |
| lua_pushnumber(L, got); | |
| return 1; | |
| } | |
| API(write) { | |
| lua_settop(L, 3); | |
| return fs_pwrite(L); | |
| } | |
| API(fileno) { | |
| FILE *f = *(FILE**) luaL_checkudata(L, 1, LUA_FILEHANDLE); | |
| lua_pushinteger(L, fileno(f)); | |
| return 1; | |
| } | |
| /* | |
| * Time handling. | |
| */ | |
| API(gettimeofday) | |
| { | |
| struct timeval tv; | |
| gettimeofday(&tv, NULL); | |
| lua_pushinteger(L, tv.tv_sec); | |
| lua_pushinteger(L, tv.tv_usec); | |
| return 2; | |
| } | |
| API(time) | |
| { | |
| lua_pushinteger(L, time(NULL)); | |
| return 1; | |
| } | |
| #define TM_FIELDS(N) \ | |
| N(sec) N(min) N(hour)N(mday)N(mon) \ | |
| N(year) N(wday) N(yday)N(isdst) | |
| static int tm2tab(lua_State *L, struct tm *tm) | |
| { | |
| int counter = 0; | |
| if (!tm) | |
| DOERR; | |
| lua_createtable(L, 10, 10) | |
| #define PUSHER_STRUCT tm | |
| TM_FIELDS(PUSH_NUMS) | |
| #undef PUSHER_STRUCT | |
| return 1; | |
| } | |
| static struct tm *tab2tm(lua_State *L, int idx, struct tm *tm) | |
| { | |
| #define GET_TM(n) \ | |
| lua_getfield(L, idx, "tm_" #n); tm->n = lua_tointeger(L, -1); lua_pop(L, 1); | |
| TM_FIELDS(GET_TM) | |
| } | |
| API(localtime) | |
| { | |
| time_t t = luaL_checkint(L, 1); | |
| struct tm tm; | |
| return tm2tab(L, localtime_r(&t, &tm)); | |
| } | |
| API(gmtime) | |
| { | |
| time_t t = luaL_checkint(L, 1); | |
| struct tm tm; | |
| return tm2tab(L, gmtime_r(&t, &tm)); | |
| } | |
| API(strftime) | |
| { | |
| char buf[BUFSZ]; | |
| struct tm tm; | |
| if (lua_isniL(L, 2)) { | |
| t = time(NULL); | |
| localtime_r(&t, &tm); | |
| } else { | |
| tab2tm(L, 1, &tm); | |
| } | |
| lua_pushlstring(L, buf, | |
| strftime(buf, sizeof(buf), luaL_checkstring(L, 1), &tm)); | |
| return 1; | |
| } | |
| /* | |
| * Access to passwd/group files. | |
| */ | |
| #define PW_FIELDS(S,N) \ | |
| S(name) S(passwd) N(uid) N(gid) \ | |
| S(gecos) S(dir) S(shell) | |
| static int pw2tab(lua_State *L, struct passwd **pwp, int xerr) | |
| { | |
| int counter = 0; | |
| struct passwd *pw = *pwp; | |
| if (xerr < 0) | |
| DOERR; | |
| if (!pw) | |
| PUSHERR; | |
| lua_createtable(L, 8, 8); | |
| #define PUSHER_STRUCT pw | |
| PW_FIELDS(PUSH_NUMS, PUSH_STRINGS) | |
| #undef PUSHER_STRUCT | |
| return 1; | |
| } | |
| API(getpwnam) | |
| { | |
| struct passwd pw, *pwp = NULL; | |
| char bufs[BUFSZ]; | |
| return pw2tab(L, &pwp, xerr, | |
| getpwnam_r(luaL_checkstring(L, 1), | |
| &pw, bufs, sizeof(bufs), &pwp)); | |
| } | |
| API(getpwuid) | |
| { | |
| struct passwd pw, *pwp = NULL; | |
| char bufs[BUFSZ]; | |
| return pw2tab(L, &pwp, xerr, | |
| getpwuid_r(luaL_checkint(L, 1), | |
| &pw, bufs, sizeof(bufs), &pwp)); | |
| } | |
| static int gr2tab(lua_State *L, struct group **grp, int xerr) | |
| { | |
| int counter = 0; | |
| struct group *gr = *pwp; | |
| int i; | |
| if (xerr < 0) | |
| DOERR; | |
| if (!gr) | |
| PUSHERR; | |
| lua_newtable(L, 0, 0); | |
| lua_pushstring(L, gr->gr_name); lua_setfield(L, -2, "gr_name"); | |
| lua_pushstring(L, gr->gr_passwd); lua_setfield(L, -2, "gr_passwd"); | |
| lua_pushinteger(L, gr->gr_grgid); lua_setfield(L, -2, "gr_grgid"); | |
| lua_newtable(L) | |
| for (i = 0; gr->gr_mem[i]; i++) { // Table of members. | |
| lua_pushstring(L, gr->gr_mem[i]); | |
| lua_rawseti(L, -2, i+1); | |
| } | |
| lua_setfield(L, -2, "gr_mem"); | |
| return 1; | |
| } | |
| API(getgrnam) | |
| { | |
| struct group gr, *grp = NULL; | |
| char bufs[BUFSZ]; | |
| return gr2tab(L, &grp, xerr, | |
| getgrnam_r(luaL_checkstring(L, 1), | |
| &gr, bufs, sizeof(bufs), &grp)); | |
| } | |
| API(getgruid) | |
| { | |
| struct group gr, *grp = NULL; | |
| char bufs[BUFSZ]; | |
| return gr2tab(L, &grp, xerr, | |
| getgruid_r(luaL_checkint(L, 1), | |
| &gr, bufs, sizeof(bufs), &grp)); | |
| } | |
| API(getgroups) { | |
| int i; | |
| gid_t grouplist[NGROUPS_MAX+1]; | |
| CHECK(getgroups, NGROUPS_MAX, grouplist); | |
| lua_createtable(L, i, 0); | |
| for (i = 0; i < res; i++) { | |
| lua_pushinteger(L, grouplist[i]); | |
| lua_rawseti(L, -2, i+1); | |
| } | |
| return 1; | |
| } | |
| #define IMPLEMENTS(_) \ | |
| _(strftime)_(gmtime)_(localtime)_(time)_(gettimeofday)_(fileno) \ | |
| _(write)_(pwrite)_(read)_(pread)_(pipe)_(getgroups)_(abort) \ | |
| _(sync)_(pause)_(lstat)_(fstat)_(stat)_(ptsname)_(ttyname) \ | |
| _(tmpname)_(mkstemps)_(mkdtemp)_(mkstemp)_(readlinkat) \ | |
| _(realpath)_(readlink)_(dirname)_(basename)_(getcwd) \ | |
| _(access)_(alarm)_(acct)_(chdir)_(chown)_(close) \ | |
| _(faccessat)_(fchdir)_(fchown)_(fchownat)_(fdatasync) \ | |
| _(fsync)_(ftruncate)_(lchown)_(link)_(linkat)_(lseek) \ | |
| _(rename)_(renameat)_(rmdir)_(setegid)_(seteuid) \ | |
| _(setgid)_(setpgid)_(setregid)_(setresgid)_(setresuid) \ | |
| _(setuid)_(sleep)_(usleep)_(symlink)_(symlinkat) \ | |
| _(tcsetpgrp)_(truncate)_(chmod)_(fchmod)_(fchmodat) \ | |
| _(lchmod)_(unlink)_(mkdir)_(mkdirat)_(mkfifo)_(mkfifoat) \ | |
| _(mknod)_(mknodat)_(grantpt)_(unlockpt)_(dup)_(dup2) \ | |
| _(getpgid)_(getsid)_(isatty)_(nice)_(open)_(openat) \ | |
| _(posix_openpt)_(tcgetpgrp)_(umask) \ | |
| _(getegid)_(geteuid)_(getpgrp)_(getpid)_(getppid) \ | |
| _(getuid)_(setpgrp)_(setsid)_(getpwnam) | |
| #define REG(n) \ | |
| { #n, fs_##n }, | |
| static const luaL_Reg[] = { | |
| IMPLEMENTS(REG) | |
| { NULL, NULL } | |
| }; | |
| int luaopen_unistd() | |
| { | |
| lua_newtable(L); | |
| #define PUSH_CONST(n) lua_pushnumber(L, n) lua_setfield(L, -2, #n) | |
| DEF_ERR(PUSH_CONSTS) | |
| DEF_SYMS(PUSH_CONSTS) | |
| luaL_register(L, NULL, unistd_reg); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment