Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/usr.bin/xinstall Overhaul link creation - splitting out hard...
details: https://anonhg.NetBSD.org/src/rev/ad5be7157715
branches: trunk
changeset: 518022:ad5be7157715
user: simonb <simonb%NetBSD.org@localhost>
date: Fri Nov 23 16:14:51 2001 +0000
description:
Overhaul link creation - splitting out hard and symbolic link handling
to separate functions and handling -r (renaming) correctly for both
cases.
Also fix most lint(1) warnings.
diffstat:
usr.bin/xinstall/xinstall.c | 198 ++++++++++++++++++++++++++++++++-----------
1 files changed, 146 insertions(+), 52 deletions(-)
diffs (truncated from 379 to 300 lines):
diff -r f6a1ba711860 -r ad5be7157715 usr.bin/xinstall/xinstall.c
--- a/usr.bin/xinstall/xinstall.c Fri Nov 23 16:09:11 2001 +0000
+++ b/usr.bin/xinstall/xinstall.c Fri Nov 23 16:14:51 2001 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: xinstall.c,v 1.60 2001/11/22 23:27:38 dillo Exp $ */
+/* $NetBSD: xinstall.c,v 1.61 2001/11/23 16:14:51 simonb Exp $ */
/*
* Copyright (c) 1987, 1993
@@ -43,20 +43,21 @@
#if 0
static char sccsid[] = "@(#)xinstall.c 8.1 (Berkeley) 7/21/93";
#else
-__RCSID("$NetBSD: xinstall.c,v 1.60 2001/11/22 23:27:38 dillo Exp $");
+__RCSID("$NetBSD: xinstall.c,v 1.61 2001/11/23 16:14:51 simonb Exp $");
#endif
#endif /* not lint */
#include <sys/param.h>
-#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/stat.h>
+#include <sys/wait.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
+#include <libgen.h>
#include <paths.h>
#include <pwd.h>
#include <stdio.h>
@@ -98,14 +99,18 @@
void backup(const char *);
void copy(int, char *, int, char *, off_t);
+int do_link(char *, char *);
+void do_symlink(char *, char *);
void install(char *, char *, u_int);
void install_dir(char *, u_int);
int main(int, char *[]);
void makelink(char *, char *);
+void metadata_log(const char *, const char *, struct timeval *, const char *);
int parseid(char *, id_t *);
void strip(char *);
-void metadata_log(const char *, const char *, struct timeval *, const char *);
void usage(void);
+char *xbasename(char *);
+char *xdirname(char *);
int
main(int argc, char *argv[])
@@ -138,6 +143,7 @@
numberedbackup = 1;
}
/* fall through; -B implies -b */
+ /*FALLTHROUGH*/
case 'b':
dobackup = 1;
break;
@@ -178,7 +184,7 @@
break;
default:
errx(1, "%c: invalid link type", *p);
- break;
+ /* NOTREACHED */
}
break;
case 'm':
@@ -204,6 +210,7 @@
if (stripArgs == NULL)
errx(1, "%s", strerror(ENOMEM));
/* fall through; -S implies -s */
+ /*FALLTHROUGH*/
case 's':
dostrip = 1;
break;
@@ -281,13 +288,17 @@
usage();
if (!no_target) {
- if (stat(*argv, &from_sb))
- err(1, "%s", *argv);
- if (!S_ISREG(to_sb.st_mode))
- errx(1, "%s: not a regular file", to_name);
- if (!dolink && to_sb.st_dev == from_sb.st_dev &&
- to_sb.st_ino == from_sb.st_ino)
- errx(1, "%s and %s are the same file", *argv, to_name);
+ /* makelink() handles checks for links */
+ if (!dolink) {
+ if (stat(*argv, &from_sb))
+ err(1, "%s", *argv);
+ if (!S_ISREG(to_sb.st_mode))
+ errx(1, "%s: not a regular file", to_name);
+ if (to_sb.st_dev == from_sb.st_dev &&
+ to_sb.st_ino == from_sb.st_ino)
+ errx(1, "%s and %s are the same file", *argv,
+ to_name);
+ }
/*
* Unlink now... avoid ETXTBSY errors later. Try and turn
* off the append/immutable bits -- if we fail, go ahead,
@@ -323,6 +334,63 @@
}
/*
+ * do_link --
+ * make a hard link, obeying dorename if set
+ * return -1 on failure
+ */
+int
+do_link(char *from_name, char *to_name)
+{
+ char tmpl[MAXPATHLEN];
+ int ret;
+
+ if (dorename) {
+ (void)snprintf(tmpl, sizeof(tmpl), "%s/inst.XXXXXX",
+ xdirname(to_name));
+ if (mktemp(tmpl) == NULL)
+ err(1, "%s", tmpl);
+ ret = link(from_name, tmpl);
+ if (ret == 0) {
+ ret = rename(tmpl, to_name);
+ if (ret < 0)
+ /* remove temporary link before exiting */
+ (void)unlink(tmpl);
+ }
+ return (ret);
+ } else
+ return (link(from_name, to_name));
+}
+
+/*
+ * do_symlink --
+ * make a symbolic link, obeying dorename if set
+ * exit on failure
+ */
+void
+do_symlink(char *from_name, char *to_name)
+{
+ char tmpl[MAXPATHLEN];
+
+ if (dorename) {
+ (void)snprintf(tmpl, sizeof(tmpl), "%s/inst.XXXXXX",
+ xdirname(to_name));
+ if (mktemp(tmpl) == NULL)
+ err(1, "%s", tmpl);
+
+ if (symlink(from_name, tmpl) == -1)
+ err(1, "symlink %s -> %s", from_name, tmpl);
+ if (rename(tmpl, to_name) == -1) {
+ /* remove temporary link before exiting */
+ (void)unlink(tmpl);
+ err(1, "%s: rename", to_name);
+ }
+ } else {
+ if (symlink(from_name, to_name) == -1)
+ err(1, "symlink %s -> %s", from_name, to_name);
+ }
+}
+
+/*
* makelink --
* make a link from source to destination
*/
@@ -333,7 +401,7 @@
/* Try hard links first */
if (dolink & (LN_HARD|LN_MIXED)) {
- if (link(from_name, to_name) == -1) {
+ if (do_link(from_name, to_name) == -1) {
if ((dolink & LN_HARD) || errno != EXDEV)
err(1, "link %s -> %s", from_name, to_name);
}
@@ -347,21 +415,34 @@
if (dolink & LN_ABSOLUTE) {
/* Convert source path to absolute */
if (realpath(from_name, src) == NULL)
- err(1, "%s", src);
- if (symlink(src, to_name) == -1)
- err(1, "symlink %s -> %s", src, to_name);
+ err(1, "%s", from_name);
+ do_symlink(src, to_name);
metadata_log(to_name, "link", NULL, src);
return;
}
if (dolink & LN_RELATIVE) {
- char *s, *d;
+ char *cp, *d, *s;
/* Resolve pathnames */
if (realpath(from_name, src) == NULL)
- err(1, "%s", src);
- if (realpath(to_name, dst) == NULL)
- err(1, "%s", dst);
+ err(1, "%s", from_name);
+
+ /*
+ * The last component of to_name may be a symlink,
+ * so use realpath to resolve only the directory.
+ */
+ cp = dirname(to_name);
+ if (realpath(cp, dst) == NULL)
+ err(1, "%s", cp);
+ /* .. and add the last component */
+ if (strcmp(dst, "/") != 0) {
+ if (strlcat(dst, "/", sizeof(dst)) > sizeof(dst))
+ errx(1, "resolved pathname too long");
+ }
+ cp = xbasename(to_name);
+ if (strlcat(dst, cp, sizeof(dst)) > sizeof(dst))
+ errx(1, "resolved pathname too long");
/* trim common path components */
for (s = src, d = dst; *s == *d; s++, d++)
@@ -372,12 +453,11 @@
/* count the number of directories we need to backtrack */
for (++d, lnk[0] = '\0'; *d; d++)
if (*d == '/')
- (void) strcat(lnk, "../");
+ (void)strcat(lnk, "../");
- (void) strcat(lnk, ++s);
+ (void)strcat(lnk, ++s);
- if (symlink(lnk, dst) == -1)
- err(1, "symlink %s -> %s", lnk, dst);
+ do_symlink(lnk, dst);
metadata_log(dst, "link", NULL, lnk);
return;
}
@@ -386,8 +466,7 @@
* If absolute or relative was not specified,
* try the names the user provided
*/
- if (symlink(from_name, to_name) == -1)
- err(1, "symlink %s -> %s", from_name, to_name);
+ do_symlink(from_name, to_name);
metadata_log(to_name, "link", NULL, from_name);
}
@@ -432,23 +511,10 @@
to_sb.st_flags & (NOCHANGEBITS))
(void)chflags(to_name, to_sb.st_flags & ~(NOCHANGEBITS));
if (dorename) {
- char *ptr, c, *dir;
-
- if ((ptr = strrchr(to_name, '/')) != NULL) {
- c = *++ptr;
- *ptr = '\0';
- dir = to_name;
- } else {
- c = '\0'; /* pacify gcc */
- dir = tmpl;
- *dir = '\0';
- }
- (void)snprintf(tmpl, sizeof(tmpl), "%sinst.XXXXXX", dir);
- if (ptr)
- *ptr = c;
+ (void)snprintf(tmpl, sizeof(tmpl), "%sinst.XXXXXX",
+ xdirname(to_name));
oto_name = to_name;
to_name = tmpl;
-
} else {
oto_name = NULL; /* pacify gcc */
if (dobackup)
@@ -458,7 +524,7 @@
}
if (dolink) {
- makelink(from_name, to_name);
+ makelink(from_name, dorename ? oto_name : to_name);
return;
}
@@ -629,6 +695,7 @@
serrno = errno;
(void)unlink(to_name);
errx(1, "vfork: %s", strerror(serrno));
+ /*NOTREACHED*/
case 0:
stripprog = getenv("STRIP");
if (stripprog == NULL)
@@ -655,6 +722,7 @@
warn("%s", stripprog);
_exit(1);
+ /*NOTREACHED*/
default:
if (wait(&status) == -1 || status)
(void)unlink(to_name);
@@ -662,14 +730,15 @@
}
/*
- * backup file "to_name" to to_name.suffix
Home |
Main Index |
Thread Index |
Old Index