version 1.9, 2002/05/29 18:33:39 |
version 1.10, 2002/06/17 07:06:39 |
|
|
If your master sources are located in /usr/local/src/X and you would like |
If your master sources are located in /usr/local/src/X and you would like |
your link tree to be in /usr/local/src/new-X, do the following: |
your link tree to be in /usr/local/src/new-X, do the following: |
|
|
% mkdir /usr/local/src/new-X |
% mkdir /usr/local/src/new-X |
% cd /usr/local/src/new-X |
% cd /usr/local/src/new-X |
% lndir ../X |
% lndir ../X |
*/ |
*/ |
|
|
#include <stdio.h> |
#include <stdio.h> |
|
|
struct except *exceptions = (struct except *)NULL; |
struct except *exceptions = (struct except *)NULL; |
|
|
int |
int |
main (argc, argv) |
main(int argc, char *argv[]) |
int argc; |
|
char **argv; |
|
{ |
{ |
char *fn, *tn; |
|
struct stat fs, ts; |
struct stat fs, ts; |
|
char *fn, *tn; |
|
|
while (++argv, --argc) { |
while (++argv, --argc) { |
if ((strcmp(*argv, "-silent") == 0) |
if ((strcmp(*argv, "-silent") == 0) || |
|| (strcmp(*argv, "-s") == 0)) |
(strcmp(*argv, "-s") == 0)) |
silent = 1; |
silent = 1; |
else if ((strcmp(*argv, "-ignorelinks") == 0) |
else if ((strcmp(*argv, "-ignorelinks") == 0) || |
|| (strcmp(*argv, "-i") == 0)) |
(strcmp(*argv, "-i") == 0)) |
ignore_links = 1; |
ignore_links = 1; |
else if (strcmp(*argv, "-e") == 0) { |
else if (strcmp(*argv, "-e") == 0) { |
++argv, --argc; |
++argv, --argc; |
|
|
if (argc < 2) |
if (argc < 2) |
usage(); |
usage(); |
addexcept(*argv); |
addexcept(*argv); |
} else if (strcmp(*argv, "--") == 0) { |
} else if (strcmp(*argv, "--") == 0) { |
++argv, --argc; |
++argv, --argc; |
break; |
break; |
} else |
} else |
break; |
break; |
} |
} |
|
|
|
if (argc < 1 || argc > 2) |
if (argc < 1 || argc > 2) |
usage(); |
usage(); |
|
|
|
fn = argv[0]; |
fn = argv[0]; |
if (argc == 2) |
if (argc == 2) |
tn = argv[1]; |
tn = argv[1]; |
else |
else |
tn = "."; |
tn = "."; |
|
|
/* to directory */ |
/* to directory */ |
if (stat(tn, &ts) < 0) |
if (stat(tn, &ts) < 0) |
err(1, "%s", tn); |
err(1, "%s", tn); |
if (!(S_ISDIR(ts.st_mode))) |
if (!(S_ISDIR(ts.st_mode))) |
errx(2, "%s: %s", tn, strerror(ENOTDIR)); |
errx(2, "%s: %s", tn, strerror(ENOTDIR)); |
if (chdir(tn) < 0) |
if (chdir(tn) < 0) |
err(1, "%s", tn); |
err(1, "%s", tn); |
|
|
/* from directory */ |
/* from directory */ |
if (stat(fn, &fs) < 0) |
if (stat(fn, &fs) < 0) |
err(1, "%s", fn); |
err(1, "%s", fn); |
if (!(S_ISDIR(fs.st_mode))) |
if (!(S_ISDIR(fs.st_mode))) |
err(2, "%s: %s", fn, strerror(ENOTDIR)); |
err(2, "%s: %s", fn, strerror(ENOTDIR)); |
|
|
exit(dodir (fn, &fs, &ts, 0)); |
exit(dodir(fn, &fs, &ts, 0)); |
} |
} |
|
|
int |
int |
equivalent(lname, rname) |
equivalent(char *lname, char *rname) |
char *lname; |
|
char *rname; |
|
{ |
{ |
char *s; |
char *s; |
|
|
if (!strcmp(lname, rname)) |
if (!strcmp(lname, rname)) |
return(1); |
return(1); |
for (s = lname; *s && (s = strchr(s, '/')); s++) { |
for (s = lname; *s && (s = strchr(s, '/')); s++) { |
while (s[1] == '/') |
while (s[1] == '/') |
strcpy(s+1, s+2); |
strcpy(s+1, s+2); |
} |
} |
return(!strcmp(lname, rname)); |
return(!strcmp(lname, rname)); |
} |
} |
|
|
void |
void |
addexcept(name) |
addexcept(char *name) |
char *name; |
|
{ |
{ |
struct except *new; |
struct except *new; |
|
|
new = (struct except *)malloc(sizeof(struct except)); |
new = (struct except *)malloc(sizeof(struct except)); |
if (new == (struct except *)NULL) |
if (new == (struct except *)NULL) |
err(1, "addexcept"); |
err(1, "addexcept"); |
new->name = strdup(name); |
new->name = strdup(name); |
if (new->name == (char *)NULL) |
if (new->name == (char *)NULL) |
err(1, "addexcept"); |
err(1, "addexcept"); |
|
|
new->next = exceptions; |
new->next = exceptions; |
exceptions = new; |
exceptions = new; |
} |
} |
|
|
|
|
|
|
* Recursively create symbolic links from the current directory to the "from" |
* Recursively create symbolic links from the current directory to the "from" |
* directory. Assumes that files described by fs and ts are directories. |
* directory. Assumes that files described by fs and ts are directories. |
*/ |
*/ |
int |
#if 0 |
dodir(fn, fs, ts, rel) |
|
char *fn; /* name of "from" directory, either absolute or |
char *fn; /* name of "from" directory, either absolute or |
relative to cwd */ |
relative to cwd */ |
struct stat *fs, *ts; /* stats for the "from" directory and cwd */ |
struct stat *fs, *ts; /* stats for the "from" directory and cwd */ |
int rel; /* if true, prepend "../" to fn before using */ |
int rel; /* if true, prepend "../" to fn before using */ |
|
#endif |
|
int |
|
dodir(char *fn, struct stat *fs, struct stat *ts, int rel) |
{ |
{ |
DIR *df; |
char buf[MAXPATHLEN + 1], symbuf[MAXPATHLEN + 1], basesym[MAXPATHLEN + 1]; |
struct dirent *dp; |
int n_dirs, symlen, basesymlen = -1; |
char buf[MAXPATHLEN + 1], *p; |
struct stat sb, sc; |
char symbuf[MAXPATHLEN + 1]; |
struct except *cur; |
char basesym[MAXPATHLEN + 1]; |
struct dirent *dp; |
struct stat sb, sc; |
char *ocurdir, *p; |
int n_dirs; |
DIR *df; |
int symlen; |
|
int basesymlen = -1; |
|
char *ocurdir; |
|
struct except *cur; |
|
|
|
if ((fs->st_dev == ts->st_dev) && (fs->st_ino == ts->st_ino)) { |
if (fs->st_dev == ts->st_dev && fs->st_ino == ts->st_ino) { |
warn("%s: From and to directories are identical!", fn); |
warn("%s: From and to directories are identical!", fn); |
return(1); |
return(1); |
} |
} |
|
|
if (rel) |
if (rel) |
strcpy(buf, "../"); |
strlcpy(buf, "../", sizeof buf); |
else |
else |
buf[0] = '\0'; |
buf[0] = '\0'; |
strlcat(buf, fn, sizeof buf); |
strlcat(buf, fn, sizeof buf); |
|
|
if (!(df = opendir(buf))) { |
if (!(df = opendir(buf))) { |
warn("%s: Cannot opendir", buf); |
warn("%s: Cannot opendir", buf); |
return(1); |
return(1); |
} |
|
|
|
p = buf + strlen(buf); |
|
*p++ = '/'; |
|
n_dirs = fs->st_nlink; |
|
while ((dp = readdir(df))) { |
|
if (dp->d_name[strlen(dp->d_name) - 1] == '~') |
|
continue; |
|
for (cur = exceptions; cur != (struct except *)NULL; |
|
cur = cur->next) { |
|
if (!strcmp (dp->d_name, cur->name)) |
|
goto next; /* can't continue */ |
|
} |
} |
strcpy(p, dp->d_name); |
|
|
|
if (n_dirs > 0) { |
p = buf + strlen(buf); |
if (stat(buf, &sb) < 0) { |
*p++ = '/'; |
warn("%s", buf); |
n_dirs = fs->st_nlink; |
continue; |
while ((dp = readdir(df))) { |
} |
if (dp->d_name[strlen(dp->d_name) - 1] == '~') |
|
|
if (S_ISDIR(sb.st_mode)) { |
|
/* directory */ |
|
n_dirs--; |
|
if (dp->d_name[0] == '.' && |
|
(dp->d_name[1] == '\0' || (dp->d_name[1] == '.' && |
|
dp->d_name[2] == '\0'))) |
|
continue; |
|
if (!strcmp(dp->d_name, "RCS")) |
|
continue; |
|
if (!strcmp(dp->d_name, "SCCS")) |
|
continue; |
|
if (!strcmp(dp->d_name, "CVS")) |
|
continue; |
|
if (!strcmp(dp->d_name, "CVS.adm")) |
|
continue; |
|
ocurdir = rcurdir; |
|
rcurdir = buf; |
|
curdir = silent ? buf : NULL; |
|
if (!silent) |
|
printf("%s:\n", buf); |
|
if ((stat(dp->d_name, &sc) < 0) && (errno == ENOENT)) { |
|
if (mkdir(dp->d_name, 0777) < 0 || |
|
stat(dp->d_name, &sc) < 0) { |
|
warn("%s", dp->d_name); |
|
curdir = rcurdir = ocurdir; |
|
continue; |
continue; |
} |
for (cur = exceptions; cur != (struct except *)NULL; |
|
cur = cur->next) { |
|
if (!strcmp (dp->d_name, cur->name)) |
|
goto next; /* can't continue */ |
} |
} |
if (readlink(dp->d_name, symbuf, sizeof(symbuf) - 1) >= 0) { |
strcpy(p, dp->d_name); |
(void)fprintf(stderr, "%s: is a link instead of a directory\n", |
|
dp->d_name); |
if (n_dirs > 0) { |
curdir = rcurdir = ocurdir; |
if (stat(buf, &sb) < 0) { |
continue; |
warn("%s", buf); |
|
continue; |
|
} |
|
|
|
if (S_ISDIR(sb.st_mode)) { |
|
/* directory */ |
|
n_dirs--; |
|
if (dp->d_name[0] == '.' && |
|
(dp->d_name[1] == '\0' || (dp->d_name[1] == '.' && |
|
dp->d_name[2] == '\0'))) |
|
continue; |
|
if (!strcmp(dp->d_name, "RCS")) |
|
continue; |
|
if (!strcmp(dp->d_name, "SCCS")) |
|
continue; |
|
if (!strcmp(dp->d_name, "CVS")) |
|
continue; |
|
if (!strcmp(dp->d_name, "CVS.adm")) |
|
continue; |
|
ocurdir = rcurdir; |
|
rcurdir = buf; |
|
curdir = silent ? buf : NULL; |
|
if (!silent) |
|
printf("%s:\n", buf); |
|
if (stat(dp->d_name, &sc) < 0 && errno == ENOENT) { |
|
if (mkdir(dp->d_name, 0777) < 0 || |
|
stat(dp->d_name, &sc) < 0) { |
|
warn("%s", dp->d_name); |
|
curdir = rcurdir = ocurdir; |
|
continue; |
|
} |
|
} |
|
if (readlink(dp->d_name, symbuf, |
|
sizeof(symbuf) - 1) >= 0) { |
|
fprintf(stderr, |
|
"%s: is a link instead of a directory\n", |
|
dp->d_name); |
|
curdir = rcurdir = ocurdir; |
|
continue; |
|
} |
|
if (chdir(dp->d_name) < 0) { |
|
warn("%s", dp->d_name); |
|
curdir = rcurdir = ocurdir; |
|
continue; |
|
} |
|
dodir(buf, &sb, &sc, (buf[0] != '/')); |
|
if (chdir("..") < 0) |
|
err(1, ".."); |
|
curdir = rcurdir = ocurdir; |
|
continue; |
|
} |
} |
} |
if (chdir(dp->d_name) < 0) { |
|
warn("%s", dp->d_name); |
|
curdir = rcurdir = ocurdir; |
|
continue; |
|
} |
|
dodir(buf, &sb, &sc, (buf[0] != '/')); |
|
if (chdir ("..") < 0) |
|
err (1, ".."); |
|
curdir = rcurdir = ocurdir; |
|
continue; |
|
} |
|
} |
|
|
|
/* non-directory */ |
/* non-directory */ |
symlen = readlink(dp->d_name, symbuf, sizeof(symbuf) - 1); |
symlen = readlink(dp->d_name, symbuf, sizeof(symbuf) - 1); |
if (symlen >= 0) |
if (symlen >= 0) |
symbuf[symlen] = '\0'; |
symbuf[symlen] = '\0'; |
|
|
/* |
/* |
* The option to ignore links exists mostly because |
* The option to ignore links exists mostly because |
* checking for them slows us down by 10-20%. |
* checking for them slows us down by 10-20%. |
* But it is off by default because this really is a useful check. |
* But it is off by default because this really is a useful check. |
*/ |
*/ |
if (!ignore_links) { |
if (!ignore_links) { |
/* see if the file in the base tree was a symlink */ |
/* see if the file in the base tree was a symlink */ |
basesymlen = readlink(buf, basesym, sizeof(basesym) - 1); |
basesymlen = readlink(buf, basesym, sizeof(basesym) - 1); |
if (basesymlen >= 0) |
if (basesymlen >= 0) |
basesym[basesymlen] = '\0'; |
basesym[basesymlen] = '\0'; |
} |
} |
|
|
if (symlen >= 0) { |
if (symlen >= 0) { |
/* Link exists in new tree. Print message if it doesn't match. */ |
/* |
if (!equivalent(basesymlen>=0 ? basesym : buf, symbuf)) |
* Link exists in new tree. Print message if |
(void)fprintf(stderr,"%s: %s\n", dp->d_name, symbuf); |
* it doesn't match. |
} else { |
*/ |
if (symlink(basesymlen>=0 ? basesym : buf, dp->d_name) < 0) |
if (!equivalent(basesymlen>=0 ? basesym : buf, symbuf)) |
warn("%s", dp->d_name); |
fprintf(stderr,"%s: %s\n", dp->d_name, symbuf); |
} |
} else { |
|
if (symlink(basesymlen>=0 ? basesym : buf, dp->d_name) < 0) |
|
warn("%s", dp->d_name); |
|
} |
next: |
next: |
} |
} |
|
|
closedir(df); |
closedir(df); |
return(0); |
return(0); |
} |
} |
|
|
void |
void |
usage() |
usage(void) |
{ |
{ |
(void)fprintf(stderr, "usage: %s [-e except] [-si] fromdir todir\n", |
(void)fprintf(stderr, "usage: %s [-e except] [-si] fromdir todir\n", |
__progname); |
__progname); |
exit(1); |
exit(1); |
} |
} |