diff options
Diffstat (limited to 'util')
-rw-r--r-- | util/Makefile.in | 19 | ||||
-rw-r--r-- | util/all.exclude | 3 | ||||
-rw-r--r-- | util/install-symlink.in | 89 | ||||
-rw-r--r-- | util/subset.exclude | 3 | ||||
-rw-r--r-- | util/subst.c | 98 | ||||
-rw-r--r-- | util/subst.conf.in | 2 | ||||
-rw-r--r-- | util/symlinks.c | 387 |
7 files changed, 560 insertions, 41 deletions
diff --git a/util/Makefile.in b/util/Makefile.in index 4ad769f6..d235fffc 100644 --- a/util/Makefile.in +++ b/util/Makefile.in @@ -16,11 +16,18 @@ SRCS = $(srcdir)/subst.c .c.o: $(E) " CC $<" $(Q) $(BUILD_CC) -c $(BUILD_CFLAGS) $< -o $@ + $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $< -PROGS= subst +PROGS= subst symlinks all:: $(PROGS) gen-tarball +dirpaths.h: + $(E) " CREATE dirpaths.h" + $(Q) echo "/* fake dirpaths.h for config.h */" > dirpaths.h + +subst.o: dirpaths.h + subst: subst.o $(E) " LD $@" $(Q) $(BUILD_CC) $(BUILD_LDFLAGS) -o subst subst.o @@ -29,6 +36,10 @@ copy_sparse: copy_sparse.o $(E) " LD $@" $(Q) $(BUILD_CC) $(BUILD_LDFLAGS) -o copy_sparse copy_sparse.o +symlinks: symlinks.o + $(E) " LD $@" + $(Q) $(BUILD_CC) $(BUILD_LDFLAGS) -o symlinks symlinks.o + gen-tarball: $(srcdir)/gen-tarball.in $(top_builddir)/config.status $(E) " CONFIG.STATUS $@" $(Q) cd $(top_builddir); CONFIG_FILES=util/gen-tarball ./config.status @@ -39,9 +50,9 @@ tarballs: gen-tarball sh gen-tarball all sh gen-tarball subset -clean: +clean:: $(RM) -f $(PROGS) \#* *.s *.o *.a *~ core *.tar.gz gen-tarball \ - copy-sparse + copy-sparse dirpaths.h mostlyclean: clean @@ -53,4 +64,4 @@ distclean: clean # Makefile dependencies follow. This must be the last section in # the Makefile.in file # -subst.o: $(srcdir)/subst.c +subst.o: $(srcdir)/subst.c $(top_builddir)/lib/config.h dirpaths.h diff --git a/util/all.exclude b/util/all.exclude index d46b9b76..d7d03b22 100644 --- a/util/all.exclude +++ b/util/all.exclude @@ -5,8 +5,7 @@ patches README.subset build -build.profiled -build.static +build[^/]* rpm.log TODO powerquest diff --git a/util/install-symlink.in b/util/install-symlink.in new file mode 100644 index 00000000..24341b8b --- /dev/null +++ b/util/install-symlink.in @@ -0,0 +1,89 @@ +#!/bin/sh +# +# install-symlink source destination destdir +# + +SYMLINKS=symlinks +LN_S="@LN_S@" +RM="@RM@" +FORCE_RELATIVE=NO +FORCE_ABSOLUTE=NO + +while echo $1 | grep -q -- ^- ; +do + case $1 in + --relative) + FORCE_RELATIVE=YES + ;; + --absolute) + FORCE_ABSOLUTE=YES + ;; + --debian) + FORCE_ABSOLUTE=NO + FORCE_RELATIVE=NO + ;; + --symlinks=*) + SYMLINKS=$(echo $1 | sed -e 's/--symlinks=//') + ;; + *) + echo "Unknown option $1" + exit 1 + ;; + esac + shift; +done + + +FIX_SYMLINK="$SYMLINKS -c" + +SRC="$1" +DEST="$2" +DESTDIR="$3" + +if ! echo $SRC | grep -q ^/ ; then + echo $SRC: Source pathname must be absolute + exit 1 +fi + +if ! echo $DEST | grep -q ^/ ; then + echo $DEST: Destination pathname must be absolute + exit 1 +fi + +if ! test -e "$DESTDIR$SRC" ; then + echo $DESTDIR$SRC: file or directory does not exist + exit 1 +fi + +$RM -f "$DESTDIR$DEST" + +if test "$LN_S" != "ln -s" ; then + $LN_S "$DESTDIR$SRC" "$DESTDIR$DEST" + exit 0 +fi + +if test $(dirname "$SRC") = $(dirname "$DEST") ; then + $LN_S "$(basename "$SRC")" "$DESTDIR$DEST" + exit 0 +fi + +TOP_SRC=$(echo $SRC | awk -F/ '{print $2}') +TOP_DEST=$(echo $DEST | awk -F/ '{print $2}') + +if test $FORCE_RELATIVE = YES ; then + TOP_SRC=FORCE + TOP_DEST=FORCE +fi + +if test $FORCE_ABSOLUTE = YES ; then + TOP_SRC=FORCE + TOP_DEST=FORCE_ABSOLUTE +fi + +if test $TOP_SRC != $TOP_DEST ; then + $LN_S "$SRC" "$DESTDIR$DEST" +else + $LN_S "$DESTDIR$SRC" "$DESTDIR$DEST" + $FIX_SYMLINK "$DESTDIR$DEST" +fi + diff --git a/util/subset.exclude b/util/subset.exclude index e6cce504..b988fa84 100644 --- a/util/subset.exclude +++ b/util/subset.exclude @@ -4,8 +4,7 @@ .pc patches build -build.profiled -build.static +build[^/]* rpm.log TODO powerquest diff --git a/util/subst.c b/util/subst.c index 8544b6da..6a5eab1b 100644 --- a/util/subst.c +++ b/util/subst.c @@ -5,6 +5,7 @@ * */ +#include "config.h" #include <stdio.h> #include <errno.h> #include <stdlib.h> @@ -13,6 +14,7 @@ #include <ctype.h> #include <sys/types.h> #include <sys/stat.h> +#include <fcntl.h> #include <time.h> #include <utime.h> @@ -30,7 +32,7 @@ struct subst_entry { struct subst_entry *next; }; -struct subst_entry *subst_table = 0; +static struct subst_entry *subst_table = 0; static int add_subst(char *name, char *value) { @@ -264,21 +266,11 @@ static void parse_config_file(FILE *f) /* * Return 0 if the files are different, 1 if the files are the same. */ -static int compare_file(const char *outfn, const char *newfn) +static int compare_file(FILE *old_f, FILE *new_f) { - FILE *old_f, *new_f; char oldbuf[2048], newbuf[2048], *oldcp, *newcp; int retval; - old_f = fopen(outfn, "r"); - if (!old_f) - return 0; - new_f = fopen(newfn, "r"); - if (!new_f) { - fclose(old_f); - return 0; - } - while (1) { oldcp = fgets(oldbuf, sizeof(oldbuf), old_f); newcp = fgets(newbuf, sizeof(newbuf), new_f); @@ -291,8 +283,6 @@ static int compare_file(const char *outfn, const char *newfn) break; } } - fclose(old_f); - fclose(new_f); return retval; } @@ -302,12 +292,14 @@ int main(int argc, char **argv) { char line[2048]; int c; - FILE *in, *out; + int fd; + FILE *in, *out, *old = NULL; char *outfn = NULL, *newfn = NULL; int verbose = 0; int adjust_timestamp = 0; + int got_atime = 0; struct stat stbuf; - struct utimbuf ut; + struct timeval tv[2]; while ((c = getopt (argc, argv, "f:tv")) != EOF) { switch (c) { @@ -351,11 +343,34 @@ int main(int argc, char **argv) } strcpy(newfn, outfn); strcat(newfn, ".new"); - out = fopen(newfn, "w"); - if (!out) { + fd = open(newfn, O_CREAT|O_TRUNC|O_RDWR, 0444); + if (fd < 0) { perror(newfn); exit(1); } + out = fdopen(fd, "w+"); + if (!out) { + perror("fdopen"); + exit(1); + } + + fd = open(outfn, O_RDONLY); + if (fd > 0) { + /* save the original atime, if possible */ + if (fstat(fd, &stbuf) == 0) { +#if HAVE_STRUCT_STAT_ST_ATIM + tv[0].tv_sec = stbuf.st_atim.tv_sec; + tv[0].tv_usec = stbuf.st_atim.tv_nsec / 1000; +#else + tv[0].tv_sec = stbuf.st_atime; + tv[0].tv_usec = 0; +#endif + got_atime = 1; + } + old = fdopen(fd, "r"); + if (!old) + close(fd); + } } else { out = stdout; outfn = 0; @@ -368,32 +383,49 @@ int main(int argc, char **argv) fputs(line, out); } fclose(in); - fclose(out); if (outfn) { - struct stat st; - if (compare_file(outfn, newfn)) { + fflush(out); + rewind(out); + if (old && compare_file(old, out)) { if (verbose) printf("No change, keeping %s.\n", outfn); if (adjust_timestamp) { - if (stat(outfn, &stbuf) == 0) { - if (verbose) - printf("Updating modtime for %s\n", outfn); - ut.actime = stbuf.st_atime; - ut.modtime = time(0); - if (utime(outfn, &ut) < 0) - perror("utime"); + if (verbose) + printf("Updating modtime for %s\n", outfn); + if (gettimeofday(&tv[1], NULL) < 0) { + perror("gettimeofday"); + exit(1); } + if (got_atime == 0) + tv[0] = tv[1]; + else if (verbose) + printf("Using original atime\n"); +#ifdef HAVE_FUTIMES + if (futimes(fileno(old), tv) < 0) + perror("futimes"); +#else + if (utimes(outfn, tv) < 0) + perror("utimes"); +#endif } - unlink(newfn); + fclose(out); + if (unlink(newfn) < 0) + perror("unlink"); } else { if (verbose) printf("Creating or replacing %s.\n", outfn); - rename(newfn, outfn); + fclose(out); + if (old) + fclose(old); + old = NULL; + if (rename(newfn, outfn) < 0) { + perror("rename"); + exit(1); + } } - /* set read-only to alert user it is a generated file */ - if (stat(outfn, &st) == 0) - chmod(outfn, st.st_mode & ~0222); } + if (old) + fclose(old); return (0); } diff --git a/util/subst.conf.in b/util/subst.conf.in index 0e074d85..64fde7ad 100644 --- a/util/subst.conf.in +++ b/util/subst.conf.in @@ -18,3 +18,5 @@ $prefix @prefix@ # Enable the documentation for the journal device mke2fs, tune2fs, and # e2fsck's man page JDEV +# Enable documentation for quota feature in mke2fs +QUOTA_MAN_COMMENT @QUOTA_MAN_COMMENT@ diff --git a/util/symlinks.c b/util/symlinks.c new file mode 100644 index 00000000..abb33f8b --- /dev/null +++ b/util/symlinks.c @@ -0,0 +1,387 @@ +#define _FILE_OFFSET_BITS 64 +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE + +#include <unistd.h> +#ifndef _POSIX_SOURCE +#define _POSIX_SOURCE +#endif +#include <stdio.h> +#include <stdlib.h> +#ifdef HAVE_MALLOC_H +#include <malloc.h> +#endif +#include <string.h> +#include <fcntl.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <time.h> +#include <stddef.h> +#include <errno.h> + +#ifndef S_ISLNK +#define S_ISLNK(mode) (((mode) & (_S_IFMT)) == (_S_IFLNK)) +#endif + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +#define progver "%s: scan/change symbolic links - v1.3 - by Mark Lord\n\n" +static char *progname; +static int verbose = 0, fix_links = 0, recurse = 0, delete = 0, shorten = 0, + testing = 0, single_fs = 1; + +/* + * tidypath removes excess slashes and "." references from a path string + */ + +static int substr (char *s, char *old, char *new) +{ + char *tmp = NULL; + int oldlen = strlen(old), newlen = 0; + + if (NULL == strstr(s, old)) + return 0; + + if (new) + newlen = strlen(new); + + if (newlen > oldlen) { + if ((tmp = malloc(strlen(s))) == NULL) { + fprintf(stderr, "no memory\n"); + exit (1); + } + } + + while (NULL != (s = strstr(s, old))) { + char *p, *old_s = s; + + if (new) { + if (newlen > oldlen) + old_s = strcpy(tmp, s); + p = new; + while (*p) + *s++ = *p++; + } + p = old_s + oldlen; + while ((*s++ = *p++)); + } + if (tmp) + free(tmp); + return 1; +} + + +static int tidy_path (char *path) +{ + int tidied = 0; + char *s, *p; + + s = path + strlen(path) - 1; + if (s[0] != '/') { /* tmp trailing slash simplifies things */ + s[1] = '/'; + s[2] = '\0'; + } + while (substr(path, "/./", "/")) + tidied = 1; + while (substr(path, "//", "/")) + tidied = 1; + + while ((p = strstr(path,"/../")) != NULL) { + s = p+3; + for (p--; p != path; p--) if (*p == '/') break; + if (*p != '/') + break; + while ((*p++ = *s++)); + tidied = 1; + } + if (*path == '\0') + strcpy(path,"/"); + p = path + strlen(path) - 1; + if (p != path && *p == '/') + *p-- = '\0'; /* remove tmp trailing slash */ + while (p != path && *p == '/') { /* remove any others */ + *p-- = '\0'; + tidied = 1; + } + while (!strncmp(path,"./",2)) { + for (p = path, s = path+2; (*p++ = *s++);); + tidied = 1; + } + return tidied; +} + +static int shorten_path (char *path, char *abspath) +{ + static char dir[PATH_MAX]; + int shortened = 0; + char *p; + + /* get rid of unnecessary "../dir" sequences */ + while (abspath && strlen(abspath) > 1 && (p = strstr(path,"../"))) { + /* find innermost occurance of "../dir", and save "dir" */ + int slashes = 2; + char *a, *s, *d = dir; + while ((s = strstr(p+3, "../"))) { + ++slashes; + p = s; + } + s = p+3; + *d++ = '/'; + while (*s && *s != '/') + *d++ = *s++; + *d++ = '/'; + *d = '\0'; + if (!strcmp(dir,"//")) + break; + /* note: p still points at ../dir */ + if (*s != '/' || !*++s) + break; + a = abspath + strlen(abspath) - 1; + while (slashes-- > 0) { + if (a <= abspath) + goto ughh; + while (*--a != '/') { + if (a <= abspath) + goto ughh; + } + } + if (strncmp(dir, a, strlen(dir))) + break; + while ((*p++ = *s++)); /* delete the ../dir */ + shortened = 1; + } +ughh: + return shortened; +} + + +static void fix_symlink (char *path, dev_t my_dev) +{ + static char lpath[PATH_MAX], new[PATH_MAX], abspath[PATH_MAX]; + char *p, *np, *lp, *tail, *msg; + struct stat stbuf, lstbuf; + int c, fix_abs = 0, fix_messy = 0, fix_long = 0; + + if ((c = readlink(path, lpath, sizeof(lpath))) == -1) { + perror(path); + return; + } + lpath[c] = '\0'; /* readlink does not null terminate it */ + + /* construct the absolute address of the link */ + abspath[0] = '\0'; + if (lpath[0] != '/') { + strcat(abspath,path); + c = strlen(abspath); + if ((c > 0) && (abspath[c-1] == '/')) + abspath[c-1] = '\0'; /* cut trailing / */ + if ((p = strrchr(abspath,'/')) != NULL) + *p = '\0'; /* cut last component */ + strcat(abspath,"/"); + } + strcat(abspath,lpath); + (void) tidy_path(abspath); + + /* check for various things */ + if (stat(abspath, &stbuf) == -1) { + printf("dangling: %s -> %s\n", path, lpath); + if (delete) { + if (unlink (path)) { + perror(path); + } else + printf("deleted: %s -> %s\n", path, lpath); + } + return; + } + + if (single_fs) + lstat(abspath, &lstbuf); /* if the above didn't fail, then this shouldn't */ + + if (single_fs && lstbuf.st_dev != my_dev) { + msg = "other_fs:"; + } else if (lpath[0] == '/') { + msg = "absolute:"; + fix_abs = 1; + } else if (verbose) { + msg = "relative:"; + } else + msg = NULL; + fix_messy = tidy_path(strcpy(new,lpath)); + if (shorten) + fix_long = shorten_path(new, path); + if (!fix_abs) { + if (fix_messy) + msg = "messy: "; + else if (fix_long) + msg = "lengthy: "; + } + if (msg != NULL) + printf("%s %s -> %s\n", msg, path, lpath); + if (!(fix_links || testing) || !(fix_messy || fix_abs || fix_long)) + return; + + if (fix_abs) { + /* convert an absolute link to relative: */ + /* point tail at first part of lpath that differs from path */ + /* point p at first part of path that differs from lpath */ + (void) tidy_path(lpath); + tail = lp = lpath; + p = path; + while (*p && (*p == *lp)) { + if (*lp++ == '/') { + tail = lp; + while (*++p == '/'); + } + } + + /* now create new, with "../"s followed by tail */ + np = new; + while (*p) { + if (*p++ == '/') { + *np++ = '.'; + *np++ = '.'; + *np++ = '/'; + while (*p == '/') ++p; + } + } + strcpy (np, tail); + (void) tidy_path(new); + if (shorten) (void) shorten_path(new, path); + } + shorten_path(new,path); + if (!testing) { + if (unlink (path)) { + perror(path); + return; + } + if (symlink(new, path)) { + perror(path); + return; + } + } + printf("changed: %s -> %s\n", path, new); +} + +static void dirwalk (char *path, int pathlen, dev_t dev) +{ + char *name; + DIR *dfd; + static struct stat st; + static struct dirent *dp; + + if ((dfd = opendir(path)) == NULL) { + perror(path); + return; + } + + name = path + pathlen; + if (*(name-1) != '/') + *name++ = '/'; + + while ((dp = readdir(dfd)) != NULL ) { + strcpy(name, dp->d_name); + if (strcmp(name, ".") && strcmp(name,"..")) { + if (lstat(path, &st) == -1) { + perror(path); + } else if (st.st_dev == dev) { + if (S_ISLNK(st.st_mode)) { + fix_symlink (path, dev); + } else if (recurse && S_ISDIR(st.st_mode)) { + dirwalk(path, strlen(path), dev); + } + } + } + } + closedir(dfd); + path[pathlen] = '\0'; +} + +static void usage_error (void) +{ + fprintf(stderr, progver, progname); + fprintf(stderr, "Usage:\t%s [-cdorstv] LINK|DIR ...\n\n", progname); + fprintf(stderr, "Flags:" + "\t-c == change absolute/messy links to relative\n" + "\t-d == delete dangling links\n" + "\t-o == warn about links across file systems\n" + "\t-r == recurse into subdirs\n" + "\t-s == shorten lengthy links (displayed in output only when -c not specified)\n" + "\t-t == show what would be done by -c\n" + "\t-v == verbose (show all symlinks)\n\n"); + exit(1); +} + +int main(int argc, char **argv) +{ +#if defined (_GNU_SOURCE) && defined (__GLIBC__) + static char path[PATH_MAX+2]; + char* cwd = get_current_dir_name(); +#else + static char path[PATH_MAX+2], cwd[PATH_MAX+2]; +#endif + int dircount = 0; + char c, *p; + + if ((progname = (char *) strrchr(*argv, '/')) == NULL) + progname = *argv; + else + progname++; + +#if defined (_GNU_SOURCE) && defined (__GLIBC__) + if (NULL == cwd) { + fprintf(stderr,"get_current_dir_name() failed\n"); +#else + if (NULL == getcwd(cwd,PATH_MAX)) { + fprintf(stderr,"getcwd() failed\n"); +#endif + exit (1); + } +#if defined (_GNU_SOURCE) && defined (__GLIBC__) + cwd = realloc(cwd, strlen(cwd)+2); + if (cwd == NULL) { + fprintf(stderr, "realloc() failed\n"); + exit (1); + } +#endif + if (!*cwd || cwd[strlen(cwd)-1] != '/') + strcat(cwd,"/"); + + while (--argc) { + p = *++argv; + if (*p == '-') { + if (*++p == '\0') + usage_error(); + while ((c = *p++)) { + if (c == 'c') fix_links = 1; + else if (c == 'd') delete = 1; + else if (c == 'o') single_fs = 0; + else if (c == 'r') recurse = 1; + else if (c == 's') shorten = 1; + else if (c == 't') testing = 1; + else if (c == 'v') verbose = 1; + else usage_error(); + } + } else { + struct stat st; + if (*p == '/') + *path = '\0'; + else + strcpy(path,cwd); + tidy_path(strcat(path, p)); + if (lstat(path, &st) == -1) + perror(path); + else if (S_ISLNK(st.st_mode)) + fix_symlink(path, st.st_dev); + else + dirwalk(path, strlen(path), st.st_dev); + ++dircount; + } + } + if (dircount == 0) + usage_error(); + exit (0); +} |