mailing list of musl libc
 help / color / mirror / code / Atom feed
* [UGLY PATCH] Support for no-legacy-syscalls archs
@ 2014-05-25  5:42 Rich Felker
  2014-05-25  9:52 ` Szabolcs Nagy
                   ` (3 more replies)
  0 siblings, 4 replies; 15+ messages in thread
From: Rich Felker @ 2014-05-25  5:42 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 359 bytes --]

Here's a proposed next phase for supporting no-legacy-syscall archs
(aarch64 and or1k, among others). It's not complete but I think it
covers most of the important syscalls for standard functionality (not
linux-specific stuff tho). Some of them might be missing some error
cases or otherwise buggy so I'm sending the patch for review before
committing.

Rich

[-- Attachment #2: no_legacy_syscall_archs.diff --]
[-- Type: text/plain, Size: 10361 bytes --]

diff --git a/src/env/__libc_start_main.c b/src/env/__libc_start_main.c
index d7481c2..f98a858 100644
--- a/src/env/__libc_start_main.c
+++ b/src/env/__libc_start_main.c
@@ -1,6 +1,7 @@
 #include <elf.h>
 #include <poll.h>
 #include <fcntl.h>
+#include <signal.h>
 #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, 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/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 <unistd.h>
 #include <string.h>
+#include <signal.h>
 #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/select/poll.c b/src/select/poll.c
index f1e73e8..4f13cfb 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,
+		&(struct timespec){ .tv_sec = timeout/1000,
+		.tv_nsec = timeout%1000*1000000 }, 0, _NSIG/8);
+#endif
 }
diff --git a/src/select/select.c b/src/select/select.c
index f93597b..5e7fe1f 100644
--- a/src/select/select.c
+++ b/src/select/select.c
@@ -4,5 +4,15 @@
 
 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 * 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 <sys/stat.h>
+#include <fcntl.h>
 #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..ad33484 100644
--- a/src/stat/futimesat.c
+++ b/src/stat/futimesat.c
@@ -2,9 +2,18 @@
 #include <sys/time.h>
 #include "syscall.h"
 
-#ifdef SYS_futimesat
 int futimesat(int dirfd, const char *pathname, const struct timeval times[2])
 {
+#ifdef SYS_futimesat
 	return syscall(SYS_futimesat, dirfd, pathname, times);
-}
+#else
+	struct timespec ts[2];
+	if (times) {
+		ts[0].tv_sec = times[0].tv_sec;
+		ts[0].tv_nsec = times[0].tv_usec * 1000;
+		ts[1].tv_sec = times[1].tv_sec;
+		ts[1].tv_nsec = times[1].tv_usec * 1000;
+	}
+	return syscall(SYS_utimensat, dirfd, pathname, times ? ts : 0, 0);
 #endif
+}
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 <sys/stat.h>
+#include <fcntl.h>
 #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 <sys/stat.h>
+#include <fcntl.h>
 #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 <sys/stat.h>
+#include <fcntl.h>
 #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 <sys/stat.h>
+#include <fcntl.h>
 #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/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 <stdio.h>
+#include <fcntl.h>
 #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/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 <unistd.h>
+#include <fcntl.h>
 #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 <unistd.h>
+#include <fcntl.h>
 #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..7bfcaf2 100644
--- a/src/unistd/dup2.c
+++ b/src/unistd/dup2.c
@@ -5,6 +5,15 @@
 int dup2(int old, int new)
 {
 	int r;
+#ifdef SYS_dup2
 	while ((r=__syscall(SYS_dup2, old, new))==-EBUSY);
+#else
+	if (old==new) {
+		if (__syscall(SYS_fcntl, old, F_GETFD) < 0)
+			return __syscall_ret(-EBADF);
+		return 0;
+	}
+	while ((r=__syscall(SYS_dup3, old, new, 0))==-EBUSY);
+#endif
 	return __syscall_ret(r);
 }
diff --git a/src/unistd/getpgrp.c b/src/unistd/getpgrp.c
index 433f42e..2c8aae6 100644
--- a/src/unistd/getpgrp.c
+++ b/src/unistd/getpgrp.c
@@ -1,7 +1,16 @@
 #include <unistd.h>
 #include "syscall.h"
+#include "pthread_impl.h"
 
 pid_t getpgrp(void)
 {
+#ifdef SYS_getpgrp
 	return __syscall(SYS_getpgrp);
+#else
+	sigset_t set;
+	__block_app_sigs(&set);
+	pid_t ret = __syscall(SYS_getpgid, __syscall(SYS_getpid));
+	__restore_sigs(&set);
+	return ret;
+#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 <unistd.h>
+#include <fcntl.h>
 #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 <unistd.h>
+#include <fcntl.h>
 #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 <unistd.h>
+#include <fcntl.h>
 #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 <unistd.h>
+#include <fcntl.h>
 #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 <unistd.h>
+#include <fcntl.h>
 #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 <unistd.h>
+#include <fcntl.h>
 #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
 }

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [UGLY PATCH] Support for no-legacy-syscalls archs
  2014-05-25  5:42 [UGLY PATCH] Support for no-legacy-syscalls archs Rich Felker
@ 2014-05-25  9:52 ` Szabolcs Nagy
  2014-05-25  9:57   ` Justin Cormack
  2014-05-25 11:45   ` Rich Felker
  2014-05-26  4:28 ` Rich Felker
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 15+ messages in thread
From: Szabolcs Nagy @ 2014-05-25  9:52 UTC (permalink / raw)
  To: musl

* Rich Felker <dalias@libc.org> [2014-05-25 01:42:37 -0400]:
> Here's a proposed next phase for supporting no-legacy-syscall archs
> (aarch64 and or1k, among others). It's not complete but I think it
> covers most of the important syscalls for standard functionality (not
> linux-specific stuff tho). Some of them might be missing some error
> cases or otherwise buggy so I'm sending the patch for review before
> committing.
...
> +#ifdef SYS_poll
>  	__syscall(SYS_poll, pfd, 3, 0);
> +#else
> +	__syscall(SYS_ppoll, pfd, 3, 0, 0, _NSIG/8);
> +#endif

cant it be done the other way around so new syscalls
are tried and then the classic ones are just fallbacks?

and what will happen with SYS_open?


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [UGLY PATCH] Support for no-legacy-syscalls archs
  2014-05-25  9:52 ` Szabolcs Nagy
@ 2014-05-25  9:57   ` Justin Cormack
  2014-05-25 11:45   ` Rich Felker
  1 sibling, 0 replies; 15+ messages in thread
From: Justin Cormack @ 2014-05-25  9:57 UTC (permalink / raw)
  To: musl

On Sun, May 25, 2014 at 10:52 AM, Szabolcs Nagy <nsz@port70.net> wrote:
> * Rich Felker <dalias@libc.org> [2014-05-25 01:42:37 -0400]:
>> Here's a proposed next phase for supporting no-legacy-syscall archs
>> (aarch64 and or1k, among others). It's not complete but I think it
>> covers most of the important syscalls for standard functionality (not
>> linux-specific stuff tho). Some of them might be missing some error
>> cases or otherwise buggy so I'm sending the patch for review before
>> committing.
> ...
>> +#ifdef SYS_poll
>>       __syscall(SYS_poll, pfd, 3, 0);
>> +#else
>> +     __syscall(SYS_ppoll, pfd, 3, 0, 0, _NSIG/8);
>> +#endif
>
> cant it be done the other way around so new syscalls
> are tried and then the classic ones are just fallbacks?

Issue seems to be that if you were running an old kernel (say no
ppoll) this would have to be called twice or add runtime conditionals,
which would be slower. Also it means that strace shows closer to what
you called. In many cases (where the new ones are Posix and portable)
users should switch to the new calls, but some are Linux only.

> and what will happen with SYS_open?

Whats the issue with open?

Justin


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [UGLY PATCH] Support for no-legacy-syscalls archs
  2014-05-25  9:52 ` Szabolcs Nagy
  2014-05-25  9:57   ` Justin Cormack
@ 2014-05-25 11:45   ` Rich Felker
  1 sibling, 0 replies; 15+ messages in thread
From: Rich Felker @ 2014-05-25 11:45 UTC (permalink / raw)
  To: musl

On Sun, May 25, 2014 at 11:52:57AM +0200, Szabolcs Nagy wrote:
> * Rich Felker <dalias@libc.org> [2014-05-25 01:42:37 -0400]:
> > Here's a proposed next phase for supporting no-legacy-syscall archs
> > (aarch64 and or1k, among others). It's not complete but I think it
> > covers most of the important syscalls for standard functionality (not
> > linux-specific stuff tho). Some of them might be missing some error
> > cases or otherwise buggy so I'm sending the patch for review before
> > committing.
> ....
> > +#ifdef SYS_poll
> >  	__syscall(SYS_poll, pfd, 3, 0);
> > +#else
> > +	__syscall(SYS_ppoll, pfd, 3, 0, 0, _NSIG/8);
> > +#endif
> 
> cant it be done the other way around so new syscalls
> are tried and then the classic ones are just fallbacks?

The "legacy" (I like the word "classic" better here, actually)
syscalls are actually preferred when available. Not only is there the
natural small amount of bloat decrease (fewer args, less chance of
having to shuffle the stack and spill registers in the caller, etc.),
and the consideration that using the new syscalls by default would
require fallback code for the ENOSYS case, but in some cases emulating
the behavior of the simpler function with the "general purpose"
syscall is actually expensive and error-prone.

I thought getpgid was an example of this (see the patch, which uses 4
syscalls instead of 1 to avoid a race reading the pid then using it,
which can race with fork from a signal handler) but it turned out an
argument of 0 to the syscall yields the getpgrp behavior, so I'm
updating that aspect of the patch.

An example that can't be optimized away is dup2, where special logic
is needed to deal with the case that dup3 treats differently. BTW,
the use of dup2 in posix_spawn also needs attention; I'm fixing it
now but the fix is rather ugly.

> and what will happen with SYS_open?

Already committed what seems to be the least invasive at both the
source and binary level. See the commit message; other approaches had
me worried that it might be too easy to break things (e.g. posix_spawn
where the child is sharing memory with the parent and thus can't touch
errno, cancellation state, etc.).

Rich


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [UGLY PATCH] Support for no-legacy-syscalls archs
  2014-05-25  5:42 [UGLY PATCH] Support for no-legacy-syscalls archs Rich Felker
  2014-05-25  9:52 ` Szabolcs Nagy
@ 2014-05-26  4:28 ` Rich Felker
  2014-05-26 18:40 ` [UGLY PATCH v2] " Rich Felker
  2014-05-27  5:26 ` [UGLY PATCH v3] " Rich Felker
  3 siblings, 0 replies; 15+ messages in thread
From: Rich Felker @ 2014-05-26  4:28 UTC (permalink / raw)
  To: musl

On Sun, May 25, 2014 at 01:42:37AM -0400, Rich Felker wrote:
> Here's a proposed next phase for supporting no-legacy-syscall archs
> (aarch64 and or1k, among others). It's not complete but I think it
> covers most of the important syscalls for standard functionality (not
> linux-specific stuff tho). Some of them might be missing some error
> cases or otherwise buggy so I'm sending the patch for review before
> committing.

Here's a list of all the syscalls we need to (conditionally) avoid:

/* non-at */
#define __NR_open 1024
#define __NR_link 1025
#define __NR_unlink 1026
#define __NR_mknod 1027
#define __NR_chmod 1028
#define __NR_chown 1029
#define __NR_mkdir 1030
#define __NR_rmdir 1031
#define __NR_lchown 1032
#define __NR_access 1033
#define __NR_rename 1034
#define __NR_readlink 1035
#define __NR_symlink 1036
#define __NR_utimes 1037
#define __NR3264_stat 1038
#define __NR3264_lstat 1039
/* non-flags */
#define __NR_pipe 1040
#define __NR_dup2 1041
#define __NR_epoll_create 1042
#define __NR_inotify_init 1043
#define __NR_eventfd 1044
#define __NR_signalfd 1045
/* deprecated */
#define __NR_alarm 1059
#define __NR_getpgrp 1060
#define __NR_pause 1061
#define __NR_time 1062
#define __NR_utime 1063
#define __NR_creat 1064
#define __NR_getdents 1065
#define __NR_futimesat 1066
#define __NR_select 1067
#define __NR_poll 1068
#define __NR_epoll_wait 1069
#define __NR_ustat 1070
#define __NR_vfork 1071
#define __NR_oldwait4 1072
#define __NR_recv 1073
#define __NR_send 1074
#define __NR_bdflush 1075
#define __NR_umount 1076
#define __NR_uselib 1077
#define __NR__sysctl 1078
#define __NR_fork 1079

With the changes so far, the only syscalls listed above that aren't
addressed yet are the ones for linux-specific features (epoll,
signalfd, etc.) and utimes, I think.

> diff --git a/src/select/poll.c b/src/select/poll.c
> index f1e73e8..4f13cfb 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,
> +		&(struct timespec){ .tv_sec = timeout/1000,
> +		.tv_nsec = timeout%1000*1000000 }, 0, _NSIG/8);
> +#endif

This may be wrong with negative values for timeout.

> diff --git a/src/select/select.c b/src/select/select.c
> index f93597b..5e7fe1f 100644
> --- a/src/select/select.c
> +++ b/src/select/select.c
> @@ -4,5 +4,15 @@
>  
>  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 * 1000;
> +	}
> +	return syscall_cp(SYS_pselect6, n, rfds, wfds, efds, tv ? &ts : 0, data);
> +#endif

This can overflow if tv_usec is nonsense.

> diff --git a/src/stat/futimesat.c b/src/stat/futimesat.c
> index dbefc84..ad33484 100644
> --- a/src/stat/futimesat.c
> +++ b/src/stat/futimesat.c
> @@ -2,9 +2,18 @@
>  #include <sys/time.h>
>  #include "syscall.h"
>  
> -#ifdef SYS_futimesat
>  int futimesat(int dirfd, const char *pathname, const struct timeval times[2])
>  {
> +#ifdef SYS_futimesat
>  	return syscall(SYS_futimesat, dirfd, pathname, times);
> -}
> +#else
> +	struct timespec ts[2];
> +	if (times) {
> +		ts[0].tv_sec = times[0].tv_sec;
> +		ts[0].tv_nsec = times[0].tv_usec * 1000;
> +		ts[1].tv_sec = times[1].tv_sec;
> +		ts[1].tv_nsec = times[1].tv_usec * 1000;
> +	}
> +	return syscall(SYS_utimensat, dirfd, pathname, times ? ts : 0, 0);
>  #endif

This is one of the cases where the legacy syscall really is junk and
we should always be using the modern one, when available. I'd like to
make futimesat, utimes, and utime _all_ call utimensat, and put the
fallback logic for using legacy syscalls when utimensat failes with
ENOSYS all in one place.

> diff --git a/src/unistd/dup2.c b/src/unistd/dup2.c
> index 87a0d44..7bfcaf2 100644
> --- a/src/unistd/dup2.c
> +++ b/src/unistd/dup2.c
> @@ -5,6 +5,15 @@
>  int dup2(int old, int new)
>  {
>  	int r;
> +#ifdef SYS_dup2
>  	while ((r=__syscall(SYS_dup2, old, new))==-EBUSY);
> +#else
> +	if (old==new) {
> +		if (__syscall(SYS_fcntl, old, F_GETFD) < 0)
> +			return __syscall_ret(-EBADF);
> +		return 0;
> +	}
> +	while ((r=__syscall(SYS_dup3, old, new, 0))==-EBUSY);
> +#endif
>  	return __syscall_ret(r);
>  }

I have a new approach to this that's less bloated: after the syscall
returns, check for r==-EINVAL && old==new, and in that case, return
new rather than an error.

> diff --git a/src/unistd/getpgrp.c b/src/unistd/getpgrp.c
> index 433f42e..2c8aae6 100644
> --- a/src/unistd/getpgrp.c
> +++ b/src/unistd/getpgrp.c
> @@ -1,7 +1,16 @@
>  #include <unistd.h>
>  #include "syscall.h"
> +#include "pthread_impl.h"
>  
>  pid_t getpgrp(void)
>  {
> +#ifdef SYS_getpgrp
>  	return __syscall(SYS_getpgrp);
> +#else
> +	sigset_t set;
> +	__block_app_sigs(&set);
> +	pid_t ret = __syscall(SYS_getpgid, __syscall(SYS_getpid));
> +	__restore_sigs(&set);
> +	return ret;
> +#endif

This can simply be __syscall(SYS_getpgid, 0). And that's so simple
it's not even worth having the #ifdef; we should just avoid the legacy
syscall unconditionally.

> 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

I think this is correct, but it could use a check. SYS_pause is also
used in exit.c but it doesn't really need to be...

Rich


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [UGLY PATCH v2] Support for no-legacy-syscalls archs
  2014-05-25  5:42 [UGLY PATCH] Support for no-legacy-syscalls archs Rich Felker
  2014-05-25  9:52 ` Szabolcs Nagy
  2014-05-26  4:28 ` Rich Felker
@ 2014-05-26 18:40 ` Rich Felker
  2014-05-26 21:13   ` Szabolcs Nagy
  2014-05-27  5:26 ` [UGLY PATCH v3] " Rich Felker
  3 siblings, 1 reply; 15+ messages in thread
From: Rich Felker @ 2014-05-26 18:40 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 814 bytes --]

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

[-- Attachment #2: no_legacy_syscall_archs_v2.diff --]
[-- Type: text/plain, Size: 13742 bytes --]

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 <elf.h>
 #include <poll.h>
 #include <fcntl.h>
+#include <signal.h>
 #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 <sys/time.h>
+#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 <unistd.h>
 #include <string.h>
+#include <signal.h>
 #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 <sys/stat.h>
+#include <fcntl.h>
 #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 <sys/time.h>
+#include <sys/stat.h>
+#include <errno.h>
 #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 <sys/stat.h>
+#include <fcntl.h>
 #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 <sys/stat.h>
+#include <fcntl.h>
 #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 <sys/stat.h>
+#include <fcntl.h>
 #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 <sys/stat.h>
+#include <fcntl.h>
 #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 <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <errno.h>
 #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 <stdio.h>
+#include <fcntl.h>
 #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 <utime.h>
-#include <sys/time.h>
-#include "syscall.h"
+#include <sys/stat.h>
+#include <time.h>
+#include <fcntl.h>
 
 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 <unistd.h>
+#include <fcntl.h>
 #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 <unistd.h>
+#include <fcntl.h>
 #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 <unistd.h>
+#include <fcntl.h>
 #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 <unistd.h>
+#include <fcntl.h>
 #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 <unistd.h>
+#include <fcntl.h>
 #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 <unistd.h>
+#include <fcntl.h>
 #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 <unistd.h>
+#include <fcntl.h>
 #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 <unistd.h>
+#include <fcntl.h>
 #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
 }

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [UGLY PATCH v2] Support for no-legacy-syscalls archs
  2014-05-26 18:40 ` [UGLY PATCH v2] " Rich Felker
@ 2014-05-26 21:13   ` Szabolcs Nagy
  2014-05-26 21:54     ` Rich Felker
  0 siblings, 1 reply; 15+ messages in thread
From: Szabolcs Nagy @ 2014-05-26 21:13 UTC (permalink / raw)
  To: musl

* Rich Felker <dalias@libc.org> [2014-05-26 14:40:36 -0400]:
> +#ifdef SYS_fork
>  	ret = syscall(SYS_fork);
> +#else
> +	ret = syscall(SYS_clone, SIGCHLD);
> +#endif

clone has more args

>  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

tv_usec may be negative

isnt it better to adjust tv_sec if usec is large?
or fail with EINVAL like in futimensat:

> +	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;
> +		}
> +	}


> +	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;
> +		}
> +	}

(tv_nsec+500)/1000 would be better rounding

but i guess 500 ns does not matter much

>  pid_t getpgrp(void)
>  {
> +#ifdef SYS_getpgrp
>  	return __syscall(SYS_getpgrp);
> +#else
> +	return __syscall(SYS_getpgid, 0);
> +#endif

you said this can be just the new call


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [UGLY PATCH v2] Support for no-legacy-syscalls archs
  2014-05-26 21:13   ` Szabolcs Nagy
@ 2014-05-26 21:54     ` Rich Felker
  2014-05-26 22:39       ` Szabolcs Nagy
  0 siblings, 1 reply; 15+ messages in thread
From: Rich Felker @ 2014-05-26 21:54 UTC (permalink / raw)
  To: musl

On Mon, May 26, 2014 at 11:13:49PM +0200, Szabolcs Nagy wrote:
> * Rich Felker <dalias@libc.org> [2014-05-26 14:40:36 -0400]:
> > +#ifdef SYS_fork
> >  	ret = syscall(SYS_fork);
> > +#else
> > +	ret = syscall(SYS_clone, SIGCHLD);
> > +#endif
> 
> clone has more args

The remaining args are only read if flags!=0 though (flags are in the
upper bits of the first argument; the lower bits are the signal to be
generated on exit). As far as I can tell, this is the correct way to
use clone to provide fork.

> >  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
> 
> tv_usec may be negative

Then the kernel should generate the EINVAL for us.

> isnt it better to adjust tv_sec if usec is large?
> or fail with EINVAL like in futimensat:

POSIX allows implementation-defined limits on the duration, but now
that you say it, what I wrote above is not not a correct
implementation of such a limit. I'm not clear on whether we should
renormalize into timespec or just reject out-of-range usec values;
unlike in some other places where timespec is used, POSIX is missing
text on select and pselect regarding how out-of-range timespec and
timeval structs should be handled...

> >  pid_t getpgrp(void)
> >  {
> > +#ifdef SYS_getpgrp
> >  	return __syscall(SYS_getpgrp);
> > +#else
> > +	return __syscall(SYS_getpgid, 0);
> > +#endif
> 
> you said this can be just the new call

Ah yes, I forgot to change that.

Rich


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [UGLY PATCH v2] Support for no-legacy-syscalls archs
  2014-05-26 21:54     ` Rich Felker
@ 2014-05-26 22:39       ` Szabolcs Nagy
  2014-05-26 22:46         ` Rich Felker
  0 siblings, 1 reply; 15+ messages in thread
From: Szabolcs Nagy @ 2014-05-26 22:39 UTC (permalink / raw)
  To: musl

* Rich Felker <dalias@libc.org> [2014-05-26 17:54:12 -0400]:
> On Mon, May 26, 2014 at 11:13:49PM +0200, Szabolcs Nagy wrote:
> > > +	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
> > 
> > tv_usec may be negative
> 
> Then the kernel should generate the EINVAL for us.
> 

but the multiplication may overflow

> > isnt it better to adjust tv_sec if usec is large?
> > or fail with EINVAL like in futimensat:
> 
> POSIX allows implementation-defined limits on the duration, but now
> that you say it, what I wrote above is not not a correct
> implementation of such a limit. I'm not clear on whether we should
> renormalize into timespec or just reject out-of-range usec values;
> unlike in some other places where timespec is used, POSIX is missing
> text on select and pselect regarding how out-of-range timespec and
> timeval structs should be handled...
> 

fwiw the kernel fixes large tv_usec in select:

...
  tv.tv_sec + (tv.tv_usec / USEC_PER_SEC),
  (tv.tv_usec % USEC_PER_SEC) * NSEC_PER_USEC))


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [UGLY PATCH v2] Support for no-legacy-syscalls archs
  2014-05-26 22:39       ` Szabolcs Nagy
@ 2014-05-26 22:46         ` Rich Felker
  0 siblings, 0 replies; 15+ messages in thread
From: Rich Felker @ 2014-05-26 22:46 UTC (permalink / raw)
  To: musl

On Tue, May 27, 2014 at 12:39:24AM +0200, Szabolcs Nagy wrote:
> * Rich Felker <dalias@libc.org> [2014-05-26 17:54:12 -0400]:
> > On Mon, May 26, 2014 at 11:13:49PM +0200, Szabolcs Nagy wrote:
> > > > +	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
> > > 
> > > tv_usec may be negative
> > 
> > Then the kernel should generate the EINVAL for us.
> 
> but the multiplication may overflow

Indeed, I missed that.

> > > isnt it better to adjust tv_sec if usec is large?
> > > or fail with EINVAL like in futimensat:
> > 
> > POSIX allows implementation-defined limits on the duration, but now
> > that you say it, what I wrote above is not not a correct
> > implementation of such a limit. I'm not clear on whether we should
> > renormalize into timespec or just reject out-of-range usec values;
> > unlike in some other places where timespec is used, POSIX is missing
> > text on select and pselect regarding how out-of-range timespec and
> > timeval structs should be handled...
> > 
> 
> fwiw the kernel fixes large tv_usec in select:
> 
> ....
>   tv.tv_sec + (tv.tv_usec / USEC_PER_SEC),

Does it handle the overflow here? :)

In any case, doing what the kernel does is probably desirable to
minimize differences between archs.

Rich


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [UGLY PATCH v3] Support for no-legacy-syscalls archs
  2014-05-25  5:42 [UGLY PATCH] Support for no-legacy-syscalls archs Rich Felker
                   ` (2 preceding siblings ...)
  2014-05-26 18:40 ` [UGLY PATCH v2] " Rich Felker
@ 2014-05-27  5:26 ` Rich Felker
  2014-05-27 11:29   ` Szabolcs Nagy
                     ` (2 more replies)
  3 siblings, 3 replies; 15+ messages in thread
From: Rich Felker @ 2014-05-27  5:26 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 706 bytes --]

This updated patch should actually compile if you #undef all the SYS_*
constants for syscalls that new archs don't provide. Major changes
include:

- use of pause in exit and quick_exit
- fixed bugs in poll and select
- linux epoll/inotify/eventfd/signalfd
- other functions i'd overlooked that use some of these syscalls

In the case of epoll, etc. I reworked the code to always prefer the
new syscalls and only fallback to the old ones if (1) they exist, and
(2) the new one returned ENOSYS. signalfd already has fallback code
that handles FD_CLOEXEC as best it can when the new syscall is not
available, but the others seem to be lacking the proper fallback code
so I should perhaps add that too.

Rich

[-- Attachment #2: no_legacy_syscall_archs_v3.diff --]
[-- Type: text/plain, Size: 22279 bytes --]

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 <elf.h>
 #include <poll.h>
 #include <fcntl.h>
+#include <signal.h>
 #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/exit/exit.c b/src/exit/exit.c
index 353f50b..6ac90c3 100644
--- a/src/exit/exit.c
+++ b/src/exit/exit.c
@@ -1,5 +1,6 @@
 #include <stdlib.h>
 #include <stdint.h>
+#include "futex.h"
 #include "libc.h"
 #include "atomic.h"
 #include "syscall.h"
@@ -24,7 +25,12 @@ _Noreturn void exit(int code)
 	static int lock;
 
 	/* If more than one thread calls exit, hang until _Exit ends it all */
-	while (a_swap(&lock, 1)) __syscall(SYS_pause);
+	while (a_swap(&lock, 1))
+#ifdef SYS_pausex
+		__syscall(SYS_pause);
+#else
+		__syscall(SYS_futex, &lock, FUTEX_WAIT, 1, 0);
+#endif
 
 	__funcs_on_exit();
 
diff --git a/src/exit/quick_exit.c b/src/exit/quick_exit.c
index 1175d80..01e304b 100644
--- a/src/exit/quick_exit.c
+++ b/src/exit/quick_exit.c
@@ -1,4 +1,5 @@
 #include <stdlib.h>
+#include "futex.h"
 #include "syscall.h"
 #include "atomic.h"
 #include "libc.h"
@@ -9,7 +10,12 @@ weak_alias(dummy, __funcs_on_quick_exit);
 _Noreturn void quick_exit(int code)
 {
 	static int lock;
-	while (a_swap(&lock, 1)) __syscall(SYS_pause);
+	while (a_swap(&lock, 1))
+#ifdef SYS_pause
+		__syscall(SYS_pause);
+#else
+		__syscall(SYS_futex, &lock, FUTEX_WAIT, 1, 0);
+#endif
 	__funcs_on_quick_exit();
 	_Exit(code);
 }
diff --git a/src/linux/epoll.c b/src/linux/epoll.c
index 030786d..b45344f 100644
--- a/src/linux/epoll.c
+++ b/src/linux/epoll.c
@@ -4,12 +4,16 @@
 
 int epoll_create(int size)
 {
-	return syscall(SYS_epoll_create, size);
+	return epoll_create1(0);
 }
 
 int epoll_create1(int flags)
 {
-	return syscall(SYS_epoll_create1, flags);
+	int r = __syscall(SYS_epoll_create1, flags);
+#ifdef SYS_epoll_create
+	if (r==-ENOSYS && !flags) r = __syscall(SYS_epoll_create, 1);
+#endif
+	return __syscall_ret(r);
 }
 
 int epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev)
@@ -19,10 +23,14 @@ int epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev)
 
 int epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to, const sigset_t *sigs)
 {
-	return syscall(SYS_epoll_pwait, fd, ev, cnt, to, sigs, _NSIG/8);
+	int r = __syscall(SYS_epoll_pwait, fd, ev, cnt, to, sigs, _NSIG/8);
+#ifdef SYS_epoll_wait
+	if (r==-ENOSYS && !sigs) r = __syscall(SYS_epoll_wait, fd, ev, cnt, to);
+#endif
+	return __syscall_ret(r);
 }
 
 int epoll_wait(int fd, struct epoll_event *ev, int cnt, int to)
 {
-	return syscall(SYS_epoll_wait, fd, ev, cnt, to);
+	return epoll_pwait(fd, ev, cnt, to, 0);
 }
diff --git a/src/linux/eventfd.c b/src/linux/eventfd.c
index 5306648..3996803 100644
--- a/src/linux/eventfd.c
+++ b/src/linux/eventfd.c
@@ -4,7 +4,11 @@
 
 int eventfd(unsigned int count, int flags)
 {
-	return syscall(flags ? SYS_eventfd2 : SYS_eventfd, count, flags);
+	int r = __syscall(SYS_eventfd2, count, flags);
+#ifdef SYS_eventfd
+	if (r==-ENOSYS && !flags) r = __syscall(SYS_eventfd, count);
+#endif
+	return __syscall_ret(r);
 }
 
 int eventfd_read(int fd, eventfd_t *value)
diff --git a/src/linux/inotify.c b/src/linux/inotify.c
index a417c89..84a5615 100644
--- a/src/linux/inotify.c
+++ b/src/linux/inotify.c
@@ -3,11 +3,15 @@
 
 int inotify_init()
 {
-	return syscall(SYS_inotify_init);
+	return inotify_init1(0);
 }
 int inotify_init1(int flags)
 {
-	return syscall(SYS_inotify_init1, flags);
+	int r = __syscall(SYS_inotify_init1, flags);
+#ifdef SYS_inotify_init
+	if (r==-ENOSYS && !flags) r = __syscall(SYS_inotify_init);
+#endif
+	return __syscall_ret(r);
 }
 
 int inotify_add_watch(int fd, const char *pathname, uint32_t mask)
diff --git a/src/linux/signalfd.c b/src/linux/signalfd.c
index da6bced..4bf4332 100644
--- a/src/linux/signalfd.c
+++ b/src/linux/signalfd.c
@@ -7,6 +7,7 @@
 int signalfd(int fd, const sigset_t *sigs, int flags)
 {
 	int ret = __syscall(SYS_signalfd4, fd, sigs, _NSIG/8, flags);
+#ifdef SYS_signalfd
 	if (ret != -ENOSYS) return __syscall_ret(ret);
 	ret = __syscall(SYS_signalfd, fd, sigs, _NSIG/8);
 	if (ret >= 0) {
@@ -15,5 +16,6 @@ int signalfd(int fd, const sigset_t *sigs, int flags)
 		if (flags & SFD_NONBLOCK)
 			__syscall(SYS_fcntl, ret, F_SETFL, O_NONBLOCK);
 	}
+#endif
 	return __syscall_ret(ret);
 }
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 <sys/time.h>
+#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..f8cf21e 100644
--- a/src/process/fork.c
+++ b/src/process/fork.c
@@ -1,5 +1,6 @@
 #include <unistd.h>
 #include <string.h>
+#include <signal.h>
 #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, 0);
+#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..9e0bcbd 100644
--- a/src/select/poll.c
+++ b/src/select/poll.c
@@ -1,8 +1,16 @@
 #include <poll.h>
+#include <time.h>
+#include <signal.h>
 #include "syscall.h"
 #include "libc.h"
 
 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..7b5f6dc 100644
--- a/src/select/select.c
+++ b/src/select/select.c
@@ -1,8 +1,26 @@
 #include <sys/select.h>
+#include <signal.h>
+#include <stdint.h>
+#include <errno.h>
 #include "syscall.h"
 #include "libc.h"
 
 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
+	syscall_arg_t data[2] = { 0, _NSIG/8 };
+	struct timespec ts;
+	if (tv) {
+		if (tv->tv_sec < 0 || tv->tv_usec < 0)
+			return __syscall_ret(-EINVAL);
+		time_t extra_secs = tv->tv_usec / 1000000;
+		ts.tv_nsec = tv->tv_usec % 1000000 * 1000;
+		const time_t max_time = (1ULL<<8*sizeof(time_t)-1)-1;
+		ts.tv_sec = extra_secs > max_time - tv->tv_sec ?
+			max_time : tv->tv_sec + extra_secs;
+	}
+	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 <sys/stat.h>
+#include <fcntl.h>
 #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/fchmod.c b/src/stat/fchmod.c
index 6d28141..93e1b64 100644
--- a/src/stat/fchmod.c
+++ b/src/stat/fchmod.c
@@ -13,5 +13,9 @@ int fchmod(int fd, mode_t mode)
 
 	char buf[15+3*sizeof(int)];
 	__procfdname(buf, fd);
+#ifdef SYS_chmod
 	return syscall(SYS_chmod, buf, mode);
+#else
+	return syscall(SYS_fchmodat, AT_FDCWD, buf, mode);
+#endif
 }
diff --git a/src/stat/fchmodat.c b/src/stat/fchmodat.c
index 12e7ff0..52029ec 100644
--- a/src/stat/fchmodat.c
+++ b/src/stat/fchmodat.c
@@ -29,7 +29,7 @@ int fchmodat(int fd, const char *path, mode_t mode, int flag)
 
 	__procfdname(proc, fd2);
 	if (!(ret = __syscall(SYS_stat, proc, &st)) && !S_ISLNK(st.st_mode))
-		ret = __syscall(SYS_chmod, proc, mode);
+		ret = __syscall(SYS_fchmodat, AT_FDCWD, proc, mode);
 
 	__syscall(SYS_close, fd2);
 	return __syscall_ret(ret);
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 <sys/time.h>
+#include <sys/stat.h>
+#include <errno.h>
 #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 <sys/stat.h>
+#include <fcntl.h>
 #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 <sys/stat.h>
+#include <fcntl.h>
 #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 <sys/stat.h>
+#include <fcntl.h>
 #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 <sys/stat.h>
+#include <fcntl.h>
 #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 <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <errno.h>
 #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/remove.c b/src/stdio/remove.c
index e147ba2..942e301 100644
--- a/src/stdio/remove.c
+++ b/src/stdio/remove.c
@@ -1,9 +1,19 @@
 #include <stdio.h>
 #include <errno.h>
+#include <fcntl.h>
 #include "syscall.h"
 
 int remove(const char *path)
 {
-	int r = syscall(SYS_unlink, path);
-	return (r && errno == EISDIR) ? syscall(SYS_rmdir, path) : r;
+#ifdef SYS_unlink
+	int r = __syscall(SYS_unlink, path);
+#else
+	int r = __syscall(SYS_unlinkat, AT_FDCWD, path, 0);
+#endif
+#ifdef SYS_rmdir
+	if (r==-EISDIR) r = __syscall(SYS_rmdir, path);
+#else
+	if (r==-EISDIR) r = __syscall(SYS_unlinkat, AT_FDCWD, path, AT_REMOVEDIR);
+#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 <stdio.h>
+#include <fcntl.h>
 #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/stdio/tempnam.c b/src/stdio/tempnam.c
index 9bf8c72..45a5f26 100644
--- a/src/stdio/tempnam.c
+++ b/src/stdio/tempnam.c
@@ -36,7 +36,12 @@ char *tempnam(const char *dir, const char *pfx)
 
 	for (try=0; try<MAXTRIES; try++) {
 		__randname(s+l-6);
+#ifdef SYS_lstat
 		r = __syscall(SYS_lstat, s, &(struct stat){0});
+#else
+		r = __syscall(SYS_fstatat, AT_FDCWD, s,
+			&(struct stat){0}, AT_SYMLINK_NOFOLLOW);
+#endif
 		if (r == -ENOENT) return strdup(s);
 	}
 	return 0;
diff --git a/src/stdio/tmpfile.c b/src/stdio/tmpfile.c
index c856994..a7d0000 100644
--- a/src/stdio/tmpfile.c
+++ b/src/stdio/tmpfile.c
@@ -17,7 +17,11 @@ FILE *tmpfile(void)
 		fd = sys_open(s, O_RDWR|O_CREAT|O_EXCL, 0600);
 		if (fd >= 0) {
 			f = __fdopen(fd, "w+");
+#ifdef SYS_unlink
 			__syscall(SYS_unlink, s);
+#else
+			__syscall(SYS_unlinkat, AT_FDCWD, s, 0);
+#endif
 			return f;
 		}
 	}
diff --git a/src/stdio/tmpnam.c b/src/stdio/tmpnam.c
index 92f699c..ccb8a4c 100644
--- a/src/stdio/tmpnam.c
+++ b/src/stdio/tmpnam.c
@@ -16,7 +16,12 @@ char *tmpnam(char *buf)
 	int r;
 	for (try=0; try<MAXTRIES; try++) {
 		__randname(s+12);
+#ifdef SYS_lstat
 		r = __syscall(SYS_lstat, s, &(struct stat){0});
+#else
+		r = __syscall(SYS_fstatat, AT_FDCWD, s,
+			&(struct stat){0}, AT_SYMLINK_NOFOLLOW);
+#endif
 		if (r == -ENOENT) return strcpy(buf ? buf : internal, s);
 	}
 	return 0;
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 <utime.h>
-#include <sys/time.h>
-#include "syscall.h"
+#include <sys/stat.h>
+#include <time.h>
+#include <fcntl.h>
 
 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 <unistd.h>
+#include <fcntl.h>
 #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 <unistd.h>
+#include <fcntl.h>
 #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/dup3.c b/src/unistd/dup3.c
index 1f7134b..0eb6caf 100644
--- a/src/unistd/dup3.c
+++ b/src/unistd/dup3.c
@@ -8,6 +8,7 @@
 int __dup3(int old, int new, int flags)
 {
 	int r;
+#ifdef SYS_dup2
 	if (old==new) return __syscall_ret(-EINVAL);
 	if (flags & O_CLOEXEC) {
 		while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY);
@@ -15,6 +16,9 @@ int __dup3(int old, int new, int flags)
 	}
 	while ((r=__syscall(SYS_dup2, old, new))==-EBUSY);
 	if (flags & O_CLOEXEC) __syscall(SYS_fcntl, new, F_SETFD, FD_CLOEXEC);
+#else
+	while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY);
+#endif
 	return __syscall_ret(r);
 }
 
diff --git a/src/unistd/fchown.c b/src/unistd/fchown.c
index 36633b0..0345984 100644
--- a/src/unistd/fchown.c
+++ b/src/unistd/fchown.c
@@ -13,5 +13,10 @@ int fchown(int fd, uid_t uid, gid_t gid)
 
 	char buf[15+3*sizeof(int)];
 	__procfdname(buf, fd);
+#ifdef SYS_chown
 	return syscall(SYS_chown, buf, uid, gid);
+#else
+	return syscall(SYS_fchownat, AT_FDCWD, buf, uid, gid);
+#endif
+
 }
diff --git a/src/unistd/getpgrp.c b/src/unistd/getpgrp.c
index 433f42e..90e9bb0 100644
--- a/src/unistd/getpgrp.c
+++ b/src/unistd/getpgrp.c
@@ -3,5 +3,5 @@
 
 pid_t getpgrp(void)
 {
-	return __syscall(SYS_getpgrp);
+	return __syscall(SYS_getpgid, 0);
 }
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 <unistd.h>
+#include <fcntl.h>
 #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 <unistd.h>
+#include <fcntl.h>
 #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..e259017 100644
--- a/src/unistd/pause.c
+++ b/src/unistd/pause.c
@@ -1,8 +1,15 @@
 #include <unistd.h>
+#include <signal.h>
 #include "syscall.h"
 #include "libc.h"
 
 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 <unistd.h>
+#include <fcntl.h>
 #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 <unistd.h>
+#include <fcntl.h>
 #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 <unistd.h>
+#include <fcntl.h>
 #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 <unistd.h>
+#include <fcntl.h>
 #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
 }

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [UGLY PATCH v3] Support for no-legacy-syscalls archs
  2014-05-27  5:26 ` [UGLY PATCH v3] " Rich Felker
@ 2014-05-27 11:29   ` Szabolcs Nagy
  2014-05-27 19:01     ` Rich Felker
  2014-05-29 21:46   ` Rich Felker
  2014-05-29 23:04   ` Rich Felker
  2 siblings, 1 reply; 15+ messages in thread
From: Szabolcs Nagy @ 2014-05-27 11:29 UTC (permalink / raw)
  To: musl

* Rich Felker <dalias@libc.org> [2014-05-27 01:26:25 -0400]:
> In the case of epoll, etc. I reworked the code to always prefer the
> new syscalls and only fallback to the old ones if (1) they exist, and
> (2) the new one returned ENOSYS. signalfd already has fallback code
> that handles FD_CLOEXEC as best it can when the new syscall is not
> available, but the others seem to be lacking the proper fallback code
> so I should perhaps add that too.

SOCK_CLOEXEC and SOCK_NONBLOCK fallbacks for socketpair are missing too

> +#ifdef SYS_pausex
> +		__syscall(SYS_pause);
> +#else
> +		__syscall(SYS_futex, &lock, FUTEX_WAIT, 1, 0);
> +#endif

pausex typo


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [UGLY PATCH v3] Support for no-legacy-syscalls archs
  2014-05-27 11:29   ` Szabolcs Nagy
@ 2014-05-27 19:01     ` Rich Felker
  0 siblings, 0 replies; 15+ messages in thread
From: Rich Felker @ 2014-05-27 19:01 UTC (permalink / raw)
  To: musl

On Tue, May 27, 2014 at 01:29:54PM +0200, Szabolcs Nagy wrote:
> * Rich Felker <dalias@libc.org> [2014-05-27 01:26:25 -0400]:
> > In the case of epoll, etc. I reworked the code to always prefer the
> > new syscalls and only fallback to the old ones if (1) they exist, and
> > (2) the new one returned ENOSYS. signalfd already has fallback code
> > that handles FD_CLOEXEC as best it can when the new syscall is not
> > available, but the others seem to be lacking the proper fallback code
> > so I should perhaps add that too.
> 
> SOCK_CLOEXEC and SOCK_NONBLOCK fallbacks for socketpair are missing too

I thought I'd already added them, but you're right.

Perhaps if we're emulating the fallback cases we should go ahead and
make it race-free. This can be done by a combination of locking and
signal masking that prevents fork, posix_spawn, and exec* during the
interval where the close-on-exec flag is not yet set on the new fd. It
would basically look like:

__block_app_sigs(&set);
__lock(cloexec_lock);
[do fallback work here]
__restore_sigs(&set);

This would not work if the fallback work were supposed to be
interruptible by signals; I'm not sure if any such cases would need to
be considered.

Our fork and posix_spawn implementations already run with all signals
blocked, so all that would need to be added to them is the locking.
Adding the code to exec* would incur some additional cost, and I'm
actually not sure how to do it right without the new program
inheriting the all-blocked signal mask.

> > +#ifdef SYS_pausex
> > +		__syscall(SYS_pause);
> > +#else
> > +		__syscall(SYS_futex, &lock, FUTEX_WAIT, 1, 0);
> > +#endif
> 
> pausex typo

Actually it was my cheap test of the fallback case that I forgot to
remove. :) Fixed. BTW do you have any better ideas for a fallback
here? Maybe some sleep variant? I just want something that will avoid
spinning and consuming cpu while we wait for exit to finish.

Rich


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [UGLY PATCH v3] Support for no-legacy-syscalls archs
  2014-05-27  5:26 ` [UGLY PATCH v3] " Rich Felker
  2014-05-27 11:29   ` Szabolcs Nagy
@ 2014-05-29 21:46   ` Rich Felker
  2014-05-29 23:04   ` Rich Felker
  2 siblings, 0 replies; 15+ messages in thread
From: Rich Felker @ 2014-05-29 21:46 UTC (permalink / raw)
  To: musl

On Tue, May 27, 2014 at 01:26:25AM -0400, Rich Felker wrote:
> diff --git a/src/exit/exit.c b/src/exit/exit.c
> index 353f50b..6ac90c3 100644
> --- a/src/exit/exit.c
> +++ b/src/exit/exit.c
> @@ -1,5 +1,6 @@
>  #include <stdlib.h>
>  #include <stdint.h>
> +#include "futex.h"
>  #include "libc.h"
>  #include "atomic.h"
>  #include "syscall.h"
> @@ -24,7 +25,12 @@ _Noreturn void exit(int code)
>  	static int lock;
>  
>  	/* If more than one thread calls exit, hang until _Exit ends it all */
> -	while (a_swap(&lock, 1)) __syscall(SYS_pause);
> +	while (a_swap(&lock, 1))
> +#ifdef SYS_pausex
> +		__syscall(SYS_pause);
> +#else
> +		__syscall(SYS_futex, &lock, FUTEX_WAIT, 1, 0);
> +#endif

Removed this change simply by dropping the code (see commit
2e55da911896a91e95b24ab5dc8a9d9b0718f4de).

> 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;
> +}
> +

This is overkill; I mistakenly thought the use of dup2 in posix_spawn
was missing the EBUSY check and loop and added all this mess. But the
EBUSY condition cannot happen in a single-threaded process that does
not share (CLONE_FILES) its descriptor table.

In fact, it seems like the EBUSY condition might be something we can
drop completely from dup2.c and dup3.c too. I'm not 100% sure yet but
it looks like it can only happen when the application invokes UB by
misusing dup2/dup3 in a multithreaded process when the destination
descriptor is not already known by the caller to be occupied.

> diff --git a/src/select/select.c b/src/select/select.c
> index f93597b..7b5f6dc 100644
> --- a/src/select/select.c
> +++ b/src/select/select.c
> @@ -1,8 +1,26 @@
>  #include <sys/select.h>
> +#include <signal.h>
> +#include <stdint.h>
> +#include <errno.h>
>  #include "syscall.h"
>  #include "libc.h"
>  
>  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
> +	syscall_arg_t data[2] = { 0, _NSIG/8 };
> +	struct timespec ts;
> +	if (tv) {
> +		if (tv->tv_sec < 0 || tv->tv_usec < 0)
> +			return __syscall_ret(-EINVAL);
> +		time_t extra_secs = tv->tv_usec / 1000000;
> +		ts.tv_nsec = tv->tv_usec % 1000000 * 1000;
> +		const time_t max_time = (1ULL<<8*sizeof(time_t)-1)-1;
> +		ts.tv_sec = extra_secs > max_time - tv->tv_sec ?
> +			max_time : tv->tv_sec + extra_secs;
> +	}
> +	return syscall_cp(SYS_pselect6, n, rfds, wfds, efds, tv ? &ts : 0, data);
> +#endif

This is a lot uglier than I'd prefer, but I don't see any way to
improve it. Blame the kernel folks...

>  }
> 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 <sys/stat.h>
> +#include <fcntl.h>
>  #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/fchmod.c b/src/stat/fchmod.c
> index 6d28141..93e1b64 100644
> --- a/src/stat/fchmod.c
> +++ b/src/stat/fchmod.c
> @@ -13,5 +13,9 @@ int fchmod(int fd, mode_t mode)
>  
>  	char buf[15+3*sizeof(int)];
>  	__procfdname(buf, fd);
> +#ifdef SYS_chmod
>  	return syscall(SYS_chmod, buf, mode);
> +#else
> +	return syscall(SYS_fchmodat, AT_FDCWD, buf, mode);
> +#endif
>  }
> diff --git a/src/stat/fchmodat.c b/src/stat/fchmodat.c
> index 12e7ff0..52029ec 100644
> --- a/src/stat/fchmodat.c
> +++ b/src/stat/fchmodat.c
> @@ -29,7 +29,7 @@ int fchmodat(int fd, const char *path, mode_t mode, int flag)
>  
>  	__procfdname(proc, fd2);
>  	if (!(ret = __syscall(SYS_stat, proc, &st)) && !S_ISLNK(st.st_mode))
> -		ret = __syscall(SYS_chmod, proc, mode);
> +		ret = __syscall(SYS_fchmodat, AT_FDCWD, proc, mode);
>  
>  	__syscall(SYS_close, fd2);
>  	return __syscall_ret(ret);
> 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 <sys/time.h>
> +#include <sys/stat.h>
> +#include <errno.h>
>  #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)

I think there's a bug here; whether comparison against 1000000U will
promote the LHS to unsigned depends on the definition of suseconds_t.

> 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 <sys/stat.h>
> +#include <sys/time.h>
> +#include <fcntl.h>
> +#include <errno.h>
>  #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);
> +

Not a big deal, but this check can be moved inside the #ifdef:

> +#ifdef SYS_futimesat
> [...]
> 
> 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

Sadly this implementation is not correct since the kernel checks for
EINVAL before EBADF; it causes dup2(fd,fd) to always report success,
even if fd is not a valid file descriptor. So I think we really need
an ugly check for validity first...

Rich


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [UGLY PATCH v3] Support for no-legacy-syscalls archs
  2014-05-27  5:26 ` [UGLY PATCH v3] " Rich Felker
  2014-05-27 11:29   ` Szabolcs Nagy
  2014-05-29 21:46   ` Rich Felker
@ 2014-05-29 23:04   ` Rich Felker
  2 siblings, 0 replies; 15+ messages in thread
From: Rich Felker @ 2014-05-29 23:04 UTC (permalink / raw)
  To: musl

On Tue, May 27, 2014 at 01:26:25AM -0400, Rich Felker wrote:
> diff --git a/src/unistd/pause.c b/src/unistd/pause.c
> index f7ed17d..e259017 100644
> --- a/src/unistd/pause.c
> +++ b/src/unistd/pause.c
> @@ -1,8 +1,15 @@
>  #include <unistd.h>
> +#include <signal.h>
>  #include "syscall.h"
>  #include "libc.h"
>  
>  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

This also potentially has a race condition: It's possible for a signal
handler to intervene between the two syscalls, changing the signal
mask, in which case the signal mask getting reverted by the sigsuspend
is potentially observable.

I'm inclined to leave it alone for now. It's unclear whether there's
even a fix using sigsuspend, and if so, it's going to be a mildly
expensive one. And the effect is only observable by doing something
that's not officially sanctioned as well-defined: changing the saved
signal mask in the ucontext received by a signal handler to effect a
new signal mask when the signal handler returns.

Of course if there's another syscall that could reasonably replace
pause, that might be a viable solution. (Perhaps ppoll with no file
descriptors and no timeout?)

Ok, yep, that works! Never mind then. Fixed.

Rich


^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2014-05-29 23:04 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-25  5:42 [UGLY PATCH] Support for no-legacy-syscalls archs Rich Felker
2014-05-25  9:52 ` Szabolcs Nagy
2014-05-25  9:57   ` Justin Cormack
2014-05-25 11:45   ` Rich Felker
2014-05-26  4:28 ` Rich Felker
2014-05-26 18:40 ` [UGLY PATCH v2] " Rich Felker
2014-05-26 21:13   ` Szabolcs Nagy
2014-05-26 21:54     ` Rich Felker
2014-05-26 22:39       ` Szabolcs Nagy
2014-05-26 22:46         ` Rich Felker
2014-05-27  5:26 ` [UGLY PATCH v3] " Rich Felker
2014-05-27 11:29   ` Szabolcs Nagy
2014-05-27 19:01     ` Rich Felker
2014-05-29 21:46   ` Rich Felker
2014-05-29 23:04   ` Rich Felker

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).