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