| Summary: | install(1) hangs when intalling files same directory. | ||
|---|---|---|---|
| Product: | Base System | Reporter: | okimoto <okimoto> |
| Component: | bin | Assignee: | freebsd-bugs (Nobody) <bugs> |
| Status: | Closed FIXED | ||
| Severity: | Affects Only Me | ||
| Priority: | Normal | ||
| Version: | 3.3-RELEASE | ||
| Hardware: | Any | ||
| OS: | Any | ||
|
Description
okimoto
1999-11-16 12:20:00 UTC
I've done a patch to xinstall, that detects if the source-file is the
same as the destination file, also if they are in the same directory:
alex:~ $ touch foo bar
alex:~ $ install foo bar .
install: foo and ./foo are the same file
alex:~ $ install foo bar ../../home/alex
install: foo and ../../home/alex/foo are the same file
alex:~ $ install foo bar /usr/home/alex
install: foo and /usr/home/alex/foo are the same file
alex:~ $ install foo bar test/..
install: foo and test/../foo are the same file
alex:~ $
Here is the patch:
--- xinstall.c.old Wed Nov 17 20:32:40 1999
+++ xinstall.c Wed Nov 17 21:48:05 1999
@@ -90,7 +90,7 @@
int debug, docompare, docopy, dodir, dopreserve, dostrip, nommap, verbose;
int mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
char *group, *owner, pathbuf[MAXPATHLEN];
-char pathbuf2[MAXPATHLEN];
+char pathbuf2[MAXPATHLEN], pathbuf3[MAXPATHLEN];
#define DIRECTORY 0x01 /* Tell install it's a directory. */
#define SETFLAGS 0x02 /* Tell install to set flags. */
@@ -105,6 +105,7 @@
void strip __P((char *));
void usage __P((void));
int trymmap __P((int));
+char * basename __P((char *));
#define ALLOW_NUMERIC_IDS 1
#ifdef ALLOW_NUMERIC_IDS
@@ -128,7 +129,7 @@
int argc;
char *argv[];
{
- struct stat from_sb, to_sb;
+ struct stat from_sb, to_sb, fileto_sb;
mode_t *set;
u_long fset;
u_int iflags;
@@ -222,8 +223,28 @@
no_target = stat(to_name = argv[argc - 1], &to_sb);
if (!no_target && (to_sb.st_mode & S_IFMT) == S_IFDIR) {
- for (; *argv != to_name; ++argv)
- install(*argv, to_name, fset, iflags | DIRECTORY);
+ for (; *argv != to_name; ++argv) {
+ if (stat(*argv, &from_sb))
+ err(EX_OSERR, "%s", *argv);
+ snprintf(pathbuf3, MAXPATHLEN,
+ "%s%s%s", to_name,
+ to_name[strlen(to_name) - 1] == '/' ? "" : "/",
+ basename(*argv));
+ if (stat(pathbuf3, &fileto_sb) && errno != ENOENT)
+ err(EX_OSERR, "%s", pathbuf3);
+ else if (errno == ENOENT)
+ goto target_ok;
+ if (!S_ISREG(fileto_sb.st_mode)) {
+ errno = EFTYPE;
+ err(EX_OSERR, "%s", pathbuf3);
+ }
+ if (fileto_sb.st_dev == from_sb.st_dev &&
+ fileto_sb.st_ino == from_sb.st_ino)
+ errx(EX_USAGE,
+ "%s and %s are the same file", *argv, pathbuf3);
+ target_ok:
+ install(*argv, pathbuf3, fset, iflags);
+ }
exit(EX_OK);
/* NOTREACHED */
}
@@ -736,4 +757,19 @@
return (1);
#endif
return (0);
+}
+
+/*
+ * basename --
+ * return the filename of a file whose absolut path is given
+ * as pointer to char.
+ */
+char *
+basename(name)
+ char *name;
+{
+ char *slash;
+
+ slash = strrchr(name, '/');
+ return (slash == NULL ? name : slash + 1);
}
On Tue, 16 Nov 1999 04:12:20 PST, okimoto@mrit.mei.co.jp wrote: > Unable kill install(1), when installing files > to same directory. > >How-To-Repeat: > 1) touch ./foo > 2) install ./foo . This doesn't cause a problem in CURRENT. Could you please test this for 3.3-STABLE. If it's still a problem there, then we'll need to investigate the difference between RELENG_3 and HEAD and figure out what fix needs to be backported. Ciao, Sheldon. Thank you for repling my report. But, I have received some mails from "alex@cichlids.com", maybe a menbar of freebsd-gnats-submit. And this problem has solved. He said this problem was 3.3-RELEASE case. But, install(1) should detect if the source-file is the same as the destination file, he also thought. So, he made a patch for "xinstall.c", and it's good. Thank you, Mr.Alexander. And thank you, Mr.Sheldon. # ..though, I should report this to somewhere? --- Yoshiyuki OKIMOTO ok. This patch seems nice.
Please discard the old one.
I also fixed a /dev/null error. Please see the thread on freebsd-bugs
about this.
Sheldon suggested to use realpath(), so I did.
Usage-log:
alex:~ $ mkdir test
mkdir: test: File exists
alex:~ $ touch foo; /usr/obj/usr/src/usr.bin/xinstall/xinstall foo
test
alex:~ $ touch foo; /usr/obj/usr/src/usr.bin/xinstall/xinstall foo
test/foo
alex:~ $ touch foo; /usr/obj/usr/src/usr.bin/xinstall/xinstall foo
test/..
xinstall: foo and /usr/home/alex/foo are the same file
alex:~ $ touch foo; /usr/obj/usr/src/usr.bin/xinstall/xinstall foo .
xinstall: foo and /usr/home/alex/foo are the same file
alex:~ $ touch foo; /usr/obj/usr/src/usr.bin/xinstall/xinstall foo ./
xinstall: foo and /usr/home/alex/foo are the same file
alex:~ $ touch foo; /usr/obj/usr/src/usr.bin/xinstall/xinstall foo
./../alex
xinstall: foo and /usr/home/alex/foo are the same file
alex:~ $ touch foo; /usr/obj/usr/src/usr.bin/xinstall/xinstall ./foo
./../alex
xinstall: ./foo and /usr/home/alex/foo are the same file
alex:~ $ touch foo; /usr/obj/usr/src/usr.bin/xinstall/xinstall test
test test.scm testdatei testwort.bak
test.c testbla testwort
alex:~ $ touch foo; /usr/obj/usr/src/usr.bin/xinstall/xinstall
test/bar test
xinstall: test/bar and /usr/home/alex/test/bar are the same file
alex:~ $ touch foo; /usr/obj/usr/src/usr.bin/xinstall/xinstall
test/bar test/..
alex:~ $ touch foo; /usr/obj/usr/src/usr.bin/xinstall/xinstall
/dev/null test
xinstall: Cannot install /dev/null to a directory
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
YES, I did it. I changed the error-msg. But I think, it's ok.
alex:~ $ rm -rf bar ; /usr/obj/usr/src/usr.bin/xinstall/xinstall
/dev/null bar ; ls -l bar
-rwxr-xr-x 1 alex alex 0 18 Nov 15:45 bar*
Patch:
--- xinstall.c.old Wed Nov 17 20:32:40 1999
+++ xinstall.c Thu Nov 18 15:48:12 1999
@@ -90,7 +90,7 @@
int debug, docompare, docopy, dodir, dopreserve, dostrip, nommap, verbose;
int mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
char *group, *owner, pathbuf[MAXPATHLEN];
-char pathbuf2[MAXPATHLEN];
+char pathbuf2[MAXPATHLEN], pathbuf3[MAXPATHLEN];
#define DIRECTORY 0x01 /* Tell install it's a directory. */
#define SETFLAGS 0x02 /* Tell install to set flags. */
@@ -319,7 +319,7 @@
u_long fset;
u_int flags;
{
- struct stat from_sb, to_sb;
+ struct stat from_sb, to_sb, fileto_sb;
int devnull, from_fd, to_fd, serrno;
char *p, *old_to_name = 0;
@@ -327,25 +327,35 @@
fprintf(stderr, "install: invoked without -C for %s to %s\n",
from_name, to_name);
+ if (strcmp(from_name, _PATH_DEVNULL) == 0) {
+ from_sb.st_flags = 0; /* XXX */
+ devnull = 1;
+ } else
+ devnull = 0;
/* If try to install NULL file to a directory, fails. */
- if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) {
+ if (flags & DIRECTORY && devnull)
+ errx(EX_USAGE, "Cannot install %s to a directory",
+ _PATH_DEVNULL);
+
+ if (flags & DIRECTORY) {
+ if (realpath(to_name, pathbuf2) == NULL)
+ errx(EX_OSERR, "%s", pathbuf2);
+ (void)snprintf(pathbuf3, sizeof(pathbuf3),
+ "%s/%s", pathbuf2,
+ (p = strrchr(from_name, '/')) ? ++p : from_name);
+ to_name = pathbuf3; /* target path is in pathbuf3 */
if (stat(from_name, &from_sb))
err(EX_OSERR, "%s", from_name);
+ if (stat(to_name, &fileto_sb) && errno != ENOENT)
+ err(EX_OSERR, "%s", to_name);
if (!S_ISREG(from_sb.st_mode)) {
errno = EFTYPE;
err(EX_OSERR, "%s", from_name);
}
- /* Build the target path. */
- if (flags & DIRECTORY) {
- (void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
- to_name,
- (p = strrchr(from_name, '/')) ? ++p : from_name);
- to_name = pathbuf;
- }
- devnull = 0;
- } else {
- from_sb.st_flags = 0; /* XXX */
- devnull = 1;
+ if (fileto_sb.st_dev == from_sb.st_dev &&
+ fileto_sb.st_ino == from_sb.st_ino)
+ errx(EX_USAGE,
+ "%s and %s are the same file", from_name, pathbuf3);
}
if (docompare) {
#### diff ends here
So long,
Alex
--
I doubt, therefore I might be.
State Changed From-To: open->closed This problem was apparently fixed in 4.0-RELEASE. See sheldonh's comments for details. |