Module Name:    src
Committed By:   christos
Date:           Thu Feb  2 20:00:40 UTC 2017

Modified Files:
        src/bin/sh: builtins.def redir.c sh.1

Log Message:
Add fdflags builtin. Discussed with Chet and he has implemented it for
bash too.


To generate a diff of this commit:
cvs rdiff -u -r1.23 -r1.24 src/bin/sh/builtins.def
cvs rdiff -u -r1.49 -r1.50 src/bin/sh/redir.c
cvs rdiff -u -r1.123 -r1.124 src/bin/sh/sh.1

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/bin/sh/builtins.def
diff -u src/bin/sh/builtins.def:1.23 src/bin/sh/builtins.def:1.24
--- src/bin/sh/builtins.def:1.23	Sun May 10 16:30:54 2015
+++ src/bin/sh/builtins.def	Thu Feb  2 15:00:40 2017
@@ -1,5 +1,5 @@
 #!/bin/sh -
-#	$NetBSD: builtins.def,v 1.23 2015/05/10 20:30:54 joerg Exp $
+#	$NetBSD: builtins.def,v 1.24 2017/02/02 20:00:40 christos Exp $
 #
 # Copyright (c) 1991, 1993
 #	The Regents of the University of California.  All rights reserved.
@@ -73,6 +73,7 @@ pwdcmd		-u pwd
 readcmd		-u read
 returncmd	-s return
 setcmd		-s set
+fdflagscmd	fdflags
 setvarcmd	setvar
 shiftcmd	-s shift
 timescmd	-s times

Index: src/bin/sh/redir.c
diff -u src/bin/sh/redir.c:1.49 src/bin/sh/redir.c:1.50
--- src/bin/sh/redir.c:1.49	Sat Jan 21 18:03:36 2017
+++ src/bin/sh/redir.c	Thu Feb  2 15:00:40 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: redir.c,v 1.49 2017/01/21 23:03:36 christos Exp $	*/
+/*	$NetBSD: redir.c,v 1.50 2017/02/02 20:00:40 christos Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)redir.c	8.2 (Berkeley) 5/4/95";
 #else
-__RCSID("$NetBSD: redir.c,v 1.49 2017/01/21 23:03:36 christos Exp $");
+__RCSID("$NetBSD: redir.c,v 1.50 2017/02/02 20:00:40 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -56,6 +56,7 @@ __RCSID("$NetBSD: redir.c,v 1.49 2017/01
  */
 
 #include "main.h"
+#include "builtins.h"
 #include "shell.h"
 #include "nodes.h"
 #include "jobs.h"
@@ -552,3 +553,201 @@ to_upper_fd(int fd)
 	(void)fcntl(fd, F_SETFD, FD_CLOEXEC);
 	return fd;
 }
+
+static const struct {
+	const char *name;
+	uint32_t value;
+} nv[] = {
+#ifdef O_APPEND
+	{ "append",	O_APPEND 	},
+#endif
+#ifdef O_ASYNC
+	{ "async",	O_ASYNC		},
+#endif
+#ifdef O_SYNC
+	{ "sync",	O_SYNC		},
+#endif
+#ifdef O_NONBLOCK
+	{ "nonblock",	O_NONBLOCK	},
+#endif
+#ifdef O_FSYNC
+	{ "fsync",	O_FSYNC		},
+#endif
+#ifdef O_DSYNC
+	{ "dsync",	O_DSYNC		},
+#endif
+#ifdef O_RSYNC
+	{ "rsync",	O_RSYNC		},
+#endif
+#ifdef O_ALTIO
+	{ "altio",	O_ALT_IO	},
+#endif
+#ifdef O_DIRECT
+	{ "direct",	O_DIRECT	},
+#endif
+#ifdef O_NOSIGPIPE
+	{ "nosigpipe",	O_NOSIGPIPE	},
+#endif
+#ifdef O_CLOEXEC
+	{ "cloexec",	O_CLOEXEC	},
+#endif
+};
+#define ALLFLAGS (O_APPEND|O_ASYNC|O_SYNC|O_NONBLOCK|O_DSYNC|O_RSYNC|\
+    O_ALT_IO|O_DIRECT|O_NOSIGPIPE|O_CLOEXEC)
+
+static int
+getflags(int fd, int p)
+{
+	int c, f;
+
+	if ((c = fcntl(fd, F_GETFD)) == -1) {
+		if (!p)
+			return -1;
+		error("Can't get status for fd=%d (%s)", fd, strerror(errno));
+	}
+	if ((f = fcntl(fd, F_GETFL)) == -1) {
+		if (!p)
+			return -1;
+		error("Can't get flags for fd=%d (%s)", fd, strerror(errno));
+	}
+	if (c)
+		f |= O_CLOEXEC;
+	return f & ALLFLAGS;
+}
+
+static void
+printone(int fd, int p, int verbose)
+{
+	int f = getflags(fd, p);
+
+	if (f == -1)
+		return;
+
+	outfmt(out1, "%d:", fd);
+	for (size_t i = 0; i < __arraycount(nv); i++) {
+		if (f & nv[i].value) {
+			outfmt(out1, "%s%s", verbose ? "+" : "", nv[i].name);
+			f &= ~nv[i].value;
+		} else if (verbose)
+			outfmt(out1, "-%s", nv[i].name);
+		else
+			continue;
+		if (f || (verbose && i != __arraycount(nv) - 1))
+			outfmt(out1, ",");
+	}
+	outfmt(out1, "\n");
+}
+
+static int
+parseflags(char *s, int *p, int *n)
+{
+	int f = 0, *v;
+
+	*p = 0;
+	*n = 0;
+	for (s = strtok(s, ","); s; s = strtok(NULL, ",")) {
+		size_t i;
+		switch (*s) {
+		case '+':
+			v = p;
+			s++;
+			break;
+		case '-':
+			v = n;
+			s++;
+			break;
+		default:
+			v = &f;
+			break;
+		}
+			
+		for (i = 0; i < __arraycount(nv); i++)
+			if (strcmp(s, nv[i].name) == 0) {
+				*v |= nv[i].value;
+				break;
+			}
+		if (i == __arraycount(nv))
+			error("Bad flag `%s'", s);
+	}
+	return f;
+}
+
+static void
+setone(int fd, int pos, int neg, int verbose)
+{
+	int f = getflags(fd, 1);
+	if (f == -1)
+		return;
+
+	int cloexec = -1;
+	if ((pos & O_CLOEXEC) && !(f & O_CLOEXEC))
+		cloexec = FD_CLOEXEC;
+	if ((neg & O_CLOEXEC) && (f & O_CLOEXEC))
+		cloexec = 0;
+
+	if (cloexec != -1 && fcntl(fd, F_SETFD, cloexec) == -1)
+		error("Can't set status for fd=%d (%s)", fd, strerror(errno));
+
+	pos &= ~O_CLOEXEC;
+	neg &= ~O_CLOEXEC;
+	f &= ~O_CLOEXEC;
+	int n = f;
+	n |= pos;
+	n &= ~neg;
+	if (n != f && fcntl(fd, F_SETFL, n) == -1)
+		error("Can't set flags for fd=%d (%s)", fd, strerror(errno));
+	if (verbose)
+		printone(fd, 1, verbose);
+}
+
+int
+fdflagscmd(int argc, char *argv[])
+{
+	char *num;
+	int verbose = 0, ch, pos = 0, neg = 0;
+	char *setflags = NULL;
+
+	optreset = 1; optind = 1; /* initialize getopt */
+	while ((ch = getopt(argc, argv, ":vs:")) != -1)
+		switch ((char)ch) {
+		case 'v':
+			verbose = 1;
+			break;
+		case 's':
+			setflags = optarg;
+			break;
+		case '?':
+		default:
+		msg:
+			error("Usage: fdflags [-v] [-s <flags>] [fd...]");
+			/* NOTREACHED */
+		}
+
+	argc -= optind, argv += optind;
+
+	if (setflags && parseflags(setflags, &pos, &neg))
+		error("Need + or - before flags");
+
+	if (argc == 0) {
+		if (setflags)
+			goto msg;
+		int maxfd = fcntl(0, F_MAXFD);
+		if (maxfd == -1)
+			error("Can't get max fd (%s)", strerror(errno));
+		for (int i = 0; i <= maxfd; i++)
+			printone(i, 0, verbose);
+		return 0;
+	}
+
+	while ((num = *argv++) != NULL) {
+		int e;
+		int fd = (int)strtoi(num, NULL, 0, 0, INT_MAX, &e);
+		if (e)
+			error("Can't parse `%s' (%s)", num, strerror(e));
+		if (setflags)
+			setone(fd, pos, neg, verbose);
+		else
+			printone(fd, 1, verbose);
+	}
+	return 0;
+}

Index: src/bin/sh/sh.1
diff -u src/bin/sh/sh.1:1.123 src/bin/sh/sh.1:1.124
--- src/bin/sh/sh.1:1.123	Thu May 12 09:15:43 2016
+++ src/bin/sh/sh.1	Thu Feb  2 15:00:40 2017
@@ -1,4 +1,4 @@
-.\"	$NetBSD: sh.1,v 1.123 2016/05/12 13:15:43 kre Exp $
+.\"	$NetBSD: sh.1,v 1.124 2017/02/02 20:00:40 christos Exp $
 .\" Copyright (c) 1991, 1993
 .\"	The Regents of the University of California.  All rights reserved.
 .\"
@@ -31,7 +31,7 @@
 .\"
 .\"	@(#)sh.1	8.6 (Berkeley) 5/4/95
 .\"
-.Dd May 9, 2016
+.Dd February 1, 2017
 .Dt SH 1
 .ds flags abCEeFfhnuvxIimpqV
 .Os
@@ -1685,6 +1685,28 @@ The number of previous commands that are
 .El
 .It fg Op Ar job
 Move the specified job or the current job to the foreground.
+.It fdflags Oo Fl v Oc Oo fd ... Oc
+.It fdflags Oo Fl v Oc Fl s Ar flags fd Oo ... Oc
+Get or set file descriptor flags.
+The 
+.Fl v
+argument enables verbose printing, printing flags that are also off, and
+the flags of the file descriptor being set after setting.
+The
+.Fl s
+flag interprets the
+.Ar flags
+argument as a comma separated list of file descriptor flags, each preceded
+with a
+.Dq +
+or a
+.Dq -
+indicating to set or clear the respective flag.
+Valid flags are:
+append,async,sync,nonblock,fsync,dsync,rsync,direct,nosigpipe,cloexec.
+See
+.Xr fcntl 2
+for more information.
 .It getopts Ar optstring var
 The
 .Tn POSIX

Reply via email to