Add fdflags builtin. Discussed with Chet and he has implemented it for

bash too.
This commit is contained in:
christos 2017-02-02 20:00:40 +00:00
parent 246a181951
commit 168f1d4a50
3 changed files with 227 additions and 5 deletions

View File

@ -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

View File

@ -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/21 23:03:36 christos Exp $");
*/
#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;
}

View File

@ -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 accessible.
.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