Re: install(1) broken

2019-02-11 Thread Marc Espie
On Sun, Feb 10, 2019 at 03:55:41PM +0100, Marc Espie wrote:
> Something similar to this  perhaps ?
> Not fully tested yet, but it should avoid the race of trying to 
> unlink tempfile several times, and also fix the file name in error messages.

That's now been tested (gone thru a build + xbuild and bulk in progress
that went thru go-bootstrap and go without issues).

Okay ?

This needs re-applying Ingo's patch first, of course, which I can either do
or we coordinate with Ingo.



Index: xinstall.c
===
RCS file: /cvs/src/usr.bin/xinstall/xinstall.c,v
retrieving revision 1.68
diff -u -p -r1.68 xinstall.c
--- xinstall.c  8 Feb 2019 12:53:44 -   1.68
+++ xinstall.c  10 Feb 2019 14:53:49 -
@@ -222,6 +222,7 @@ install(char *from_name, char *to_name, 
struct timespec ts[2];
int devnull, from_fd, to_fd, serrno, files_match = 0;
char *p;
+   char *target_name = tempfile;
 
(void)memset((void *)_sb, 0, sizeof(from_sb));
(void)memset((void *)_sb, 0, sizeof(to_sb));
@@ -311,10 +312,14 @@ install(char *from_name, char *to_name, 
} else {
files_match = 1;
(void)unlink(tempfile);
+   target_name = to_name;
+   (void)close(temp_fd);
}
}
-   (void)close(to_fd);
-   to_fd = temp_fd;
+   if (!files_match) {
+   (void)close(to_fd);
+   to_fd = temp_fd;
+   }
}
 
/*
@@ -333,13 +338,15 @@ install(char *from_name, char *to_name, 
if ((gid != (gid_t)-1 || uid != (uid_t)-1) &&
fchown(to_fd, uid, gid)) {
serrno = errno;
-   (void)unlink(tempfile);
-   errx(1, "%s: chown/chgrp: %s", tempfile, strerror(serrno));
+   if (target_name == tempfile)
+   (void)unlink(tempfile);
+   errx(1, "%s: chown/chgrp: %s", target_name, strerror(serrno));
}
if (fchmod(to_fd, mode)) {
serrno = errno;
-   (void)unlink(tempfile);
-   errx(1, "%s: chmod: %s", tempfile, strerror(serrno));
+   if (target_name == tempfile)
+   (void)unlink(tempfile);
+   errx(1, "%s: chmod: %s", target_name, strerror(serrno));
}
 
/*
@@ -349,7 +356,7 @@ install(char *from_name, char *to_name, 
if (fchflags(to_fd,
flags & SETFLAGS ? fset : from_sb.st_flags & ~UF_NODUMP)) {
if (errno != EOPNOTSUPP || (from_sb.st_flags & ~UF_NODUMP) != 0)
-   warnx("%s: chflags: %s", tempfile, strerror(errno));
+   warnx("%s: chflags: %s", target_name, strerror(errno));
}
 
if (flags & USEFSYNC)



Re: install(1) broken

2019-02-10 Thread Ted Unangst
Marc Espie wrote:
> Something similar to this  perhaps ?
> Not fully tested yet, but it should avoid the race of trying to 
> unlink tempfile several times, and also fix the file name in error messages.

That's probably better.



Re: install(1) broken

2019-02-10 Thread Marc Espie
Something similar to this  perhaps ?
Not fully tested yet, but it should avoid the race of trying to 
unlink tempfile several times, and also fix the file name in error messages.

Index: xinstall.c
===
RCS file: /cvs/src/usr.bin/xinstall/xinstall.c,v
retrieving revision 1.68
diff -u -p -r1.68 xinstall.c
--- xinstall.c  8 Feb 2019 12:53:44 -   1.68
+++ xinstall.c  10 Feb 2019 14:53:49 -
@@ -222,6 +222,7 @@ install(char *from_name, char *to_name, 
struct timespec ts[2];
int devnull, from_fd, to_fd, serrno, files_match = 0;
char *p;
+   char *target_name = tempfile;
 
(void)memset((void *)_sb, 0, sizeof(from_sb));
(void)memset((void *)_sb, 0, sizeof(to_sb));
@@ -311,10 +312,14 @@ install(char *from_name, char *to_name, 
} else {
files_match = 1;
(void)unlink(tempfile);
+   target_name = to_name;
+   (void)close(temp_fd);
}
}
-   (void)close(to_fd);
-   to_fd = temp_fd;
+   if (!files_match) {
+   (void)close(to_fd);
+   to_fd = temp_fd;
+   }
}
 
/*
@@ -333,13 +338,15 @@ install(char *from_name, char *to_name, 
if ((gid != (gid_t)-1 || uid != (uid_t)-1) &&
fchown(to_fd, uid, gid)) {
serrno = errno;
-   (void)unlink(tempfile);
-   errx(1, "%s: chown/chgrp: %s", tempfile, strerror(serrno));
+   if (target_name == tempfile)
+   (void)unlink(tempfile);
+   errx(1, "%s: chown/chgrp: %s", target_name, strerror(serrno));
}
if (fchmod(to_fd, mode)) {
serrno = errno;
-   (void)unlink(tempfile);
-   errx(1, "%s: chmod: %s", tempfile, strerror(serrno));
+   if (target_name == tempfile)
+   (void)unlink(tempfile);
+   errx(1, "%s: chmod: %s", target_name, strerror(serrno));
}
 
/*
@@ -349,7 +356,7 @@ install(char *from_name, char *to_name, 
if (fchflags(to_fd,
flags & SETFLAGS ? fset : from_sb.st_flags & ~UF_NODUMP)) {
if (errno != EOPNOTSUPP || (from_sb.st_flags & ~UF_NODUMP) != 0)
-   warnx("%s: chflags: %s", tempfile, strerror(errno));
+   warnx("%s: chflags: %s", target_name, strerror(errno));
}
 
if (flags & USEFSYNC)



Re: install(1) broken

2019-02-10 Thread Marc Espie
On Sat, Feb 09, 2019 at 05:23:09PM -0500, Ted Unangst wrote:
> Marc Espie wrote:
> > hey, your commit to install(1) broke something.
> > 
> > Specifically lang/go-boostrap now produces a broken package which can't
> > be used to build go.
> > 
> > All the go/bootstrap/pkg/tool/openbsd_amd64/*
> > have lost their x bit
> > 
> > Relevant fake install information, it definitely looks like the last line
> > is now a no-op.
> 
> > # These get installed via `find' however we need them to be executable
> > /pobj/go-bootstrap-1.4.20171003/bin/install -d -m 755 
> > /pobj/go-bootstrap-1.4.20171003/fake-amd64/usr/local/go/bootstrap/pkg/tool//openbsd_amd64
> > /pobj/go-bootstrap-1.4.20171003/bin/install -c  -m 755 -p 
> > /pobj/go-bootstrap-1.4.20171003/go/pkg/tool//openbsd_amd64/* 
> > /pobj/go-bootstrap-1.4.20171003/fake-amd64/usr/local/go/bootstrap/pkg/tool//openbsd_amd64
> 
> Yes. This is a weird way to invoke chmod, but that's what it wants.
> 
> I think this was a long standing bug in install? If the files match, we need
> to continue on with to_fd == existing file so that metadata updates work.
> 
> 
> Index: xinstall.c
> ===
> RCS file: /cvs/src/usr.bin/xinstall/xinstall.c,v
> retrieving revision 1.68
> diff -u -p -r1.68 xinstall.c
> --- xinstall.c8 Feb 2019 12:53:44 -   1.68
> +++ xinstall.c9 Feb 2019 22:21:03 -
> @@ -313,8 +313,12 @@ install(char *from_name, char *to_name, 
>   (void)unlink(tempfile);
>   }
>   }
> - (void)close(to_fd);
> - to_fd = temp_fd;
> + if (!files_match) {
> + (void)close(to_fd);
> + to_fd = temp_fd;
> + } else {
> + close(temp_fd);
> + }
>   }
>  
>   /*
I'm afraid this needs to be slightly more complex, probably to put the
remaining code in its own function, or something.

Specifically, the error paths for the fchown and fchmod  will be all bogus
in that case, referring to a tempfile  that's already been removed, and
is not even the target...



Re: install(1) broken

2019-02-09 Thread Marc Espie
On Sat, Feb 09, 2019 at 05:23:09PM -0500, Ted Unangst wrote:
> Marc Espie wrote:
> > hey, your commit to install(1) broke something.
> > 
> > Specifically lang/go-boostrap now produces a broken package which can't
> > be used to build go.
> > 
> > All the go/bootstrap/pkg/tool/openbsd_amd64/*
> > have lost their x bit
> > 
> > Relevant fake install information, it definitely looks like the last line
> > is now a no-op.
> 
> > # These get installed via `find' however we need them to be executable
> > /pobj/go-bootstrap-1.4.20171003/bin/install -d -m 755 
> > /pobj/go-bootstrap-1.4.20171003/fake-amd64/usr/local/go/bootstrap/pkg/tool//openbsd_amd64
> > /pobj/go-bootstrap-1.4.20171003/bin/install -c  -m 755 -p 
> > /pobj/go-bootstrap-1.4.20171003/go/pkg/tool//openbsd_amd64/* 
> > /pobj/go-bootstrap-1.4.20171003/fake-amd64/usr/local/go/bootstrap/pkg/tool//openbsd_amd64
> 
> Yes. This is a weird way to invoke chmod, but that's what it wants.

This actually makes some kind of sense in a broader context.

Specifically, install_flags are a somewhat standard way to enforce
ownership/permissions on a file, whether while copying it from one place
to another... or after moving it.

It's way simpler to bundle everything into a single variable than having
several separate variables to do things.



Re: install(1) broken

2019-02-09 Thread Ted Unangst
Marc Espie wrote:
> hey, your commit to install(1) broke something.
> 
> Specifically lang/go-boostrap now produces a broken package which can't
> be used to build go.
> 
> All the go/bootstrap/pkg/tool/openbsd_amd64/*
> have lost their x bit
> 
> Relevant fake install information, it definitely looks like the last line
> is now a no-op.

> # These get installed via `find' however we need them to be executable
> /pobj/go-bootstrap-1.4.20171003/bin/install -d -m 755 
> /pobj/go-bootstrap-1.4.20171003/fake-amd64/usr/local/go/bootstrap/pkg/tool//openbsd_amd64
> /pobj/go-bootstrap-1.4.20171003/bin/install -c  -m 755 -p 
> /pobj/go-bootstrap-1.4.20171003/go/pkg/tool//openbsd_amd64/* 
> /pobj/go-bootstrap-1.4.20171003/fake-amd64/usr/local/go/bootstrap/pkg/tool//openbsd_amd64

Yes. This is a weird way to invoke chmod, but that's what it wants.

I think this was a long standing bug in install? If the files match, we need
to continue on with to_fd == existing file so that metadata updates work.


Index: xinstall.c
===
RCS file: /cvs/src/usr.bin/xinstall/xinstall.c,v
retrieving revision 1.68
diff -u -p -r1.68 xinstall.c
--- xinstall.c  8 Feb 2019 12:53:44 -   1.68
+++ xinstall.c  9 Feb 2019 22:21:03 -
@@ -313,8 +313,12 @@ install(char *from_name, char *to_name, 
(void)unlink(tempfile);
}
}
-   (void)close(to_fd);
-   to_fd = temp_fd;
+   if (!files_match) {
+   (void)close(to_fd);
+   to_fd = temp_fd;
+   } else {
+   close(temp_fd);
+   }
}
 
/*