diff --git a/compat/time32/timespec_get_time32.c b/compat/time32/timespec_get_time32.c index e9ca94cb..b39b12ee 100644 --- a/compat/time32/timespec_get_time32.c +++ b/compat/time32/timespec_get_time32.c @@ -1,3 +1,4 @@ +#define _BSD_SOURCE #include "time32.h" #include #include diff --git a/include/stdlib.h b/include/stdlib.h index 194c2033..5734b1f0 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 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/sys/time.h b/include/sys/time.h index cdc67ef6..fd773896 100644 --- a/include/sys/time.h +++ b/include/sys/time.h @@ -13,6 +13,7 @@ int gettimeofday (struct timeval *__restrict, void *__restrict); #define ITIMER_REAL 0 #define ITIMER_VIRTUAL 1 #define ITIMER_PROF 2 +#define __USE_TIME_BITS64 1 struct itimerval { struct timeval it_interval; diff --git a/include/time.h b/include/time.h index 5494df18..2412fe22 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 || defined(_BSD_SOURCE) || defined(_GNU_SOURCE) +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) \ @@ -137,7 +140,10 @@ __REDIR(mktime, __mktime64); __REDIR(gmtime, __gmtime64); __REDIR(localtime, __localtime64); __REDIR(ctime, __ctime64); +# if __STDC_VERSION__ >= 201112L || defined(_BSD_SOURCE) \ + || defined(_GNU_SOURCE) __REDIR(timespec_get, __timespec_get_time64); +# endif #if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \ || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \ || defined(_BSD_SOURCE) diff --git a/include/unistd.h b/include/unistd.h index 7bcbff94..6fd67160 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -33,16 +33,23 @@ extern "C" { #include 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); @@ -202,8 +209,6 @@ ssize_t copy_file_range(int, off_t *, int, off_t *, size_t, unsigned); #define off64_t off_t #endif -#define POSIX_CLOSE_RESTART 0 - #define _XOPEN_VERSION 700 #define _XOPEN_UNIX 1 #define _XOPEN_ENH_I18N 1 @@ -276,6 +281,7 @@ ssize_t copy_file_range(int, off_t *, int, off_t *, size_t, unsigned); #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 @@ -419,6 +425,7 @@ ssize_t copy_file_range(int, off_t *, int, off_t *, size_t, unsigned); #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 @@ -461,6 +468,8 @@ ssize_t copy_file_range(int, off_t *, int, off_t *, size_t, unsigned); #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..83e47e87 100644 --- a/src/conf/fpathconf.c +++ b/src/conf/fpathconf.c @@ -4,8 +4,8 @@ long fpathconf(int fd, int name) { - static const short values[] = { - [_PC_LINK_MAX] = _POSIX_LINK_MAX, + static const long values[] = { + [_PC_LINK_MAX] = -1, [_PC_MAX_CANON] = _POSIX_MAX_CANON, [_PC_MAX_INPUT] = _POSIX_MAX_INPUT, [_PC_NAME_MAX] = NAME_MAX, @@ -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 3baaed32..04369596 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 2bc7b500..4a601eaf 100644 --- a/src/locale/setlocale.c +++ b/src/locale/setlocale.c @@ -14,6 +14,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/misc/forkpty.c b/src/misc/forkpty.c index caf13adb..43494b96 100644 --- a/src/misc/forkpty.c +++ b/src/misc/forkpty.c @@ -1,3 +1,4 @@ +#define _GNU_SOURCE #include #include #include diff --git a/src/misc/wordexp.c b/src/misc/wordexp.c index db83a69f..be9cb6d5 100644 --- a/src/misc/wordexp.c +++ b/src/misc/wordexp.c @@ -1,3 +1,4 @@ +#define _GNU_SOURCE #include #include #include 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 +#include #include +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 +#include +#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 extern char **__environ; +extern int __execsh(const char *, char *const []); int __execvpe(const char *file, char *const argv[], char *const envp[]) { @@ -54,7 +55,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 5af59b80..3f61d278 100644 --- a/src/process/system.c +++ b/src/process/system.c @@ -18,7 +18,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/stdio/popen.c b/src/stdio/popen.c index 92cb57ee..70c5d6ec 100644 --- a/src/stdio/popen.c +++ b/src/stdio/popen.c @@ -1,3 +1,4 @@ +#define _GNU_SOURCE #include #include #include diff --git a/src/thread/pthread_attr_setinheritsched.c b/src/thread/pthread_attr_setinheritsched.c index ca264be7..fbfff6f8 100644 --- a/src/thread/pthread_attr_setinheritsched.c +++ b/src/thread/pthread_attr_setinheritsched.c @@ -3,7 +3,7 @@ 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/strftime.c b/src/time/strftime.c index cc53d536..98caa1f6 100644 --- a/src/time/strftime.c +++ b/src/time/strftime.c @@ -95,6 +95,8 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm * case 'H': val = tm->tm_hour; goto number; + case 'l': + def_pad = ' '; case 'I': val = tm->tm_hour; if (!val) val = 12; diff --git a/src/time/timespec_get.c b/src/time/timespec_get.c index 40ea9c1c..e396da09 100644 --- a/src/time/timespec_get.c +++ b/src/time/timespec_get.c @@ -1,3 +1,4 @@ +#define _BSD_SOURCE #include /* There is no other implemented value than TIME_UTC; all other values diff --git a/src/unistd/faccessat.c b/src/unistd/faccessat.c index 76bbd4c7..0b4564f9 100644 --- a/src/unistd/faccessat.c +++ b/src/unistd/faccessat.c @@ -1,3 +1,4 @@ +#define _GNU_SOURCE #include #include #include 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/src/unistd/renameat.c b/src/unistd/renameat.c index c3b40a25..6af5aed6 100644 --- a/src/unistd/renameat.c +++ b/src/unistd/renameat.c @@ -1,11 +1,93 @@ +#include +#include +#include +#include #include +#include +#include +#include +#include #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) { -#ifdef SYS_renameat + char old_copy[PATH_MAX+1], new_copy[PATH_MAX+1]; + char *base; + size_t old_size, new_size; + struct stat oldstat, newstat; + int r; + + if ((old_size = strlen(old)) > PATH_MAX || \ + (new_size = strlen(new)) > PATH_MAX) { + errno = ENAMETOOLONG; + return -1; + } + + 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, AT_SYMLINK_NOFOLLOW) == 0 && \ + fstatat(newfd, new, &newstat, AT_SYMLINK_NOFOLLOW) == 0 && \ + oldstat.st_dev == newstat.st_dev && \ + oldstat.st_ino == newstat.st_ino) return 0; + + 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; + } + + /* 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'; + 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); -#else - return syscall(SYS_renameat2, oldfd, old, newfd, new, 0); -#endif }