1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <csignal>
17 #include <cstdio>
18 #include <dirent.h>
19 #include <fcntl.h>
20 #include <js_native_api.h>
21 #include <js_native_api_types.h>
22 #include <node_api.h>
23 #include <spawn.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 
27 #define FAIL (-1)
28 #define SUCCESS 0
29 #define PARAM_0 0
30 #define PARAM_1 1
31 #define PARAM_256 256
32 #define PARAM_0777 0777
33 #define PARAM_MINUS_1 (-1)
34 #define BAD_FD (-1)
35 
PosixSpawn(napi_env env, napi_callback_info info)36 static napi_value PosixSpawn(napi_env env, napi_callback_info info)
37 {
38     size_t argc = PARAM_1;
39     napi_value args[1] = {nullptr};
40     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
41     int param;
42     napi_get_value_int32(env, args[0], &param);
43 
44     int ret;
45     pid_t pid;
46     if (param == PARAM_0) {
47         posix_spawnattr_t attr;
48         posix_spawnattr_init(&attr);
49         const char *argv[] = {"sh", "-c", "echo", nullptr};
50         ret = posix_spawn(&pid, "/bin/sh", nullptr, &attr, (char *const *)argv, nullptr);
51         posix_spawnattr_destroy(&attr);
52     } else {
53         ret = posix_spawn(&pid, "unexitfile", nullptr, nullptr, nullptr, nullptr);
54     }
55 
56     if (ret != SUCCESS) {
57         ret = FAIL;
58     }
59     napi_value result = nullptr;
60     napi_create_int32(env, ret, &result);
61     return result;
62 }
63 
PosixSpawnFileActionsAddclose(napi_env env, napi_callback_info info)64 static napi_value PosixSpawnFileActionsAddclose(napi_env env, napi_callback_info info)
65 {
66     size_t argc = PARAM_1;
67     napi_value args[1] = {nullptr};
68     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
69     int param;
70     napi_get_value_int32(env, args[0], &param);
71 
72     int ret;
73     posix_spawn_file_actions_t actions;
74     posix_spawn_file_actions_init(&actions);
75     if (param == PARAM_0) {
76         int p[2];
77         pipe(p);
78         ret = posix_spawn_file_actions_addclose(&actions, p[0]);
79         close(p[1]);
80         close(p[0]);
81     } else {
82         ret = posix_spawn_file_actions_addclose(&actions, BAD_FD);
83     }
84     posix_spawn_file_actions_destroy(&actions);
85     if (ret != PARAM_0) {
86         ret = FAIL;
87     }
88 
89     napi_value result = nullptr;
90     napi_create_int32(env, ret, &result);
91     return result;
92 }
93 
PosixSpawnFileActionsAddDup2(napi_env env, napi_callback_info info)94 static napi_value PosixSpawnFileActionsAddDup2(napi_env env, napi_callback_info info)
95 {
96     size_t argc = PARAM_1;
97     napi_value args[1] = {nullptr};
98     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
99     int param;
100     napi_get_value_int32(env, args[0], &param);
101 
102     int ret;
103     posix_spawn_file_actions_t actions;
104     if (param == PARAM_0) {
105         posix_spawn_file_actions_init(&actions);
106         ret = posix_spawn_file_actions_adddup2(&actions, SUCCESS, SUCCESS);
107         posix_spawn_file_actions_destroy(&actions);
108     } else {
109         ret = posix_spawn_file_actions_adddup2(&actions, BAD_FD, BAD_FD);
110     }
111     if (ret != SUCCESS) {
112         ret = FAIL;
113     }
114 
115     napi_value result = nullptr;
116     napi_create_int32(env, ret, &result);
117     return result;
118 }
119 
PosixSpawnFileActionsAddOpen(napi_env env, napi_callback_info info)120 static napi_value PosixSpawnFileActionsAddOpen(napi_env env, napi_callback_info info)
121 {
122     char path[] = "/data/storage/el2/base/files/fzl.txt";
123     size_t argc = PARAM_1;
124     napi_value args[1] = {nullptr};
125     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
126     int param;
127     napi_get_value_int32(env, args[0], &param);
128 
129     int ret;
130     posix_spawn_file_actions_t actions;
131     if (param == PARAM_0) {
132         int fd = open(path, O_CREAT, PARAM_0777);
133         posix_spawn_file_actions_init(&actions);
134         ret = posix_spawn_file_actions_addopen(&actions, fd, path, O_CREAT, S_IXGRP);
135         posix_spawn_file_actions_destroy(&actions);
136         close(fd);
137         remove(path);
138     } else {
139         ret = posix_spawn_file_actions_addopen(&actions, BAD_FD, path, O_CREAT, S_IXGRP);
140     }
141     if (ret != SUCCESS) {
142         ret = FAIL;
143     }
144 
145     napi_value result = nullptr;
146     napi_create_int32(env, ret, &result);
147     return result;
148 }
149 
PosixSpawnFileActionsDestroy(napi_env env, napi_callback_info info)150 static napi_value PosixSpawnFileActionsDestroy(napi_env env, napi_callback_info info)
151 {
152     size_t argc = PARAM_1;
153     napi_value args[1] = {nullptr};
154     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
155     int param;
156     napi_get_value_int32(env, args[0], &param);
157 
158     int ret = FAIL;
159     if (param == PARAM_0) {
160         posix_spawn_file_actions_t actions;
161         posix_spawn_file_actions_init(&actions);
162         ret = posix_spawn_file_actions_destroy(&actions);
163     }
164 
165     napi_value result = nullptr;
166     napi_create_int32(env, ret, &result);
167     return result;
168 }
169 
PosixSpawnFileActionsInit(napi_env env, napi_callback_info info)170 static napi_value PosixSpawnFileActionsInit(napi_env env, napi_callback_info info)
171 {
172     size_t argc = PARAM_1;
173     napi_value args[1] = {nullptr};
174     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
175     int param;
176     napi_get_value_int32(env, args[0], &param);
177 
178     int ret = FAIL;
179     if (param == PARAM_0) {
180         posix_spawn_file_actions_t actions;
181         ret = posix_spawn_file_actions_init(&actions);
182         posix_spawn_file_actions_destroy(&actions);
183     }
184 
185     napi_value result = nullptr;
186     napi_create_int32(env, ret, &result);
187     return result;
188 }
189 
PosixSpawnAttrDestroy(napi_env env, napi_callback_info info)190 static napi_value PosixSpawnAttrDestroy(napi_env env, napi_callback_info info)
191 {
192     size_t argc = PARAM_1;
193     napi_value args[1] = {nullptr};
194     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
195     int param;
196     napi_get_value_int32(env, args[0], &param);
197 
198     int ret = FAIL;
199     if (param == PARAM_0) {
200         posix_spawnattr_t attr;
201         posix_spawnattr_init(&attr);
202         ret = posix_spawnattr_destroy(&attr);
203     }
204 
205     napi_value result = nullptr;
206     napi_create_int32(env, ret, &result);
207     return result;
208 }
209 
PosixSpawnAttrGetflags(napi_env env, napi_callback_info info)210 static napi_value PosixSpawnAttrGetflags(napi_env env, napi_callback_info info)
211 {
212     size_t argc = PARAM_1;
213     napi_value args[1] = {nullptr};
214     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
215     int param;
216     napi_get_value_int32(env, args[0], &param);
217 
218     int ret = FAIL;
219     posix_spawnattr_t attr;
220     if (param == PARAM_0) {
221         short flags = PARAM_0;
222         posix_spawnattr_init(&attr);
223         posix_spawnattr_setflags(&attr, POSIX_SPAWN_RESETIDS);
224         ret = posix_spawnattr_getflags(&attr, &flags);
225         posix_spawnattr_destroy(&attr);
226     }
227 
228     napi_value result = nullptr;
229     napi_create_int32(env, ret, &result);
230     return result;
231 }
232 
PosixSpawnAttrGetpGroup(napi_env env, napi_callback_info info)233 static napi_value PosixSpawnAttrGetpGroup(napi_env env, napi_callback_info info)
234 {
235     size_t argc = PARAM_1;
236     napi_value args[1] = {nullptr};
237     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
238     int param;
239     napi_get_value_int32(env, args[0], &param);
240 
241     int ret = FAIL;
242     if (param == PARAM_0) {
243         posix_spawnattr_t spawnattr;
244         pid_t group = PARAM_MINUS_1;
245         posix_spawnattr_init(&spawnattr);
246         ret = posix_spawnattr_getpgroup(&spawnattr, &group);
247         posix_spawnattr_destroy(&spawnattr);
248     }
249 
250     napi_value result = nullptr;
251     napi_create_int32(env, ret, &result);
252     return result;
253 }
254 
PosixSpawnAttrGetSigDefault(napi_env env, napi_callback_info info)255 static napi_value PosixSpawnAttrGetSigDefault(napi_env env, napi_callback_info info)
256 {
257     size_t argc = PARAM_1;
258     napi_value args[1] = {nullptr};
259     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
260     int param;
261     napi_get_value_int32(env, args[0], &param);
262 
263     int ret = FAIL;
264     if (param == PARAM_0) {
265         posix_spawnattr_t spawnattr;
266         sigset_t sigset;
267         posix_spawnattr_init(&spawnattr);
268         ret = posix_spawnattr_getsigdefault(&spawnattr, &sigset);
269         posix_spawnattr_destroy(&spawnattr);
270     }
271 
272     napi_value result = nullptr;
273     napi_create_int32(env, ret, &result);
274     return result;
275 }
276 
PosixSpawnAttrGetSigMask(napi_env env, napi_callback_info info)277 static napi_value PosixSpawnAttrGetSigMask(napi_env env, napi_callback_info info)
278 {
279     size_t argc = PARAM_1;
280     napi_value args[1] = {nullptr};
281     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
282     int param;
283     napi_get_value_int32(env, args[0], &param);
284 
285     int ret = FAIL;
286     if (param == PARAM_0) {
287         posix_spawnattr_t spawnattr;
288         sigset_t mask;
289         posix_spawnattr_init(&spawnattr);
290         ret = posix_spawnattr_getsigmask(&spawnattr, &mask);
291         posix_spawnattr_destroy(&spawnattr);
292     }
293 
294     napi_value result = nullptr;
295     napi_create_int32(env, ret, &result);
296     return result;
297 }
298 
PosixSpawnAttrInit(napi_env env, napi_callback_info info)299 static napi_value PosixSpawnAttrInit(napi_env env, napi_callback_info info)
300 {
301     size_t argc = PARAM_1;
302     napi_value args[1] = {nullptr};
303     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
304     int param;
305     napi_get_value_int32(env, args[0], &param);
306 
307     int ret = FAIL;
308     if (param == PARAM_0) {
309         posix_spawnattr_t attr;
310         ret = posix_spawnattr_init(&attr);
311         posix_spawnattr_destroy(&attr);
312     }
313 
314     napi_value result = nullptr;
315     napi_create_int32(env, ret, &result);
316     return result;
317 }
318 
PosixSpawnAttrSetFlags(napi_env env, napi_callback_info info)319 static napi_value PosixSpawnAttrSetFlags(napi_env env, napi_callback_info info)
320 {
321     size_t argc = PARAM_1;
322     napi_value args[1] = {nullptr};
323     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
324     int param;
325     napi_get_value_int32(env, args[0], &param);
326 
327     int ret;
328     posix_spawnattr_t spawnattr;
329     posix_spawnattr_init(&spawnattr);
330     if (param == PARAM_0) {
331         ret = posix_spawnattr_setflags(&spawnattr, POSIX_SPAWN_RESETIDS);
332     } else {
333         ret = posix_spawnattr_setflags(&spawnattr, PARAM_256);
334     }
335     posix_spawnattr_destroy(&spawnattr);
336     if (ret != PARAM_0) {
337         ret = FAIL;
338     }
339 
340     napi_value result = nullptr;
341     napi_create_int32(env, ret, &result);
342     return result;
343 }
344 
PosixSpawnAttrSetPGroup(napi_env env, napi_callback_info info)345 static napi_value PosixSpawnAttrSetPGroup(napi_env env, napi_callback_info info)
346 {
347     size_t argc = PARAM_1;
348     napi_value args[1] = {nullptr};
349     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
350     int param;
351     napi_get_value_int32(env, args[0], &param);
352 
353     int ret = FAIL;
354     if (param == PARAM_0) {
355         posix_spawnattr_t attr;
356         pid_t group = PARAM_MINUS_1;
357         posix_spawnattr_init(&attr);
358         ret = posix_spawnattr_setpgroup(&attr, group);
359         posix_spawnattr_destroy(&attr);
360     }
361 
362     napi_value result = nullptr;
363     napi_create_int32(env, ret, &result);
364     return result;
365 }
366 
PosixSpawnAttrSetSigDefault(napi_env env, napi_callback_info info)367 static napi_value PosixSpawnAttrSetSigDefault(napi_env env, napi_callback_info info)
368 {
369     size_t argc = PARAM_1;
370     napi_value args[1] = {nullptr};
371     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
372     int param;
373     napi_get_value_int32(env, args[0], &param);
374 
375     int ret = FAIL;
376     if (param == PARAM_0) {
377         posix_spawnattr_t attr;
378         sigset_t sigset;
379         sigemptyset(&sigset);
380         sigaddset(&sigset, SIGCHLD);
381         posix_spawnattr_init(&attr);
382         ret = posix_spawnattr_setsigdefault(&attr, &sigset);
383         posix_spawnattr_destroy(&attr);
384     }
385 
386     napi_value result = nullptr;
387     napi_create_int32(env, ret, &result);
388     return result;
389 }
390 
PosixSpawnAttrSetSigMask(napi_env env, napi_callback_info info)391 static napi_value PosixSpawnAttrSetSigMask(napi_env env, napi_callback_info info)
392 {
393     size_t argc = PARAM_1;
394     napi_value args[1] = {nullptr};
395     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
396     int param;
397     napi_get_value_int32(env, args[0], &param);
398 
399     int ret = FAIL;
400     if (param == PARAM_0) {
401         posix_spawnattr_t attr;
402         sigset_t sigset;
403         sigemptyset(&sigset);
404         sigaddset(&sigset, SIGCHLD);
405         posix_spawnattr_init(&attr);
406         ret = posix_spawnattr_setsigmask(&attr, &sigset);
407         posix_spawnattr_destroy(&attr);
408     }
409 
410     napi_value result = nullptr;
411     napi_create_int32(env, ret, &result);
412     return result;
413 }
414 
PosixSpawnP(napi_env env, napi_callback_info info)415 static napi_value PosixSpawnP(napi_env env, napi_callback_info info)
416 {
417     size_t argc = PARAM_1;
418     napi_value args[1] = {nullptr};
419     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
420     int param;
421     napi_get_value_int32(env, args[0], &param);
422 
423     int ret;
424     pid_t pid;
425     if (param == PARAM_0) {
426         pid = getpid();
427         posix_spawnattr_t attr;
428         posix_spawnattr_init(&attr);
429         const char *argv[] = {"/bin/echo", "hello", nullptr};
430         ret = posix_spawnp(&pid, "echo", nullptr, &attr, (char *const *)argv, nullptr);
431         posix_spawnattr_destroy(&attr);
432     } else {
433         ret = posix_spawn(&pid, "unexitfile", nullptr, nullptr, nullptr, nullptr);
434     }
435 
436     if (ret != SUCCESS) {
437         ret = FAIL;
438     }
439     napi_value result = nullptr;
440     napi_create_int32(env, ret, &result);
441     return result;
442 }
443 
Init(napi_env env, napi_value exports)444 EXTERN_C_START static napi_value Init(napi_env env, napi_value exports)
445 {
446     napi_property_descriptor desc[] = {
447         {"posixSpawn", nullptr, PosixSpawn, nullptr, nullptr, nullptr, napi_default, nullptr},
448         {"posixSpawnFileActionsAddClose", nullptr, PosixSpawnFileActionsAddclose, nullptr, nullptr, nullptr,
449          napi_default, nullptr},
450         {"posixSpawnFileActionsAdddup2", nullptr, PosixSpawnFileActionsAddDup2, nullptr, nullptr, nullptr, napi_default,
451          nullptr},
452         {"posixSpawnFileActionsAddopen", nullptr, PosixSpawnFileActionsAddOpen, nullptr, nullptr, nullptr, napi_default,
453          nullptr},
454         {"posixSpawnFileActionsDestroy", nullptr, PosixSpawnFileActionsDestroy, nullptr, nullptr, nullptr, napi_default,
455          nullptr},
456         {"posixSpawnFileActionsInit", nullptr, PosixSpawnFileActionsInit, nullptr, nullptr, nullptr, napi_default,
457          nullptr},
458         {"posixSpawnAttrDestroy", nullptr, PosixSpawnAttrDestroy, nullptr, nullptr, nullptr, napi_default, nullptr},
459         {"posixSpawnAttrGetFlags", nullptr, PosixSpawnAttrGetflags, nullptr, nullptr, nullptr, napi_default, nullptr},
460         {"posixSpawnAttrGetpGroup", nullptr, PosixSpawnAttrGetpGroup, nullptr, nullptr, nullptr, napi_default, nullptr},
461         {"posixSpawnAttrGetSigDefault", nullptr, PosixSpawnAttrGetSigDefault, nullptr, nullptr, nullptr, napi_default,
462          nullptr},
463         {"posixSpawnAttrGetSigMask", nullptr, PosixSpawnAttrGetSigMask, nullptr, nullptr, nullptr, napi_default,
464          nullptr},
465         {"posixSpawnAttrInit", nullptr, PosixSpawnAttrInit, nullptr, nullptr, nullptr, napi_default, nullptr},
466         {"posixSpawnAttrSetFlags", nullptr, PosixSpawnAttrSetFlags, nullptr, nullptr, nullptr, napi_default, nullptr},
467         {"posixSpawnAttrSetPGroup", nullptr, PosixSpawnAttrSetPGroup, nullptr, nullptr, nullptr, napi_default, nullptr},
468         {"posixSpawnAttrSetSigDefault", nullptr, PosixSpawnAttrSetSigDefault, nullptr, nullptr, nullptr, napi_default,
469          nullptr},
470         {"posixSpawnAttrSetSigMask", nullptr, PosixSpawnAttrSetSigMask, nullptr, nullptr, nullptr, napi_default,
471          nullptr},
472         {"posixSpawnP", nullptr, PosixSpawnP, nullptr, nullptr, nullptr, napi_default, nullptr}};
473     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
474     return exports;
475 }
476 EXTERN_C_END
477 
478 static napi_module demoModule = {
479     .nm_version = 1,
480     .nm_flags = 0,
481     .nm_filename = "spawnndk1",
482     .nm_register_func = Init,
483     .nm_modname = "libspawnndk1",
484     .nm_priv = ((void *)0),
485     .reserved = {0},
486 };
487 
RegisterModule(void)488 extern "C" __attribute__((constructor)) void RegisterModule(void) { napi_module_register(&demoModule); }