diff options
Diffstat (limited to 'libc-top-half/musl/src/misc')
39 files changed, 1828 insertions, 0 deletions
diff --git a/libc-top-half/musl/src/misc/a64l.c b/libc-top-half/musl/src/misc/a64l.c new file mode 100644 index 0000000..6055771 --- /dev/null +++ b/libc-top-half/musl/src/misc/a64l.c @@ -0,0 +1,29 @@ +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + +static const char digits[] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +long a64l(const char *s) +{ + int e; + uint32_t x = 0; + for (e=0; e<36 && *s; e+=6, s++) { + const char *d = strchr(digits, *s); + if (!d) break; + x |= (uint32_t)(d-digits)<<e; + } + return (int32_t)x; +} + +char *l64a(long x0) +{ + static char s[7]; + char *p; + uint32_t x = x0; + for (p=s; x; p++, x>>=6) + *p = digits[x&63]; + *p = 0; + return s; +} diff --git a/libc-top-half/musl/src/misc/basename.c b/libc-top-half/musl/src/misc/basename.c new file mode 100644 index 0000000..438377b --- /dev/null +++ b/libc-top-half/musl/src/misc/basename.c @@ -0,0 +1,14 @@ +#include <string.h> +#include <libgen.h> + +char *basename(char *s) +{ + size_t i; + if (!s || !*s) return "."; + i = strlen(s)-1; + for (; i&&s[i]=='/'; i--) s[i] = 0; + for (; i&&s[i-1]!='/'; i--); + return s+i; +} + +weak_alias(basename, __xpg_basename); diff --git a/libc-top-half/musl/src/misc/dirname.c b/libc-top-half/musl/src/misc/dirname.c new file mode 100644 index 0000000..dd57088 --- /dev/null +++ b/libc-top-half/musl/src/misc/dirname.c @@ -0,0 +1,14 @@ +#include <string.h> +#include <libgen.h> + +char *dirname(char *s) +{ + size_t i; + if (!s || !*s) return "."; + i = strlen(s)-1; + for (; s[i]=='/'; i--) if (!i) return "/"; + for (; s[i]!='/'; i--) if (!i) return "."; + for (; s[i]=='/'; i--) if (!i) return "/"; + s[i+1] = 0; + return s; +} diff --git a/libc-top-half/musl/src/misc/ffs.c b/libc-top-half/musl/src/misc/ffs.c new file mode 100644 index 0000000..673ce5a --- /dev/null +++ b/libc-top-half/musl/src/misc/ffs.c @@ -0,0 +1,7 @@ +#include <strings.h> +#include "atomic.h" + +int ffs(int i) +{ + return i ? a_ctz_l(i)+1 : 0; +} diff --git a/libc-top-half/musl/src/misc/ffsl.c b/libc-top-half/musl/src/misc/ffsl.c new file mode 100644 index 0000000..0105c66 --- /dev/null +++ b/libc-top-half/musl/src/misc/ffsl.c @@ -0,0 +1,7 @@ +#include <strings.h> +#include "atomic.h" + +int ffsl(long i) +{ + return i ? a_ctz_l(i)+1 : 0; +} diff --git a/libc-top-half/musl/src/misc/ffsll.c b/libc-top-half/musl/src/misc/ffsll.c new file mode 100644 index 0000000..0c5ced8 --- /dev/null +++ b/libc-top-half/musl/src/misc/ffsll.c @@ -0,0 +1,7 @@ +#include <strings.h> +#include "atomic.h" + +int ffsll(long long i) +{ + return i ? a_ctz_64(i)+1 : 0; +} diff --git a/libc-top-half/musl/src/misc/fmtmsg.c b/libc-top-half/musl/src/misc/fmtmsg.c new file mode 100644 index 0000000..0c66076 --- /dev/null +++ b/libc-top-half/musl/src/misc/fmtmsg.c @@ -0,0 +1,96 @@ +/* Public domain fmtmsg() + * Written by Isaac Dunham, 2014 + */ +#include <fmtmsg.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) +#include <pthread.h> +#endif + +/* + * If lstr is the first part of bstr, check that the next char in bstr + * is either \0 or : + */ +static int _strcolcmp(const char *lstr, const char *bstr) +{ + size_t i = 0; + while (lstr[i] && bstr[i] && (bstr[i] == lstr[i])) i++; + if ( lstr[i] || (bstr[i] && bstr[i] != ':')) return 1; + return 0; +} + +int fmtmsg(long classification, const char *label, int severity, + const char *text, const char *action, const char *tag) +{ + int ret = 0, i, consolefd, verb = 0; + char *errstring = MM_NULLSEV, *cmsg = getenv("MSGVERB"); + char *const msgs[] = { + "label", "severity", "text", "action", "tag", NULL + }; + int cs; + +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); +#endif + + if (severity == MM_HALT) errstring = "HALT: "; + else if (severity == MM_ERROR) errstring = "ERROR: "; + else if (severity == MM_WARNING) errstring = "WARNING: "; + else if (severity == MM_INFO) errstring = "INFO: "; + + if (classification & MM_CONSOLE) { + consolefd = open("/dev/console", O_WRONLY); + if (consolefd < 0) { + ret = MM_NOCON; + } else { + if (dprintf(consolefd, "%s%s%s%s%s%s%s%s\n", + label?label:"", label?": ":"", + severity?errstring:"", text?text:"", + action?"\nTO FIX: ":"", + action?action:"", action?" ":"", + tag?tag:"" )<1) + ret = MM_NOCON; + close(consolefd); + } + } + + if (classification & MM_PRINT) { + while (cmsg && cmsg[0]) { + for(i=0; msgs[i]; i++) { + if (!_strcolcmp(msgs[i], cmsg)) break; + } + if (msgs[i] == NULL) { + //ignore MSGVERB-unrecognized component + verb = 0xFF; + break; + } else { + verb |= (1 << i); + cmsg = strchr(cmsg, ':'); + if (cmsg) cmsg++; + } + } + if (!verb) verb = 0xFF; + if (dprintf(2, "%s%s%s%s%s%s%s%s\n", + (verb&1 && label) ? label : "", + (verb&1 && label) ? ": " : "", + (verb&2 && severity) ? errstring : "", + (verb&4 && text) ? text : "", + (verb&8 && action) ? "\nTO FIX: " : "", + (verb&8 && action) ? action : "", + (verb&8 && action) ? " " : "", + (verb&16 && tag) ? tag : "" ) < 1) + ret |= MM_NOMSG; + } + if ((ret & (MM_NOCON|MM_NOMSG)) == (MM_NOCON|MM_NOMSG)) + ret = MM_NOTOK; + +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) + pthread_setcancelstate(cs, 0); +#endif + + return ret; +} diff --git a/libc-top-half/musl/src/misc/forkpty.c b/libc-top-half/musl/src/misc/forkpty.c new file mode 100644 index 0000000..caf13ad --- /dev/null +++ b/libc-top-half/musl/src/misc/forkpty.c @@ -0,0 +1,57 @@ +#include <pty.h> +#include <utmp.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/wait.h> +#include <pthread.h> + +int forkpty(int *pm, char *name, const struct termios *tio, const struct winsize *ws) +{ + int m, s, ec=0, p[2], cs; + pid_t pid=-1; + sigset_t set, oldset; + + if (openpty(&m, &s, name, tio, ws) < 0) return -1; + + sigfillset(&set); + pthread_sigmask(SIG_BLOCK, &set, &oldset); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + if (pipe2(p, O_CLOEXEC)) { + close(s); + goto out; + } + + pid = fork(); + if (!pid) { + close(m); + close(p[0]); + if (login_tty(s)) { + write(p[1], &errno, sizeof errno); + _exit(127); + } + close(p[1]); + pthread_setcancelstate(cs, 0); + pthread_sigmask(SIG_SETMASK, &oldset, 0); + return 0; + } + close(s); + close(p[1]); + if (read(p[0], &ec, sizeof ec) > 0) { + int status; + waitpid(pid, &status, 0); + pid = -1; + errno = ec; + } + close(p[0]); + +out: + if (pid > 0) *pm = m; + else close(m); + + pthread_setcancelstate(cs, 0); + pthread_sigmask(SIG_SETMASK, &oldset, 0); + + return pid; +} diff --git a/libc-top-half/musl/src/misc/get_current_dir_name.c b/libc-top-half/musl/src/misc/get_current_dir_name.c new file mode 100644 index 0000000..782cddc --- /dev/null +++ b/libc-top-half/musl/src/misc/get_current_dir_name.c @@ -0,0 +1,15 @@ +#define _GNU_SOURCE +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <unistd.h> +#include <sys/stat.h> + +char *get_current_dir_name(void) { + struct stat a, b; + char *res = getenv("PWD"); + if (res && *res && !stat(res, &a) && !stat(".", &b) + && (a.st_dev == b.st_dev) && (a.st_ino == b.st_ino)) + return strdup(res); + return getcwd(0, 0); +} diff --git a/libc-top-half/musl/src/misc/getauxval.c b/libc-top-half/musl/src/misc/getauxval.c new file mode 100644 index 0000000..57f21ee --- /dev/null +++ b/libc-top-half/musl/src/misc/getauxval.c @@ -0,0 +1,15 @@ +#include <sys/auxv.h> +#include <errno.h> +#include "libc.h" + +unsigned long __getauxval(unsigned long item) +{ + size_t *auxv = libc.auxv; + if (item == AT_SECURE) return libc.secure; + for (; *auxv; auxv+=2) + if (*auxv==item) return auxv[1]; + errno = ENOENT; + return 0; +} + +weak_alias(__getauxval, getauxval); diff --git a/libc-top-half/musl/src/misc/getdomainname.c b/libc-top-half/musl/src/misc/getdomainname.c new file mode 100644 index 0000000..59df566 --- /dev/null +++ b/libc-top-half/musl/src/misc/getdomainname.c @@ -0,0 +1,17 @@ +#define _GNU_SOURCE +#include <unistd.h> +#include <sys/utsname.h> +#include <string.h> +#include <errno.h> + +int getdomainname(char *name, size_t len) +{ + struct utsname temp; + uname(&temp); + if (!len || strlen(temp.domainname) >= len) { + errno = EINVAL; + return -1; + } + strcpy(name, temp.domainname); + return 0; +} diff --git a/libc-top-half/musl/src/misc/getentropy.c b/libc-top-half/musl/src/misc/getentropy.c new file mode 100644 index 0000000..651ea95 --- /dev/null +++ b/libc-top-half/musl/src/misc/getentropy.c @@ -0,0 +1,33 @@ +#define _BSD_SOURCE +#include <unistd.h> +#include <sys/random.h> +#include <pthread.h> +#include <errno.h> + +int getentropy(void *buffer, size_t len) +{ + int cs, ret = 0; + char *pos = buffer; + + if (len > 256) { + errno = EIO; + return -1; + } + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + while (len) { + ret = getrandom(pos, len, 0); + if (ret < 0) { + if (errno == EINTR) continue; + else break; + } + pos += ret; + len -= ret; + ret = 0; + } + + pthread_setcancelstate(cs, 0); + + return ret; +} diff --git a/libc-top-half/musl/src/misc/gethostid.c b/libc-top-half/musl/src/misc/gethostid.c new file mode 100644 index 0000000..25bb35d --- /dev/null +++ b/libc-top-half/musl/src/misc/gethostid.c @@ -0,0 +1,6 @@ +#include <unistd.h> + +long gethostid() +{ + return 0; +} diff --git a/libc-top-half/musl/src/misc/getopt.c b/libc-top-half/musl/src/misc/getopt.c new file mode 100644 index 0000000..c3f6699 --- /dev/null +++ b/libc-top-half/musl/src/misc/getopt.c @@ -0,0 +1,105 @@ +#define _BSD_SOURCE +#include <unistd.h> +#include <wchar.h> +#include <string.h> +#include <limits.h> +#include <stdlib.h> +#include "locale_impl.h" +#include "stdio_impl.h" + +char *optarg; +int optind=1, opterr=1, optopt, __optpos, __optreset=0; + +#define optpos __optpos +weak_alias(__optreset, optreset); + +void __getopt_msg(const char *a, const char *b, const char *c, size_t l) +{ + FILE *f = stderr; + b = __lctrans_cur(b); + FLOCK(f); + fputs(a, f)>=0 + && fwrite(b, strlen(b), 1, f) + && fwrite(c, 1, l, f)==l + && putc('\n', f); + FUNLOCK(f); +} + +int getopt(int argc, char * const argv[], const char *optstring) +{ + int i; + wchar_t c, d; + int k, l; + char *optchar; + + if (!optind || __optreset) { + __optreset = 0; + __optpos = 0; + optind = 1; + } + + if (optind >= argc || !argv[optind]) + return -1; + + if (argv[optind][0] != '-') { + if (optstring[0] == '-') { + optarg = argv[optind++]; + return 1; + } + return -1; + } + + if (!argv[optind][1]) + return -1; + + if (argv[optind][1] == '-' && !argv[optind][2]) + return optind++, -1; + + if (!optpos) optpos++; + if ((k = mbtowc(&c, argv[optind]+optpos, MB_LEN_MAX)) < 0) { + k = 1; + c = 0xfffd; /* replacement char */ + } + optchar = argv[optind]+optpos; + optpos += k; + + if (!argv[optind][optpos]) { + optind++; + optpos = 0; + } + + if (optstring[0] == '-' || optstring[0] == '+') + optstring++; + + i = 0; + d = 0; + do { + l = mbtowc(&d, optstring+i, MB_LEN_MAX); + if (l>0) i+=l; else i++; + } while (l && d != c); + + if (d != c || c == ':') { + optopt = c; + if (optstring[0] != ':' && opterr) + __getopt_msg(argv[0], ": unrecognized option: ", optchar, k); + return '?'; + } + if (optstring[i] == ':') { + optarg = 0; + if (optstring[i+1] != ':' || optpos) { + optarg = argv[optind++] + optpos; + optpos = 0; + } + if (optind > argc) { + optopt = c; + if (optstring[0] == ':') return ':'; + if (opterr) __getopt_msg(argv[0], + ": option requires an argument: ", + optchar, k); + return '?'; + } + } + return c; +} + +weak_alias(getopt, __posix_getopt); diff --git a/libc-top-half/musl/src/misc/getopt_long.c b/libc-top-half/musl/src/misc/getopt_long.c new file mode 100644 index 0000000..6949ab1 --- /dev/null +++ b/libc-top-half/musl/src/misc/getopt_long.c @@ -0,0 +1,148 @@ +#define _GNU_SOURCE +#include <stddef.h> +#include <stdlib.h> +#include <limits.h> +#include <getopt.h> +#include <stdio.h> +#include <string.h> +#include "stdio_impl.h" + +extern int __optpos, __optreset; + +static void permute(char *const *argv, int dest, int src) +{ + char **av = (char **)argv; + char *tmp = av[src]; + int i; + for (i=src; i>dest; i--) + av[i] = av[i-1]; + av[dest] = tmp; +} + +static int __getopt_long_core(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly); + +static int __getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly) +{ + int ret, skipped, resumed; + if (!optind || __optreset) { + __optreset = 0; + __optpos = 0; + optind = 1; + } + if (optind >= argc || !argv[optind]) return -1; + skipped = optind; + if (optstring[0] != '+' && optstring[0] != '-') { + int i; + for (i=optind; ; i++) { + if (i >= argc || !argv[i]) return -1; + if (argv[i][0] == '-' && argv[i][1]) break; + } + optind = i; + } + resumed = optind; + ret = __getopt_long_core(argc, argv, optstring, longopts, idx, longonly); + if (resumed > skipped) { + int i, cnt = optind-resumed; + for (i=0; i<cnt; i++) + permute(argv, skipped, optind-1); + optind = skipped + cnt; + } + return ret; +} + +static int __getopt_long_core(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly) +{ + optarg = 0; + if (longopts && argv[optind][0] == '-' && + ((longonly && argv[optind][1] && argv[optind][1] != '-') || + (argv[optind][1] == '-' && argv[optind][2]))) + { + int colon = optstring[optstring[0]=='+'||optstring[0]=='-']==':'; + int i, cnt, match; + char *arg, *opt, *start = argv[optind]+1; + for (cnt=i=0; longopts[i].name; i++) { + const char *name = longopts[i].name; + opt = start; + if (*opt == '-') opt++; + while (*opt && *opt != '=' && *opt == *name) + name++, opt++; + if (*opt && *opt != '=') continue; + arg = opt; + match = i; + if (!*name) { + cnt = 1; + break; + } + cnt++; + } + if (cnt==1 && longonly && arg-start == mblen(start, MB_LEN_MAX)) { + int l = arg-start; + for (i=0; optstring[i]; i++) { + int j; + for (j=0; j<l && start[j]==optstring[i+j]; j++); + if (j==l) { + cnt++; + break; + } + } + } + if (cnt==1) { + i = match; + opt = arg; + optind++; + if (*opt == '=') { + if (!longopts[i].has_arg) { + optopt = longopts[i].val; + if (colon || !opterr) + return '?'; + __getopt_msg(argv[0], + ": option does not take an argument: ", + longopts[i].name, + strlen(longopts[i].name)); + return '?'; + } + optarg = opt+1; + } else if (longopts[i].has_arg == required_argument) { + if (!(optarg = argv[optind])) { + optopt = longopts[i].val; + if (colon) return ':'; + if (!opterr) return '?'; + __getopt_msg(argv[0], + ": option requires an argument: ", + longopts[i].name, + strlen(longopts[i].name)); + return '?'; + } + optind++; + } + if (idx) *idx = i; + if (longopts[i].flag) { + *longopts[i].flag = longopts[i].val; + return 0; + } + return longopts[i].val; + } + if (argv[optind][1] == '-') { + optopt = 0; + if (!colon && opterr) + __getopt_msg(argv[0], cnt ? + ": option is ambiguous: " : + ": unrecognized option: ", + argv[optind]+2, + strlen(argv[optind]+2)); + optind++; + return '?'; + } + } + return getopt(argc, argv, optstring); +} + +int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx) +{ + return __getopt_long(argc, argv, optstring, longopts, idx, 0); +} + +int getopt_long_only(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx) +{ + return __getopt_long(argc, argv, optstring, longopts, idx, 1); +} diff --git a/libc-top-half/musl/src/misc/getpriority.c b/libc-top-half/musl/src/misc/getpriority.c new file mode 100644 index 0000000..5c0b168 --- /dev/null +++ b/libc-top-half/musl/src/misc/getpriority.c @@ -0,0 +1,9 @@ +#include <sys/resource.h> +#include "syscall.h" + +int getpriority(int which, id_t who) +{ + int ret = syscall(SYS_getpriority, which, who); + if (ret < 0) return ret; + return 20-ret; +} diff --git a/libc-top-half/musl/src/misc/getresgid.c b/libc-top-half/musl/src/misc/getresgid.c new file mode 100644 index 0000000..d00d9a9 --- /dev/null +++ b/libc-top-half/musl/src/misc/getresgid.c @@ -0,0 +1,8 @@ +#define _GNU_SOURCE +#include <unistd.h> +#include "syscall.h" + +int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid) +{ + return syscall(SYS_getresgid, rgid, egid, sgid); +} diff --git a/libc-top-half/musl/src/misc/getresuid.c b/libc-top-half/musl/src/misc/getresuid.c new file mode 100644 index 0000000..d75d5d4 --- /dev/null +++ b/libc-top-half/musl/src/misc/getresuid.c @@ -0,0 +1,8 @@ +#define _GNU_SOURCE +#include <unistd.h> +#include "syscall.h" + +int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) +{ + return syscall(SYS_getresuid, ruid, euid, suid); +} diff --git a/libc-top-half/musl/src/misc/getrlimit.c b/libc-top-half/musl/src/misc/getrlimit.c new file mode 100644 index 0000000..2ab2f0f --- /dev/null +++ b/libc-top-half/musl/src/misc/getrlimit.c @@ -0,0 +1,26 @@ +#include <sys/resource.h> +#include <errno.h> +#include "syscall.h" + +#define FIX(x) do{ if ((x)>=SYSCALL_RLIM_INFINITY) (x)=RLIM_INFINITY; }while(0) + +int getrlimit(int resource, struct rlimit *rlim) +{ + unsigned long k_rlim[2]; + int ret = syscall(SYS_prlimit64, 0, resource, 0, rlim); + if (!ret) { + FIX(rlim->rlim_cur); + FIX(rlim->rlim_max); + } + if (!ret || errno != ENOSYS) + return ret; + if (syscall(SYS_getrlimit, resource, k_rlim) < 0) + return -1; + rlim->rlim_cur = k_rlim[0] == -1UL ? RLIM_INFINITY : k_rlim[0]; + rlim->rlim_max = k_rlim[1] == -1UL ? RLIM_INFINITY : k_rlim[1]; + FIX(rlim->rlim_cur); + FIX(rlim->rlim_max); + return 0; +} + +weak_alias(getrlimit, getrlimit64); diff --git a/libc-top-half/musl/src/misc/getrusage.c b/libc-top-half/musl/src/misc/getrusage.c new file mode 100644 index 0000000..8e03e2e --- /dev/null +++ b/libc-top-half/musl/src/misc/getrusage.c @@ -0,0 +1,35 @@ +#include <sys/resource.h> +#include <string.h> +#include <errno.h> +#include "syscall.h" + +int getrusage(int who, struct rusage *ru) +{ + int r; +#ifdef SYS_getrusage_time64 + long long kru64[18]; + r = __syscall(SYS_getrusage_time64, who, kru64); + if (!r) { + ru->ru_utime = (struct timeval) + { .tv_sec = kru64[0], .tv_usec = kru64[1] }; + ru->ru_stime = (struct timeval) + { .tv_sec = kru64[2], .tv_usec = kru64[3] }; + char *slots = (char *)&ru->ru_maxrss; + for (int i=0; i<14; i++) + *(long *)(slots + i*sizeof(long)) = kru64[4+i]; + } + if (SYS_getrusage_time64 == SYS_getrusage || r != -ENOSYS) + return __syscall_ret(r); +#endif + char *dest = (char *)&ru->ru_maxrss - 4*sizeof(long); + r = __syscall(SYS_getrusage, who, dest); + if (!r && sizeof(time_t) > sizeof(long)) { + long kru[4]; + memcpy(kru, dest, 4*sizeof(long)); + ru->ru_utime = (struct timeval) + { .tv_sec = kru[0], .tv_usec = kru[1] }; + ru->ru_stime = (struct timeval) + { .tv_sec = kru[2], .tv_usec = kru[3] }; + } + return __syscall_ret(r); +} diff --git a/libc-top-half/musl/src/misc/getsubopt.c b/libc-top-half/musl/src/misc/getsubopt.c new file mode 100644 index 0000000..53ee957 --- /dev/null +++ b/libc-top-half/musl/src/misc/getsubopt.c @@ -0,0 +1,23 @@ +#include <stdlib.h> +#include <string.h> + +int getsubopt(char **opt, char *const *keys, char **val) +{ + char *s = *opt; + int i; + + *val = NULL; + *opt = strchr(s, ','); + if (*opt) *(*opt)++ = 0; + else *opt = s + strlen(s); + + for (i=0; keys[i]; i++) { + size_t l = strlen(keys[i]); + if (strncmp(keys[i], s, l)) continue; + if (s[l] == '=') + *val = s + l + 1; + else if (s[l]) continue; + return i; + } + return -1; +} diff --git a/libc-top-half/musl/src/misc/initgroups.c b/libc-top-half/musl/src/misc/initgroups.c new file mode 100644 index 0000000..922a958 --- /dev/null +++ b/libc-top-half/musl/src/misc/initgroups.c @@ -0,0 +1,11 @@ +#define _GNU_SOURCE +#include <grp.h> +#include <limits.h> + +int initgroups(const char *user, gid_t gid) +{ + gid_t groups[NGROUPS_MAX]; + int count = NGROUPS_MAX; + if (getgrouplist(user, gid, groups, &count) < 0) return -1; + return setgroups(count, groups); +} diff --git a/libc-top-half/musl/src/misc/ioctl.c b/libc-top-half/musl/src/misc/ioctl.c new file mode 100644 index 0000000..35804f0 --- /dev/null +++ b/libc-top-half/musl/src/misc/ioctl.c @@ -0,0 +1,151 @@ +#include <sys/ioctl.h> +#include <stdarg.h> +#include <errno.h> +#include <time.h> +#include <sys/time.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include <endian.h> +#include "syscall.h" + +#define alignof(t) offsetof(struct { char c; t x; }, x) + +#define W 1 +#define R 2 +#define WR 3 + +struct ioctl_compat_map { + int new_req, old_req; + unsigned char old_size, dir, force_align, noffs; + unsigned char offsets[8]; +}; + +#define NINTH(a,b,c,d,e,f,g,h,i,...) i +#define COUNT(...) NINTH(__VA_ARGS__,8,7,6,5,4,3,2,1,0) +#define OFFS(...) COUNT(__VA_ARGS__), { __VA_ARGS__ } + +/* yields a type for a struct with original size n, with a misaligned + * timeval/timespec expanded from 32- to 64-bit. for use with ioctl + * number producing macros; only size of result is meaningful. */ +#define new_misaligned(n) struct { int i; time_t t; char c[(n)-4]; } + +struct v4l2_event { + uint32_t a; + uint64_t b[8]; + uint32_t c[2], ts[2], d[9]; +}; + +static const struct ioctl_compat_map compat_map[] = { + { SIOCGSTAMP, SIOCGSTAMP_OLD, 8, R, 0, OFFS(0, 4) }, + { SIOCGSTAMPNS, SIOCGSTAMPNS_OLD, 8, R, 0, OFFS(0, 4) }, + + /* SNDRV_TIMER_IOCTL_STATUS */ + { _IOR('T', 0x14, char[96]), _IOR('T', 0x14, 88), 88, R, 0, OFFS(0,4) }, + + /* SNDRV_PCM_IOCTL_STATUS[_EXT] */ + { _IOR('A', 0x20, char[128]), _IOR('A', 0x20, char[108]), 108, R, 1, OFFS(4,8,12,16,52,56,60,64) }, + { _IOWR('A', 0x24, char[128]), _IOWR('A', 0x24, char[108]), 108, WR, 1, OFFS(4,8,12,16,52,56,60,64) }, + + /* SNDRV_RAWMIDI_IOCTL_STATUS */ + { _IOWR('W', 0x20, char[48]), _IOWR('W', 0x20, char[36]), 36, WR, 1, OFFS(4,8) }, + + /* SNDRV_PCM_IOCTL_SYNC_PTR - with 3 subtables */ + { _IOWR('A', 0x23, char[136]), _IOWR('A', 0x23, char[132]), 0, WR, 1, 0 }, + { 0, 0, 4, WR, 1, 0 }, /* snd_pcm_sync_ptr (flags only) */ + { 0, 0, 32, WR, 1, OFFS(8,12,16,24,28) }, /* snd_pcm_mmap_status */ + { 0, 0, 4, WR, 1, 0 }, /* snd_pcm_mmap_control (each member) */ + + /* VIDIOC_QUERYBUF, VIDIOC_QBUF, VIDIOC_DQBUF, VIDIOC_PREPARE_BUF */ + { _IOWR('V', 9, new_misaligned(68)), _IOWR('V', 9, char[68]), 68, WR, 1, OFFS(20, 24) }, + { _IOWR('V', 15, new_misaligned(68)), _IOWR('V', 15, char[68]), 68, WR, 1, OFFS(20, 24) }, + { _IOWR('V', 17, new_misaligned(68)), _IOWR('V', 17, char[68]), 68, WR, 1, OFFS(20, 24) }, + { _IOWR('V', 93, new_misaligned(68)), _IOWR('V', 93, char[68]), 68, WR, 1, OFFS(20, 24) }, + + /* VIDIOC_DQEVENT */ + { _IOR('V', 89, new_misaligned(120)), _IOR('V', 89, struct v4l2_event), sizeof(struct v4l2_event), + R, 0, OFFS(offsetof(struct v4l2_event, ts[0]), offsetof(struct v4l2_event, ts[1])) }, + + /* VIDIOC_OMAP3ISP_STAT_REQ */ + { _IOWR('V', 192+6, char[32]), _IOWR('V', 192+6, char[24]), 22, WR, 0, OFFS(0,4) }, + + /* PPPIOCGIDLE */ + { _IOR('t', 63, char[16]), _IOR('t', 63, char[8]), 8, R, 0, OFFS(0,4) }, + + /* PPGETTIME, PPSETTIME */ + { _IOR('p', 0x95, char[16]), _IOR('p', 0x95, char[8]), 8, R, 0, OFFS(0,4) }, + { _IOW('p', 0x96, char[16]), _IOW('p', 0x96, char[8]), 8, W, 0, OFFS(0,4) }, + + /* LPSETTIMEOUT */ + { _IOW(0x6, 0xf, char[16]), 0x060f, 8, W, 0, OFFS(0,4) }, +}; + +static void convert_ioctl_struct(const struct ioctl_compat_map *map, char *old, char *new, int dir) +{ + int new_offset = 0; + int old_offset = 0; + int old_size = map->old_size; + if (!(dir & map->dir)) return; + if (!map->old_size) { + /* offsets hard-coded for SNDRV_PCM_IOCTL_SYNC_PTR; + * if another exception appears this needs changing. */ + convert_ioctl_struct(map+1, old, new, dir); + convert_ioctl_struct(map+2, old+4, new+8, dir); + /* snd_pcm_mmap_control, special-cased due to kernel + * type definition having been botched. */ + int adj = BYTE_ORDER==BIG_ENDIAN ? 4 : 0; + convert_ioctl_struct(map+3, old+68, new+72+adj, dir); + convert_ioctl_struct(map+3, old+72, new+76+3*adj, dir); + return; + } + for (int i=0; i < map->noffs; i++) { + int ts_offset = map->offsets[i]; + int len = ts_offset-old_offset; + if (dir==W) memcpy(old+old_offset, new+new_offset, len); + else memcpy(new+new_offset, old+old_offset, len); + new_offset += len; + old_offset += len; + long long new_ts; + long old_ts; + int align = map->force_align ? sizeof(time_t) : alignof(time_t); + new_offset += (align-1) & -new_offset; + if (dir==W) { + memcpy(&new_ts, new+new_offset, sizeof new_ts); + old_ts = new_ts; + memcpy(old+old_offset, &old_ts, sizeof old_ts); + } else { + memcpy(&old_ts, old+old_offset, sizeof old_ts); + new_ts = old_ts; + memcpy(new+new_offset, &new_ts, sizeof new_ts); + } + new_offset += sizeof new_ts; + old_offset += sizeof old_ts; + } + if (dir==W) memcpy(old+old_offset, new+new_offset, old_size-old_offset); + else memcpy(new+new_offset, old+old_offset, old_size-old_offset); +} + +int ioctl(int fd, int req, ...) +{ + void *arg; + va_list ap; + va_start(ap, req); + arg = va_arg(ap, void *); + va_end(ap); + int r = __syscall(SYS_ioctl, fd, req, arg); + if (SIOCGSTAMP != SIOCGSTAMP_OLD && req && r==-ENOTTY) { + for (int i=0; i<sizeof compat_map/sizeof *compat_map; i++) { + if (compat_map[i].new_req != req) continue; + union { + long long align; + char buf[256]; + } u; + convert_ioctl_struct(&compat_map[i], u.buf, arg, W); + r = __syscall(SYS_ioctl, fd, compat_map[i].old_req, u.buf); + if (r<0) break; + convert_ioctl_struct(&compat_map[i], u.buf, arg, R); + break; + } + } + return __syscall_ret(r); +} diff --git a/libc-top-half/musl/src/misc/issetugid.c b/libc-top-half/musl/src/misc/issetugid.c new file mode 100644 index 0000000..ddc2ca0 --- /dev/null +++ b/libc-top-half/musl/src/misc/issetugid.c @@ -0,0 +1,8 @@ +#define _BSD_SOURCE +#include <unistd.h> +#include "libc.h" + +int issetugid(void) +{ + return libc.secure; +} diff --git a/libc-top-half/musl/src/misc/lockf.c b/libc-top-half/musl/src/misc/lockf.c new file mode 100644 index 0000000..16a80be --- /dev/null +++ b/libc-top-half/musl/src/misc/lockf.c @@ -0,0 +1,32 @@ +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +int lockf(int fd, int op, off_t size) +{ + struct flock l = { + .l_type = F_WRLCK, + .l_whence = SEEK_CUR, + .l_len = size, + }; + switch (op) { + case F_TEST: + l.l_type = F_RDLCK; + if (fcntl(fd, F_GETLK, &l) < 0) + return -1; + if (l.l_type == F_UNLCK || l.l_pid == getpid()) + return 0; + errno = EACCES; + return -1; + case F_ULOCK: + l.l_type = F_UNLCK; + case F_TLOCK: + return fcntl(fd, F_SETLK, &l); + case F_LOCK: + return fcntl(fd, F_SETLKW, &l); + } + errno = EINVAL; + return -1; +} + +weak_alias(lockf, lockf64); diff --git a/libc-top-half/musl/src/misc/login_tty.c b/libc-top-half/musl/src/misc/login_tty.c new file mode 100644 index 0000000..f0be0a0 --- /dev/null +++ b/libc-top-half/musl/src/misc/login_tty.c @@ -0,0 +1,14 @@ +#include <utmp.h> +#include <sys/ioctl.h> +#include <unistd.h> + +int login_tty(int fd) +{ + setsid(); + if (ioctl(fd, TIOCSCTTY, (char *)0)) return -1; + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + if (fd>2) close(fd); + return 0; +} diff --git a/libc-top-half/musl/src/misc/mntent.c b/libc-top-half/musl/src/misc/mntent.c new file mode 100644 index 0000000..eabb820 --- /dev/null +++ b/libc-top-half/musl/src/misc/mntent.c @@ -0,0 +1,77 @@ +#include <stdio.h> +#include <string.h> +#include <mntent.h> +#include <errno.h> + +static char *internal_buf; +static size_t internal_bufsize; + +#define SENTINEL (char *)&internal_buf + +FILE *setmntent(const char *name, const char *mode) +{ + return fopen(name, mode); +} + +int endmntent(FILE *f) +{ + if (f) fclose(f); + return 1; +} + +struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen) +{ + int cnt, n[8], use_internal = (linebuf == SENTINEL); + + mnt->mnt_freq = 0; + mnt->mnt_passno = 0; + + do { + if (use_internal) { + getline(&internal_buf, &internal_bufsize, f); + linebuf = internal_buf; + } else { + fgets(linebuf, buflen, f); + } + if (feof(f) || ferror(f)) return 0; + if (!strchr(linebuf, '\n')) { + fscanf(f, "%*[^\n]%*[\n]"); + errno = ERANGE; + return 0; + } + cnt = sscanf(linebuf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d", + n, n+1, n+2, n+3, n+4, n+5, n+6, n+7, + &mnt->mnt_freq, &mnt->mnt_passno); + } while (cnt < 2 || linebuf[n[0]] == '#'); + + linebuf[n[1]] = 0; + linebuf[n[3]] = 0; + linebuf[n[5]] = 0; + linebuf[n[7]] = 0; + + mnt->mnt_fsname = linebuf+n[0]; + mnt->mnt_dir = linebuf+n[2]; + mnt->mnt_type = linebuf+n[4]; + mnt->mnt_opts = linebuf+n[6]; + + return mnt; +} + +struct mntent *getmntent(FILE *f) +{ + static struct mntent mnt; + return getmntent_r(f, &mnt, SENTINEL, 0); +} + +int addmntent(FILE *f, const struct mntent *mnt) +{ + if (fseek(f, 0, SEEK_END)) return 1; + return fprintf(f, "%s\t%s\t%s\t%s\t%d\t%d\n", + mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, mnt->mnt_opts, + mnt->mnt_freq, mnt->mnt_passno) < 0; +} + +char *hasmntopt(const struct mntent *mnt, const char *opt) +{ + return strstr(mnt->mnt_opts, opt); +} diff --git a/libc-top-half/musl/src/misc/nftw.c b/libc-top-half/musl/src/misc/nftw.c new file mode 100644 index 0000000..ebfd615 --- /dev/null +++ b/libc-top-half/musl/src/misc/nftw.c @@ -0,0 +1,148 @@ +#include <ftw.h> +#include <dirent.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> +#include <limits.h> +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) +#include <pthread.h> +#endif + +struct history +{ + struct history *chain; + dev_t dev; + ino_t ino; + int level; + int base; +}; + +#undef dirfd +#define dirfd(d) (*(int *)d) + +static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, struct FTW *), int fd_limit, int flags, struct history *h) +{ + size_t l = strlen(path), j = l && path[l-1]=='/' ? l-1 : l; + struct stat st; + struct history new; + int type; + int r; + int dfd; + int err; + struct FTW lev; + + if ((flags & FTW_PHYS) ? lstat(path, &st) : stat(path, &st) < 0) { + if (!(flags & FTW_PHYS) && errno==ENOENT && !lstat(path, &st)) + type = FTW_SLN; + else if (errno != EACCES) return -1; + else type = FTW_NS; + } else if (S_ISDIR(st.st_mode)) { + if (flags & FTW_DEPTH) type = FTW_DP; + else type = FTW_D; + } else if (S_ISLNK(st.st_mode)) { + if (flags & FTW_PHYS) type = FTW_SL; + else type = FTW_SLN; + } else { + type = FTW_F; + } + + if ((flags & FTW_MOUNT) && h && st.st_dev != h->dev) + return 0; + + new.chain = h; + new.dev = st.st_dev; + new.ino = st.st_ino; + new.level = h ? h->level+1 : 0; + new.base = j+1; + + lev.level = new.level; + if (h) { + lev.base = h->base; + } else { + size_t k; + for (k=j; k && path[k]=='/'; k--); + for (; k && path[k-1]!='/'; k--); + lev.base = k; + } + + if (type == FTW_D || type == FTW_DP) { + dfd = open(path, O_RDONLY); + err = errno; + if (dfd < 0 && err == EACCES) type = FTW_DNR; + if (!fd_limit) close(dfd); + } + + if (!(flags & FTW_DEPTH) && (r=fn(path, &st, type, &lev))) + return r; + + for (; h; h = h->chain) + if (h->dev == st.st_dev && h->ino == st.st_ino) + return 0; + + if ((type == FTW_D || type == FTW_DP) && fd_limit) { + if (dfd < 0) { + errno = err; + return -1; + } + DIR *d = fdopendir(dfd); + if (d) { + struct dirent *de; + while ((de = readdir(d))) { + if (de->d_name[0] == '.' + && (!de->d_name[1] + || (de->d_name[1]=='.' + && !de->d_name[2]))) continue; + if (strlen(de->d_name) >= PATH_MAX-l) { + errno = ENAMETOOLONG; + closedir(d); + return -1; + } + path[j]='/'; + strcpy(path+j+1, de->d_name); + if ((r=do_nftw(path, fn, fd_limit-1, flags, &new))) { + closedir(d); + return r; + } + } + closedir(d); + } else { + close(dfd); + return -1; + } + } + + path[l] = 0; + if ((flags & FTW_DEPTH) && (r=fn(path, &st, type, &lev))) + return r; + + return 0; +} + +int nftw(const char *path, int (*fn)(const char *, const struct stat *, int, struct FTW *), int fd_limit, int flags) +{ + int r, cs; + size_t l; + char pathbuf[PATH_MAX+1]; + + if (fd_limit <= 0) return 0; + + l = strlen(path); + if (l > PATH_MAX) { + errno = ENAMETOOLONG; + return -1; + } + memcpy(pathbuf, path, l+1); + +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); +#endif + r = do_nftw(pathbuf, fn, fd_limit, flags, NULL); +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) + pthread_setcancelstate(cs, 0); +#endif + return r; +} + +weak_alias(nftw, nftw64); diff --git a/libc-top-half/musl/src/misc/openpty.c b/libc-top-half/musl/src/misc/openpty.c new file mode 100644 index 0000000..c107406 --- /dev/null +++ b/libc-top-half/musl/src/misc/openpty.c @@ -0,0 +1,40 @@ +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <pty.h> +#include <stdio.h> +#include <pthread.h> + +/* Nonstandard, but vastly superior to the standard functions */ + +int openpty(int *pm, int *ps, char *name, const struct termios *tio, const struct winsize *ws) +{ + int m, s, n=0, cs; + char buf[20]; + + m = open("/dev/ptmx", O_RDWR|O_NOCTTY); + if (m < 0) return -1; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + if (ioctl(m, TIOCSPTLCK, &n) || ioctl (m, TIOCGPTN, &n)) + goto fail; + + if (!name) name = buf; + snprintf(name, sizeof buf, "/dev/pts/%d", n); + if ((s = open(name, O_RDWR|O_NOCTTY)) < 0) + goto fail; + + if (tio) tcsetattr(s, TCSANOW, tio); + if (ws) ioctl(s, TIOCSWINSZ, ws); + + *pm = m; + *ps = s; + + pthread_setcancelstate(cs, 0); + return 0; +fail: + close(m); + pthread_setcancelstate(cs, 0); + return -1; +} diff --git a/libc-top-half/musl/src/misc/ptsname.c b/libc-top-half/musl/src/misc/ptsname.c new file mode 100644 index 0000000..58c151c --- /dev/null +++ b/libc-top-half/musl/src/misc/ptsname.c @@ -0,0 +1,13 @@ +#include <stdlib.h> +#include <errno.h> + +char *ptsname(int fd) +{ + static char buf[9 + sizeof(int)*3 + 1]; + int err = __ptsname_r(fd, buf, sizeof buf); + if (err) { + errno = err; + return 0; + } + return buf; +} diff --git a/libc-top-half/musl/src/misc/pty.c b/libc-top-half/musl/src/misc/pty.c new file mode 100644 index 0000000..a057714 --- /dev/null +++ b/libc-top-half/musl/src/misc/pty.c @@ -0,0 +1,35 @@ +#include <stdlib.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> +#include "syscall.h" + +int posix_openpt(int flags) +{ + int r = open("/dev/ptmx", flags); + if (r < 0 && errno == ENOSPC) errno = EAGAIN; + return r; +} + +int grantpt(int fd) +{ + return 0; +} + +int unlockpt(int fd) +{ + int unlock = 0; + return ioctl(fd, TIOCSPTLCK, &unlock); +} + +int __ptsname_r(int fd, char *buf, size_t len) +{ + int pty, err; + if (!buf) len = 0; + if ((err = __syscall(SYS_ioctl, fd, TIOCGPTN, &pty))) return -err; + if (snprintf(buf, len, "/dev/pts/%d", pty) >= len) return ERANGE; + return 0; +} + +weak_alias(__ptsname_r, ptsname_r); diff --git a/libc-top-half/musl/src/misc/realpath.c b/libc-top-half/musl/src/misc/realpath.c new file mode 100644 index 0000000..db8b74d --- /dev/null +++ b/libc-top-half/musl/src/misc/realpath.c @@ -0,0 +1,156 @@ +#include <stdlib.h> +#include <limits.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> + +static size_t slash_len(const char *s) +{ + const char *s0 = s; + while (*s == '/') s++; + return s-s0; +} + +char *realpath(const char *restrict filename, char *restrict resolved) +{ + char stack[PATH_MAX+1]; + char output[PATH_MAX]; + size_t p, q, l, l0, cnt=0, nup=0; + int check_dir=0; + + if (!filename) { + errno = EINVAL; + return 0; + } + l = strnlen(filename, sizeof stack); + if (!l) { + errno = ENOENT; + return 0; + } + if (l >= PATH_MAX) goto toolong; + p = sizeof stack - l - 1; + q = 0; + memcpy(stack+p, filename, l+1); + + /* Main loop. Each iteration pops the next part from stack of + * remaining path components and consumes any slashes that follow. + * If not a link, it's moved to output; if a link, contents are + * pushed to the stack. */ +restart: + for (; ; p+=slash_len(stack+p)) { + /* If stack starts with /, the whole component is / or // + * and the output state must be reset. */ + if (stack[p] == '/') { + check_dir=0; + nup=0; + q=0; + output[q++] = '/'; + p++; + /* Initial // is special. */ + if (stack[p] == '/' && stack[p+1] != '/') + output[q++] = '/'; + continue; + } + + char *z = __strchrnul(stack+p, '/'); + l0 = l = z-(stack+p); + + if (!l && !check_dir) break; + + /* Skip any . component but preserve check_dir status. */ + if (l==1 && stack[p]=='.') { + p += l; + continue; + } + + /* Copy next component onto output at least temporarily, to + * call readlink, but wait to advance output position until + * determining it's not a link. */ + if (q && output[q-1] != '/') { + if (!p) goto toolong; + stack[--p] = '/'; + l++; + } + if (q+l >= PATH_MAX) goto toolong; + memcpy(output+q, stack+p, l); + output[q+l] = 0; + p += l; + + int up = 0; + if (l0==2 && stack[p-2]=='.' && stack[p-1]=='.') { + up = 1; + /* Any non-.. path components we could cancel start + * after nup repetitions of the 3-byte string "../"; + * if there are none, accumulate .. components to + * later apply to cwd, if needed. */ + if (q <= 3*nup) { + nup++; + q += l; + continue; + } + /* When previous components are already known to be + * directories, processing .. can skip readlink. */ + if (!check_dir) goto skip_readlink; + } + ssize_t k = readlink(output, stack, p); + if (k==p) goto toolong; + if (!k) { + errno = ENOENT; + return 0; + } + if (k<0) { + if (errno != EINVAL) return 0; +skip_readlink: + check_dir = 0; + if (up) { + while(q && output[q-1]!='/') q--; + if (q>1 && (q>2 || output[0]!='/')) q--; + continue; + } + if (l0) q += l; + check_dir = stack[p]; + continue; + } + if (++cnt == SYMLOOP_MAX) { + errno = ELOOP; + return 0; + } + + /* If link contents end in /, strip any slashes already on + * stack to avoid /->// or //->/// or spurious toolong. */ + if (stack[k-1]=='/') while (stack[p]=='/') p++; + p -= k; + memmove(stack+p, stack, k); + + /* Skip the stack advancement in case we have a new + * absolute base path. */ + goto restart; + } + + output[q] = 0; + + if (output[0] != '/') { + if (!getcwd(stack, sizeof stack)) return 0; + l = strlen(stack); + /* Cancel any initial .. components. */ + p = 0; + while (nup--) { + while(l>1 && stack[l-1]!='/') l--; + if (l>1) l--; + p += 2; + if (p<q) p++; + } + if (q-p && stack[l-1]!='/') stack[l++] = '/'; + if (l + (q-p) + 1 >= PATH_MAX) goto toolong; + memmove(output + l, output + p, q - p + 1); + memcpy(output, stack, l); + q = l + q-p; + } + + if (resolved) return memcpy(resolved, output, q+1); + else return strdup(output); + +toolong: + errno = ENAMETOOLONG; + return 0; +} diff --git a/libc-top-half/musl/src/misc/setdomainname.c b/libc-top-half/musl/src/misc/setdomainname.c new file mode 100644 index 0000000..22d3f74 --- /dev/null +++ b/libc-top-half/musl/src/misc/setdomainname.c @@ -0,0 +1,8 @@ +#define _GNU_SOURCE +#include <unistd.h> +#include "syscall.h" + +int setdomainname(const char *name, size_t len) +{ + return syscall(SYS_setdomainname, name, len); +} diff --git a/libc-top-half/musl/src/misc/setpriority.c b/libc-top-half/musl/src/misc/setpriority.c new file mode 100644 index 0000000..3098cdf --- /dev/null +++ b/libc-top-half/musl/src/misc/setpriority.c @@ -0,0 +1,7 @@ +#include <sys/resource.h> +#include "syscall.h" + +int setpriority(int which, id_t who, int prio) +{ + return syscall(SYS_setpriority, which, who, prio); +} diff --git a/libc-top-half/musl/src/misc/setrlimit.c b/libc-top-half/musl/src/misc/setrlimit.c new file mode 100644 index 0000000..8340aee --- /dev/null +++ b/libc-top-half/musl/src/misc/setrlimit.c @@ -0,0 +1,47 @@ +#include <sys/resource.h> +#include <errno.h> +#include "syscall.h" +#include "libc.h" + +#define MIN(a, b) ((a)<(b) ? (a) : (b)) +#define FIX(x) do{ if ((x)>=SYSCALL_RLIM_INFINITY) (x)=RLIM_INFINITY; }while(0) + +struct ctx { + unsigned long lim[2]; + int res; + int err; +}; + +static void do_setrlimit(void *p) +{ + struct ctx *c = p; + if (c->err>0) return; + c->err = -__syscall(SYS_setrlimit, c->res, c->lim); +} + +int setrlimit(int resource, const struct rlimit *rlim) +{ + struct rlimit tmp; + if (SYSCALL_RLIM_INFINITY != RLIM_INFINITY) { + tmp = *rlim; + FIX(tmp.rlim_cur); + FIX(tmp.rlim_max); + rlim = &tmp; + } + int ret = __syscall(SYS_prlimit64, 0, resource, rlim, 0); + if (ret != -ENOSYS) return __syscall_ret(ret); + + struct ctx c = { + .lim[0] = MIN(rlim->rlim_cur, MIN(-1UL, SYSCALL_RLIM_INFINITY)), + .lim[1] = MIN(rlim->rlim_max, MIN(-1UL, SYSCALL_RLIM_INFINITY)), + .res = resource, .err = -1 + }; + __synccall(do_setrlimit, &c); + if (c.err) { + if (c.err>0) errno = c.err; + return -1; + } + return 0; +} + +weak_alias(setrlimit, setrlimit64); diff --git a/libc-top-half/musl/src/misc/syscall.c b/libc-top-half/musl/src/misc/syscall.c new file mode 100644 index 0000000..6f3ef65 --- /dev/null +++ b/libc-top-half/musl/src/misc/syscall.c @@ -0,0 +1,21 @@ +#define _BSD_SOURCE +#include <unistd.h> +#include "syscall.h" +#include <stdarg.h> + +#undef syscall + +long syscall(long n, ...) +{ + va_list ap; + syscall_arg_t a,b,c,d,e,f; + va_start(ap, n); + a=va_arg(ap, syscall_arg_t); + b=va_arg(ap, syscall_arg_t); + c=va_arg(ap, syscall_arg_t); + d=va_arg(ap, syscall_arg_t); + e=va_arg(ap, syscall_arg_t); + f=va_arg(ap, syscall_arg_t); + va_end(ap); + return __syscall_ret(__syscall(n,a,b,c,d,e,f)); +} diff --git a/libc-top-half/musl/src/misc/syslog.c b/libc-top-half/musl/src/misc/syslog.c new file mode 100644 index 0000000..b802acd --- /dev/null +++ b/libc-top-half/musl/src/misc/syslog.c @@ -0,0 +1,162 @@ +#include <stdarg.h> +#include <sys/socket.h> +#include <stdio.h> +#include <unistd.h> +#include <syslog.h> +#include <time.h> +#include <signal.h> +#include <string.h> +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) +#include <pthread.h> +#endif +#include <errno.h> +#include <fcntl.h> +#include "lock.h" +#include "fork_impl.h" + +static volatile int lock[1]; +static char log_ident[32]; +static int log_opt; +static int log_facility = LOG_USER; +static int log_mask = 0xff; +static int log_fd = -1; +volatile int *const __syslog_lockptr = lock; + +int setlogmask(int maskpri) +{ + LOCK(lock); + int ret = log_mask; + if (maskpri) log_mask = maskpri; + UNLOCK(lock); + return ret; +} + +static const struct { + short sun_family; + char sun_path[9]; +} log_addr = { + AF_UNIX, + "/dev/log" +}; + +void closelog(void) +{ +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) + int cs; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); +#endif + LOCK(lock); + close(log_fd); + log_fd = -1; + UNLOCK(lock); +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) + pthread_setcancelstate(cs, 0); +#endif +} + +static void __openlog() +{ + log_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); + if (log_fd >= 0) connect(log_fd, (void *)&log_addr, sizeof log_addr); +} + +void openlog(const char *ident, int opt, int facility) +{ +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) + int cs; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); +#endif + LOCK(lock); + + if (ident) { + size_t n = strnlen(ident, sizeof log_ident - 1); + memcpy(log_ident, ident, n); + log_ident[n] = 0; + } else { + log_ident[0] = 0; + } + log_opt = opt; + log_facility = facility; + + if ((opt & LOG_NDELAY) && log_fd<0) __openlog(); + + UNLOCK(lock); +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) + pthread_setcancelstate(cs, 0); +#endif +} + +static int is_lost_conn(int e) +{ + return e==ECONNREFUSED || e==ECONNRESET || e==ENOTCONN || e==EPIPE; +} + +static void _vsyslog(int priority, const char *message, va_list ap) +{ + char timebuf[16]; + time_t now; + struct tm tm; + char buf[1024]; + int errno_save = errno; + int pid; + int l, l2; + int hlen; + int fd; + + if (log_fd < 0) __openlog(); + + if (!(priority & LOG_FACMASK)) priority |= log_facility; + + now = time(NULL); + gmtime_r(&now, &tm); + strftime(timebuf, sizeof timebuf, "%b %e %T", &tm); + + pid = (log_opt & LOG_PID) ? getpid() : 0; + l = snprintf(buf, sizeof buf, "<%d>%s %n%s%s%.0d%s: ", + priority, timebuf, &hlen, log_ident, "["+!pid, pid, "]"+!pid); + errno = errno_save; + l2 = vsnprintf(buf+l, sizeof buf - l, message, ap); + if (l2 >= 0) { + if (l2 >= sizeof buf - l) l = sizeof buf - 1; + else l += l2; + if (buf[l-1] != '\n') buf[l++] = '\n'; + if (send(log_fd, buf, l, 0) < 0 && (!is_lost_conn(errno) + || connect(log_fd, (void *)&log_addr, sizeof log_addr) < 0 + || send(log_fd, buf, l, 0) < 0) + && (log_opt & LOG_CONS)) { + fd = open("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); + if (fd >= 0) { + dprintf(fd, "%.*s", l-hlen, buf+hlen); + close(fd); + } + } + if (log_opt & LOG_PERROR) dprintf(2, "%.*s", l-hlen, buf+hlen); + } +} + +static void __vsyslog(int priority, const char *message, va_list ap) +{ +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) + int cs; +#endif + if (!(log_mask & LOG_MASK(priority&7)) || (priority&~0x3ff)) return; +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); +#endif + LOCK(lock); + _vsyslog(priority, message, ap); + UNLOCK(lock); +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) + pthread_setcancelstate(cs, 0); +#endif +} + +void syslog(int priority, const char *message, ...) +{ + va_list ap; + va_start(ap, message); + __vsyslog(priority, message, ap); + va_end(ap); +} + +weak_alias(__vsyslog, vsyslog); diff --git a/libc-top-half/musl/src/misc/uname.c b/libc-top-half/musl/src/misc/uname.c new file mode 100644 index 0000000..36e816a --- /dev/null +++ b/libc-top-half/musl/src/misc/uname.c @@ -0,0 +1,32 @@ +#include <sys/utsname.h> +#ifdef __wasilibc_unmodified_upstream // Implement uname with placeholders +#include "syscall.h" +#else +#include <string.h> +#endif + +int uname(struct utsname *uts) +{ +#ifdef __wasilibc_unmodified_upstream // Implement uname with placeholders + return syscall(SYS_uname, uts); +#else + // Just fill in the fields with placeholder values. + strcpy(uts->sysname, "wasi"); + strcpy(uts->nodename, "(none)"); + strcpy(uts->release, "0.0.0"); + strcpy(uts->version, "0.0.0"); +#if defined(__wasm32__) + strcpy(uts->machine, "wasm32"); +#elif defined(__wasm64__) + strcpy(uts->machine, "wasm64"); +#else + strcpy(uts->machine, "unknown"); +#endif +#ifdef _GNU_SOURCE + strcpy(uts->domainname, "(none)"); +#else + strcpy(uts->__domainname, "(none)"); +#endif + return 0; +#endif +} diff --git a/libc-top-half/musl/src/misc/wordexp.c b/libc-top-half/musl/src/misc/wordexp.c new file mode 100644 index 0000000..db83a69 --- /dev/null +++ b/libc-top-half/musl/src/misc/wordexp.c @@ -0,0 +1,187 @@ +#include <wordexp.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <stdint.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <signal.h> +#include <errno.h> +#include <fcntl.h> +#include "pthread_impl.h" + +static void reap(pid_t pid) +{ + int status; + while (waitpid(pid, &status, 0) < 0 && errno == EINTR); +} + +static char *getword(FILE *f) +{ + char *s = 0; + return getdelim(&s, (size_t [1]){0}, 0, f) < 0 ? 0 : s; +} + +static int do_wordexp(const char *s, wordexp_t *we, int flags) +{ + size_t i, l; + int sq=0, dq=0; + size_t np=0; + char *w, **tmp; + char *redir = (flags & WRDE_SHOWERR) ? "" : "2>/dev/null"; + int err = 0; + FILE *f; + size_t wc = 0; + char **wv = 0; + int p[2]; + pid_t pid; + sigset_t set; + + if (flags & WRDE_REUSE) wordfree(we); + + if (flags & WRDE_NOCMD) for (i=0; s[i]; i++) switch (s[i]) { + case '\\': + if (!sq && !s[++i]) return WRDE_SYNTAX; + break; + case '\'': + if (!dq) sq^=1; + break; + case '"': + if (!sq) dq^=1; + break; + case '(': + if (np) { + np++; + break; + } + case ')': + if (np) { + np--; + break; + } + case '\n': + case '|': + case '&': + case ';': + case '<': + case '>': + case '{': + case '}': + if (!(sq|dq|np)) return WRDE_BADCHAR; + break; + case '$': + if (sq) break; + if (s[i+1]=='(' && s[i+2]=='(') { + i += 2; + np += 2; + break; + } else if (s[i+1] != '(') break; + case '`': + if (sq) break; + return WRDE_CMDSUB; + } + + if (flags & WRDE_APPEND) { + wc = we->we_wordc; + wv = we->we_wordv; + } + + i = wc; + if (flags & WRDE_DOOFFS) { + if (we->we_offs > SIZE_MAX/sizeof(void *)/4) + goto nospace; + i += we->we_offs; + } else { + we->we_offs = 0; + } + + if (pipe2(p, O_CLOEXEC) < 0) goto nospace; + __block_all_sigs(&set); + pid = fork(); + __restore_sigs(&set); + if (pid < 0) { + close(p[0]); + close(p[1]); + goto nospace; + } + if (!pid) { + if (p[1] == 1) fcntl(1, F_SETFD, 0); + else dup2(p[1], 1); + execl("/bin/sh", "sh", "-c", + "eval \"printf %s\\\\\\\\0 x $1 $2\"", + "sh", s, redir, (char *)0); + _exit(1); + } + close(p[1]); + + f = fdopen(p[0], "r"); + if (!f) { + close(p[0]); + kill(pid, SIGKILL); + reap(pid); + goto nospace; + } + + l = wv ? i+1 : 0; + + free(getword(f)); + if (feof(f)) { + fclose(f); + reap(pid); + return WRDE_SYNTAX; + } + + while ((w = getword(f))) { + if (i+1 >= l) { + l += l/2+10; + tmp = realloc(wv, l*sizeof(char *)); + if (!tmp) break; + wv = tmp; + } + wv[i++] = w; + wv[i] = 0; + } + if (!feof(f)) err = WRDE_NOSPACE; + + fclose(f); + reap(pid); + + if (!wv) wv = calloc(i+1, sizeof *wv); + + we->we_wordv = wv; + we->we_wordc = i; + + if (flags & WRDE_DOOFFS) { + if (wv) for (i=we->we_offs; i; i--) + we->we_wordv[i-1] = 0; + we->we_wordc -= we->we_offs; + } + return err; + +nospace: + if (!(flags & WRDE_APPEND)) { + we->we_wordc = 0; + we->we_wordv = 0; + } + return WRDE_NOSPACE; +} + +int wordexp(const char *restrict s, wordexp_t *restrict we, int flags) +{ + int r, cs; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + r = do_wordexp(s, we, flags); + pthread_setcancelstate(cs, 0); + return r; +} + +void wordfree(wordexp_t *we) +{ + size_t i; + if (!we->we_wordv) return; + for (i=0; i<we->we_wordc; i++) free(we->we_wordv[we->we_offs+i]); + free(we->we_wordv); + we->we_wordv = 0; + we->we_wordc = 0; +} |