summaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
authorHiroki Sato <hrs@FreeBSD.org>2020-02-20 03:01:27 +0000
committerHiroki Sato <hrs@FreeBSD.org>2020-02-20 03:01:27 +0000
commitbe860ca2a7d0473e54e19f565a911f9d687370bd (patch)
tree4e5b38b24c23c63016c326315c2d2516dab16fce /bin
parentcafbf0c664f859e23d1804730c44a6ffb8c131e2 (diff)
downloadsrc-test2-be860ca2a7d0473e54e19f565a911f9d687370bd.tar.gz
src-test2-be860ca2a7d0473e54e19f565a911f9d687370bd.zip
Notes
Diffstat (limited to 'bin')
-rw-r--r--bin/sh/miscbltin.c74
1 files changed, 73 insertions, 1 deletions
diff --git a/bin/sh/miscbltin.c b/bin/sh/miscbltin.c
index b7619650233b..ad3d862fb6ef 100644
--- a/bin/sh/miscbltin.c
+++ b/bin/sh/miscbltin.c
@@ -66,10 +66,79 @@ __FBSDID("$FreeBSD$");
#undef eflag
+#define READ_BUFLEN 1024
+struct fdctx {
+ int fd;
+ size_t off; /* offset in buf */
+ size_t buflen;
+ char *ep; /* tail pointer */
+ char buf[READ_BUFLEN];
+};
+
+static void fdctx_init(int, struct fdctx *);
+static void fdctx_destroy(struct fdctx *);
+static ssize_t fdgetc(struct fdctx *, char *);
int readcmd(int, char **);
int umaskcmd(int, char **);
int ulimitcmd(int, char **);
+static void
+fdctx_init(int fd, struct fdctx *fdc)
+{
+ off_t cur;
+
+ /* Check if fd is seekable. */
+ cur = lseek(fd, 0, SEEK_CUR);
+ *fdc = (struct fdctx){
+ .fd = fd,
+ .buflen = (cur != -1) ? READ_BUFLEN : 1,
+ .ep = &fdc->buf[0], /* No data */
+ };
+}
+
+static ssize_t
+fdgetc(struct fdctx *fdc, char *c)
+{
+ ssize_t nread;
+
+ if (&fdc->buf[fdc->off] == fdc->ep) {
+ nread = read(fdc->fd, fdc->buf, fdc->buflen);
+ if (nread > 0) {
+ fdc->off = 0;
+ fdc->ep = fdc->buf + nread;
+ } else
+ return (nread);
+ }
+ *c = fdc->buf[fdc->off++];
+
+ return (1);
+}
+
+static void
+fdctx_destroy(struct fdctx *fdc)
+{
+ size_t residue;
+
+ if (fdc->buflen > 1) {
+ /*
+ * Reposition the file offset. Here is the layout of buf:
+ *
+ * | off
+ * v
+ * |*****************|-------|
+ * buf ep buf+buflen
+ * |<- residue ->|
+ *
+ * off: current character
+ * ep: offset just after read(2)
+ * residue: length for reposition
+ */
+ residue = (fdc->ep - fdc->buf) - fdc->off;
+ if (residue > 0)
+ (void) lseek(fdc->fd, -residue, SEEK_CUR);
+ }
+}
+
/*
* The read builtin. The -r option causes backslashes to be treated like
* ordinary characters.
@@ -108,6 +177,7 @@ readcmd(int argc __unused, char **argv __unused)
fd_set ifds;
ssize_t nread;
int sig;
+ struct fdctx fdctx;
rflag = 0;
prompt = NULL;
@@ -173,8 +243,9 @@ readcmd(int argc __unused, char **argv __unused)
backslash = 0;
STARTSTACKSTR(p);
lastnonifs = lastnonifsws = -1;
+ fdctx_init(STDIN_FILENO, &fdctx);
for (;;) {
- nread = read(STDIN_FILENO, &c, 1);
+ nread = fdgetc(&fdctx, &c);
if (nread == -1) {
if (errno == EINTR) {
sig = pendingsig;
@@ -260,6 +331,7 @@ readcmd(int argc __unused, char **argv __unused)
STARTSTACKSTR(p);
lastnonifs = lastnonifsws = -1;
}
+ fdctx_destroy(&fdctx);
STACKSTRNUL(p);
/*