diff --git a/lib/libc/sys-minix/socket.c b/lib/libc/sys-minix/socket.c index e4e29dc21..cc00596a0 100644 --- a/lib/libc/sys-minix/socket.c +++ b/lib/libc/sys-minix/socket.c @@ -18,12 +18,17 @@ __weak_alias(socket, _socket) #define DEBUG 0 -static int _tcp_socket(int protocol); -static int _udp_socket(int protocol); +static int _tcp_socket(int type, int protocol); +static int _udp_socket(int type, int protocol); static int _uds_socket(int type, int protocol); +static void _socket_flags(int type, int *result); int socket(int domain, int type, int protocol) { + int sock_type; + + sock_type = type & ~SOCK_FLAGS_MASK; + #if DEBUG fprintf(stderr, "socket: domain %d, type %d, protocol %d\n", domain, type, protocol); @@ -37,15 +42,16 @@ int socket(int domain, int type, int protocol) return -1; } - if (domain == AF_UNIX && (type == SOCK_STREAM || - type == SOCK_DGRAM || type == SOCK_SEQPACKET)) + if (domain == AF_UNIX && (sock_type == SOCK_STREAM || + sock_type == SOCK_DGRAM || + sock_type == SOCK_SEQPACKET)) return _uds_socket(type, protocol); - if (domain == AF_INET && type == SOCK_STREAM) - return _tcp_socket(protocol); + if (domain == AF_INET && sock_type == SOCK_STREAM) + return _tcp_socket(type, protocol); - if (domain == AF_INET && type == SOCK_DGRAM) - return _udp_socket(protocol); + if (domain == AF_INET && sock_type == SOCK_DGRAM) + return _udp_socket(type, protocol); #if DEBUG fprintf(stderr, "socket: nothing for domain %d, type %d, protocol %d\n", @@ -55,9 +61,25 @@ int socket(int domain, int type, int protocol) return -1; } -static int _tcp_socket(int protocol) +static void +_socket_flags(int type, int *result) { - int fd; + /* Process socket flags */ + if (type & SOCK_CLOEXEC) { + *result |= O_CLOEXEC; + } + if (type & SOCK_NONBLOCK) { + *result |= O_NONBLOCK; + } + if (type & SOCK_NOSIGPIPE) { + *result |= O_NOSIGPIPE; + } +} + +static int _tcp_socket(int type, int protocol) +{ + int flags = O_RDWR; + if (protocol != 0 && protocol != IPPROTO_TCP) { #if DEBUG @@ -66,13 +88,15 @@ static int _tcp_socket(int protocol) errno= EPROTONOSUPPORT; return -1; } - fd= open(TCP_DEVICE, O_RDWR); - return fd; + + _socket_flags(type, &flags); + + return open(TCP_DEVICE, flags); } -static int _udp_socket(int protocol) +static int _udp_socket(int type, int protocol) { - int r, fd, t_errno; + int r, fd, t_errno, flags = O_RDWR; struct sockaddr_in sin; if (protocol != 0 && protocol != IPPROTO_UDP) @@ -83,7 +107,8 @@ static int _udp_socket(int protocol) errno= EPROTONOSUPPORT; return -1; } - fd= open(UDP_DEVICE, O_RDWR); + _socket_flags(type, &flags); + fd= open(UDP_DEVICE, flags); if (fd == -1) return fd; @@ -104,7 +129,7 @@ static int _udp_socket(int protocol) static int _uds_socket(int type, int protocol) { - int fd, r; + int fd, r, flags = O_RDWR, sock_type; if (protocol != 0) { #if DEBUG @@ -114,7 +139,8 @@ static int _uds_socket(int type, int protocol) return -1; } - fd= open(UDS_DEVICE, O_RDWR); + _socket_flags(type, &flags); + fd= open(UDS_DEVICE, flags); if (fd == -1) { return fd; } @@ -122,7 +148,8 @@ static int _uds_socket(int type, int protocol) /* set the type for the socket via ioctl (SOCK_DGRAM, * SOCK_STREAM, SOCK_SEQPACKET, etc) */ - r= ioctl(fd, NWIOSUDSTYPE, &type); + sock_type = type & ~SOCK_FLAGS_MASK; + r= ioctl(fd, NWIOSUDSTYPE, &sock_type); if (r == -1) { int ioctl_errno; diff --git a/servers/vfs/misc.c b/servers/vfs/misc.c index 03de68ca4..705ba9509 100644 --- a/servers/vfs/misc.c +++ b/servers/vfs/misc.c @@ -286,7 +286,16 @@ int do_fcntl() break; } - + case F_GETNOSIGPIPE: + /* POSIX: return value other than -1 is flag is set, else -1 */ + r = -1; + if (f->filp_flags & O_NOSIGPIPE) + r = 0; + break; + case F_SETNOSIGPIPE: + fl = (O_NOSIGPIPE); + f->filp_flags = (f->filp_flags & ~fl) | (fcntl_argx & fl); + break; default: r = EINVAL; } diff --git a/servers/vfs/pipe.c b/servers/vfs/pipe.c index 4a61e7e75..9c7e230a5 100644 --- a/servers/vfs/pipe.c +++ b/servers/vfs/pipe.c @@ -174,7 +174,7 @@ endpoint_t map_to_fs_e; * pipe_check * *===========================================================================*/ int pipe_check( -struct vnode *vp, /* the inode of the pipe */ +struct filp *filp, /* the filp of the pipe */ int rw_flag, /* READING or WRITING */ int oflags, /* flags set by open or fcntl */ int bytes, /* bytes to be read or written (all chunks) */ @@ -186,9 +186,12 @@ int notouch /* check only */ * and there is no writer, return 0 bytes. If a process is writing to a * pipe and no one is reading from it, give a broken pipe error. */ + struct vnode *vp; off_t pos; int r = OK; + vp = filp->filp_vno; + /* Reads start at the beginning; writes append to pipes */ if (notouch) /* In this case we don't actually care whether data transfer * would succeed. See POSIX 1003.1-2008 */ @@ -221,10 +224,6 @@ int notouch /* check only */ /* Process is writing to a pipe. */ if (find_filp(vp, R_BIT) == NULL) { - /* Process is writing, but there is no reader. Tell kernel to generate - * a SIGPIPE signal. */ - if (!notouch) sys_kill(fp->fp_endpoint, SIGPIPE); - return(EPIPE); } diff --git a/servers/vfs/proto.h b/servers/vfs/proto.h index b98d7420d..48865d6cb 100644 --- a/servers/vfs/proto.h +++ b/servers/vfs/proto.h @@ -186,7 +186,7 @@ int do_check_perms(void); int do_pipe(void); int map_vnode(struct vnode *vp, endpoint_t fs_e); void unpause(endpoint_t proc_e); -int pipe_check(struct vnode *vp, int rw_flag, int oflags, int bytes, +int pipe_check(struct filp *filp, int rw_flag, int oflags, int bytes, int notouch); void release(struct vnode *vp, int op, int count); void revive(endpoint_t proc_e, int returned); diff --git a/servers/vfs/read.c b/servers/vfs/read.c index 05f173aa2..90e8c4a72 100644 --- a/servers/vfs/read.c +++ b/servers/vfs/read.c @@ -124,27 +124,23 @@ int read_write(int rw_flag, struct filp *f, char *buf, size_t size, register struct vnode *vp; u64_t position, res_pos, new_pos; unsigned int cum_io, cum_io_incr, res_cum_io; - int op, oflags, r; + int op, r; position = f->filp_pos; - oflags = f->filp_flags; vp = f->filp_vno; r = OK; cum_io = 0; if (size > SSIZE_MAX) return(EINVAL); - if (S_ISFIFO(vp->v_mode)) { + op = (rw_flag == READING ? VFS_DEV_READ : VFS_DEV_WRITE); + + if (S_ISFIFO(vp->v_mode)) { /* Pipes */ if (fp->fp_cum_io_partial != 0) { panic("VFS: read_write: fp_cum_io_partial not clear"); } r = rw_pipe(rw_flag, for_e, f, buf, size); - return(r); - } - - op = (rw_flag == READING ? VFS_DEV_READ : VFS_DEV_WRITE); - - if (S_ISCHR(vp->v_mode)) { /* Character special files. */ + } else if (S_ISCHR(vp->v_mode)) { /* Character special files. */ dev_t dev; int suspend_reopen; @@ -154,7 +150,7 @@ int read_write(int rw_flag, struct filp *f, char *buf, size_t size, suspend_reopen = (f->filp_state & FS_NEEDS_REOPEN); dev = (dev_t) vp->v_sdev; - r = dev_io(op, dev, for_e, buf, position, size, oflags, + r = dev_io(op, dev, for_e, buf, position, size, f->filp_flags, suspend_reopen); if (r >= 0) { cum_io = r; @@ -178,7 +174,7 @@ int read_write(int rw_flag, struct filp *f, char *buf, size_t size, } else { /* Regular files */ if (rw_flag == WRITING) { /* Check for O_APPEND flag. */ - if (oflags & O_APPEND) position = cvul64(vp->v_size); + if (f->filp_flags & O_APPEND) position = cvul64(vp->v_size); } /* Issue request */ @@ -208,7 +204,18 @@ int read_write(int rw_flag, struct filp *f, char *buf, size_t size, f->filp_pos = position; - if (r == OK) return(cum_io); + if (r == EPIPE && rw_flag == WRITING) { + /* Process is writing, but there is no reader. Tell the kernel to + * generate s SIGPIPE signal. + */ + if (!(f->filp_flags & O_NOSIGPIPE)) { + sys_kill(fp->fp_endpoint, SIGPIPE); + } + } + + if (r == OK) { + return(cum_io); + } return(r); } @@ -277,7 +284,7 @@ size_t req_size; /* fp->fp_cum_io_partial is only nonzero when doing partial writes */ cum_io = fp->fp_cum_io_partial; - r = pipe_check(vp, rw_flag, oflags, req_size, 0); + r = pipe_check(f, rw_flag, oflags, req_size, 0); if (r <= 0) { if (r == SUSPEND) pipe_suspend(f, buf, req_size); return(r); diff --git a/servers/vfs/select.c b/servers/vfs/select.c index d62f4aa10..bc46430b3 100644 --- a/servers/vfs/select.c +++ b/servers/vfs/select.c @@ -453,7 +453,7 @@ static int select_request_pipe(struct filp *f, int *ops, int block) if ((*ops & (SEL_RD|SEL_ERR))) { /* Check if we can read 1 byte */ - err = pipe_check(f->filp_vno, READING, f->filp_flags & ~O_NONBLOCK, 1, + err = pipe_check(f, READING, f->filp_flags & ~O_NONBLOCK, 1, 1 /* Check only */); if (err != SUSPEND) @@ -470,7 +470,7 @@ static int select_request_pipe(struct filp *f, int *ops, int block) if ((*ops & (SEL_WR|SEL_ERR))) { /* Check if we can write 1 byte */ - err = pipe_check(f->filp_vno, WRITING, f->filp_flags & ~O_NONBLOCK, 1, + err = pipe_check(f, WRITING, f->filp_flags & ~O_NONBLOCK, 1, 1 /* Check only */); if (err != SUSPEND) diff --git a/sys/sys/fcntl.h b/sys/sys/fcntl.h index fcfaa9ad5..15b4a0c21 100644 --- a/sys/sys/fcntl.h +++ b/sys/sys/fcntl.h @@ -73,7 +73,9 @@ * restart */ #define O_CLOEXEC 020000 /* close on exec */ - +#if defined(_NETBSD_SOURCE) +#define O_NOSIGPIPE 040000 /* don't deliver sigpipe */ +#endif #ifndef __minix /* NOT SUPPORTED! */ #if defined(_NETBSD_SOURCE) @@ -126,6 +128,10 @@ #define F_SETLK 6 /* set record locking information */ #define F_SETLKW 7 /* set record locking info; wait if blocked */ #define F_FREESP 8 /* free a section of a regular file */ +#if defined(_NETBSD_SOURCE) +#define F_GETNOSIGPIPE 9 +#define F_SETNOSIGPIPE 10 +#endif /* File descriptor flags used for fcntl(). POSIX Table 6-2. */ #define FD_CLOEXEC 1 /* close on exec flag for third arg of fcntl */