fred@umcp-cs.UUCP (07/29/83)
This is the 4.1BSD pwd.c with a few improvements. The standard pwd didn't check the status returned by ``stat'' and ``chdir'' sys calls. This can produce some annoying results if it runs into an unreadable directory. Specifically: if you did a: chmod 0 . pwd in some directory other than the root, it would print ``/''. Totally wrong, and since there is no error message it could be misleading. When it does print out an error message it wouldn't tell you which directory the error occurred in. This version of pwd catches these sort of errors, and prints out whatever partial path it has built up, preceded by the device and inode numbers of the highest-level directory it was able to chdir to. Unfortunately this will become obsolete under 4.2BSD, but it should be useful under other Unices as well. ********************************************************************* static char *sccsid = "@(#)pwd.c 4.1 (Berkeley: UM modified) 26-Jul-1983"; /* * Print working (current) directory * * Modified to handle ``stat'' and ``chdir'' errors gracefully, * and to print out partial paths preceded by device and inode * numbers. * 22-Jul-1983: Fred Blonder <fred@umcp-cs> * % cc -s -O pwd.c -o pwd */ #include <stdio.h> #include <sys/param.h> #include <sys/stat.h> #include <sys/dir.h> char dot[] = "."; char dotdot[] = ".."; char name[BUFSIZ], *np = &name[BUFSIZ]; int file; struct stat d, dd; struct direct dir; dev_t c_dev; ino_t c_ino; main() { int rdev, rino; *--np = '\0'; if (stat("/", &d) < 0) { perror("pwd: Can't stat ``/''."); exit(1); } rdev = d.st_dev; rino = d.st_ino; for (;;) { if (stat(dot, &d) < 0) { perror("pwd: Can't stat directory."); dump_path(); } if (d.st_ino==rino && d.st_dev==rdev) prname(); if ((file = open(dotdot,0)) < 0) { fprintf(stderr,"pwd: cannot open ..\n"); dump_path(); } if (fstat(file, &dd) < 0) { perror("pwd: fstat failed"); dump_path(); } if (chdir(dotdot) < 0) { perror("pwd: Can't chdir to ``..''."); dump_path(); } if(d.st_dev == dd.st_dev) { if(d.st_ino == dd.st_ino) prname(); do if (read(file, (char *)&dir, sizeof(dir)) < sizeof(dir)) { fprintf(stderr,"read error in ..\n"); dump_path(); } while (dir.d_ino != d.st_ino); } else do { if(read(file, (char *)&dir, sizeof(dir)) < sizeof(dir)) { fprintf(stderr,"read error in ..\n"); dump_path(); } if (stat(dir.d_name, &dd) < 0) /* error */ continue; /* ignore this one */ } while(dd.st_ino != d.st_ino || dd.st_dev != d.st_dev); close(file); cat(); } } prname() { printf("%s\n", np); exit(0); } cat() { register i; c_dev = dd.st_dev; c_ino = dd.st_ino; if ((i = strlen(dir.d_name)) > DIRSIZ) i = DIRSIZ; if ((strlen(np) + i + 2) > BUFSIZ) { fprintf("pwd: Path name too long: > %d characters.\n", BUFSIZ); dump_path(); } np = &np[-i]; strncpy(np, dir.d_name, i); *--np = '/'; } dump_path() { if (np < &name[BUFSIZ-1]) fprintf(stderr, "Known path is: dev (%d/%d) #%d%s\n", (c_dev >> 8) & 0377, c_dev & 0377, c_ino, np); exit(1); }