Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/libexec/flua/modules/lposix.c
35071 views
1
/*-
2
* Copyright (c) 2019, 2023 Kyle Evans <[email protected]>
3
*
4
* SPDX-License-Identifier: BSD-2-Clause
5
*/
6
7
#include <sys/stat.h>
8
#include <sys/utsname.h>
9
#include <sys/wait.h>
10
11
#include <errno.h>
12
#include <fnmatch.h>
13
#include <grp.h>
14
#include <libgen.h>
15
#include <pwd.h>
16
#include <stdlib.h>
17
#include <string.h>
18
#include <unistd.h>
19
20
#include <lua.h>
21
#include "lauxlib.h"
22
#include "lposix.h"
23
24
static void
25
enforce_max_args(lua_State *L, int max)
26
{
27
int narg;
28
29
narg = lua_gettop(L);
30
luaL_argcheck(L, narg <= max, max + 1, "too many arguments");
31
}
32
33
/*
34
* Minimal implementation of luaposix needed for internal FreeBSD bits.
35
*/
36
static int
37
lua__exit(lua_State *L)
38
{
39
int code;
40
41
enforce_max_args(L, 1);
42
code = luaL_checkinteger(L, 1);
43
44
_exit(code);
45
}
46
47
static int
48
lua_basename(lua_State *L)
49
{
50
char *inpath, *outpath;
51
52
enforce_max_args(L, 1);
53
inpath = strdup(luaL_checkstring(L, 1));
54
if (inpath == NULL) {
55
lua_pushnil(L);
56
lua_pushstring(L, strerror(ENOMEM));
57
lua_pushinteger(L, ENOMEM);
58
return (3);
59
}
60
61
outpath = basename(inpath);
62
lua_pushstring(L, outpath);
63
free(inpath);
64
return (1);
65
}
66
67
static int
68
lua_chmod(lua_State *L)
69
{
70
const char *path;
71
mode_t mode;
72
73
enforce_max_args(L, 2);
74
path = luaL_checkstring(L, 1);
75
mode = (mode_t)luaL_checkinteger(L, 2);
76
77
if (chmod(path, mode) == -1) {
78
lua_pushnil(L);
79
lua_pushstring(L, strerror(errno));
80
lua_pushinteger(L, errno);
81
return (3);
82
}
83
lua_pushinteger(L, 0);
84
return (1);
85
}
86
87
static int
88
lua_chown(lua_State *L)
89
{
90
const char *path;
91
uid_t owner = (uid_t)-1;
92
gid_t group = (gid_t)-1;
93
int error;
94
95
enforce_max_args(L, 3);
96
97
path = luaL_checkstring(L, 1);
98
if (lua_isinteger(L, 2))
99
owner = (uid_t)lua_tointeger(L, 2);
100
else if (lua_isstring(L, 2)) {
101
char buf[4096];
102
struct passwd passwd, *pwd;
103
104
error = getpwnam_r(lua_tostring(L, 2), &passwd,
105
buf, sizeof(buf), &pwd);
106
if (error == 0)
107
owner = pwd->pw_uid;
108
else
109
return (luaL_argerror(L, 2,
110
lua_pushfstring(L, "unknown user %s",
111
lua_tostring(L, 2))));
112
} else if (!lua_isnoneornil(L, 2)) {
113
const char *type = luaL_typename(L, 2);
114
return (luaL_argerror(L, 2,
115
lua_pushfstring(L, "integer or string expected, got %s",
116
type)));
117
}
118
119
if (lua_isinteger(L, 3))
120
group = (gid_t)lua_tointeger(L, 3);
121
else if (lua_isstring(L, 3)) {
122
char buf[4096];
123
struct group gr, *grp;
124
125
error = getgrnam_r(lua_tostring(L, 3), &gr, buf, sizeof(buf),
126
&grp);
127
if (error == 0)
128
group = grp->gr_gid;
129
else
130
return (luaL_argerror(L, 3,
131
lua_pushfstring(L, "unknown group %s",
132
lua_tostring(L, 3))));
133
} else if (!lua_isnoneornil(L, 3)) {
134
const char *type = luaL_typename(L, 3);
135
return (luaL_argerror(L, 3,
136
lua_pushfstring(L, "integer or string expected, got %s",
137
type)));
138
}
139
140
if (chown(path, owner, group) == -1) {
141
lua_pushnil(L);
142
lua_pushstring(L, strerror(errno));
143
lua_pushinteger(L, errno);
144
return (3);
145
}
146
lua_pushinteger(L, 0);
147
return (1);
148
}
149
150
static int
151
lua_pclose(lua_State *L)
152
{
153
int error, fd;
154
155
enforce_max_args(L, 1);
156
157
fd = luaL_checkinteger(L, 1);
158
if (fd < 0) {
159
error = EBADF;
160
goto err;
161
}
162
163
if (close(fd) == 0) {
164
lua_pushinteger(L, 0);
165
return (1);
166
}
167
168
error = errno;
169
err:
170
lua_pushnil(L);
171
lua_pushstring(L, strerror(error));
172
lua_pushinteger(L, error);
173
return (3);
174
175
}
176
177
static int
178
lua_dup2(lua_State *L)
179
{
180
int error, oldd, newd;
181
182
enforce_max_args(L, 2);
183
184
oldd = luaL_checkinteger(L, 1);
185
if (oldd < 0) {
186
error = EBADF;
187
goto err;
188
}
189
190
newd = luaL_checkinteger(L, 2);
191
if (newd < 0) {
192
error = EBADF;
193
goto err;
194
}
195
196
error = dup2(oldd, newd);
197
if (error >= 0) {
198
lua_pushinteger(L, error);
199
return (1);
200
}
201
202
error = errno;
203
err:
204
lua_pushnil(L);
205
lua_pushstring(L, strerror(error));
206
lua_pushinteger(L, error);
207
return (3);
208
}
209
210
static int
211
lua_execp(lua_State *L)
212
{
213
int argc, error;
214
const char *file;
215
const char **argv;
216
217
enforce_max_args(L, 2);
218
219
file = luaL_checkstring(L, 1);
220
luaL_checktype(L, 2, LUA_TTABLE);
221
222
lua_len(L, 2);
223
argc = lua_tointeger(L, -1);
224
225
/*
226
* Use lua_newuserdatauv() to allocate a scratch buffer that is tracked
227
* and freed by lua's GC. This avoid any chance of a leak if a lua error
228
* is raised later in this function (e.g. by luaL_argerror()).
229
* The (argc + 2) size gives enough space in the buffer for argv[0] and
230
* the terminating NULL.
231
*/
232
argv = lua_newuserdatauv(L, (argc + 2) * sizeof(char *), 0);
233
234
/*
235
* Sequential tables in lua start at index 1 by convention.
236
* If there happens to be a string at index 0, use that to
237
* override the default argv[0]. This matches the lposix API.
238
*/
239
lua_pushinteger(L, 0);
240
lua_gettable(L, 2);
241
argv[0] = lua_tostring(L, -1);
242
if (argv[0] == NULL) {
243
argv[0] = file;
244
}
245
246
for (int i = 1; i <= argc; i++) {
247
lua_pushinteger(L, i);
248
lua_gettable(L, 2);
249
argv[i] = lua_tostring(L, -1);
250
if (argv[i] == NULL) {
251
luaL_argerror(L, 2,
252
"argv table must contain only strings");
253
}
254
}
255
argv[argc + 1] = NULL;
256
257
execvp(file, (char **)argv);
258
error = errno;
259
260
lua_pushnil(L);
261
lua_pushstring(L, strerror(error));
262
lua_pushinteger(L, error);
263
return (3);
264
}
265
266
static int
267
lua_fnmatch(lua_State *L)
268
{
269
const char *pattern, *string;
270
int flags;
271
272
enforce_max_args(L, 3);
273
pattern = luaL_checkstring(L, 1);
274
string = luaL_checkstring(L, 2);
275
flags = luaL_optinteger(L, 3, 0);
276
277
lua_pushinteger(L, fnmatch(pattern, string, flags));
278
279
return (1);
280
}
281
282
static int
283
lua_uname(lua_State *L)
284
{
285
struct utsname name;
286
int error;
287
288
enforce_max_args(L, 0);
289
290
error = uname(&name);
291
if (error != 0) {
292
error = errno;
293
lua_pushnil(L);
294
lua_pushstring(L, strerror(error));
295
lua_pushinteger(L, error);
296
return (3);
297
}
298
299
lua_newtable(L);
300
#define setkv(f) do { \
301
lua_pushstring(L, name.f); \
302
lua_setfield(L, -2, #f); \
303
} while (0)
304
setkv(sysname);
305
setkv(nodename);
306
setkv(release);
307
setkv(version);
308
setkv(machine);
309
#undef setkv
310
311
return (1);
312
}
313
314
static int
315
lua_dirname(lua_State *L)
316
{
317
char *inpath, *outpath;
318
319
enforce_max_args(L, 1);
320
321
inpath = strdup(luaL_checkstring(L, 1));
322
if (inpath == NULL) {
323
lua_pushnil(L);
324
lua_pushstring(L, strerror(ENOMEM));
325
lua_pushinteger(L, ENOMEM);
326
return (3);
327
}
328
329
outpath = dirname(inpath);
330
lua_pushstring(L, outpath);
331
free(inpath);
332
return (1);
333
}
334
335
static int
336
lua_fork(lua_State *L)
337
{
338
pid_t pid;
339
340
enforce_max_args(L, 0);
341
342
pid = fork();
343
if (pid < 0) {
344
lua_pushnil(L);
345
lua_pushstring(L, strerror(errno));
346
lua_pushinteger(L, errno);
347
return (3);
348
}
349
350
lua_pushinteger(L, pid);
351
return (1);
352
}
353
354
static int
355
lua_getpid(lua_State *L)
356
{
357
enforce_max_args(L, 0);
358
359
lua_pushinteger(L, getpid());
360
return (1);
361
}
362
363
static int
364
lua_pipe(lua_State *L)
365
{
366
int error, fd[2];
367
368
enforce_max_args(L, 0);
369
370
error = pipe(fd);
371
if (error != 0) {
372
lua_pushnil(L);
373
lua_pushstring(L, strerror(errno));
374
lua_pushinteger(L, errno);
375
return (1);
376
}
377
378
lua_pushinteger(L, fd[0]);
379
lua_pushinteger(L, fd[1]);
380
return (2);
381
}
382
383
static int
384
lua_read(lua_State *L)
385
{
386
char *buf;
387
ssize_t ret;
388
size_t sz;
389
int error, fd;
390
391
enforce_max_args(L, 2);
392
fd = luaL_checkinteger(L, 1);
393
sz = luaL_checkinteger(L, 2);
394
395
if (fd < 0) {
396
error = EBADF;
397
goto err;
398
}
399
400
buf = malloc(sz);
401
if (buf == NULL)
402
goto err;
403
404
/*
405
* For 0-byte reads, we'll still push the empty string and let the
406
* caller deal with EOF to match lposix semantics.
407
*/
408
ret = read(fd, buf, sz);
409
if (ret >= 0)
410
lua_pushlstring(L, buf, ret);
411
else if (ret < 0)
412
error = errno; /* Save to avoid clobber by free() */
413
414
free(buf);
415
if (error != 0)
416
goto err;
417
418
/* Just the string pushed. */
419
return (1);
420
err:
421
lua_pushnil(L);
422
lua_pushstring(L, strerror(error));
423
lua_pushinteger(L, error);
424
return (3);
425
}
426
427
static int
428
lua_realpath(lua_State *L)
429
{
430
const char *inpath;
431
char *outpath;
432
433
enforce_max_args(L, 1);
434
inpath = luaL_checkstring(L, 1);
435
436
outpath = realpath(inpath, NULL);
437
if (outpath == NULL) {
438
lua_pushnil(L);
439
lua_pushstring(L, strerror(errno));
440
lua_pushinteger(L, errno);
441
return (3);
442
}
443
444
lua_pushstring(L, outpath);
445
free(outpath);
446
return (1);
447
}
448
449
static int
450
lua_wait(lua_State *L)
451
{
452
pid_t pid;
453
int options, status;
454
455
enforce_max_args(L, 2);
456
pid = luaL_optinteger(L, 1, -1);
457
options = luaL_optinteger(L, 2, 0);
458
459
status = 0;
460
pid = waitpid(pid, &status, options);
461
if (pid < 0) {
462
lua_pushnil(L);
463
lua_pushstring(L, strerror(errno));
464
lua_pushinteger(L, errno);
465
return (3);
466
}
467
468
lua_pushinteger(L, pid);
469
if (pid == 0) {
470
lua_pushliteral(L, "running");
471
return (2);
472
}
473
474
if (WIFCONTINUED(status)) {
475
lua_pushliteral(L, "continued");
476
return (2);
477
} else if(WIFSTOPPED(status)) {
478
lua_pushliteral(L, "stopped");
479
lua_pushinteger(L, WSTOPSIG(status));
480
return (3);
481
} else if (WIFEXITED(status)) {
482
lua_pushliteral(L, "exited");
483
lua_pushinteger(L, WEXITSTATUS(status));
484
return (3);
485
} else if (WIFSIGNALED(status)) {
486
lua_pushliteral(L, "killed");
487
lua_pushinteger(L, WTERMSIG(status));
488
return (3);
489
}
490
491
return (1);
492
}
493
494
static int
495
lua_write(lua_State *L)
496
{
497
const char *buf;
498
size_t bufsz, sz;
499
ssize_t ret;
500
off_t offset;
501
int error, fd;
502
503
enforce_max_args(L, 4);
504
505
fd = luaL_checkinteger(L, 1);
506
if (fd < 0) {
507
error = EBADF;
508
goto err;
509
}
510
511
buf = luaL_checkstring(L, 2);
512
513
bufsz = lua_rawlen(L, 2);
514
sz = luaL_optinteger(L, 3, bufsz);
515
516
offset = luaL_optinteger(L, 4, 0);
517
518
519
if ((size_t)offset > bufsz || offset + sz > bufsz) {
520
lua_pushnil(L);
521
lua_pushfstring(L,
522
"write: invalid access offset %zu, size %zu in a buffer size %zu",
523
offset, sz, bufsz);
524
lua_pushinteger(L, EINVAL);
525
return (3);
526
}
527
528
ret = write(fd, buf + offset, sz);
529
if (ret < 0) {
530
error = errno;
531
goto err;
532
}
533
534
lua_pushinteger(L, ret);
535
return (1);
536
err:
537
lua_pushnil(L);
538
lua_pushstring(L, strerror(error));
539
lua_pushinteger(L, error);
540
return (3);
541
}
542
543
#define REG_DEF(n, func) { #n, func }
544
#define REG_SIMPLE(n) REG_DEF(n, lua_ ## n)
545
static const struct luaL_Reg libgenlib[] = {
546
REG_SIMPLE(basename),
547
REG_SIMPLE(dirname),
548
{ NULL, NULL },
549
};
550
551
static const struct luaL_Reg stdliblib[] = {
552
REG_SIMPLE(realpath),
553
{ NULL, NULL },
554
};
555
556
static const struct luaL_Reg fnmatchlib[] = {
557
REG_SIMPLE(fnmatch),
558
{ NULL, NULL },
559
};
560
561
static const struct luaL_Reg sys_statlib[] = {
562
REG_SIMPLE(chmod),
563
{ NULL, NULL },
564
};
565
566
static const struct luaL_Reg sys_utsnamelib[] = {
567
REG_SIMPLE(uname),
568
{ NULL, NULL },
569
};
570
571
static const struct luaL_Reg sys_waitlib[] = {
572
REG_SIMPLE(wait),
573
{NULL, NULL},
574
};
575
576
static const struct luaL_Reg unistdlib[] = {
577
REG_SIMPLE(_exit),
578
REG_SIMPLE(chown),
579
REG_DEF(close, lua_pclose),
580
REG_SIMPLE(dup2),
581
REG_SIMPLE(execp),
582
REG_SIMPLE(fork),
583
REG_SIMPLE(getpid),
584
REG_SIMPLE(pipe),
585
REG_SIMPLE(read),
586
REG_SIMPLE(write),
587
{ NULL, NULL },
588
};
589
590
#undef REG_SIMPLE
591
#undef REG_DEF
592
593
static int
594
luaopen_posix_libgen(lua_State *L)
595
{
596
luaL_newlib(L, libgenlib);
597
return (1);
598
}
599
600
static int
601
luaopen_posix_stdlib(lua_State *L)
602
{
603
luaL_newlib(L, stdliblib);
604
return (1);
605
}
606
607
static int
608
luaopen_posix_fnmatch(lua_State *L)
609
{
610
luaL_newlib(L, fnmatchlib);
611
612
#define setkv(f) do { \
613
lua_pushinteger(L, f); \
614
lua_setfield(L, -2, #f); \
615
} while (0)
616
setkv(FNM_PATHNAME);
617
setkv(FNM_NOESCAPE);
618
setkv(FNM_NOMATCH);
619
setkv(FNM_PERIOD);
620
#undef setkv
621
622
return 1;
623
}
624
625
static int
626
luaopen_posix_sys_stat(lua_State *L)
627
{
628
luaL_newlib(L, sys_statlib);
629
return (1);
630
}
631
632
static int
633
luaopen_posix_sys_utsname(lua_State *L)
634
{
635
luaL_newlib(L, sys_utsnamelib);
636
return 1;
637
}
638
639
static int
640
luaopen_posix_sys_wait(lua_State *L)
641
{
642
luaL_newlib(L, sys_waitlib);
643
644
#define lua_pushflag(L, flag) do { \
645
lua_pushinteger(L, flag); \
646
lua_setfield(L, -2, #flag); \
647
} while(0)
648
649
/* Only these two exported by lposix */
650
lua_pushflag(L, WNOHANG);
651
lua_pushflag(L, WUNTRACED);
652
653
lua_pushflag(L, WCONTINUED);
654
lua_pushflag(L, WSTOPPED);
655
#ifdef WTRAPPED
656
lua_pushflag(L, WTRAPPED);
657
#endif
658
lua_pushflag(L, WEXITED);
659
lua_pushflag(L, WNOWAIT);
660
#undef lua_pushflag
661
662
return (1);
663
}
664
665
static int
666
luaopen_posix_unistd(lua_State *L)
667
{
668
luaL_newlib(L, unistdlib);
669
return (1);
670
}
671
672
int
673
luaopen_posix(lua_State *L)
674
{
675
lua_newtable(L); /* posix */
676
677
luaL_requiref(L, "posix.fnmatch", luaopen_posix_fnmatch, 0);
678
lua_setfield(L, -2, "fnmatch");
679
680
luaL_requiref(L, "posix.libgen", luaopen_posix_libgen, 0);
681
lua_setfield(L, -2, "libgen");
682
683
luaL_requiref(L, "posix.stdlib", luaopen_posix_stdlib, 0);
684
lua_setfield(L, -2, "stdlib");
685
686
lua_newtable(L); /* posix.sys */
687
luaL_requiref(L, "posix.sys.stat", luaopen_posix_sys_stat, 0);
688
lua_setfield(L, -2, "stat");
689
luaL_requiref(L, "posix.sys.utsname", luaopen_posix_sys_utsname, 0);
690
lua_setfield(L, -2, "utsname");
691
luaL_requiref(L, "posix.sys.wait", luaopen_posix_sys_wait, 0);
692
lua_setfield(L, -2, "wait");
693
lua_setfield(L, -2, "sys");
694
695
luaL_requiref(L, "posix.unistd", luaopen_posix_unistd, 0);
696
lua_setfield(L, -2, "unistd");
697
698
return (1);
699
}
700
701