Re: [hackers] [sbase] [PATCH 00/10] IO improvements and some bug fixes

2016-12-04 Thread Laslo Hunhold
On Sun,  4 Dec 2016 21:55:02 -0800
Michael Forney  wrote:

Dear Michael,

> I finally got around to addressing the issues with fread I raised at
> the end of http://lists.suckless.org/dev/1504/26580.html.
>
> This patch series eliminates several uses of fread/fwrite where plain
> read/write are more appropriate. To help with the common case of
> writing an entire buffer to a file descriptor, I added a writeall
> function (which works similar to plan9's standard write function and
> the Write/write_all functions in go/rust). All users of concat were
> better suited to work on plain file descriptors except for tail, so I
> switched concat to a read/writeall loop, and tail to use a
> fgetc/fputc loop.

fgetc/fputc really can slow down your program, which I noticed when I
wrote farbfeld-filters. Working on a buffer-basis rather than a
char-by-char-basis really speeds up things a lot (for me it was around
50%-70%). Can you provide some performance-information e.g. for cat(1)?
Does it get any faster with the writeall()-loop? What other benefits do
we see here?
Can you elaborate in this thread again why we should do
raw I/O? In a naïve sense, the operating system can "shedule" reads and
writes more efficiently with the buffered I/O.

> The result should be more efficient (no copy between read/write
> buffers, and data is processed as it comes in), and is roughly the
> same complexity as before. In most cases, we now pull in less of
> stdio, so statically linked binaries get smaller. Additionally,
> cat/tee on a pipe/terminal is now usable.

That makes sense.

> Along the way, I found and fixed several bugs, mostly dealing with
> error checking.
> I've been running with these patches for a couple days now and
> haven't noticed any regressions.

That is great! I'm glad you test your patches before submitting, which
I have been guilty of neglecting for so many times.

Cheers

Laslo

-- 
Laslo Hunhold 



[hackers] [sbase] [PATCH 03/10] libutil: Add writeall utility function

2016-12-04 Thread Michael Forney
writeall makes successive write calls to write an entire buffer to the
output file descriptor. It returns the number of bytes written, or -1 on
the first error.
---
 Makefile   |  3 ++-
 libutil/writeall.c | 21 +
 util.h |  3 +++
 3 files changed, 26 insertions(+), 1 deletion(-)
 create mode 100644 libutil/writeall.c

diff --git a/Makefile b/Makefile
index 25bab70..a337ead 100644
--- a/Makefile
+++ b/Makefile
@@ -79,7 +79,8 @@ LIBUTILSRC =\
libutil/strlcpy.c\
libutil/strsep.c\
libutil/strtonum.c\
-   libutil/unescape.c
+   libutil/unescape.c\
+   libutil/writeall.c
 
 LIB = $(LIBUTF) $(LIBUTIL)
 
diff --git a/libutil/writeall.c b/libutil/writeall.c
new file mode 100644
index 000..4725ced
--- /dev/null
+++ b/libutil/writeall.c
@@ -0,0 +1,21 @@
+/* See LICENSE file for copyright and license details. */
+#include 
+
+#include "../util.h"
+
+ssize_t
+writeall(int fd, const void *buf, size_t len)
+{
+   const char *p = buf;
+   ssize_t n;
+
+   while (len) {
+   n = write(fd, p, len);
+   if (n <= 0)
+   return n;
+   p += n;
+   len -= n;
+   }
+
+   return p - (const char *)buf;
+}
diff --git a/util.h b/util.h
index b5860dc..eaad3ce 100644
--- a/util.h
+++ b/util.h
@@ -62,6 +62,9 @@ char *strsep(char **, const char *);
 int enregcomp(int, regex_t *, const char *, int);
 int eregcomp(regex_t *, const char *, int);
 
+/* io */
+ssize_t writeall(int, const void *, size_t);
+
 /* misc */
 void enmasse(int, char **, int (*)(const char *, const char *, int));
 void fnck(const char *, const char *, int (*)(const char *, const char *, 
int), int);
-- 
2.11.0




[hackers] [sbase] [PATCH 08/10] cp: Only call chmod with -p or -a

2016-12-04 Thread Michael Forney
Previously, when the destination file was created with fopen, we needed
to use fchmod to set its permissions.

Now that we pass in the mode to creat, we already get the desired
behavior of creating the file with the same mode as the source file
modified by the user's file creation mask.

This fixes the issue where a directory or special file created with
mkdir/mknod does not end up with the appropriate mode with -p or -a
(since it may have been narrowed by the umask).

This also allows us to clear the SUID and SGID bits from the mode if the
chown fails, as specified by POSIX.
---
 libutil/cp.c | 10 +-
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/libutil/cp.c b/libutil/cp.c
index 8cd0a7d..339c892 100644
--- a/libutil/cp.c
+++ b/libutil/cp.c
@@ -134,15 +134,11 @@ cp(const char *s1, const char *s2, int depth)
return 0;
}
 
-   /* preserve permissions by default */
-   fchmod(f2, st.st_mode);
-
close(f1);
close(f2);
}
 
if (cp_aflag || cp_pflag) {
-   /* timestamp and owner */
if (!S_ISLNK(st.st_mode)) {
times[0] = st.st_atim;
times[1] = st.st_mtim;
@@ -151,7 +147,11 @@ cp(const char *s1, const char *s2, int depth)
if (chown(s2, st.st_uid, st.st_gid) < 0) {
weprintf("chown %s:", s2);
cp_status = 1;
-   return 0;
+   st.st_mode &= ~(S_ISUID | S_ISGID);
+   }
+   if (chmod(s2, st.st_mode) < 0) {
+   weprintf("chmod %s:", s2);
+   cp_status = 1;
}
} else {
if (lchown(s2, st.st_uid, st.st_gid) < 0) {
-- 
2.11.0




[hackers] [sbase] [PATCH 00/10] IO improvements and some bug fixes

2016-12-04 Thread Michael Forney
I finally got around to addressing the issues with fread I raised at the end of
http://lists.suckless.org/dev/1504/26580.html.

This patch series eliminates several uses of fread/fwrite where plain read/write
are more appropriate. To help with the common case of writing an entire buffer
to a file descriptor, I added a writeall function (which works similar to
plan9's standard write function and the Write/write_all functions in go/rust).
All users of concat were better suited to work on plain file descriptors except
for tail, so I switched concat to a read/writeall loop, and tail to use a
fgetc/fputc loop.

The result should be more efficient (no copy between read/write buffers, and
data is processed as it comes in), and is roughly the same complexity as before.
In most cases, we now pull in less of stdio, so statically linked binaries get
smaller. Additionally, cat/tee on a pipe/terminal is now usable.

Along the way, I found and fixed several bugs, mostly dealing with error
checking.

I've been running with these patches for a couple days now and haven't noticed
any regressions.

Michael Forney (10):
  crypt: Add some missing error checks for cryptsum
  od: Fix buffer overflow if -N flag is larger than BUFSIZ
  libutil: Add writeall utility function
  Don't use buffered IO (fread) when not appropriate
  tail: Use getc and putc instead of concat
  xinstall: Check result of fchmod
  concat: Use plain read/write instead of buffered stdio
  cp: Only call chmod with -p or -a
  tail: Use fstat in case file is removed
  cp: Check result of utimensat

 Makefile   |  3 ++-
 cat.c  | 34 ++
 cksum.c| 31 +--
 crypt.h|  2 +-
 libutil/concat.c   | 24 ++--
 libutil/cp.c   | 52 ++--
 libutil/crypt.c| 47 ++-
 libutil/writeall.c | 21 +
 od.c   | 47 ---
 sponge.c   | 31 +--
 tail.c | 38 --
 tee.c  | 39 +++
 text.h |  1 -
 util.h |  4 
 xinstall.c | 26 +-
 15 files changed, 214 insertions(+), 186 deletions(-)
 create mode 100644 libutil/writeall.c

-- 
2.11.0




[hackers] [sbase] [PATCH 09/10] tail: Use fstat in case file is removed

2016-12-04 Thread Michael Forney
---
 tail.c | 16 +++-
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/tail.c b/tail.c
index ad97308..000be62 100644
--- a/tail.c
+++ b/tail.c
@@ -133,7 +133,7 @@ main(int argc, char *argv[])
}
if (many)
printf("%s==> %s <==\n", newline ? "\n" : "", 
*argv);
-   if (stat(*argv, &st1) < 0)
+   if (fstat(fileno(fp), &st1) < 0)
eprintf("stat %s:", *argv);
if (!(S_ISFIFO(st1.st_mode) || S_ISREG(st1.st_mode)))
fflag = 0;
@@ -153,15 +153,13 @@ main(int argc, char *argv[])
if (ferror(fp))
eprintf("fgetc %s:", *argv);
clearerr(fp);
-   /* ignore error in case file was removed, we 
continue
-* tracking the existing open file descriptor */
-   if (!stat(*argv, &st2)) {
-   if (st2.st_size < st1.st_size) {
-   fprintf(stderr, "%s: file 
truncated\n", *argv);
-   rewind(fp);
-   }
-   st1 = st2;
+   if (fstat(fileno(fp), &st2) < 0)
+   eprintf("fstat:");
+   if (st2.st_size < st1.st_size) {
+   fprintf(stderr, "%s: file truncated\n", 
*argv);
+   rewind(fp);
}
+   st1 = st2;
sleep(1);
}
}
-- 
2.11.0




[hackers] [sbase] [PATCH 06/10] xinstall: Check result of fchmod

2016-12-04 Thread Michael Forney
---
 xinstall.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/xinstall.c b/xinstall.c
index bf921fb..5a0e390 100644
--- a/xinstall.c
+++ b/xinstall.c
@@ -119,7 +119,8 @@ install(const char *s1, const char *s2, int depth)
}
concat(f1, s1, f2, s2);
 
-   fchmod(fileno(f2), mode);
+   if (fchmod(fileno(f2), mode) < 0)
+   eprintf("fchmod %s:", s2);
 
if (fclose(f2) == EOF)
eprintf("fclose %s:", s2);
-- 
2.11.0




[hackers] [sbase] [PATCH 04/10] Don't use buffered IO (fread) when not appropriate

2016-12-04 Thread Michael Forney
fread reads the entire requested size (BUFSIZ), which causes tools to
block if only small amounts of data are available at a time. At best,
this causes unnecessary copies and inefficiency, at worst, tools like
tee and cat are almost unusable in some cases since they only display
large chunks of data at a time.
---
 cksum.c | 31 +--
 crypt.h |  2 +-
 libutil/crypt.c | 37 +++--
 od.c| 42 ++
 tee.c   | 39 +++
 5 files changed, 82 insertions(+), 69 deletions(-)

diff --git a/cksum.c b/cksum.c
index 570ca81..b53ec17 100644
--- a/cksum.c
+++ b/cksum.c
@@ -1,7 +1,9 @@
 /* See LICENSE file for copyright and license details. */
+#include 
 #include 
 #include 
 #include 
+#include 
 
 #include "util.h"
 
@@ -61,19 +63,20 @@ static const unsigned long crctab[] = { 0x,
 };
 
 static void
-cksum(FILE *fp, const char *s)
+cksum(int fd, const char *s)
 {
-   size_t len = 0, i, n;
+   ssize_t n;
+   size_t len = 0, i;
uint32_t ck = 0;
unsigned char buf[BUFSIZ];
 
-   while ((n = fread(buf, 1, sizeof(buf), fp))) {
+   while ((n = read(fd, buf, sizeof(buf))) > 0) {
for (i = 0; i < n; i++)
ck = (ck << 8) ^ crctab[(ck >> 24) ^ buf[i]];
len += n;
}
-   if (ferror(fp)) {
-   weprintf("fread %s:", s ? s : "");
+   if (n < 0) {
+   weprintf("read %s:", s ? s : "");
ret = 1;
return;
}
@@ -92,29 +95,29 @@ cksum(FILE *fp, const char *s)
 int
 main(int argc, char *argv[])
 {
-   FILE *fp;
+   int fd;
 
argv0 = argv[0], argc--, argv++;
 
if (!argc) {
-   cksum(stdin, NULL);
+   cksum(0, NULL);
} else {
for (; *argv; argc--, argv++) {
if (!strcmp(*argv, "-")) {
*argv = "";
-   fp = stdin;
-   } else if (!(fp = fopen(*argv, "r"))) {
-   weprintf("fopen %s:", *argv);
+   fd = 0;
+   } else if ((fd = open(*argv, O_RDONLY)) < 0) {
+   weprintf("open %s:", *argv);
ret = 1;
continue;
}
-   cksum(fp, *argv);
-   if (fp != stdin && fshut(fp, *argv))
-   ret = 1;
+   cksum(fd, *argv);
+   if (fd != 0)
+   close(fd);
}
}
 
-   ret |= fshut(stdin, "") | fshut(stdout, "");
+   ret |= fshut(stdout, "");
 
return ret;
 }
diff --git a/crypt.h b/crypt.h
index e0cc08d..2fd2932 100644
--- a/crypt.h
+++ b/crypt.h
@@ -8,5 +8,5 @@ struct crypt_ops {
 
 int cryptcheck(int, char **, struct crypt_ops *, uint8_t *, size_t);
 int cryptmain(int, char **, struct crypt_ops *, uint8_t *, size_t);
-int cryptsum(struct crypt_ops *, FILE *, const char *, uint8_t *);
+int cryptsum(struct crypt_ops *, int, const char *, uint8_t *);
 void mdprint(const uint8_t *, const char *, size_t);
diff --git a/libutil/crypt.c b/libutil/crypt.c
index 6991c39..e285614 100644
--- a/libutil/crypt.c
+++ b/libutil/crypt.c
@@ -1,8 +1,10 @@
 /* See LICENSE file for copyright and license details. */
+#include 
 #include 
 #include 
 #include 
 #include 
+#include 
 
 #include "../crypt.h"
 #include "../text.h"
@@ -41,7 +43,7 @@ static void
 mdchecklist(FILE *listfp, struct crypt_ops *ops, uint8_t *md, size_t sz,
 int *formatsucks, int *noread, int *nonmatch)
 {
-   FILE *fp;
+   int fd;
size_t bufsiz = 0;
int r;
char *line = NULL, *file, *p;
@@ -59,12 +61,12 @@ mdchecklist(FILE *listfp, struct crypt_ops *ops, uint8_t 
*md, size_t sz,
file += 2;
for (p = file; *p && *p != '\n' && *p != '\r'; p++); /* strip 
newline */
*p = '\0';
-   if (!(fp = fopen(file, "r"))) {
-   weprintf("fopen %s:", file);
+   if ((fd = open(file, O_RDONLY)) < 0) {
+   weprintf("open %s:", file);
(*noread)++;
continue;
}
-   if (cryptsum(ops, fp, file, md)) {
+   if (cryptsum(ops, fd, file, md)) {
(*noread)++;
continue;
}
@@ -77,7 +79,7 @@ mdchecklist(FILE *listfp, struct crypt_ops *ops, uint8_t *md, 
size_t sz,
} else {
(*formatsucks)++;
}
-   fclose(fp);
+   close(fd);
}
free(line);
 }
@@ -124,11 +126,11 @@ cryptcheck(int argc, char 

[hackers] [sbase] [PATCH 02/10] od: Fix buffer overflow if -N flag is larger than BUFSIZ

2016-12-04 Thread Michael Forney
Previously, if max was specified, od will call read with that size,
potentially overflowing buf with data read from the file.
---
 od.c | 11 +--
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/od.c b/od.c
index 9b83501..b5884e7 100644
--- a/od.c
+++ b/od.c
@@ -132,20 +132,19 @@ od(FILE *fp, char *fname, int last)
size_t i;
unsigned char buf[BUFSIZ];
static off_t addr;
-   size_t buflen;
+   size_t n;
 
while (skip - addr > 0) {
-   buflen = fread(buf, 1, MIN(skip - addr, BUFSIZ), fp);
-   addr += buflen;
+   n = fread(buf, 1, MIN(skip - addr, sizeof(buf)), fp);
+   addr += n;
if (feof(fp) || ferror(fp))
return;
}
if (!line)
line = emalloc(linelen);
 
-   while ((buflen = fread(buf, 1, max >= 0 ?
-  max - (addr - skip) : BUFSIZ, fp))) {
-   for (i = 0; i < buflen; i++, addr++) {
+   while ((n = fread(buf, 1, MIN((size_t)max - (addr - skip), 
sizeof(buf)), fp))) {
+   for (i = 0; i < n; i++, addr++) {
line[lineoff++] = buf[i];
if (lineoff == linelen) {
printline(line, lineoff, addr - lineoff + 1);
-- 
2.11.0




[hackers] [sbase] [PATCH 10/10] cp: Check result of utimensat

2016-12-04 Thread Michael Forney
POSIX says that if duplicating the modification/access times fails, then
an error should be written to stderr.
---
 libutil/cp.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/libutil/cp.c b/libutil/cp.c
index 339c892..15e4ce5 100644
--- a/libutil/cp.c
+++ b/libutil/cp.c
@@ -142,8 +142,10 @@ cp(const char *s1, const char *s2, int depth)
if (!S_ISLNK(st.st_mode)) {
times[0] = st.st_atim;
times[1] = st.st_mtim;
-   utimensat(AT_FDCWD, s2, times, 0);
-
+   if (utimensat(AT_FDCWD, s2, times, 0) < 0) {
+   weprintf("utimensat %s:", s2);
+   cp_status = 1;
+   }
if (chown(s2, st.st_uid, st.st_gid) < 0) {
weprintf("chown %s:", s2);
cp_status = 1;
-- 
2.11.0




[hackers] [sbase] [PATCH 01/10] crypt: Add some missing error checks for cryptsum

2016-12-04 Thread Michael Forney
Previously, if a file failed to read in a checksum list, it would be
reported as not matched rather than a read failure.

Also, if reading from stdin failed, previously a bogus checksum would be
printed anyway.
---
 libutil/crypt.c | 16 ++--
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/libutil/crypt.c b/libutil/crypt.c
index 3f849ba..6991c39 100644
--- a/libutil/crypt.c
+++ b/libutil/crypt.c
@@ -64,7 +64,10 @@ mdchecklist(FILE *listfp, struct crypt_ops *ops, uint8_t 
*md, size_t sz,
(*noread)++;
continue;
}
-   cryptsum(ops, fp, file, md);
+   if (cryptsum(ops, fp, file, md)) {
+   (*noread)++;
+   continue;
+   }
r = mdcheckline(line, md, sz);
if (r == 1) {
printf("%s: OK\n", file);
@@ -125,8 +128,10 @@ cryptmain(int argc, char *argv[], struct crypt_ops *ops, 
uint8_t *md, size_t sz)
int ret = 0;
 
if (argc == 0) {
-   cryptsum(ops, stdin, "", md);
-   mdprint(md, "", sz);
+   if (cryptsum(ops, stdin, "", md))
+   ret = 1;
+   else
+   mdprint(md, "", sz);
} else {
for (; *argv; argc--, argv++) {
if ((*argv)[0] == '-' && !(*argv)[1]) {
@@ -137,11 +142,10 @@ cryptmain(int argc, char *argv[], struct crypt_ops *ops, 
uint8_t *md, size_t sz)
ret = 1;
continue;
}
-   if (cryptsum(ops, fp, *argv, md)) {
+   if (cryptsum(ops, fp, *argv, md))
ret = 1;
-   } else {
+   else
mdprint(md, *argv, sz);
-   }
if (fp != stdin && fshut(fp, *argv))
ret = 1;
}
-- 
2.11.0




[hackers] [sbase] [PATCH 05/10] tail: Use getc and putc instead of concat

2016-12-04 Thread Michael Forney
The FILE streams are buffered, so the end result is essentially the
same, except now lines are printed as they are read since we don't wait
until the entire buffer is filled.

This also fixes an issue where only part of the lines during the follow
were printed if they contained NUL bytes.
---
 tail.c | 22 +-
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/tail.c b/tail.c
index 711707f..ad97308 100644
--- a/tail.c
+++ b/tail.c
@@ -20,6 +20,7 @@ dropinit(FILE *fp, const char *str, size_t n)
char *buf = NULL;
size_t size = 0, i = 1;
ssize_t len;
+   int c;
 
if (mode == 'n') {
while (i < n && (len = getline(&buf, &size, fp)) > 0)
@@ -30,7 +31,10 @@ dropinit(FILE *fp, const char *str, size_t n)
i++;
}
free(buf);
-   concat(fp, str, stdout, "");
+   while ((c = fgetc(fp)) != EOF) {
+   if (fputc(c, stdout) == EOF)
+   break;
+   }
 }
 
 static void
@@ -88,9 +92,9 @@ main(int argc, char *argv[])
 {
struct stat st1, st2;
FILE *fp;
-   size_t tmpsize, n = 10;
-   int fflag = 0, ret = 0, newline = 0, many = 0;
-   char *numstr, *tmp;
+   size_t n = 10;
+   int fflag = 0, ret = 0, newline = 0, many = 0, c;
+   char *numstr;
void (*tail)(FILE *, const char *, size_t) = taketail;
 
ARGBEGIN {
@@ -141,13 +145,13 @@ main(int argc, char *argv[])
ret = 1;
continue;
}
-   for (tmp = NULL, tmpsize = 0;;) {
-   while (getline(&tmp, &tmpsize, fp) > 0) {
-   fputs(tmp, stdout);
-   fflush(stdout);
+   for (;;) {
+   while ((c = fgetc(fp)) != EOF) {
+   if (fputc(c, stdout) == EOF)
+   eprintf("fputc :");
}
if (ferror(fp))
-   eprintf("readline %s:", *argv);
+   eprintf("fgetc %s:", *argv);
clearerr(fp);
/* ignore error in case file was removed, we 
continue
 * tracking the existing open file descriptor */
-- 
2.11.0




[hackers] [sbase] [PATCH 07/10] concat: Use plain read/write instead of buffered stdio

2016-12-04 Thread Michael Forney
If we are just copying data from one file to another, we don't need to
fill a complete buffer, just read a chunk at a time, and write it to the
output.
---
 cat.c| 34 ++
 libutil/concat.c | 24 ++--
 libutil/cp.c | 42 --
 sponge.c | 31 +--
 text.h   |  1 -
 util.h   |  1 +
 xinstall.c   | 25 -
 7 files changed, 70 insertions(+), 88 deletions(-)

diff --git a/cat.c b/cat.c
index e3741aa..55585dd 100644
--- a/cat.c
+++ b/cat.c
@@ -1,22 +1,11 @@
 /* See LICENSE file for copyright and license details. */
-#include 
+#include 
 #include 
 #include 
 
-#include "text.h"
 #include "util.h"
 
 static void
-uconcat(FILE *fp1, const char *s1, FILE *fp2, const char *s2)
-{
-   int c;
-
-   setbuf(fp2, NULL);
-   while ((c = getc(fp1)) != EOF)
-   putc(c, fp2);
-}
-
-static void
 usage(void)
 {
eprintf("usage: %s [-u] [file ...]\n", argv0);
@@ -25,37 +14,34 @@ usage(void)
 int
 main(int argc, char *argv[])
 {
-   FILE *fp;
-   int ret = 0;
-   void (*cat)(FILE *, const char *, FILE *, const char *) = &concat;
+   int fd, ret = 0;
 
ARGBEGIN {
case 'u':
-   cat = &uconcat;
break;
default:
usage();
} ARGEND
 
if (!argc) {
-   cat(stdin, "", stdout, "");
+   if (concat(0, "", 1, "") < 0)
+   ret = 1;
} else {
for (; *argv; argc--, argv++) {
if (!strcmp(*argv, "-")) {
*argv = "";
-   fp = stdin;
-   } else if (!(fp = fopen(*argv, "r"))) {
-   weprintf("fopen %s:", *argv);
+   fd = 0;
+   } else if ((fd = open(*argv, O_RDONLY)) < 0) {
+   weprintf("open %s:", *argv);
ret = 1;
continue;
}
-   cat(fp, *argv, stdout, "");
-   if (fp != stdin && fshut(fp, *argv))
+   if (concat(fd, *argv, 1, "") < 0)
ret = 1;
+   if (fd != 0)
+   close(fd);
}
}
 
-   ret |= fshut(stdin, "") | fshut(stdout, "");
-
return ret;
 }
diff --git a/libutil/concat.c b/libutil/concat.c
index fad9471..3f617e2 100644
--- a/libutil/concat.c
+++ b/libutil/concat.c
@@ -1,19 +1,23 @@
 /* See LICENSE file for copyright and license details. */
-#include 
+#include 
 
-#include "../text.h"
 #include "../util.h"
 
-void
-concat(FILE *fp1, const char *s1, FILE *fp2, const char *s2)
+int
+concat(int f1, const char *s1, int f2, const char *s2)
 {
char buf[BUFSIZ];
-   size_t n;
+   ssize_t n;
 
-   while ((n = fread(buf, 1, sizeof(buf), fp1))) {
-   fwrite(buf, 1, n, fp2);
-
-   if (feof(fp1) || ferror(fp1) || ferror(fp2))
-   break;
+   while ((n = read(f1, buf, sizeof(buf))) > 0) {
+   if (writeall(f2, buf, n) < 0) {
+   weprintf("write %s:", s2);
+   return -1;
+   }
+   }
+   if (n < 0) {
+   weprintf("read %s:", s1);
+   return -1;
}
+   return 0;
 }
diff --git a/libutil/cp.c b/libutil/cp.c
index c398962..8cd0a7d 100644
--- a/libutil/cp.c
+++ b/libutil/cp.c
@@ -12,7 +12,6 @@
 #include 
 
 #include "../fs.h"
-#include "../text.h"
 #include "../util.h"
 
 int cp_aflag  = 0;
@@ -27,7 +26,7 @@ int
 cp(const char *s1, const char *s2, int depth)
 {
DIR *dp;
-   FILE *f1, *f2;
+   int f1, f2;
struct dirent *d;
struct stat st;
struct timespec times[2];
@@ -112,43 +111,34 @@ cp(const char *s1, const char *s2, int depth)
return 0;
}
} else {
-   if (!(f1 = fopen(s1, "r"))) {
-   weprintf("fopen %s:", s1);
+   if ((f1 = open(s1, O_RDONLY)) < 0) {
+   weprintf("open %s:", s1);
cp_status = 1;
return 0;
}
-   if (!(f2 = fopen(s2, "w"))) {
-   if (cp_fflag) {
-   if (unlink(s2) < 0 && errno != ENOENT) {
-   weprintf("unlink %s:", s2);
-   cp_status = 1;
-   return 0;
-   } else if (!(f2 = fopen(s2, "w"))) {
-   weprintf("fopen %s:", s2);
-   cp_status = 1;
- 

[hackers] [scc] [driver] fix temporary object generation for old POSIX || Quentin Rameau

2016-12-04 Thread git
commit 700201165e35131fd7c6e64e8e97f591a9724500
Author: Quentin Rameau 
AuthorDate: Sun Dec 4 10:36:21 2016 +0100
Commit: Quentin Rameau 
CommitDate: Sun Dec 4 12:30:55 2016 +0100

[driver] fix temporary object generation for old POSIX

Pre-susv4 mkstemp don't impose a filename format and don't provide
EINVAL error on which we were counting.

diff --git a/driver/posix/scc.c b/driver/posix/scc.c
index 74f5299..7f3e64e 100644
--- a/driver/posix/scc.c
+++ b/driver/posix/scc.c
@@ -163,10 +163,12 @@ outfname(char *path, char *type)
n = snprintf(new, newsz, "%.*s%c%s", (int)pathln, path, sep, type);
if (n < 0 || n >= newsz)
die("scc: wrong output filename");
-   if ((tmpfd = mkstemp(new)) < 0 && errno != EINVAL)
-   die("scc: could not create output file '%s': %s",
-   new, strerror(errno));
-   close(tmpfd);
+   if (sep == '/') {
+   if ((tmpfd = mkstemp(new)) < 0)
+   die("scc: could not create output file '%s': %s",
+   new, strerror(errno));
+   close(tmpfd);
+   }
 
return new;
 }



[hackers] [scc] Makefile: remove unnecessary mkdir bin/ || Quentin Rameau

2016-12-04 Thread git
commit 9c999e2862eb82d8a19b7ba8b2bd42a0256f860e
Author: Quentin Rameau 
AuthorDate: Fri Dec 2 11:41:54 2016 +0100
Commit: Quentin Rameau 
CommitDate: Sun Dec 4 12:30:59 2016 +0100

Makefile: remove unnecessary mkdir bin/

diff --git a/Makefile b/Makefile
index d6a2caa..98e5f0b 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,6 @@ driver/$(DRIVER)/scc: bin
ln -f driver/$(DRIVER)/scc bin/scc
 
 $(ARCHS): bin
-   mkdir -p bin
for i in cc1 cc2; \
do \
(cd $$i; \



[hackers] [scc] Makefiles: build a binary for each arch target || Quentin Rameau

2016-12-04 Thread git
commit 2f972eea17a78f21c5ffbce5be12b42ca91cb80c
Author: Quentin Rameau 
AuthorDate: Sun Dec 4 10:34:37 2016 +0100
Commit: Quentin Rameau 
CommitDate: Sun Dec 4 12:30:59 2016 +0100

Makefiles: build a binary for each arch target

This fixes a build issue when common code would be modified while having
a pre-built arch .o file, the arch-specific binary wouldn't be rebuilt.

diff --git a/Makefile b/Makefile
index 98e5f0b..588d808 100644
--- a/Makefile
+++ b/Makefile
@@ -20,10 +20,10 @@ $(ARCHS): bin
for i in cc1 cc2; \
do \
(cd $$i; \
-   ARCH=$@ $(MAKE) -e $$i || exit); \
+   ARCH=$@ $(MAKE) -e $$i-$@ || exit); \
done
-   ln -f cc1/cc1 bin/cc1-$@
-   ln -f cc2/cc2 bin/cc2-$@
+   ln -f cc1/cc1-$@ bin/
+   ln -f cc2/cc2-$@ bin/
 
 bin:
mkdir -p bin
diff --git a/cc1/Makefile b/cc1/Makefile
index 25df906..8b36fb1 100644
--- a/cc1/Makefile
+++ b/cc1/Makefile
@@ -6,7 +6,7 @@ include ../config.mk
 OBJS = types.o decl.o lex.o error.o symbol.o main.o expr.o \
code.o stmt.o cpp.o fold.o init.o arch/$(ARCH)/arch.o
 
-all: cc1
+all: cc1-$(ARCH)
 
 cpp.o: stallman.msg
 $(OBJS): cc1.h ../inc/cc.h ../inc/sizes.h
@@ -17,15 +17,15 @@ $(OBJS): cc1.h ../inc/cc.h ../inc/sizes.h
 ../lib/libcc.a:
cd ../lib && $(MAKE) -e
 
-cc1: $(OBJS) ../lib/libcc.a
+cc1-$(ARCH): $(OBJS) ../lib/libcc.a
$(CC) $(SCC_LDFLAGS) $(OBJS) ../lib/libcc.a -o $@
 
-cpp: cc1
-   ln -f cc1 cpp
+cpp: cc1-$(ARCH)
+   ln -f $< cpp
 
 test:
cd tests && ./chktest.sh *.c
 
 clean:
rm -f $(OBJS)
-   rm -f cc1 cpp
+   rm -f cc1-* cpp
diff --git a/cc2/Makefile b/cc2/Makefile
index ee0f35d..244b137 100644
--- a/cc2/Makefile
+++ b/cc2/Makefile
@@ -7,7 +7,7 @@ OBJS = main.o parser.o peep.o symbol.o node.o code.o optm.o\
arch/$(ARCH)/code.o arch/$(ARCH)/cgen.o \
arch/$(ARCH)/types.o arch/$(ARCH)/optm.o
 
-all: cc2
+all: cc2-$(ARCH)
 
 main.o: error.h
 $(OBJS): cc2.h ../inc/sizes.h ../inc/cc.h
@@ -24,9 +24,9 @@ error.h: cc2.h
 ../inc/sizes.h:
cp ../inc/sizes_$(STD).h $@
 
-cc2: $(OBJS) ../lib/libcc.a
+cc2-$(ARCH): $(OBJS) ../lib/libcc.a
$(CC) $(SCC_LDFLAGS) $(OBJS) ../lib/libcc.a -o $@
 
 clean:
rm -f $(OBJS)
-   rm -f cc2 error.h
+   rm -f cc2-* error.h