Add fdflags builtin. Discussed with Chet and he has implemented it for
bash too.
This commit is contained in:
parent
246a181951
commit
168f1d4a50
@ -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
|
||||
|
203
bin/sh/redir.c
203
bin/sh/redir.c
@ -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;
|
||||
}
|
||||
|
26
bin/sh/sh.1
26
bin/sh/sh.1
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user