summaryrefslogtreecommitdiff
path: root/quickjs-libc.c
diff options
context:
space:
mode:
authorbellard <6490144+bellard@users.noreply.github.com>2020-09-06 19:04:20 +0200
committerbellard <6490144+bellard@users.noreply.github.com>2020-09-06 19:04:20 +0200
commit1722758717730ac0838418f142d82ca3cff4ad4b (patch)
tree24971b26d2ae8c5442bc5a898b203ce1d75a7e0e /quickjs-libc.c
parent383e2b06c8af144b5cd729dc7bc4ce2e2613f178 (diff)
downloadquickjs-1722758717730ac0838418f142d82ca3cff4ad4b.tar.gz
quickjs-1722758717730ac0838418f142d82ca3cff4ad4b.zip
2020-04-12 release
Diffstat (limited to 'quickjs-libc.c')
-rw-r--r--quickjs-libc.c180
1 files changed, 174 insertions, 6 deletions
diff --git a/quickjs-libc.c b/quickjs-libc.c
index 3ff5168..4e6d221 100644
--- a/quickjs-libc.c
+++ b/quickjs-libc.c
@@ -239,6 +239,7 @@ static JSValue js_printf_internal(JSContext *ctx,
case 's':
if (i >= argc)
goto missing;
+ /* XXX: handle strings containing null characters */
string_arg = JS_ToCString(ctx, argv[i++]);
if (!string_arg)
goto fail;
@@ -843,6 +844,7 @@ static JSValue js_std_file_puts(JSContext *ctx, JSValueConst this_val,
FILE *f;
int i;
const char *str;
+ size_t len;
if (magic == 0) {
f = stdout;
@@ -853,10 +855,10 @@ static JSValue js_std_file_puts(JSContext *ctx, JSValueConst this_val,
}
for(i = 0; i < argc; i++) {
- str = JS_ToCString(ctx, argv[i]);
+ str = JS_ToCStringLen(ctx, &len, argv[i]);
if (!str)
return JS_EXCEPTION;
- fputs(str, f);
+ fwrite(str, 1, len, f);
JS_FreeCString(ctx, str);
}
return JS_UNDEFINED;
@@ -2325,6 +2327,121 @@ static JSValue js_os_utimes(JSContext *ctx, JSValueConst this_val,
return JS_NewInt32(ctx, ret);
}
+static char **build_envp(JSContext *ctx, JSValueConst obj)
+{
+ uint32_t len, i;
+ JSPropertyEnum *tab;
+ char **envp, *pair;
+ const char *key, *str;
+ JSValue val;
+ size_t key_len, str_len;
+
+ if (JS_GetOwnPropertyNames(ctx, &tab, &len, obj,
+ JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0)
+ return NULL;
+ envp = js_mallocz(ctx, sizeof(envp[0]) * ((size_t)len + 1));
+ if (!envp)
+ goto fail;
+ for(i = 0; i < len; i++) {
+ val = JS_GetProperty(ctx, obj, tab[i].atom);
+ if (JS_IsException(val))
+ goto fail;
+ str = JS_ToCString(ctx, val);
+ JS_FreeValue(ctx, val);
+ if (!str)
+ goto fail;
+ key = JS_AtomToCString(ctx, tab[i].atom);
+ if (!key) {
+ JS_FreeCString(ctx, str);
+ goto fail;
+ }
+ key_len = strlen(key);
+ str_len = strlen(str);
+ pair = js_malloc(ctx, key_len + str_len + 2);
+ if (!pair) {
+ JS_FreeCString(ctx, key);
+ JS_FreeCString(ctx, str);
+ goto fail;
+ }
+ memcpy(pair, key, key_len);
+ pair[key_len] = '=';
+ memcpy(pair + key_len + 1, str, str_len);
+ pair[key_len + 1 + str_len] = '\0';
+ envp[i] = pair;
+ JS_FreeCString(ctx, key);
+ JS_FreeCString(ctx, str);
+ }
+ done:
+ for(i = 0; i < len; i++)
+ JS_FreeAtom(ctx, tab[i].atom);
+ js_free(ctx, tab);
+ return envp;
+ fail:
+ if (envp) {
+ for(i = 0; i < len; i++)
+ js_free(ctx, envp[i]);
+ js_free(ctx, envp);
+ envp = NULL;
+ }
+ goto done;
+}
+
+/* execvpe is not available on non GNU systems */
+static int my_execvpe(const char *filename, char **argv, char **envp)
+{
+ char *path, *p, *p_next, *p1;
+ char buf[PATH_MAX];
+ size_t filename_len, path_len;
+ BOOL eacces_error;
+
+ filename_len = strlen(filename);
+ if (filename_len == 0) {
+ errno = ENOENT;
+ return -1;
+ }
+ if (strchr(filename, '/'))
+ return execve(filename, argv, envp);
+
+ path = getenv("PATH");
+ if (!path)
+ path = "/bin:/usr/bin";
+ eacces_error = FALSE;
+ p = path;
+ for(p = path; p != NULL; p = p_next) {
+ p1 = strchr(p, ':');
+ if (!p1) {
+ p_next = NULL;
+ path_len = strlen(p);
+ } else {
+ p_next = p1 + 1;
+ path_len = p1 - p;
+ }
+ /* path too long */
+ if ((path_len + 1 + filename_len + 1) > PATH_MAX)
+ continue;
+ memcpy(buf, p, path_len);
+ buf[path_len] = '/';
+ memcpy(buf + path_len + 1, filename, filename_len);
+ buf[path_len + 1 + filename_len] = '\0';
+
+ execve(buf, argv, envp);
+
+ switch(errno) {
+ case EACCES:
+ eacces_error = TRUE;
+ break;
+ case ENOENT:
+ case ENOTDIR:
+ break;
+ default:
+ return -1;
+ }
+ }
+ if (eacces_error)
+ errno = EACCES;
+ return -1;
+}
+
/* exec(args[, options]) -> exitcode */
static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
@@ -2332,11 +2449,13 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
JSValueConst options, args = argv[0];
JSValue val, ret_val;
const char **exec_argv, *file = NULL, *str, *cwd = NULL;
+ char **envp = environ;
uint32_t exec_argc, i;
int ret, pid, status;
BOOL block_flag = TRUE, use_path = TRUE;
static const char *std_name[3] = { "stdin", "stdout", "stderr" };
int std_fds[3];
+ uint32_t uid = -1, gid = -1;
val = JS_GetPropertyStr(ctx, args, "length");
if (JS_IsException(val))
@@ -2410,6 +2529,36 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
std_fds[i] = fd;
}
}
+
+ val = JS_GetPropertyStr(ctx, options, "env");
+ if (JS_IsException(val))
+ goto exception;
+ if (!JS_IsUndefined(val)) {
+ envp = build_envp(ctx, val);
+ JS_FreeValue(ctx, val);
+ if (!envp)
+ goto exception;
+ }
+
+ val = JS_GetPropertyStr(ctx, options, "uid");
+ if (JS_IsException(val))
+ goto exception;
+ if (!JS_IsUndefined(val)) {
+ ret = JS_ToUint32(ctx, &uid, val);
+ JS_FreeValue(ctx, val);
+ if (ret)
+ goto exception;
+ }
+
+ val = JS_GetPropertyStr(ctx, options, "gid");
+ if (JS_IsException(val))
+ goto exception;
+ if (!JS_IsUndefined(val)) {
+ ret = JS_ToUint32(ctx, &gid, val);
+ JS_FreeValue(ctx, val);
+ if (ret)
+ goto exception;
+ }
}
pid = fork();
@@ -2435,12 +2584,21 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
if (chdir(cwd) < 0)
_exit(127);
}
+ if (uid != -1) {
+ if (setuid(uid) < 0)
+ _exit(127);
+ }
+ if (gid != -1) {
+ if (setgid(gid) < 0)
+ _exit(127);
+ }
+
if (!file)
file = exec_argv[0];
if (use_path)
- ret = execvp(file, (char **)exec_argv);
+ ret = my_execvpe(file, (char **)exec_argv, envp);
else
- ret = execv(file, (char **)exec_argv);
+ ret = execve(file, (char **)exec_argv, envp);
_exit(127);
}
/* parent */
@@ -2467,6 +2625,15 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
for(i = 0; i < exec_argc; i++)
JS_FreeCString(ctx, exec_argv[i]);
js_free(ctx, exec_argv);
+ if (envp != environ) {
+ char **p;
+ p = envp;
+ while (*p != NULL) {
+ js_free(ctx, *p);
+ p++;
+ }
+ js_free(ctx, envp);
+ }
return ret_val;
exception:
ret_val = JS_EXCEPTION;
@@ -2700,14 +2867,15 @@ static JSValue js_print(JSContext *ctx, JSValueConst this_val,
{
int i;
const char *str;
+ size_t len;
for(i = 0; i < argc; i++) {
if (i != 0)
putchar(' ');
- str = JS_ToCString(ctx, argv[i]);
+ str = JS_ToCStringLen(ctx, &len, argv[i]);
if (!str)
return JS_EXCEPTION;
- fputs(str, stdout);
+ fwrite(str, 1, len, stdout);
JS_FreeCString(ctx, str);
}
putchar('\n');