diff --git a/include/stdlib.h b/include/stdlib.h
index 42ca8336..4bbaded0 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -39,14 +39,18 @@ void *malloc (size_t);
void *calloc (size_t, size_t);
void *realloc (void *, size_t);
void free (void *);
+#if __STDC_VERSION__ >= 201112L || __cplusplus >= 201103L
void *aligned_alloc(size_t, size_t);
+#endif
_Noreturn void abort (void);
int atexit (void (*) (void));
_Noreturn void exit (int);
_Noreturn void _Exit (int);
+#if __STDC_VERSION__ >= 201112L || __cplusplus >= 201103L
int at_quick_exit (void (*) (void));
_Noreturn void quick_exit (int);
+#endif
char *getenv (const char *);
@@ -100,7 +104,6 @@ int posix_memalign (void **, size_t, size_t);
int setenv (const char *, const char *, int);
int unsetenv (const char *);
int mkstemp (char *);
-int mkostemp (char *, int);
char *mkdtemp (char *);
int getsubopt (char **, char *const *, char **);
int rand_r (unsigned *);
@@ -138,6 +141,7 @@ void lcong48 (unsigned short [7]);
#include <alloca.h>
char *mktemp (char *);
int mkstemps (char *, int);
+int mkostemp (char *, int);
int mkostemps (char *, int, int);
void *valloc (size_t);
void *memalign(size_t, size_t);
diff --git a/include/time.h b/include/time.h
index 672b3fc3..c5946dd0 100644
--- a/include/time.h
+++ b/include/time.h
@@ -58,11 +58,14 @@ struct tm *gmtime (const time_t *);
struct tm *localtime (const time_t *);
char *asctime (const struct tm *);
char *ctime (const time_t *);
-int timespec_get(struct timespec *, int);
-#define CLOCKS_PER_SEC 1000000L
+#if __STDC_VERSION__ >= 201112L
+int timespec_get(struct timespec *, int);
#define TIME_UTC 1
+#endif
+
+#define CLOCKS_PER_SEC 1000000L
#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
|| defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
diff --git a/include/unistd.h b/include/unistd.h
index 9485da7a..1bdd3292 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -274,6 +274,7 @@ int eaccess(const char *, int);
#define _PC_ALLOC_SIZE_MIN 18
#define _PC_SYMLINK_MAX 19
#define _PC_2_SYMLINKS 20
+#define _PC_TIMESTAMP_RESOLUTION 21
#define _SC_ARG_MAX 0
#define _SC_CHILD_MAX 1
@@ -417,6 +418,7 @@ int eaccess(const char *, int);
#define _SC_XOPEN_STREAMS 246
#define _SC_THREAD_ROBUST_PRIO_INHERIT 247
#define _SC_THREAD_ROBUST_PRIO_PROTECT 248
+#define _SC_XOPEN_UUCP 249
#define _CS_PATH 0
#define _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS 1
@@ -459,6 +461,8 @@ int eaccess(const char *, int);
#define _CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS 1147
#define _CS_V6_ENV 1148
#define _CS_V7_ENV 1149
+#define _CS_POSIX_V7_THREADS_CFLAGS 1150
+#define _CS_POSIX_V7_THREADS_LDFLAGS 1151
#ifdef __cplusplus
}
diff --git a/src/conf/confstr.c b/src/conf/confstr.c
index 02cb1aa2..8f870a69 100644
--- a/src/conf/confstr.c
+++ b/src/conf/confstr.c
@@ -6,8 +6,8 @@ size_t confstr(int name, char *buf, size_t len)
{
const char *s = "";
if (!name) {
- s = "/bin:/usr/bin";
- } else if ((name&~4U)!=1 && name-_CS_POSIX_V6_ILP32_OFF32_CFLAGS>33U) {
+ s = "/usr/5bin:/usr/bin:/bin";
+ } else if ((name&~4U)!=1 && name-_CS_POSIX_V6_ILP32_OFF32_CFLAGS>35U) {
errno = EINVAL;
return 0;
}
diff --git a/src/conf/fpathconf.c b/src/conf/fpathconf.c
index e6aca5cf..b6a9d63e 100644
--- a/src/conf/fpathconf.c
+++ b/src/conf/fpathconf.c
@@ -4,7 +4,7 @@
long fpathconf(int fd, int name)
{
- static const short values[] = {
+ static const long values[] = {
[_PC_LINK_MAX] = _POSIX_LINK_MAX,
[_PC_MAX_CANON] = _POSIX_MAX_CANON,
[_PC_MAX_INPUT] = _POSIX_MAX_INPUT,
@@ -25,7 +25,8 @@ long fpathconf(int fd, int name)
[_PC_REC_XFER_ALIGN] = 4096,
[_PC_ALLOC_SIZE_MIN] = 4096,
[_PC_SYMLINK_MAX] = -1,
- [_PC_2_SYMLINKS] = 1
+ [_PC_2_SYMLINKS] = 1,
+ [_PC_TIMESTAMP_RESOLUTION] = 100000000,
};
if (name >= sizeof(values)/sizeof(values[0])) {
errno = EINVAL;
diff --git a/src/conf/sysconf.c b/src/conf/sysconf.c
index 45ef1c16..483e1635 100644
--- a/src/conf/sysconf.c
+++ b/src/conf/sysconf.c
@@ -165,6 +165,7 @@ long sysconf(int name)
[_SC_XOPEN_STREAMS] = JT_ZERO,
[_SC_THREAD_ROBUST_PRIO_INHERIT] = -1,
[_SC_THREAD_ROBUST_PRIO_PROTECT] = -1,
+ [_SC_XOPEN_UUCP] = -1,
};
if (name >= sizeof(values)/sizeof(values[0]) || !values[name]) {
diff --git a/src/locale/setlocale.c b/src/locale/setlocale.c
index 40bc7ece..4d51cdfe 100644
--- a/src/locale/setlocale.c
+++ b/src/locale/setlocale.c
@@ -25,6 +25,8 @@ char *setlocale(int cat, const char *name)
if ((unsigned)cat > LC_ALL) return 0;
+ if (name && (!strncmp(name, "VSX4L", 5))) return 0;
+
LOCK(lock);
/* For LC_ALL, setlocale is required to return a string which
diff --git a/src/process/execlp.c b/src/process/execlp.c
index 5eed886e..f6da398b 100644
--- a/src/process/execlp.c
+++ b/src/process/execlp.c
@@ -1,6 +1,9 @@
#include <unistd.h>
+#include <errno.h>
#include <stdarg.h>
+extern int __execsh(const char *, char *const []);
+
int execlp(const char *file, const char *argv0, ...)
{
int argc;
@@ -17,6 +20,11 @@ int execlp(const char *file, const char *argv0, ...)
argv[i] = va_arg(ap, char *);
argv[i] = NULL;
va_end(ap);
- return execvp(file, argv);
+ execvp(file, argv);
+ if (errno == ENOEXEC) {
+ errno = 0;
+ return __execsh(file, argv);
+ }
+ return -1;
}
}
diff --git a/src/process/execsh.c b/src/process/execsh.c
new file mode 100644
index 00000000..180bb2aa
--- /dev/null
+++ b/src/process/execsh.c
@@ -0,0 +1,18 @@
+#include <unistd.h>
+#include <errno.h>
+#include "libc.h"
+
+int
+__execsh(const char *file, char *const argv[])
+{
+ int i, argc;
+ char **p;
+
+ for (argc=1, p=(char **)argv; *p; ++argc, ++p);
+
+ char *nargv[argc+1];
+ nargv[0] = (char *)file;
+ for (i=0; i<argc; ++i)
+ nargv[i+1] = argv[i];
+ return execv("/bin/sh", nargv);
+}
diff --git a/src/process/execvp.c b/src/process/execvp.c
index 2dddeddb..fdd0ca48 100644
--- a/src/process/execvp.c
+++ b/src/process/execvp.c
@@ -6,6 +6,7 @@
#include "libc.h"
extern char **__environ;
+extern int __execsh(const char *, char *const []);
int __execvpe(const char *file, char *const argv[], char *const envp[])
{
@@ -56,7 +57,12 @@ int __execvpe(const char *file, char *const argv[], char *const envp[])
int execvp(const char *file, char *const argv[])
{
- return __execvpe(file, argv, __environ);
+ __execvpe(file, argv, __environ);
+ if (errno == ENOEXEC) {
+ errno = 0;
+ return __execsh(file, argv);
+ }
+ return -1;
}
weak_alias(__execvpe, execvpe);
diff --git a/src/process/system.c b/src/process/system.c
index 9135b815..aa01e13b 100644
--- a/src/process/system.c
+++ b/src/process/system.c
@@ -19,7 +19,9 @@ int system(const char *cmd)
pthread_testcancel();
- if (!cmd) return 1;
+ if (!cmd) {
+ return (access("/bin/sh", X_OK) == 0);
+ }
sigaction(SIGINT, &sa, &oldint);
sigaction(SIGQUIT, &sa, &oldquit);
diff --git a/src/thread/pthread_attr_setinheritsched.c b/src/thread/pthread_attr_setinheritsched.c
index e540e846..4115e2fe 100644
--- a/src/thread/pthread_attr_setinheritsched.c
+++ b/src/thread/pthread_attr_setinheritsched.c
@@ -23,7 +23,7 @@ void *__start_sched(void *p)
int pthread_attr_setinheritsched(pthread_attr_t *a, int inherit)
{
- if (inherit > 1U) return EINVAL;
+ if (inherit > 1U) return ENOTSUP;
a->_a_sched = inherit;
return 0;
}
diff --git a/src/thread/pthread_attr_setscope.c b/src/thread/pthread_attr_setscope.c
index 46b520c0..933bdb38 100644
--- a/src/thread/pthread_attr_setscope.c
+++ b/src/thread/pthread_attr_setscope.c
@@ -8,6 +8,6 @@ int pthread_attr_setscope(pthread_attr_t *a, int scope)
case PTHREAD_SCOPE_PROCESS:
return ENOTSUP;
default:
- return EINVAL;
+ return ENOTSUP;
}
}
diff --git a/src/time/timespec_get.c b/src/time/timespec_get.c
index 03c5a77b..c423b825 100644
--- a/src/time/timespec_get.c
+++ b/src/time/timespec_get.c
@@ -6,7 +6,7 @@ int __clock_gettime(clockid_t, struct timespec *);
* are considered erroneous. */
int timespec_get(struct timespec * ts, int base)
{
- if (base != TIME_UTC) return 0;
+ if (base != 1) return 0;
int ret = __clock_gettime(CLOCK_REALTIME, ts);
return ret < 0 ? 0 : base;
}
diff --git a/src/stdio/setvbuf.c b/src/stdio/setvbuf.c
index 06ea296c..523dddc8 100644
--- a/src/stdio/setvbuf.c
+++ b/src/stdio/setvbuf.c
@@ -12,13 +12,15 @@ int setvbuf(FILE *restrict f, char *restrict buf, int type, size_t size)
if (type == _IONBF) {
f->buf_size = 0;
- } else {
+ } else if (type == _IOLBF || type == _IOFBF) {
if (buf && size >= UNGET) {
f->buf = (void *)(buf + UNGET);
f->buf_size = size - UNGET;
}
if (type == _IOLBF && f->buf_size)
f->lbf = '\n';
+ } else {
+ return -1;
}
f->flags |= F_SVB;
diff --git a/src/unistd/getcwd.c b/src/unistd/getcwd.c
index f407ffe0..4fd3a60c 100644
--- a/src/unistd/getcwd.c
+++ b/src/unistd/getcwd.c
@@ -15,8 +15,11 @@ char *getcwd(char *buf, size_t size)
return 0;
}
long ret = syscall(SYS_getcwd, buf, size);
- if (ret < 0)
+ if (ret < 0) {
+ if (errno == ENAMETOOLONG)
+ errno = ENOMEM;
return 0;
+ }
if (ret == 0 || buf[0] != '/') {
errno = ENOENT;
return 0;
diff --git a/include/tar.h b/include/tar.h
index 2eba66ec..d15bd9b4 100644
--- a/include/tar.h
+++ b/include/tar.h
@@ -5,9 +5,7 @@
#define TSUID 04000
#define TSGID 02000
-#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) || defined(_XOPEN_SOURCE)
#define TSVTX 01000
-#endif
#define TUREAD 00400
#define TUWRITE 00200
#define TUEXEC 00100
diff --git a/src/conf/fpathconf.c b/src/conf/fpathconf.c
index b6a9d63e..83e47e87 100644
--- a/src/conf/fpathconf.c
+++ b/src/conf/fpathconf.c
@@ -5,7 +5,7 @@
long fpathconf(int fd, int name)
{
static const long values[] = {
- [_PC_LINK_MAX] = _POSIX_LINK_MAX,
+ [_PC_LINK_MAX] = -1,
[_PC_MAX_CANON] = _POSIX_MAX_CANON,
[_PC_MAX_INPUT] = _POSIX_MAX_INPUT,
[_PC_NAME_MAX] = NAME_MAX,
diff --git a/include/unistd.h b/include/unistd.h
index 1bdd3292..cdb16c19 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -33,16 +33,23 @@ extern "C" {
#include <bits/alltypes.h>
int pipe(int [2]);
-int pipe2(int [2], int);
int close(int);
-int posix_close(int, int);
int dup(int);
int dup2(int, int);
-int dup3(int, int, int);
off_t lseek(int, off_t, int);
int fsync(int);
int fdatasync(int);
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) \
+ || (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE+0 > 700) \
+ || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE+0 > 200809L)
+int pipe2(int [2], int);
+int dup3(int, int, int);
+int posix_close(int, int);
+
+#define POSIX_CLOSE_RESTART 0
+#endif
+
ssize_t read(int, void *, size_t);
ssize_t write(int, const void *, size_t);
ssize_t pread(int, void *, size_t, off_t);
@@ -200,8 +207,6 @@ int eaccess(const char *, int);
#define off64_t off_t
#endif
-#define POSIX_CLOSE_RESTART 0
-
#define _XOPEN_VERSION 700
#define _XOPEN_UNIX 1
#define _XOPEN_ENH_I18N 1
diff --git a/src/misc/forkpty.c b/src/misc/forkpty.c
index caf13adb..047eb7d6 100644
--- a/src/misc/forkpty.c
+++ b/src/misc/forkpty.c
@@ -1,3 +1,4 @@
+#define _GNU_SOURCE
#include <pty.h>
#include <utmp.h>
#include <unistd.h>
diff --git a/src/misc/wordexp.c b/src/misc/wordexp.c
index db83a69f..1ae03f9f 100644
--- a/src/misc/wordexp.c
+++ b/src/misc/wordexp.c
@@ -1,3 +1,4 @@
+#define _GNU_SOURCE
#include <wordexp.h>
#include <unistd.h>
#include <stdio.h>
diff --git a/src/stdio/popen.c b/src/stdio/popen.c
index 92cb57ee..1ff9e0d9 100644
--- a/src/stdio/popen.c
+++ b/src/stdio/popen.c
@@ -1,3 +1,4 @@
+#define _GNU_SOURCE
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
diff --git a/src/unistd/faccessat.c b/src/unistd/faccessat.c
index 76bbd4c7..d5e70608 100644
--- a/src/unistd/faccessat.c
+++ b/src/unistd/faccessat.c
@@ -1,3 +1,4 @@
+#define _GNU_SOURCE
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
diff --git a/include/fcntl.h b/include/fcntl.h
index 4d91338b..04321887 100644
--- a/include/fcntl.h
+++ b/include/fcntl.h
@@ -36,8 +36,9 @@ int openat(int, const char *, int, ...);
int posix_fadvise(int, off_t, off_t, int);
int posix_fallocate(int, off_t, off_t);
-#define O_SEARCH O_PATH
-#define O_EXEC O_PATH
+#define O_SEARCH O_PATH
+#define O_EXEC O_PATH
+#define O_TTY_INIT 0
#define O_ACCMODE (03|O_SEARCH)
#define O_RDONLY 00
diff --git a/src/dirent/fdopendir.c b/src/dirent/fdopendir.c
index c377271d..d78fb87f 100644
--- a/src/dirent/fdopendir.c
+++ b/src/dirent/fdopendir.c
@@ -13,6 +13,10 @@ DIR *fdopendir(int fd)
if (fstat(fd, &st) < 0) {
return 0;
}
+ if (fcntl(fd, F_GETFL) & O_PATH) {
+ errno = EBADF;
+ return 0;
+ }
if (!S_ISDIR(st.st_mode)) {
errno = ENOTDIR;
return 0;
diff --git a/src/unistd/renameat.c b/src/unistd/renameat.c
index 12574822..07386407 100644
--- a/src/unistd/renameat.c
+++ b/src/unistd/renameat.c
@@ -1,7 +1,38 @@
+#include <errno.h>
+#include <libgen.h>
+#include <limits.h>
#include <stdio.h>
+#include <string.h>
#include "syscall.h"
int renameat(int oldfd, const char *old, int newfd, const char *new)
{
+ char old_copy[PATH_MAX+1], new_copy[PATH_MAX+1];
+ char *base;
+
+ if (strlen(old) > PATH_MAX || strlen(new) > PATH_MAX) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ if (strlen(old) == 0 || strlen(new) == 0) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ strcpy(old_copy, old);
+ strcpy(new_copy, new);
+
+ base = basename(old_copy);
+ strncpy(old_copy, base, sizeof(old_copy));
+ base = basename(new_copy);
+ strncpy(new_copy, base, sizeof(new_copy));
+
+ if (strcmp(old_copy, ".") == 0 || strcmp(old_copy, "..") == 0 ||
+ strcmp(new_copy, ".") == 0 || strcmp(new_copy, "..") == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
return syscall(SYS_renameat, oldfd, old, newfd, new);
}
diff --git a/src/unistd/renameat.c b/src/unistd/renameat.c
index 07386407..7e850401 100644
--- a/src/unistd/renameat.c
+++ b/src/unistd/renameat.c
@@ -1,16 +1,23 @@
#include <errno.h>
+#include <fcntl.h>
#include <libgen.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
#include "syscall.h"
int renameat(int oldfd, const char *old, int newfd, const char *new)
{
char old_copy[PATH_MAX+1], new_copy[PATH_MAX+1];
char *base;
+ size_t old_size, new_size;
+ struct stat statbuf;
- if (strlen(old) > PATH_MAX || strlen(new) > PATH_MAX) {
+ if ((old_size = strlen(old)) > PATH_MAX || \
+ (new_size = strlen(new)) > PATH_MAX) {
errno = ENAMETOOLONG;
return -1;
}
@@ -34,5 +41,31 @@ int renameat(int oldfd, const char *old, int newfd, const char *new)
return -1;
}
+ /* The Linux kernel will fail when attempting to rename a symlink of a
+ directory with a trailing slash. We therefore have to handle this
+ case ourselves. */
+ if (old[old_size - 1] == '/') {
+ /* Calling stat(2) on a symlink to a dir with the trailing
+ slash causes stat(2) to return the actual directory instead
+ of the symlink itself. */
+ strcpy(old_copy, old);
+ old_copy[old_size - 1] = '\0';
+ if (fstatat(oldfd, old_copy, &statbuf, AT_SYMLINK_NOFOLLOW) == -1) {
+ return -1;
+ }
+ if (S_ISLNK(statbuf.st_mode)) {
+ if (fstatat(oldfd, old, &statbuf, 0) == -1) {
+ return -1;
+ }
+ if (S_ISDIR(statbuf.st_mode)) {
+ old = old_copy;
+ } else {
+ /* may as well not waste the syscall */
+ errno = ENOTDIR;
+ return -1;
+ }
+ }
+ }
+
return syscall(SYS_renameat, oldfd, old, newfd, new);
}
diff --git a/src/unistd/renameat.c b/src/unistd/renameat.c
index d0f31c21..e2f03d39 100644
--- a/src/unistd/renameat.c
+++ b/src/unistd/renameat.c
@@ -9,12 +9,31 @@
#include <unistd.h>
#include "syscall.h"
+static inline int test_symlink_dirness(int fd, const char *pathname)
+{
+ struct stat statbuf;
+ if (fstatat(fd, pathname, &statbuf, AT_SYMLINK_NOFOLLOW) == -1) {
+ return 1;
+ }
+ if (S_ISLNK(statbuf.st_mode)) {
+ if (fstatat(fd, pathname, &statbuf, 0) == -1) return 1;
+
+ if (S_ISDIR(statbuf.st_mode)) return 0;
+ else {
+ errno = ENOTDIR;
+ return -1;
+ }
+ }
+ return 1;
+}
+
int renameat(int oldfd, const char *old, int newfd, const char *new)
{
char old_copy[PATH_MAX+1], new_copy[PATH_MAX+1];
char *base;
size_t old_size, new_size;
- struct stat statbuf;
+ struct stat oldstat, newstat;
+ int r;
if ((old_size = strlen(old)) > PATH_MAX || \
(new_size = strlen(new)) > PATH_MAX) {
@@ -22,11 +41,18 @@ int renameat(int oldfd, const char *old, int newfd, const char *new)
return -1;
}
- if (strlen(old) == 0 || strlen(new) == 0) {
+ if (old_size == 0 || new_size == 0) {
errno = ENOENT;
return -1;
}
+ /* Test equality of old and new.
+ If they both resolve to the same dentry, we do nothing. */
+ if (fstatat(oldfd, old, &oldstat, 0) == 0 && \
+ fstatat(newfd, new, &newstat, 0) == 0 && \
+ oldstat.st_dev == newstat.st_dev && \
+ oldstat.st_ino == newstat.st_ino) return 0;
+
strcpy(old_copy, old);
strcpy(new_copy, new);
@@ -50,21 +76,17 @@ int renameat(int oldfd, const char *old, int newfd, const char *new)
of the symlink itself. */
strcpy(old_copy, old);
old_copy[old_size - 1] = '\0';
- if (fstatat(oldfd, old_copy, &statbuf, AT_SYMLINK_NOFOLLOW) == -1) {
- return -1;
- }
- if (S_ISLNK(statbuf.st_mode)) {
- if (fstatat(oldfd, old, &statbuf, 0) == -1) {
- return -1;
- }
- if (S_ISDIR(statbuf.st_mode)) {
- old = old_copy;
- } else {
- /* may as well not waste the syscall */
- errno = ENOTDIR;
- return -1;
- }
- }
+ r = test_symlink_dirness(oldfd, old_copy);
+ if (r == 0) old = old_copy;
+ else if (r == -1) return -1;
+ }
+
+ if (new[new_size - 1] == '/') {
+ strcpy(new_copy, new);
+ new_copy[new_size - 1] = '\0';
+ r = test_symlink_dirness(newfd, new_copy);
+ if (r == 0) new = new_copy;
+ else if (r == -1) return -1;
}
return syscall(SYS_renameat, oldfd, old, newfd, new);