提交 d193769a 编写于 作者: W wangchen

fix: L1 toybox 命令功能实现

【背景】
解决toybox已支持命令的遗留问题,新增命令功能。

【修改方案】
1. 移植toybox并在原码其他仓进行适配。

【影响】
对现有的产品编译不会有影响。

re #I41N2A
Signed-off-by: Nwangchen <253227059@qq.com>
上级 0f5c5ad1
#include <locale.h>
#include <langinfo.h>
#include <unsupported_api.h>
#include "locale_impl.h"
static const char c_time[] =
"Sun\0" "Mon\0" "Tue\0" "Wed\0" "Thu\0" "Fri\0" "Sat\0"
"Sunday\0" "Monday\0" "Tuesday\0" "Wednesday\0"
"Thursday\0" "Friday\0" "Saturday\0"
"Jan\0" "Feb\0" "Mar\0" "Apr\0" "May\0" "Jun\0"
"Jul\0" "Aug\0" "Sep\0" "Oct\0" "Nov\0" "Dec\0"
"January\0" "February\0" "March\0" "April\0"
"May\0" "June\0" "July\0" "August\0"
"September\0" "October\0" "November\0" "December\0"
"AM\0" "PM\0"
"%a %b %e %T %Y\0"
"%m/%d/%y\0"
"%H:%M:%S\0"
"%I:%M:%S %p\0"
"\0"
"\0"
"%m/%d/%y\0"
"0123456789\0"
"%a %b %e %T %Y\0"
"%H:%M:%S";
static const char c_messages[] = "^[yY]\0" "^[nN]\0" "yes\0" "no";
static const char c_numeric[] = ".\0" "";
char *__nl_langinfo_l(nl_item item, locale_t loc)
{
int cat = item >> 16;
int idx = item & 65535;
const char *str;
unsupported_api(__FUNCTION__);
if (item == CODESET) return loc->cat[LC_CTYPE] ? "UTF-8" : "ASCII";
/* _NL_LOCALE_NAME extension */
if (idx == 65535 && cat < LC_ALL)
return loc->cat[cat] ? (char *)loc->cat[cat]->name : "C";
switch (cat) {
case LC_NUMERIC:
if (idx > 1) return "";
str = c_numeric;
break;
case LC_TIME:
if (idx > 0x31) return "";
str = c_time;
break;
case LC_MONETARY:
if (idx > 0) return "";
str = "";
break;
case LC_MESSAGES:
if (idx > 3) return "";
str = c_messages;
break;
default:
return "";
}
for (; idx; idx--, str++) for (; *str; str++);
if (cat != LC_NUMERIC && *str) str = LCTRANS(str, cat, loc);
return (char *)str;
}
char *__nl_langinfo(nl_item item)
{
unsupported_api(__FUNCTION__);
return __nl_langinfo_l(item, CURRENT_LOCALE);
}
weak_alias(__nl_langinfo, nl_langinfo);
weak_alias(__nl_langinfo_l, nl_langinfo_l);
#include <stdio.h>
#include <string.h>
#include <mntent.h>
#include <errno.h>
#include <unsupported_api.h>
static char *internal_buf;
static size_t internal_bufsize;
#define SENTINEL (char *)&internal_buf
FILE *setmntent(const char *name, const char *mode)
{
unsupported_api(__FUNCTION__);
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;
unsupported_api(__FUNCTION__);
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;
unsupported_api(__FUNCTION__);
return getmntent_r(f, &mnt, SENTINEL, 0);
}
int addmntent(FILE *f, const struct mntent *mnt)
{
unsupported_api(__FUNCTION__);
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)
{
unsupported_api(__FUNCTION__);
return strstr(mnt->mnt_opts, opt);
}
#include <netdb.h>
#include <unsupported_api.h>
#include "locale_impl.h"
static const char msgs[] =
"Invalid flags\0"
"Name does not resolve\0"
"Try again\0"
"Non-recoverable error\0"
"Unknown error\0"
"Unrecognized address family or invalid length\0"
"Unrecognized socket type\0"
"Unrecognized service\0"
"Unknown error\0"
"Out of memory\0"
"System error\0"
"Overflow\0"
"\0Unknown error";
const char *gai_strerror(int ecode)
{
const char *s;
unsupported_api(__FUNCTION__);
for (s=msgs, ecode++; ecode && *s; ecode++, s++) for (; *s; s++);
if (!*s) s++;
return LCTRANS_CUR(s);
}
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <endian.h>
#include <errno.h>
#include <unsupported_api.h>
#include "lookup.h"
int getaddrinfo(const char *restrict host, const char *restrict serv, const struct addrinfo *restrict hint, struct addrinfo **restrict res)
{
struct service ports[MAXSERVS];
struct address addrs[MAXADDRS];
char canon[256], *outcanon;
int nservs, naddrs, nais, canon_len, i, j, k;
int family = AF_UNSPEC, flags = 0, proto = 0, socktype = 0;
struct aibuf *out;
unsupported_api(__FUNCTION__);
if (!host && !serv) return EAI_NONAME;
if (hint) {
family = hint->ai_family;
flags = hint->ai_flags;
proto = hint->ai_protocol;
socktype = hint->ai_socktype;
const int mask = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST |
AI_V4MAPPED | AI_ALL | AI_ADDRCONFIG | AI_NUMERICSERV;
if ((flags & mask) != flags)
return EAI_BADFLAGS;
switch (family) {
case AF_INET:
case AF_INET6:
case AF_UNSPEC:
break;
default:
return EAI_FAMILY;
}
}
if (flags & AI_ADDRCONFIG) {
/* Define the "an address is configured" condition for address
* families via ability to create a socket for the family plus
* routability of the loopback address for the family. */
static const struct sockaddr_in lo4 = {
.sin_family = AF_INET, .sin_port = 65535,
.sin_addr.s_addr = __BYTE_ORDER == __BIG_ENDIAN
? 0x7f000001 : 0x0100007f
};
static const struct sockaddr_in6 lo6 = {
.sin6_family = AF_INET6, .sin6_port = 65535,
.sin6_addr = IN6ADDR_LOOPBACK_INIT
};
int tf[2] = { AF_INET, AF_INET6 };
const void *ta[2] = { &lo4, &lo6 };
socklen_t tl[2] = { sizeof lo4, sizeof lo6 };
for (i=0; i<2; i++) {
if (family==tf[1-i]) continue;
int s = socket(tf[i], SOCK_CLOEXEC|SOCK_DGRAM,
IPPROTO_UDP);
if (s>=0) {
int cs;
pthread_setcancelstate(
PTHREAD_CANCEL_DISABLE, &cs);
int r = connect(s, ta[i], tl[i]);
pthread_setcancelstate(cs, 0);
close(s);
if (!r) continue;
}
switch (errno) {
case EADDRNOTAVAIL:
case EAFNOSUPPORT:
case EHOSTUNREACH:
case ENETDOWN:
case ENETUNREACH:
break;
default:
return EAI_SYSTEM;
}
if (family == tf[i]) return EAI_NONAME;
family = tf[1-i];
}
}
nservs = __lookup_serv(ports, serv, proto, socktype, flags);
if (nservs < 0) return nservs;
naddrs = __lookup_name(addrs, canon, host, family, flags);
if (naddrs < 0) return naddrs;
nais = nservs * naddrs;
canon_len = strlen(canon);
out = calloc(1, nais * sizeof(*out) + canon_len + 1);
if (!out) return EAI_MEMORY;
if (canon_len) {
outcanon = (void *)&out[nais];
memcpy(outcanon, canon, canon_len+1);
} else {
outcanon = 0;
}
for (k=i=0; i<naddrs; i++) for (j=0; j<nservs; j++, k++) {
out[k].slot = k;
out[k].ai = (struct addrinfo){
.ai_family = addrs[i].family,
.ai_socktype = ports[j].socktype,
.ai_protocol = ports[j].proto,
.ai_addrlen = addrs[i].family == AF_INET
? sizeof(struct sockaddr_in)
: sizeof(struct sockaddr_in6),
.ai_addr = (void *)&out[k].sa,
.ai_canonname = outcanon };
if (k) out[k-1].ai.ai_next = &out[k].ai;
switch (addrs[i].family) {
case AF_INET:
out[k].sa.sin.sin_family = AF_INET;
out[k].sa.sin.sin_port = htons(ports[j].port);
memcpy(&out[k].sa.sin.sin_addr, &addrs[i].addr, 4);
break;
case AF_INET6:
out[k].sa.sin6.sin6_family = AF_INET6;
out[k].sa.sin6.sin6_port = htons(ports[j].port);
out[k].sa.sin6.sin6_scope_id = addrs[i].scopeid;
memcpy(&out[k].sa.sin6.sin6_addr, &addrs[i].addr, 16);
break;
}
}
out[0].ref = nais;
*res = &out->ai;
return 0;
}
......@@ -38,7 +38,6 @@ struct group *getgrnam(const char *name)
{
struct group *res;
size_t size=0, nmem=0;
unsupported_api(__FUNCTION__);
__getgr_a(name, 0, &gr, &line, &size, &mem, &nmem, &res);
return res;
}
......@@ -36,7 +36,6 @@ struct passwd *getpwuid(uid_t uid)
struct passwd *getpwnam(const char *name)
{
struct passwd *res;
unsupported_api(__FUNCTION__);
__getpw_a(name, 0, &pw, &line, &size, &res);
return res;
}
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unsupported_api.h>
#include "syscall.h"
int fchmod(int fd, mode_t mode)
{
unsupported_api(__FUNCTION__);
int ret = __syscall(SYS_fchmod, fd, mode);
if (ret != -EBADF || __syscall(SYS_fcntl, fd, F_GETFD) < 0)
return __syscall_ret(ret);
char buf[15+3*sizeof(int)];
__procfdname(buf, fd);
#ifdef SYS_chmod
return syscall(SYS_chmod, buf, mode);
#else
return syscall(SYS_fchmodat, AT_FDCWD, buf, mode);
#endif
}
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unsupported_api.h>
#include "syscall.h"
#include "kstat.h"
int fchmodat(int fd, const char *path, mode_t mode, int flag)
{
unsupported_api(__FUNCTION__);
if (!flag) return syscall(SYS_fchmodat, fd, path, mode, flag);
if (flag != AT_SYMLINK_NOFOLLOW)
return __syscall_ret(-EINVAL);
struct kstat st;
int ret, fd2;
char proc[15+3*sizeof(int)];
if ((ret = __syscall(SYS_fstatat, fd, path, &st, flag)))
return __syscall_ret(ret);
if (S_ISLNK(st.st_mode))
return __syscall_ret(-EOPNOTSUPP);
if ((fd2 = __syscall(SYS_openat, fd, path, O_RDONLY|O_PATH|O_NOFOLLOW|O_NOCTTY|O_CLOEXEC)) < 0) {
if (fd2 == -ELOOP)
return __syscall_ret(-EOPNOTSUPP);
return __syscall_ret(fd2);
}
__procfdname(proc, fd2);
ret = __syscall(SYS_fstatat, AT_FDCWD, proc, &st, 0);
if (!ret) {
if (S_ISLNK(st.st_mode)) ret = -EOPNOTSUPP;
else ret = __syscall(SYS_fchmodat, AT_FDCWD, proc, mode);
}
__syscall(SYS_close, fd2);
return __syscall_ret(ret);
}
#include <sys/stat.h>
#include <unsupported_api.h>
int futimens(int fd, const struct timespec times[2])
{
unsupported_api(__FUNCTION__);
return utimensat(fd, 0, times, 0);
}
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>
#include <unsupported_api.h>
#include "syscall.h"
#define IS32BIT(x) !((x)+0x80000000ULL>>32)
#define NS_SPECIAL(ns) ((ns)==UTIME_NOW || (ns)==UTIME_OMIT)
int utimensat(int fd, const char *path, const struct timespec times[2], int flags)
{
int r;
unsupported_api(__FUNCTION__);
if (times && times[0].tv_nsec==UTIME_NOW && times[1].tv_nsec==UTIME_NOW)
times = 0;
#ifdef SYS_utimensat_time64
r = -ENOSYS;
time_t s0=0, s1=0;
long ns0=0, ns1=0;
if (times) {
ns0 = times[0].tv_nsec;
ns1 = times[1].tv_nsec;
if (!NS_SPECIAL(ns0)) s0 = times[0].tv_sec;
if (!NS_SPECIAL(ns1)) s1 = times[1].tv_sec;
}
if (SYS_utimensat == SYS_utimensat_time64 || !IS32BIT(s0) || !IS32BIT(s1))
r = __syscall(SYS_utimensat_time64, fd, path, times ?
((long long[]){s0, ns0, s1, ns1}) : 0, flags);
if (SYS_utimensat == SYS_utimensat_time64 || r!=-ENOSYS)
return __syscall_ret(r);
if (!IS32BIT(s0) || !IS32BIT(s1))
return __syscall_ret(-ENOTSUP);
r = __syscall(SYS_utimensat, fd, path,
times ? ((long[]){s0, ns0, s1, ns1}) : 0, flags);
#else
r = __syscall(SYS_utimensat, fd, path, times, flags);
#endif
#ifdef SYS_futimesat
if (r != -ENOSYS || flags) return __syscall_ret(r);
long *tv=0, tmp[4];
if (times) {
int i;
tv = tmp;
for (i=0; i<2; i++) {
if (times[i].tv_nsec >= 1000000000ULL) {
if (NS_SPECIAL(times[i].tv_nsec))
return __syscall_ret(-ENOSYS);
return __syscall_ret(-EINVAL);
}
tmp[2*i+0] = times[i].tv_sec;
tmp[2*i+1] = times[i].tv_nsec / 1000;
}
}
r = __syscall(SYS_futimesat, fd, path, tv);
if (r != -ENOSYS || fd != AT_FDCWD) return __syscall_ret(r);
r = __syscall(SYS_utimes, path, tv);
#endif
return __syscall_ret(r);
}
#include "time_impl.h"
#include <stdint.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include "libc.h"
#include "lock.h"
#include <unsupported_api.h>
long __timezone = 0;
int __daylight = 0;
char *__tzname[2] = { 0, 0 };
weak_alias(__timezone, timezone);
weak_alias(__daylight, daylight);
weak_alias(__tzname, tzname);
static char std_name[TZNAME_MAX+1];
static char dst_name[TZNAME_MAX+1];
const char __utc[] = "UTC";
static int dst_off;
static int r0[5], r1[5];
static const unsigned char *zi, *trans, *index, *types, *abbrevs, *abbrevs_end;
static size_t map_size;
static char old_tz_buf[32];
static char *old_tz = old_tz_buf;
static size_t old_tz_size = sizeof old_tz_buf;
static volatile int lock[1];
static int getint(const char **p)
{
unsigned x;
for (x=0; **p-'0'<10U; (*p)++) x = **p-'0' + 10*x;
return x;
}
static int getoff(const char **p)
{
int neg = 0;
if (**p == '-') {
++*p;
neg = 1;
} else if (**p == '+') {
++*p;
}
int off = 3600*getint(p);
if (**p == ':') {
++*p;
off += 60*getint(p);
if (**p == ':') {
++*p;
off += getint(p);
}
}
return neg ? -off : off;
}
static void getrule(const char **p, int rule[5])
{
int r = rule[0] = **p;
if (r!='M') {
if (r=='J') ++*p;
else rule[0] = 0;
rule[1] = getint(p);
} else {
++*p; rule[1] = getint(p);
++*p; rule[2] = getint(p);
++*p; rule[3] = getint(p);
}
if (**p=='/') {
++*p;
rule[4] = getoff(p);
} else {
rule[4] = 7200;
}
}
static void getname(char *d, const char **p)
{
int i;
if (**p == '<') {
++*p;
for (i=0; (*p)[i]!='>' && i<TZNAME_MAX; i++)
d[i] = (*p)[i];
++*p;
} else {
for (i=0; ((*p)[i]|32)-'a'<26U && i<TZNAME_MAX; i++)
d[i] = (*p)[i];
}
*p += i;
d[i] = 0;
}
#define VEC(...) ((const unsigned char[]){__VA_ARGS__})
static uint32_t zi_read32(const unsigned char *z)
{
return (unsigned)z[0]<<24 | z[1]<<16 | z[2]<<8 | z[3];
}
static size_t zi_dotprod(const unsigned char *z, const unsigned char *v, size_t n)
{
size_t y;
uint32_t x;
for (y=0; n; n--, z+=4, v++) {
x = zi_read32(z);
y += x * *v;
}
return y;
}
static void do_tzset()
{
char buf[NAME_MAX+25], *pathname=buf+24;
const char *try, *s, *p;
const unsigned char *map = 0;
size_t i;
static const char search[] =
"/usr/share/zoneinfo/\0/share/zoneinfo/\0/etc/zoneinfo/\0";
s = getenv("TZ");
if (!s) s = "/etc/localtime";
if (!*s) s = __utc;
if (old_tz && !strcmp(s, old_tz)) return;
for (i=0; i<5; i++) r0[i] = r1[i] = 0;
if (zi) __munmap((void *)zi, map_size);
/* Cache the old value of TZ to check if it has changed. Avoid
* free so as not to pull it into static programs. Growth
* strategy makes it so free would have minimal benefit anyway. */
i = strlen(s);
if (i > PATH_MAX+1) s = __utc, i = 3;
if (i >= old_tz_size) {
old_tz_size *= 2;
if (i >= old_tz_size) old_tz_size = i+1;
if (old_tz_size > PATH_MAX+2) old_tz_size = PATH_MAX+2;
old_tz = malloc(old_tz_size);
}
if (old_tz) memcpy(old_tz, s, i+1);
/* Non-suid can use an absolute tzfile pathname or a relative
* pathame beginning with "."; in secure mode, only the
* standard path will be searched. */
if (*s == ':' || ((p=strchr(s, '/')) && !memchr(s, ',', p-s))) {
if (*s == ':') s++;
if (*s == '/' || *s == '.') {
if (!libc.secure || !strcmp(s, "/etc/localtime"))
map = __map_file(s, &map_size);
} else {
size_t l = strlen(s);
if (l <= NAME_MAX && !strchr(s, '.')) {
memcpy(pathname, s, l+1);
pathname[l] = 0;
for (try=search; !map && *try; try+=l+1) {
l = strlen(try);
memcpy(pathname-l, try, l);
map = __map_file(pathname-l, &map_size);
}
}
}
if (!map) s = __utc;
}
if (map && (map_size < 44 || memcmp(map, "TZif", 4))) {
__munmap((void *)map, map_size);
map = 0;
s = __utc;
}
zi = map;
if (map) {
int scale = 2;
if (sizeof(time_t) > 4 && map[4]=='2') {
size_t skip = zi_dotprod(zi+20, VEC(1,1,8,5,6,1), 6);
trans = zi+skip+44+44;
scale++;
} else {
trans = zi+44;
}
index = trans + (zi_read32(trans-12) << scale);
types = index + zi_read32(trans-12);
abbrevs = types + 6*zi_read32(trans-8);
abbrevs_end = abbrevs + zi_read32(trans-4);
if (zi[map_size-1] == '\n') {
for (s = (const char *)zi+map_size-2; *s!='\n'; s--);
s++;
} else {
const unsigned char *p;
__tzname[0] = __tzname[1] = 0;
__daylight = __timezone = dst_off = 0;
for (p=types; p<abbrevs; p+=6) {
if (!p[4] && !__tzname[0]) {
__tzname[0] = (char *)abbrevs + p[5];
__timezone = -zi_read32(p);
}
if (p[4] && !__tzname[1]) {
__tzname[1] = (char *)abbrevs + p[5];
dst_off = -zi_read32(p);
__daylight = 1;
}
}
if (!__tzname[0]) __tzname[0] = __tzname[1];
if (!__tzname[0]) __tzname[0] = (char *)__utc;
if (!__daylight) {
__tzname[1] = __tzname[0];
dst_off = __timezone;
}
return;
}
}
if (!s) s = __utc;
getname(std_name, &s);
__tzname[0] = std_name;
__timezone = getoff(&s);
getname(dst_name, &s);
__tzname[1] = dst_name;
if (dst_name[0]) {
__daylight = 1;
if (*s == '+' || *s=='-' || *s-'0'<10U)
dst_off = getoff(&s);
else
dst_off = __timezone - 3600;
} else {
__daylight = 0;
dst_off = __timezone;
}
if (*s == ',') s++, getrule(&s, r0);
if (*s == ',') s++, getrule(&s, r1);
}
/* Search zoneinfo rules to find the one that applies to the given time,
* and determine alternate opposite-DST-status rule that may be needed. */
static size_t scan_trans(long long t, int local, size_t *alt)
{
int scale = 3 - (trans == zi+44);
uint64_t x;
int off = 0;
size_t a = 0, n = (index-trans)>>scale, m;
if (!n) {
if (alt) *alt = 0;
return 0;
}
/* Binary search for 'most-recent rule before t'. */
while (n > 1) {
m = a + n/2;
x = zi_read32(trans + (m<<scale));
if (scale == 3) x = x<<32 | zi_read32(trans + (m<<scale) + 4);
else x = (int32_t)x;
if (local) off = (int32_t)zi_read32(types + 6 * index[m-1]);
if (t - off < (int64_t)x) {
n /= 2;
} else {
a = m;
n -= n/2;
}
}
/* First and last entry are special. First means to use lowest-index
* non-DST type. Last means to apply POSIX-style rule if available. */
n = (index-trans)>>scale;
if (a == n-1) return -1;
if (a == 0) {
x = zi_read32(trans + (a<<scale));
if (scale == 3) x = x<<32 | zi_read32(trans + (a<<scale) + 4);
else x = (int32_t)x;
if (local) off = (int32_t)zi_read32(types + 6 * index[a-1]);
if (t - off < (int64_t)x) {
for (a=0; a<(abbrevs-types)/6; a++) {
if (types[6*a+4] != types[4]) break;
}
if (a == (abbrevs-types)/6) a = 0;
if (types[6*a+4]) {
*alt = a;
return 0;
} else {
*alt = 0;
return a;
}
}
}
/* Try to find a neighboring opposite-DST-status rule. */
if (alt) {
if (a && types[6*index[a-1]+4] != types[6*index[a]+4])
*alt = index[a-1];
else if (a+1<n && types[6*index[a+1]+4] != types[6*index[a]+4])
*alt = index[a+1];
else
*alt = index[a];
}
return index[a];
}
static int days_in_month(int m, int is_leap)
{
if (m==2) return 28+is_leap;
else return 30+((0xad5>>(m-1))&1);
}
/* Convert a POSIX DST rule plus year to seconds since epoch. */
static long long rule_to_secs(const int *rule, int year)
{
int is_leap;
long long t = __year_to_secs(year, &is_leap);
int x, m, n, d;
if (rule[0]!='M') {
x = rule[1];
if (rule[0]=='J' && (x < 60 || !is_leap)) x--;
t += 86400 * x;
} else {
m = rule[1];
n = rule[2];
d = rule[3];
t += __month_to_secs(m-1, is_leap);
int wday = (int)((t + 4*86400) % (7*86400)) / 86400;
int days = d - wday;
if (days < 0) days += 7;
if (n == 5 && days+28 >= days_in_month(m, is_leap)) n = 4;
t += 86400 * (days + 7*(n-1));
}
t += rule[4];
return t;
}
/* Determine the time zone in effect for a given time in seconds since the
* epoch. It can be given in local or universal time. The results will
* indicate whether DST is in effect at the queried time, and will give both
* the GMT offset for the active zone/DST rule and the opposite DST. This
* enables a caller to efficiently adjust for the case where an explicit
* DST specification mismatches what would be in effect at the time. */
void __secs_to_zone(long long t, int local, int *isdst, long *offset, long *oppoff, const char **zonename)
{
LOCK(lock);
do_tzset();
if (zi) {
size_t alt, i = scan_trans(t, local, &alt);
if (i != -1) {
*isdst = types[6*i+4];
*offset = (int32_t)zi_read32(types+6*i);
*zonename = (const char *)abbrevs + types[6*i+5];
if (oppoff) *oppoff = (int32_t)zi_read32(types+6*alt);
UNLOCK(lock);
return;
}
}
if (!__daylight) goto std;
/* FIXME: may be broken if DST changes right at year boundary?
* Also, this could be more efficient.*/
long long y = t / 31556952 + 70;
while (__year_to_secs(y, 0) > t) y--;
while (__year_to_secs(y+1, 0) < t) y++;
long long t0 = rule_to_secs(r0, y);
long long t1 = rule_to_secs(r1, y);
if (!local) {
t0 += __timezone;
t1 += dst_off;
}
if (t0 < t1) {
if (t >= t0 && t < t1) goto dst;
goto std;
} else {
if (t >= t1 && t < t0) goto std;
goto dst;
}
std:
*isdst = 0;
*offset = -__timezone;
if (oppoff) *oppoff = -dst_off;
*zonename = __tzname[0];
UNLOCK(lock);
return;
dst:
*isdst = 1;
*offset = -dst_off;
if (oppoff) *oppoff = -__timezone;
*zonename = __tzname[1];
UNLOCK(lock);
}
static void __tzset()
{
unsupported_api(__FUNCTION__);
LOCK(lock);
do_tzset();
UNLOCK(lock);
}
weak_alias(__tzset, tzset);
const char *__tm_to_tzname(const struct tm *tm)
{
const void *p = tm->__tm_zone;
LOCK(lock);
do_tzset();
if (p != __utc && p != __tzname[0] && p != __tzname[1] &&
(!zi || (uintptr_t)p-(uintptr_t)abbrevs >= abbrevs_end - abbrevs))
p = "";
UNLOCK(lock);
return p;
}
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <unsupported_api.h>
#include "syscall.h"
#include "pthread_impl.h"
struct ctx {
int fd;
const char *filename;
int amode;
int p;
};
static int checker(void *p)
{
struct ctx *c = p;
int ret;
if (__syscall(SYS_setregid, __syscall(SYS_getegid), -1)
|| __syscall(SYS_setreuid, __syscall(SYS_geteuid), -1))
__syscall(SYS_exit, 1);
ret = __syscall(SYS_faccessat, c->fd, c->filename, c->amode, 0);
__syscall(SYS_write, c->p, &ret, sizeof ret);
return 0;
}
int faccessat(int fd, const char *filename, int amode, int flag)
{
unsupported_api(__FUNCTION__);
if (!flag || (flag==AT_EACCESS && getuid()==geteuid() && getgid()==getegid()))
return syscall(SYS_faccessat, fd, filename, amode, flag);
if (flag != AT_EACCESS)
return __syscall_ret(-EINVAL);
char stack[1024];
sigset_t set;
pid_t pid;
int status;
int ret, p[2];
if (pipe2(p, O_CLOEXEC)) return __syscall_ret(-EBUSY);
struct ctx c = { .fd = fd, .filename = filename, .amode = amode, .p = p[1] };
__block_all_sigs(&set);
pid = __clone(checker, stack+sizeof stack, 0, &c);
__syscall(SYS_close, p[1]);
if (pid<0 || __syscall(SYS_read, p[0], &ret, sizeof ret) != sizeof(ret))
ret = -EBUSY;
__syscall(SYS_close, p[0]);
__syscall(SYS_wait4, pid, &status, __WCLONE, 0);
__restore_sigs(&set);
return __syscall_ret(ret);
}
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <unsupported_api.h>
#include "syscall.h"
int fchown(int fd, uid_t uid, gid_t gid)
{
unsupported_api(__FUNCTION__);
int ret = __syscall(SYS_fchown, fd, uid, gid);
if (ret != -EBADF || __syscall(SYS_fcntl, fd, F_GETFD) < 0)
return __syscall_ret(ret);
char buf[15+3*sizeof(int)];
__procfdname(buf, fd);
#ifdef SYS_chown
return syscall(SYS_chown, buf, uid, gid);
#else
return syscall(SYS_fchownat, AT_FDCWD, buf, uid, gid, 0);
#endif
}
#include <unistd.h>
#include <unsupported_api.h>
#include "syscall.h"
int fchownat(int fd, const char *path, uid_t uid, gid_t gid, int flag)
{
unsupported_api(__FUNCTION__);
return syscall(SYS_fchownat, fd, path, uid, gid, flag);
}
#include <unistd.h>
#include "syscall.h"
#include <unsupported_api.h>
pid_t getsid(pid_t pid)
{
unsupported_api(__FUNCTION__);
return syscall(SYS_getsid, pid);
}
#include <unistd.h>
#include <unsupported_api.h>
#include "syscall.h"
pid_t setsid(void)
{
unsupported_api(__FUNCTION__);
return syscall(SYS_setsid);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册