diff options
Diffstat (limited to 'src/misc')
| -rw-r--r-- | src/misc/getentropy.c | 2 | ||||
| -rw-r--r-- | src/misc/getopt.c | 3 | ||||
| -rw-r--r-- | src/misc/getrlimit.c | 8 | ||||
| -rw-r--r-- | src/misc/initgroups.c | 26 | ||||
| -rw-r--r-- | src/misc/ioctl.c | 149 | ||||
| -rw-r--r-- | src/misc/lockf.c | 2 | ||||
| -rw-r--r-- | src/misc/mntent.c | 66 | ||||
| -rw-r--r-- | src/misc/nftw.c | 28 | ||||
| -rw-r--r-- | src/misc/pty.c | 4 | ||||
| -rw-r--r-- | src/misc/realpath.c | 159 | ||||
| -rw-r--r-- | src/misc/setrlimit.c | 45 | ||||
| -rw-r--r-- | src/misc/syslog.c | 5 | 
12 files changed, 407 insertions, 90 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/initgroups.c b/src/misc/initgroups.c index 922a9581..101f5c7b 100644 --- a/src/misc/initgroups.c +++ b/src/misc/initgroups.c @@ -1,11 +1,29 @@  #define _GNU_SOURCE  #include <grp.h>  #include <limits.h> +#include <stdlib.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); +	gid_t buf[32], *groups = buf; +	int count = sizeof buf / sizeof *buf, prev_count = count; +	while (getgrouplist(user, gid, groups, &count) < 0) { +		if (groups != buf) free(groups); + +		/* Return if failure isn't buffer size */ +		if (count <= prev_count) +			return -1; + +		/* Always increase by at least 50% to limit to +		 * logarithmically many retries on TOCTOU races. */ +		if (count < prev_count + (prev_count>>1)) +			count = prev_count + (prev_count>>1); + +		groups = calloc(count, sizeof *groups); +		if (!groups) return -1; +		prev_count = count; +	} +	int ret = setgroups(count, groups); +	if (groups != buf) free(groups); +	return ret;  } diff --git a/src/misc/ioctl.c b/src/misc/ioctl.c index 6f31d4bc..35804f02 100644 --- a/src/misc/ioctl.c +++ b/src/misc/ioctl.c @@ -3,8 +3,128 @@  #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; @@ -13,23 +133,18 @@ int ioctl(int fd, int req, ...)  	arg = va_arg(ap, void *);  	va_end(ap);  	int r = __syscall(SYS_ioctl, fd, req, arg); -	if (r==-ENOTTY) switch (req) { -	case SIOCGSTAMP: -	case SIOCGSTAMPNS: -		if (SIOCGSTAMP==SIOCGSTAMP_OLD) break; -		if (req==SIOCGSTAMP) req=SIOCGSTAMP_OLD; -		if (req==SIOCGSTAMPNS) req=SIOCGSTAMPNS_OLD; -		long t32[2]; -		r = __syscall(SYS_ioctl, fd, req, t32); -		if (r<0) break; -		if (req==SIOCGSTAMP_OLD) { -			struct timeval *tv = arg; -			tv->tv_sec = t32[0]; -			tv->tv_usec = t32[1]; -		} else { -			struct timespec *ts = arg; -			ts->tv_sec = t32[0]; -			ts->tv_nsec = t32[1]; +	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/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..76f9c162 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 %n%*[^ \t\n]%n %n%*[^ \t\n]%n %n%*[^ \t\n]%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;  } @@ -73,5 +115,13 @@ int addmntent(FILE *f, const struct mntent *mnt)  char *hasmntopt(const struct mntent *mnt, const char *opt)  { -	return strstr(mnt->mnt_opts, opt); +	size_t l = strlen(opt); +	char *p = mnt->mnt_opts; +	for (;;) { +		if (!strncmp(p, opt, l) && (!p[l] || p[l]==',' || p[l]=='=')) +			return p; +		p = strchr(p, ','); +		if (!p) return 0; +		p++; +	}  } 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/pty.c b/src/misc/pty.c index b9cb5eaa..a0577147 100644 --- a/src/misc/pty.c +++ b/src/misc/pty.c @@ -7,7 +7,9 @@  int posix_openpt(int flags)  { -	return open("/dev/ptmx", flags); +	int r = open("/dev/ptmx", flags); +	if (r < 0 && errno == ENOSPC) errno = EAGAIN; +	return r;  }  int grantpt(int fd) 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: ", | 
