diff options
author | 2019-04-10 10:36:01 -0500 | |
---|---|---|
committer | 2019-04-10 11:03:43 -0500 | |
commit | a1fafc4a96e07d20678a243d2f158c4a3f06a17a (patch) | |
tree | 909ab9fee31ef2231fc93bc0bcc73441eab7773d | |
parent | 6ebc7d6bc8ab973d0ba949eeb363821811ce8dc5 (diff) | |
download | pseudo-a1fafc4a96e07d20678a243d2f158c4a3f06a17a.tar.gz pseudo-a1fafc4a96e07d20678a243d2f158c4a3f06a17a.tar.bz2 pseudo-a1fafc4a96e07d20678a243d2f158c4a3f06a17a.zip |
Try to handle blocking open.
This is a heck of a special case: If you call open on a FIFO/pipe,
and you didn't have O_NONBLOCK, and you used O_RDONLY or O_WRONLY,
but not O_RDWR, the open can block forever. Unfortunately, pseudo
assumes syscalls complete. We attempt to drop the lock and restore
our state, then recover it later.
Why? Because the .NET runtime does this for a debug hook.
-rw-r--r-- | ChangeLog.txt | 4 | ||||
-rw-r--r-- | ports/linux/guts/openat.c | 37 |
2 files changed, 41 insertions, 0 deletions
diff --git a/ChangeLog.txt b/ChangeLog.txt index f79c2d1..b5f64c7 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,7 @@ +2019-04-10: + * (seebs) Experimental workaround for special non-blocking open + case. + 2019-04-09: * (seebs) Partial fix for db corruption issue. * (seebs) Make a glibc renameat2 wrapper that just fails because diff --git a/ports/linux/guts/openat.c b/ports/linux/guts/openat.c index 924e354..cc6b118 100644 --- a/ports/linux/guts/openat.c +++ b/ports/linux/guts/openat.c @@ -7,8 +7,10 @@ * int rc = -1; */ struct stat64 buf; + int overly_magic_nonblocking = 0; int existed = 1; int save_errno; + sigset_t local_saved_sigmask; /* mask out mode bits appropriately */ mode = mode & ~pseudo_umask; @@ -61,6 +63,27 @@ errno = save_errno; } + /* if a pipe is opened without O_NONBLOCK, for only reading or + * only writing, it can block forever. We need to do extra magic + * in that case... + */ + if (!(flags & O_NONBLOCK) && ((flags & (O_WRONLY | O_RDONLY | O_RDWR)) != O_RDWR)) { + save_errno = errno; +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + rc = real___xstat64(_STAT_VER, path, &buf); +#else + rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, 0); +#endif + if (rc != -1 && S_ISFIFO(buf.st_mode)) { + overly_magic_nonblocking = 1; + } + } + + /* this is a horrible special case and i do not know whether it will work */ + if (overly_magic_nonblocking) { + pseudo_droplock(); + sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, &local_saved_sigmask); + } /* because we are not actually root, secretly mask in 0600 to the * underlying mode. The ", 0" is because the only time mode matters * is if a file is going to be created, in which case it's @@ -71,6 +94,20 @@ #else rc = real_openat(dirfd, path, flags, PSEUDO_FS_MODE(mode, 0)); #endif + if (overly_magic_nonblocking) { + save_errno = errno; + sigprocmask(SIG_SETMASK, &local_saved_sigmask, NULL); + /* well this is a problem. we can't NOT proceed; we may have + * already opened the file! we can't even return up the call + * stack to stuff that's going to try to drop the lock. + */ + if (pseudo_getlock()) { + pseudo_diag("PANIC: after opening a readonly/writeonly FIFO (path '%s', fd %d, errno %d, saved errno %d), could not regain lock. unrecoverable. sorry. bye.\n", + path, rc, errno, save_errno); + abort(); + } + errno = save_errno; + } if (rc != -1) { save_errno = errno; |