summaryrefslogtreecommitdiff
path: root/src/misc
diff options
context:
space:
mode:
Diffstat (limited to 'src/misc')
-rw-r--r--src/misc/getentropy.c2
-rw-r--r--src/misc/getopt.c3
-rw-r--r--src/misc/getrlimit.c8
-rw-r--r--src/misc/ioctl.c27
-rw-r--r--src/misc/lockf.c2
-rw-r--r--src/misc/mntent.c56
-rw-r--r--src/misc/nftw.c28
-rw-r--r--src/misc/realpath.c159
-rw-r--r--src/misc/setrlimit.c45
-rw-r--r--src/misc/syslog.c5
10 files changed, 261 insertions, 74 deletions
diff --git a/src/misc/getentropy.c b/src/misc/getentropy.c
index d2f282ce..651ea95f 100644
--- a/src/misc/getentropy.c
+++ b/src/misc/getentropy.c
@@ -6,7 +6,7 @@
int getentropy(void *buffer, size_t len)
{
- int cs, ret;
+ int cs, ret = 0;
char *pos = buffer;
if (len > 256) {
diff --git a/src/misc/getopt.c b/src/misc/getopt.c
index c3f66995..b02b81c3 100644
--- a/src/misc/getopt.c
+++ b/src/misc/getopt.c
@@ -87,7 +87,8 @@ int getopt(int argc, char * const argv[], const char *optstring)
if (optstring[i] == ':') {
optarg = 0;
if (optstring[i+1] != ':' || optpos) {
- optarg = argv[optind++] + optpos;
+ optarg = argv[optind++];
+ if (optpos) optarg += optpos;
optpos = 0;
}
if (optind > argc) {
diff --git a/src/misc/getrlimit.c b/src/misc/getrlimit.c
index 2ab2f0f4..a5558d81 100644
--- a/src/misc/getrlimit.c
+++ b/src/misc/getrlimit.c
@@ -6,12 +6,13 @@
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);
}
+#ifdef SYS_getrlimit
+ unsigned long k_rlim[2];
if (!ret || errno != ENOSYS)
return ret;
if (syscall(SYS_getrlimit, resource, k_rlim) < 0)
@@ -21,6 +22,7 @@ int getrlimit(int resource, struct rlimit *rlim)
FIX(rlim->rlim_cur);
FIX(rlim->rlim_max);
return 0;
+#else
+ return ret;
+#endif
}
-
-weak_alias(getrlimit, getrlimit64);
diff --git a/src/misc/ioctl.c b/src/misc/ioctl.c
index 89477511..35804f02 100644
--- a/src/misc/ioctl.c
+++ b/src/misc/ioctl.c
@@ -4,7 +4,9 @@
#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)
@@ -28,6 +30,12 @@ struct ioctl_compat_map {
* 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) },
@@ -46,16 +54,17 @@ static const struct ioctl_compat_map compat_map[] = {
{ _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, 8, WR, 1, OFFS(0,4) }, /* snd_pcm_mmap_control */
+ { 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(72)), _IOWR('V', 9, char[72]), 72, WR, 0, OFFS(20) },
- { _IOWR('V', 15, new_misaligned(72)), _IOWR('V', 15, char[72]), 72, WR, 0, OFFS(20) },
- { _IOWR('V', 17, new_misaligned(72)), _IOWR('V', 17, char[72]), 72, WR, 0, OFFS(20) },
- { _IOWR('V', 93, new_misaligned(72)), _IOWR('V', 93, char[72]), 72, WR, 0, OFFS(20) },
+ { _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(96)), _IOR('V', 89, char[96]), 96, R, 0, OFFS(76,80) },
+ { _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) },
@@ -82,7 +91,11 @@ static void convert_ioctl_struct(const struct ioctl_compat_map *map, char *old,
* 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);
- convert_ioctl_struct(map+3, old+68, new+72, 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++) {
diff --git a/src/misc/lockf.c b/src/misc/lockf.c
index 16a80bec..0162442b 100644
--- a/src/misc/lockf.c
+++ b/src/misc/lockf.c
@@ -28,5 +28,3 @@ int lockf(int fd, int op, off_t size)
errno = EINVAL;
return -1;
}
-
-weak_alias(lockf, lockf64);
diff --git a/src/misc/mntent.c b/src/misc/mntent.c
index eabb8200..78bf0cd0 100644
--- a/src/misc/mntent.c
+++ b/src/misc/mntent.c
@@ -2,6 +2,7 @@
#include <string.h>
#include <mntent.h>
#include <errno.h>
+#include <limits.h>
static char *internal_buf;
static size_t internal_bufsize;
@@ -19,9 +20,46 @@ int endmntent(FILE *f)
return 1;
}
+static char *unescape_ent(char *beg)
+{
+ char *dest = beg;
+ const char *src = beg;
+ while (*src) {
+ const char *val;
+ unsigned char cval = 0;
+ if (*src != '\\') {
+ *dest++ = *src++;
+ continue;
+ }
+ if (src[1] == '\\') {
+ ++src;
+ *dest++ = *src++;
+ continue;
+ }
+ val = src + 1;
+ for (int i = 0; i < 3; ++i) {
+ if (*val >= '0' && *val <= '7') {
+ cval <<= 3;
+ cval += *val++ - '0';
+ } else {
+ break;
+ }
+ }
+ if (cval) {
+ *dest++ = cval;
+ src = val;
+ } else {
+ *dest++ = *src++;
+ }
+ }
+ *dest = 0;
+ return beg;
+}
+
struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen)
{
- int cnt, n[8], use_internal = (linebuf == SENTINEL);
+ int n[8], use_internal = (linebuf == SENTINEL);
+ size_t len, i;
mnt->mnt_freq = 0;
mnt->mnt_passno = 0;
@@ -39,20 +77,24 @@ struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int bufle
errno = ERANGE;
return 0;
}
- cnt = sscanf(linebuf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d",
+
+ len = strlen(linebuf);
+ if (len > INT_MAX) continue;
+ for (i = 0; i < sizeof n / sizeof *n; i++) n[i] = len;
+ sscanf(linebuf, " %n%*[^ \t]%n %n%*[^ \t]%n %n%*[^ \t]%n %n%*[^ \t]%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]] == '#');
+ } while (linebuf[n[0]] == '#' || n[1]==len);
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];
+ mnt->mnt_fsname = unescape_ent(linebuf+n[0]);
+ mnt->mnt_dir = unescape_ent(linebuf+n[2]);
+ mnt->mnt_type = unescape_ent(linebuf+n[4]);
+ mnt->mnt_opts = unescape_ent(linebuf+n[6]);
return mnt;
}
diff --git a/src/misc/nftw.c b/src/misc/nftw.c
index 0a464100..71bc62ee 100644
--- a/src/misc/nftw.c
+++ b/src/misc/nftw.c
@@ -1,5 +1,6 @@
#include <ftw.h>
#include <dirent.h>
+#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
@@ -26,16 +27,19 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int,
struct history new;
int type;
int r;
+ int dfd;
+ int err;
struct FTW lev;
+ st.st_dev = st.st_ino = 0;
+
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 (access(path, R_OK) < 0) type = FTW_DNR;
- else if (flags & FTW_DEPTH) type = FTW_DP;
+ 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;
@@ -44,7 +48,7 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int,
type = FTW_F;
}
- if ((flags & FTW_MOUNT) && h && st.st_dev != h->dev)
+ if ((flags & FTW_MOUNT) && h && type != FTW_NS && st.st_dev != h->dev)
return 0;
new.chain = h;
@@ -63,6 +67,13 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int,
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;
@@ -71,7 +82,11 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int,
return 0;
if ((type == FTW_D || type == FTW_DP) && fd_limit) {
- DIR *d = opendir(path);
+ if (dfd < 0) {
+ errno = err;
+ return -1;
+ }
+ DIR *d = fdopendir(dfd);
if (d) {
struct dirent *de;
while ((de = readdir(d))) {
@@ -92,7 +107,8 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int,
}
}
closedir(d);
- } else if (errno != EACCES) {
+ } else {
+ close(dfd);
return -1;
}
}
@@ -124,5 +140,3 @@ int nftw(const char *path, int (*fn)(const char *, const struct stat *, int, str
pthread_setcancelstate(cs, 0);
return r;
}
-
-weak_alias(nftw, nftw64);
diff --git a/src/misc/realpath.c b/src/misc/realpath.c
index d2708e59..db8b74dc 100644
--- a/src/misc/realpath.c
+++ b/src/misc/realpath.c
@@ -1,43 +1,156 @@
#include <stdlib.h>
#include <limits.h>
-#include <sys/stat.h>
-#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
-#include "syscall.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)
{
- int fd;
- ssize_t r;
- struct stat st1, st2;
- char buf[15+3*sizeof(int)];
- char tmp[PATH_MAX];
+ 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);
- fd = sys_open(filename, O_PATH|O_NONBLOCK|O_CLOEXEC);
- if (fd < 0) return 0;
- __procfdname(buf, fd);
+ if (!l && !check_dir) break;
- r = readlink(buf, tmp, sizeof tmp - 1);
- if (r < 0) goto err;
- tmp[r] = 0;
+ /* Skip any . component but preserve check_dir status. */
+ if (l==1 && stack[p]=='.') {
+ p += l;
+ continue;
+ }
- fstat(fd, &st1);
- r = stat(tmp, &st2);
- if (r<0 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) {
- if (!r) errno = ELOOP;
- goto err;
+ /* 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;
}
- __syscall(SYS_close, fd);
- return resolved ? strcpy(resolved, tmp) : strdup(tmp);
-err:
- __syscall(SYS_close, fd);
+ 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/src/misc/setrlimit.c b/src/misc/setrlimit.c
index 7a66ab29..edb413fa 100644
--- a/src/misc/setrlimit.c
+++ b/src/misc/setrlimit.c
@@ -6,45 +6,46 @@
#define MIN(a, b) ((a)<(b) ? (a) : (b))
#define FIX(x) do{ if ((x)>=SYSCALL_RLIM_INFINITY) (x)=RLIM_INFINITY; }while(0)
-static int __setrlimit(int resource, const struct rlimit *rlim)
-{
- unsigned long k_rlim[2];
- 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 ret;
- k_rlim[0] = MIN(rlim->rlim_cur, MIN(-1UL, SYSCALL_RLIM_INFINITY));
- k_rlim[1] = MIN(rlim->rlim_max, MIN(-1UL, SYSCALL_RLIM_INFINITY));
- return __syscall(SYS_setrlimit, resource, k_rlim);
-}
-
struct ctx {
- const struct rlimit *rlim;
+ unsigned long lim[2];
int res;
int err;
};
+#ifdef SYS_setrlimit
static void do_setrlimit(void *p)
{
struct ctx *c = p;
if (c->err>0) return;
- c->err = -__setrlimit(c->res, c->rlim);
+ c->err = -__syscall(SYS_setrlimit, c->res, c->lim);
}
+#endif
int setrlimit(int resource, const struct rlimit *rlim)
{
- struct ctx c = { .res = resource, .rlim = rlim, .err = -1 };
+ 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);
+#ifdef SYS_setrlimit
+ 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;
+#else
+ return __syscall_ret(ret);
+#endif
}
-
-weak_alias(setrlimit, setrlimit64);
diff --git a/src/misc/syslog.c b/src/misc/syslog.c
index 13d4b0a6..710202f9 100644
--- a/src/misc/syslog.c
+++ b/src/misc/syslog.c
@@ -10,6 +10,8 @@
#include <errno.h>
#include <fcntl.h>
#include "lock.h"
+#include "fork_impl.h"
+#include "locale_impl.h"
static volatile int lock[1];
static char log_ident[32];
@@ -17,6 +19,7 @@ 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)
{
@@ -97,7 +100,7 @@ static void _vsyslog(int priority, const char *message, va_list ap)
now = time(NULL);
gmtime_r(&now, &tm);
- strftime(timebuf, sizeof timebuf, "%b %e %T", &tm);
+ strftime_l(timebuf, sizeof timebuf, "%b %e %T", &tm, C_LOCALE);
pid = (log_opt & LOG_PID) ? getpid() : 0;
l = snprintf(buf, sizeof buf, "<%d>%s %n%s%s%.0d%s: ",