From da9976c4c0c7155c87db2bb30f1e72cea54896c0 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Sat, 7 Mar 2026 15:56:26 +1100 Subject: [PATCH] Ground -> unistd interface --- libs/unistd/unistd.c | 316 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 316 insertions(+) create mode 100644 libs/unistd/unistd.c diff --git a/libs/unistd/unistd.c b/libs/unistd/unistd.c new file mode 100644 index 0000000..97e03db --- /dev/null +++ b/libs/unistd/unistd.c @@ -0,0 +1,316 @@ +#include +#include +#include +#include +#include +#include + +// Allows Ground to access the POSIX standard library. +// Read more here: https://en.wikipedia.org/wiki/Unistd.h + +// Misc functions + +GroundValue groundCrypt(GroundScope* scope, List args) { + char* hash = crypt(args.values[0].data.stringVal, args.values[1].data.stringVal); + if (hash == NULL) { + ERROR(strerror(errno), "CryptError"); + } + return groundCreateValue(STRING, hash); +} + +GroundValue groundGetHostId(GroundScope* scope, List args) { + return groundCreateValue(INT, (int64_t) gethostid()); +} + +GroundValue groundSetHostId(GroundScope* scope, List args) { + int result = sethostid((long) args.values[0].data.intVal); + if (result < 0) { + ERROR(strerror(errno), "SetHostIdError"); + } + return groundCreateValue(INT, (int64_t) result); +} + +GroundValue groundGetHostname(GroundScope* scope, List args) { + char* buf = malloc(256); + if (buf == NULL) { + ERROR("Couldn't allocate memory to store hostname", "GetHostnameError"); + } + int result = gethostname(buf, 255); + if (result < 0) { + ERROR(strerror(errno), "GetHostnameError"); + } + return groundCreateValue(INT, (int64_t) result); +} + +GroundValue groundSetHostname(GroundScope* scope, List args) { + int result = sethostname(args.values[0].data.stringVal, strlen(args.values[0].data.stringVal)); + if (result < 0) { + ERROR(strerror(errno), "SetHostnameError"); + } + return groundCreateValue(INT, (int64_t) result); +} + +// Signals + +GroundValue groundAlarm(GroundScope* scope, List args) { + unsigned result = alarm((unsigned) args.values[0].data.intVal); + return groundCreateValue(INT, (int64_t) result); +} + +GroundValue groundPause(GroundScope* scope, List args) { + int result = pause(); + ERROR(strerror(errno), "PauseError"); +} + +// Filesystem + +GroundValue groundAccess(GroundScope* scope, List args) { + int result = access(args.values[0].data.stringVal, (int) args.values[1].data.intVal); + return groundCreateValue(INT, (int64_t) result); +} + +GroundValue groundChdir(GroundScope* scope, List args) { + int result = chdir(args.values[0].data.stringVal); + if (result < 0) { + ERROR(strerror(errno), "ChdirError"); + } + return groundCreateValue(INT, (int64_t) result); +} + +GroundValue groundChown(GroundScope* scope, List args) { + int result = chown(args.values[0].data.stringVal, (uid_t) args.values[1].data.intVal, (gid_t) args.values[2].data.intVal); + if (result < 0) { + ERROR(strerror(errno), "ChownError"); + } + return groundCreateValue(INT, (int64_t) result); +} + +GroundValue groundLink(GroundScope* scope, List args) { + int result = link(args.values[0].data.stringVal, args.values[1].data.stringVal); + if (result < 1) { + ERROR(strerror(errno), "LinkError"); + } + return groundCreateValue(INT, (int64_t) result); +} + +GroundValue groundRmdir(GroundScope* scope, List args) { + int result = rmdir(args.values[0].data.stringVal); + if (result < 1) { + ERROR(strerror(errno), "RmdirError"); + } + return groundCreateValue(INT, (int64_t) result); +} + +GroundValue groundSymlink(GroundScope* scope, List args) { + int result = symlink(args.values[0].data.stringVal, args.values[1].data.stringVal); + if (result < 1) { + ERROR(strerror(errno), "SymlinkError"); + } + return groundCreateValue(INT, (int64_t) result); +} + +// Process + +GroundValue groundExit(GroundScope* scope, List args) { + _exit(args.values[0].data.intVal); + ERROR("Couldn't exit (huh?)", "ExitError"); +} + +GroundValue groundExecv(GroundScope* scope, List args) { + char** argv = malloc(sizeof(char*) * args.values[1].data.listVal.size + 1); + if (argv == NULL) { + ERROR("Couldn't allocate memory for execv list", "ExecvError"); + } + + for (size_t i = 0; i < args.values[1].data.listVal.size; i++) { + if (args.values[1].data.listVal.values[i].type != STRING) { + ERROR("Expecting all arguments in list to be of String type", "ExecvError"); + } + argv[i] = args.values[1].data.listVal.values[i].data.stringVal; + } + argv[args.values[1].data.listVal.size] = NULL; + + int result = execv(args.values[0].data.stringVal, argv); + + ERROR(strerror(errno), "ExecvError"); +} + +GroundValue groundExecvp(GroundScope* scope, List args) { + char** argv = malloc(sizeof(char*) * args.values[1].data.listVal.size + 1); + if (argv == NULL) { + ERROR("Couldn't allocate memory for execv list", "ExecvpError"); + } + + for (size_t i = 0; i < args.values[1].data.listVal.size; i++) { + if (args.values[1].data.listVal.values[i].type != STRING) { + ERROR("Expecting all arguments in list to be of String type", "ExecvpError"); + } + argv[i] = args.values[1].data.listVal.values[i].data.stringVal; + } + argv[args.values[1].data.listVal.size] = NULL; + + int result = execvp(args.values[0].data.stringVal, argv); + + ERROR(strerror(errno), "ExecvpError"); +} + +GroundValue groundFork(GroundScope* scope, List args) { + pid_t id = fork(); + if (id < 0) { + ERROR(strerror(errno), "ForkError"); + } + return groundCreateValue(INT, id); +} + +GroundValue groundGetPid(GroundScope* scope, List args) { + return groundCreateValue(INT, (int64_t) getpid()); +} + +GroundValue groundGetPPid(GroundScope* scope, List args) { + return groundCreateValue(INT, (int64_t) getppid()); +} + +GroundValue groundGetSid(GroundScope* scope, List args) { + pid_t result = getsid((pid_t) args.values[0].data.intVal); + if (result < 0) { + ERROR(strerror(errno), "GetSidError"); + } + return groundCreateValue(INT, (int64_t) result); +} + +GroundValue groundNice(GroundScope* scope, List args) { + int result = nice((int) args.values[0].data.intVal); + if (result < 0) { + ERROR(strerror(errno), "NiceError"); + } + return groundCreateValue(INT, (int64_t) result); +} + +GroundValue groundSetSid(GroundScope* scope, List args) { + pid_t result = setsid(); + if (result < 0) { + ERROR(strerror(errno), "SetSidError"); + } + return groundCreateValue(INT, (int64_t) result); +} + +GroundValue groundSleep(GroundScope* scope, List args) { + unsigned int result = sleep((unsigned int) args.values[0].data.intVal); + return groundCreateValue(INT, (int64_t) result); +} + +// User/Group + +GroundValue groundGetGid(GroundScope* scope, List args) { + return groundCreateValue(INT, (int64_t) getgid()); +} + +GroundValue groundGetEGid(GroundScope* scope, List args) { + return groundCreateValue(INT, (int64_t) getegid()); +} + +GroundValue groundGetUid(GroundScope* scope, List args) { + return groundCreateValue(INT, (int64_t) getuid()); +} + +GroundValue groundGetEUid(GroundScope* scope, List args) { + return groundCreateValue(INT, (int64_t) geteuid()); +} + +GroundValue groundGetLogin(GroundScope* scope, List args) { + char* login = getlogin(); + if (login == NULL) { + ERROR(strerror(errno), "GetLoginError"); + } + return groundCreateValue(STRING, login); +} + +GroundValue groundSetEUid(GroundScope* scope, List args) { + int result = seteuid((uid_t) args.values[0].data.intVal); + if (result < -1) { + ERROR(strerror(errno), "SetEUidError"); + } + return groundCreateValue(INT, (int64_t) result); +} + +GroundValue groundSetEGid(GroundScope* scope, List args) { + int result = setegid((uid_t) args.values[0].data.intVal); + if (result < -1) { + ERROR(strerror(errno), "SetEGidError"); + } + return groundCreateValue(INT, (int64_t) result); +} + +GroundValue groundSetREUid(GroundScope* scope, List args) { + int result = setreuid((uid_t) args.values[0].data.intVal, (uid_t) args.values[1].data.intVal); + if (result < -1) { + ERROR(strerror(errno), "SetREUidError"); + } + return groundCreateValue(INT, (int64_t) result); +} + +GroundValue groundSetREGid(GroundScope* scope, List args) { + int result = setregid((gid_t) args.values[0].data.intVal, (gid_t) args.values[1].data.intVal); + if (result < -1) { + ERROR(strerror(errno), "SetREGidError"); + } + return groundCreateValue(INT, (int64_t) result); +} + +GroundValue groundSetUid(GroundScope* scope, List args) { + int result = setuid((uid_t) args.values[0].data.intVal); + if (result < -1) { + ERROR(strerror(errno), "SetUidError"); + } + return groundCreateValue(INT, (int64_t) result); +} + +void ground_init(GroundScope* scope) { + + // Misc + groundAddNativeFunction(scope, "unistd_Crypt", groundCrypt, STRING, 2, STRING, "key", STRING, "value"); + groundAddNativeFunction(scope, "unistd_GetHostId", groundGetHostId, STRING, 0); + groundAddNativeFunction(scope, "unistd_SetHostId", groundSetHostId, INT, 1, INT, "hostid"); + groundAddNativeFunction(scope, "unistd_GetHostname", groundGetHostname, INT, 0); + groundAddNativeFunction(scope, "unistd_SetHostname", groundGetHostname, INT, 1, STRING, "name"); + + // Signals + groundAddNativeFunction(scope, "unistd_Alarm", groundAlarm, INT, 1, INT, "seconds"); + groundAddNativeFunction(scope, "unistd_Pause", groundPause, INT, 0); + + // Filesystem + groundAddValueToScope(scope, "unistd_F_OK", groundCreateValue(INT, F_OK)); + groundAddValueToScope(scope, "unistd_R_OK", groundCreateValue(INT, R_OK)); + groundAddValueToScope(scope, "unistd_W_OK", groundCreateValue(INT, W_OK)); + groundAddValueToScope(scope, "unistd_X_OK", groundCreateValue(INT, X_OK)); + + groundAddNativeFunction(scope, "unistd_Access", groundAccess, INT, 2, STRING, "path", INT, "mode"); + groundAddNativeFunction(scope, "unistd_Chdir", groundAccess, INT, 1, STRING, "path"); + groundAddNativeFunction(scope, "unistd_Chown", groundChown, INT, 3, STRING, "path", INT, "owner", INT, "group"); + groundAddNativeFunction(scope, "unistd_Link", groundLink, INT, 2, STRING, "oldpath", STRING, "newpath"); + groundAddNativeFunction(scope, "unistd_Rmdir", groundRmdir, INT, 1, STRING, "path"); + groundAddNativeFunction(scope, "unistd_Symlink", groundSymlink, INT, 2, STRING, "target", STRING, "linkpath"); + + // Process + groundAddNativeFunction(scope, "unistd_Exit", groundExit, INT, 1, INT, "status"); + groundAddNativeFunction(scope, "unistd_Execv", groundExecv, INT, 2, STRING, "path", LIST, "argv"); + groundAddNativeFunction(scope, "unistd_Execvp", groundExecvp, INT, 2, STRING, "path", LIST, "argv"); + groundAddNativeFunction(scope, "unistd_Fork", groundFork, INT, 0); + groundAddNativeFunction(scope, "unistd_GetPid", groundGetPid, INT, 0); + groundAddNativeFunction(scope, "unistd_GetPPid", groundGetPPid, INT, 0); + groundAddNativeFunction(scope, "unistd_GetSid", groundGetSid, INT, 1, INT, "pid"); + groundAddNativeFunction(scope, "unistd_Nice", groundNice, INT, 1, INT, "inc"); + groundAddNativeFunction(scope, "unistd_SetSid", groundSetSid, INT, 0); + groundAddNativeFunction(scope, "unistd_Sleep", groundSleep, INT, 1, INT, "seconds"); + + // User/Group + groundAddNativeFunction(scope, "unistd_GetGid", groundGetGid, INT, 0); + groundAddNativeFunction(scope, "unistd_GetEGid", groundGetEGid, INT, 0); + groundAddNativeFunction(scope, "unistd_GetUid", groundGetUid, INT, 0); + groundAddNativeFunction(scope, "unistd_GetEUid", groundGetEUid, INT, 0); + groundAddNativeFunction(scope, "unistd_GetLogin", groundGetLogin, STRING, 0); + groundAddNativeFunction(scope, "unistd_SetEUid", groundSetEUid, INT, 1, INT, "euid"); + groundAddNativeFunction(scope, "unistd_SetEGid", groundSetEGid, INT, 1, INT, "euid"); + groundAddNativeFunction(scope, "unistd_SetREUid", groundSetEGid, INT, 1, INT, "ruid", INT, "euid"); + groundAddNativeFunction(scope, "unistd_SetREGid", groundSetEGid, INT, 1, INT, "rgid", INT, "egid"); +}