From mboxrd@z Thu Jan 1 00:00:00 1970 X-Msuck: nntp://news.gmane.org/gmane.linux.lib.musl.general/5163 Path: news.gmane.org!not-for-mail From: Rich Felker Newsgroups: gmane.linux.lib.musl.general Subject: [UGLY PATCH v2] Support for no-legacy-syscalls archs Date: Mon, 26 May 2014 14:40:36 -0400 Message-ID: <20140526184036.GZ507@brightrain.aerifal.cx> References: <20140525054237.GA18085@brightrain.aerifal.cx> Reply-To: musl@lists.openwall.com NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="z9ECzHErBrwFF8sy" X-Trace: ger.gmane.org 1401129660 21310 80.91.229.3 (26 May 2014 18:41:00 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Mon, 26 May 2014 18:41:00 +0000 (UTC) To: musl@lists.openwall.com Original-X-From: musl-return-5168-gllmg-musl=m.gmane.org@lists.openwall.com Mon May 26 20:40:54 2014 Return-path: Envelope-to: gllmg-musl@plane.gmane.org Original-Received: from mother.openwall.net ([195.42.179.200]) by plane.gmane.org with smtp (Exim 4.69) (envelope-from ) id 1WozpM-00076i-RI for gllmg-musl@plane.gmane.org; Mon, 26 May 2014 20:40:53 +0200 Original-Received: (qmail 31855 invoked by uid 550); 26 May 2014 18:40:51 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: Original-Received: (qmail 31845 invoked from network); 26 May 2014 18:40:50 -0000 Content-Disposition: inline In-Reply-To: <20140525054237.GA18085@brightrain.aerifal.cx> User-Agent: Mutt/1.5.21 (2010-09-15) Original-Sender: Rich Felker Xref: news.gmane.org gmane.linux.lib.musl.general:5163 Archived-At: --z9ECzHErBrwFF8sy Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Here's the v2 of this patch. Some small bugs and inefficiencies have been fixed, but the main big difference is that the whole utime-family has been reworked to all go through utimensat, and the latter now has fallbacks for old kernels that lack the new syscall. While this increases the weight of all of these functions on modern systems that do have the legacy syscalls (and thus might lack the new one, if they're using outdated kernels) it eliminates the incentive for programmers to use the outdated libc functions to get better behavior on ancient, unsupported kernels, and puts all the fallback logic in a common place rather than splitting it out over multiple functions. Comments welcome. I'm still going to hold off a bit longer on committing this in case there are better ideas for how to do it. Rich --z9ECzHErBrwFF8sy Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="no_legacy_syscall_archs_v2.diff" diff --git a/src/env/__libc_start_main.c b/src/env/__libc_start_main.c index d7481c2..c10a3f3 100644 --- a/src/env/__libc_start_main.c +++ b/src/env/__libc_start_main.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "syscall.h" #include "atomic.h" #include "libc.h" @@ -48,7 +49,11 @@ void __init_libc(char **envp, char *pn) && !aux[AT_SECURE]) return; struct pollfd pfd[3] = { {.fd=0}, {.fd=1}, {.fd=2} }; +#ifdef SYS_poll __syscall(SYS_poll, pfd, 3, 0); +#else + __syscall(SYS_ppoll, pfd, 3, &(struct timespec){0}, 0, _NSIG/8); +#endif for (i=0; i<3; i++) if (pfd[i].revents&POLLNVAL) if (__sys_open("/dev/null", O_RDWR)<0) a_crash(); diff --git a/src/linux/utimes.c b/src/linux/utimes.c index 70c0695..b814c88 100644 --- a/src/linux/utimes.c +++ b/src/linux/utimes.c @@ -1,7 +1,10 @@ #include +#include "fcntl.h" #include "syscall.h" +int __futimesat(int, const char *, const struct timeval [2]); + int utimes(const char *path, const struct timeval times[2]) { - return syscall(SYS_utimes, path, times); + return __futimesat(AT_FDCWD, path, times); } diff --git a/src/process/fork.c b/src/process/fork.c index 864c7d7..89b04c6 100644 --- a/src/process/fork.c +++ b/src/process/fork.c @@ -1,5 +1,6 @@ #include #include +#include #include "syscall.h" #include "libc.h" #include "pthread_impl.h" @@ -16,7 +17,11 @@ pid_t fork(void) sigset_t set; __fork_handler(-1); __block_all_sigs(&set); +#ifdef SYS_fork ret = syscall(SYS_fork); +#else + ret = syscall(SYS_clone, SIGCHLD); +#endif if (libc.has_thread_pointer && !ret) { pthread_t self = __pthread_self(); self->tid = self->pid = __syscall(SYS_getpid); diff --git a/src/process/posix_spawn.c b/src/process/posix_spawn.c index 08644f5..6fa33cb 100644 --- a/src/process/posix_spawn.c +++ b/src/process/posix_spawn.c @@ -22,6 +22,18 @@ struct args { void __get_handler_set(sigset_t *); +static int do_dup2(int old, int new) +{ + int r; +#ifdef SYS_dup2 + while ((r=__syscall(SYS_dup2, old, new))==-EBUSY); +#else + while ((r=__syscall(SYS_dup3, old, new, 0))==-EBUSY); + if (r==-EINVAL && old==new) return new; +#endif + return r; +} + static int child(void *args_vp) { int i, ret; @@ -92,14 +104,14 @@ static int child(void *args_vp) goto fail; break; case FDOP_DUP2: - if ((ret=__syscall(SYS_dup2, op->srcfd, op->fd))<0) + if ((ret=do_dup2(op->srcfd, op->fd))<0) goto fail; break; case FDOP_OPEN: fd = __sys_open(op->path, op->oflag, op->mode); if ((ret=fd) < 0) goto fail; if (fd != op->fd) { - if ((ret=__syscall(SYS_dup2, fd, op->fd))<0) + if ((ret=do_dup2(fd, op->fd))<0) goto fail; __syscall(SYS_close, fd); } diff --git a/src/select/poll.c b/src/select/poll.c index f1e73e8..f756643 100644 --- a/src/select/poll.c +++ b/src/select/poll.c @@ -4,5 +4,11 @@ int poll(struct pollfd *fds, nfds_t n, int timeout) { +#ifdef SYS_poll return syscall_cp(SYS_poll, fds, n, timeout); +#else + return syscall_cp(SYS_ppoll, fds, n, timeout>=0 ? + &(struct timespec){ .tv_sec = timeout/1000, + .tv_nsec = timeout%1000*1000000 } : 0, 0, _NSIG/8); +#endif } diff --git a/src/select/select.c b/src/select/select.c index f93597b..cbff8c0 100644 --- a/src/select/select.c +++ b/src/select/select.c @@ -4,5 +4,16 @@ int select(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, struct timeval *restrict tv) { +#ifdef SYS_select return syscall_cp(SYS_select, n, rfds, wfds, efds, tv); +#else + long data[2] = { 0, _NSIG/8 }; + struct timespec ts; + if (tv) { + ts.tv_sec = tv->tv_sec; + ts.tv_nsec = tv->tv_usec > 999999 ? + 999999999 : tv->tv_usec * 1000; + } + return syscall_cp(SYS_pselect6, n, rfds, wfds, efds, tv ? &ts : 0, data); +#endif } diff --git a/src/stat/chmod.c b/src/stat/chmod.c index beb66e5..d4f53c5 100644 --- a/src/stat/chmod.c +++ b/src/stat/chmod.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int chmod(const char *path, mode_t mode) { +#ifdef SYS_chmod return syscall(SYS_chmod, path, mode); +#else + return syscall(SYS_fchmodat, AT_FDCWD, path, mode); +#endif } diff --git a/src/stat/futimesat.c b/src/stat/futimesat.c index dbefc84..5990aa6 100644 --- a/src/stat/futimesat.c +++ b/src/stat/futimesat.c @@ -1,10 +1,23 @@ #define _GNU_SOURCE #include +#include +#include #include "syscall.h" +#include "libc.h" -#ifdef SYS_futimesat -int futimesat(int dirfd, const char *pathname, const struct timeval times[2]) +int __futimesat(int dirfd, const char *pathname, const struct timeval times[2]) { - return syscall(SYS_futimesat, dirfd, pathname, times); + struct timespec ts[2]; + if (times) { + int i; + for (i=0; i<2; i++) { + if (times[i].tv_usec >= 1000000U) + return __syscall_ret(-EINVAL); + ts[i].tv_sec = times[i].tv_sec; + ts[i].tv_nsec = times[i].tv_usec * 1000; + } + } + return utimensat(dirfd, pathname, times ? ts : 0, 0); } -#endif + +weak_alias(__futimesat, futimesat); diff --git a/src/stat/lstat.c b/src/stat/lstat.c index 8f60358..5e8b84f 100644 --- a/src/stat/lstat.c +++ b/src/stat/lstat.c @@ -1,10 +1,15 @@ #include +#include #include "syscall.h" #include "libc.h" int lstat(const char *restrict path, struct stat *restrict buf) { +#ifdef SYS_lstat return syscall(SYS_lstat, path, buf); +#else + return syscall(SYS_fstatat, AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW); +#endif } LFS64(lstat); diff --git a/src/stat/mkdir.c b/src/stat/mkdir.c index 770e1cc..32625b7 100644 --- a/src/stat/mkdir.c +++ b/src/stat/mkdir.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int mkdir(const char *path, mode_t mode) { +#ifdef SYS_mkdir return syscall(SYS_mkdir, path, mode); +#else + return syscall(SYS_mkdirat, AT_FDCWD, path, mode); +#endif } diff --git a/src/stat/mknod.c b/src/stat/mknod.c index c319657..beebd84 100644 --- a/src/stat/mknod.c +++ b/src/stat/mknod.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int mknod(const char *path, mode_t mode, dev_t dev) { +#ifdef SYS_mknod return syscall(SYS_mknod, path, mode, dev); +#else + return syscall(SYS_mknodat, AT_FDCWD, path, mode, dev); +#endif } diff --git a/src/stat/stat.c b/src/stat/stat.c index c6de716..b4433a0 100644 --- a/src/stat/stat.c +++ b/src/stat/stat.c @@ -1,10 +1,15 @@ #include +#include #include "syscall.h" #include "libc.h" int stat(const char *restrict path, struct stat *restrict buf) { +#ifdef SYS_stat return syscall(SYS_stat, path, buf); +#else + return syscall(SYS_fstatat, AT_FDCWD, path, buf, 0); +#endif } LFS64(stat); diff --git a/src/stat/utimensat.c b/src/stat/utimensat.c index 929698b..abc8d74 100644 --- a/src/stat/utimensat.c +++ b/src/stat/utimensat.c @@ -1,7 +1,40 @@ #include +#include +#include +#include #include "syscall.h" int utimensat(int fd, const char *path, const struct timespec times[2], int flags) { - return syscall(SYS_utimensat, fd, path, times, flags); + int r = __syscall(SYS_utimensat, fd, path, times, flags); + if (r != -ENOSYS || flags) return __syscall_ret(r); + +#ifdef SYS_futimesat + struct timeval *tv = 0; + if (times) { + struct timeval tmp[2]; + int i; + tv = tmp; + for (i=0; i<2; i++) { + if (times[i].tv_nsec >= 1000000000U) { + if (times[i].tv_nsec == UTIME_NOW && + times[1-i].tv_nsec == UTIME_NOW) { + tv = 0; + break; + } + if (times[i].tv_nsec == UTIME_OMIT) + return __syscall_ret(-ENOSYS); + return __syscall_ret(-EINVAL); + } + tmp[i].tv_sec = times[i].tv_sec; + tmp[i].tv_usec = 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); } diff --git a/src/stdio/rename.c b/src/stdio/rename.c index 97f1453..04c90c0 100644 --- a/src/stdio/rename.c +++ b/src/stdio/rename.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int rename(const char *old, const char *new) { +#ifdef SYS_rename return syscall(SYS_rename, old, new); +#else + return syscall(SYS_renameat, AT_FDCWD, old, AT_FDCWD, new); +#endif } diff --git a/src/time/utime.c b/src/time/utime.c index b2b5741..3b5f4e3 100644 --- a/src/time/utime.c +++ b/src/time/utime.c @@ -1,14 +1,16 @@ #include -#include -#include "syscall.h" +#include +#include +#include int utime(const char *path, const struct utimbuf *times) { + struct timespec *ts = 0; if (times) { - struct timeval tv[2] = { + struct timespec tmp[2] = { { .tv_sec = times->actime }, { .tv_sec = times->modtime } }; - return syscall(SYS_utimes, path, tv); + ts = tmp; } - return syscall(SYS_utimes, path, 0); + return utimensat(AT_FDCWD, path, ts, 0); } diff --git a/src/unistd/access.c b/src/unistd/access.c index e7ce73a..d6eed68 100644 --- a/src/unistd/access.c +++ b/src/unistd/access.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int access(const char *filename, int amode) { +#ifdef SYS_access return syscall(SYS_access, filename, amode); +#else + return syscall(SYS_faccessat, AT_FDCWD, filename, amode, 0); +#endif } diff --git a/src/unistd/chown.c b/src/unistd/chown.c index 95f6f61..14b0325 100644 --- a/src/unistd/chown.c +++ b/src/unistd/chown.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int chown(const char *path, uid_t uid, gid_t gid) { +#ifdef SYS_chown return syscall(SYS_chown, path, uid, gid); +#else + return syscall(SYS_fchownat, AT_FDCWD, path, uid, gid, 0); +#endif } diff --git a/src/unistd/dup2.c b/src/unistd/dup2.c index 87a0d44..ed04a89 100644 --- a/src/unistd/dup2.c +++ b/src/unistd/dup2.c @@ -5,6 +5,11 @@ int dup2(int old, int new) { int r; +#ifdef SYS_dup2 while ((r=__syscall(SYS_dup2, old, new))==-EBUSY); +#else + while ((r=__syscall(SYS_dup3, old, new, 0))==-EBUSY); + if (r==-EINVAL && old==new) return new; +#endif return __syscall_ret(r); } diff --git a/src/unistd/getpgrp.c b/src/unistd/getpgrp.c index 433f42e..5a74d4f 100644 --- a/src/unistd/getpgrp.c +++ b/src/unistd/getpgrp.c @@ -3,5 +3,9 @@ pid_t getpgrp(void) { +#ifdef SYS_getpgrp return __syscall(SYS_getpgrp); +#else + return __syscall(SYS_getpgid, 0); +#endif } diff --git a/src/unistd/lchown.c b/src/unistd/lchown.c index de871ae..ccd5ee0 100644 --- a/src/unistd/lchown.c +++ b/src/unistd/lchown.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int lchown(const char *path, uid_t uid, gid_t gid) { +#ifdef SYS_lchown return syscall(SYS_lchown, path, uid, gid); +#else + return syscall(SYS_fchownat, AT_FDCWD, path, uid, gid, AT_SYMLINK_NOFOLLOW); +#endif } diff --git a/src/unistd/link.c b/src/unistd/link.c index 20193f2..feec18e 100644 --- a/src/unistd/link.c +++ b/src/unistd/link.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int link(const char *existing, const char *new) { +#ifdef SYS_link return syscall(SYS_link, existing, new); +#else + return syscall(SYS_linkat, AT_FDCWD, existing, AT_FDCWD, new, 0); +#endif } diff --git a/src/unistd/pause.c b/src/unistd/pause.c index f7ed17d..50bf3b1 100644 --- a/src/unistd/pause.c +++ b/src/unistd/pause.c @@ -4,5 +4,11 @@ int pause(void) { +#ifdef SYS_pause return syscall_cp(SYS_pause); +#else + sigset_t mask; + __syscall(SYS_rt_sigprocmask, SIG_BLOCK, 0, &mask, _NSIG/8); + return syscall_cp(SYS_rt_sigsuspend, &mask, _NSIG/8); +#endif } diff --git a/src/unistd/pipe.c b/src/unistd/pipe.c index 36c6f13..d07b8d2 100644 --- a/src/unistd/pipe.c +++ b/src/unistd/pipe.c @@ -3,5 +3,9 @@ int pipe(int fd[2]) { +#ifdef SYS_pipe return syscall(SYS_pipe, fd); +#else + return syscall(SYS_pipe2, fd, 0); +#endif } diff --git a/src/unistd/readlink.c b/src/unistd/readlink.c index ec291e3..a152d52 100644 --- a/src/unistd/readlink.c +++ b/src/unistd/readlink.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize) { +#ifdef SYS_readlink return syscall(SYS_readlink, path, buf, bufsize); +#else + return syscall(SYS_readlinkat, AT_FDCWD, path, buf, bufsize); +#endif } diff --git a/src/unistd/rmdir.c b/src/unistd/rmdir.c index dfe1605..6825ffc 100644 --- a/src/unistd/rmdir.c +++ b/src/unistd/rmdir.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int rmdir(const char *path) { +#ifdef SYS_rmdir return syscall(SYS_rmdir, path); +#else + return syscall(SYS_unlinkat, AT_FDCWD, path, AT_REMOVEDIR); +#endif } diff --git a/src/unistd/symlink.c b/src/unistd/symlink.c index 5902d45..0973d78 100644 --- a/src/unistd/symlink.c +++ b/src/unistd/symlink.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int symlink(const char *existing, const char *new) { +#ifdef SYS_symlink return syscall(SYS_symlink, existing, new); +#else + return syscall(SYS_symlinkat, existing, AT_FDCWD, new); +#endif } diff --git a/src/unistd/unlink.c b/src/unistd/unlink.c index bdb37be..c40c28d 100644 --- a/src/unistd/unlink.c +++ b/src/unistd/unlink.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int unlink(const char *path) { +#ifdef SYS_unlink return syscall(SYS_unlink, path); +#else + return syscall(SYS_unlinkat, AT_FDCWD, path, 0); +#endif } --z9ECzHErBrwFF8sy--