From: ianmdlvl Date: Sat, 22 Jul 2006 14:56:42 +0000 (+0000) Subject: @@ -1,3 +1,11 @@ X-Git-Tag: debian_version_4_1_1~5 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=chiark-utils.git;a=commitdiff_plain;h=2ecf9414320f30c767b9ba1c9c343529a0cb9504 @@ -1,3 +1,11 @@ +chiark-utils (4.1.1) unstable; urgency=low + + * summer sorts the output and identifies hardlink + targets instead of printing link count. + + + -- + chiark-utils (4.1.0) unstable; urgency=low New facilities: --- diff --git a/cprogs/summer.c b/cprogs/summer.c index 773719f..887409d 100644 --- a/cprogs/summer.c +++ b/cprogs/summer.c @@ -7,7 +7,8 @@ #define _GNU_SOURCE -#include +#include +#include #include #include #include @@ -26,10 +27,24 @@ #define CSUMXL 32 static int quiet=0, hidectime=0, hideatime=0; -static int hidedirsizelinkcount=0, hidelinkmtime=0; +static int hidedirsize=0, hidelinkmtime=0; static int filenamefieldsep=' '; static FILE *errfile; +static void malloc_fail(void) { perror("summer: alloc failed"); exit(12); } + +static void *mmalloc(size_t sz) { + void *r; + r= malloc(sz); if (!r) malloc_fail(); + return r; +} + +static void *mrealloc(void *p, size_t sz) { + void *r; + r= realloc(p, sz); if (!r && sz) malloc_fail(); + return r; +} + static void fn_escaped(FILE *f, const char *fn) { int c; while ((c= *fn++)) { @@ -121,38 +136,67 @@ static void csum_str(const char *s) { printf("%-*s", CSUMXL, s); } -struct FTW; +static void linktargpath(const char *linktarg) { + printf(" -> "); + fn_escaped(stdout, linktarg); +} + +struct hardlink { + dev_t dev; + ino_t ino; + char path[1]; +}; +static void *hardlinks; + +static void pu10(void) { printf(" %10s", "?"); } + +static int hardlink_compar(const void *av, const void *bv) { + const struct hardlink *a=av, *b=bv; + if (a->ino != b->ino) return b->ino - a->ino; + return b->dev - a->dev; +} -static int item(const char *path, const struct stat *stab, - int flag, struct FTW *ftws) { +static void recurse(const char *path); + +static void node(const char *path) { char linktarg[MAXFN+1]; + struct hardlink *foundhl; + const struct stat *stab; + struct stat stabuf; + int r; - switch (flag) { - case FTW_D: - case FTW_F: - case FTW_SL: - if (S_ISREG(stab->st_mode)) csum_file(path); - else if (S_ISDIR(stab->st_mode)) csum_str("dir"); - else if (S_ISCHR(stab->st_mode)) csum_dev('c',stab); - else if (S_ISBLK(stab->st_mode)) csum_dev('b',stab); - else if (S_ISFIFO(stab->st_mode)) csum_str("pipe"); - else if (S_ISLNK(stab->st_mode)) csum_str("link"); - else if (S_ISSOCK(stab->st_mode)) csum_str("sock"); - else problem(path,CSUMXL,"badobj: 0x%lx", (unsigned long)stab->st_mode); - break; - - case FTW_NS: - case FTW_DNR: - problem_e(path,CSUMXL,"inaccessible"); - break; - - default: - problem(path,CSUMXL,"ftw flag 0x%x: %s",flag); + r= lstat(path, &stabuf); + stab= r ? 0 : &stabuf; + + foundhl= 0; + if (stab && stab->st_nlink>1) { + struct hardlink *newhl, **foundhl_node; + newhl= mmalloc(sizeof(*newhl) + strlen(path)); + newhl->dev= stab->st_dev; + newhl->ino= stab->st_ino; + foundhl_node= tsearch(newhl, &hardlinks, hardlink_compar); + if (!foundhl_node) malloc_fail(); + foundhl= *foundhl_node; + if (foundhl!=newhl) { + free(newhl); /* hardlink to an earlier object */ + } else { + foundhl= 0; /* new object with link count>1 */ + strcpy(newhl->path, path); + } } - if (S_ISLNK(stab->st_mode)) { - int r; - + if (!stab) problem_e(path,CSUMXL,"inaccessible"); + else if (foundhl) csum_str("hardlink"); + else if (S_ISREG(stab->st_mode)) csum_file(path); + else if (S_ISDIR(stab->st_mode)) csum_str("dir"); + else if (S_ISCHR(stab->st_mode)) csum_dev('c',stab); + else if (S_ISBLK(stab->st_mode)) csum_dev('b',stab); + else if (S_ISFIFO(stab->st_mode)) csum_str("pipe"); + else if (S_ISLNK(stab->st_mode)) csum_str("symlink"); + else if (S_ISSOCK(stab->st_mode)) csum_str("sock"); + else problem(path,CSUMXL,"badobj: 0x%lx", (unsigned long)stab->st_mode); + + if (stab && S_ISLNK(stab->st_mode)) { r= readlink(path, linktarg, sizeof(linktarg)-1); if (r==sizeof(linktarg)) { problem(path,-1,"readlink too big"); r=-1; } else if (r<0) { problem_e(path,-1,"readlink"); } @@ -162,51 +206,118 @@ static int item(const char *path, const struct stat *stab, else linktarg[r]= 0; } - if (S_ISDIR(stab->st_mode) && hidedirsizelinkcount) - printf(" %10s %4s","dir","dir"); - else - printf(" %10lu %4d", - (unsigned long)stab->st_size, - (int)stab->st_nlink); - - printf(" %4o %10ld %10ld", - (unsigned)stab->st_mode & 07777U, - (unsigned long)stab->st_uid, - (unsigned long)stab->st_gid); + if (stab) { + if (S_ISDIR(stab->st_mode) && hidedirsize) + printf(" %10s","dir"); + else + printf(" %10lu", + (unsigned long)stab->st_size); + + printf(" %4o %10ld %10ld", + (unsigned)stab->st_mode & 07777U, + (unsigned long)stab->st_uid, + (unsigned long)stab->st_gid); + } else { + printf(" %10s %4s %10s %10s", "?","?","?","?"); + } - if (!hideatime) - printf(" %10lu", - (unsigned long)stab->st_atime); + if (!hideatime) { + if (stab) + printf(" %10lu", + (unsigned long)stab->st_atime); + else + pu10(); + } - if (S_ISLNK(stab->st_mode) && hidelinkmtime) - printf(" %10s","link"); + if (stab) + if (S_ISLNK(stab->st_mode) && hidelinkmtime) + printf(" %10s","link"); + else + printf(" %10lu", + (unsigned long)stab->st_mtime); else - printf(" %10lu", - (unsigned long)stab->st_mtime); + pu10(); + + if (!hidectime) { + if (stab) + printf(" %10lu", + (unsigned long)stab->st_ctime); + else + pu10(); + } - if (!hidectime) - printf(" %10lu", - (unsigned long)stab->st_ctime); putchar(filenamefieldsep); fn_escaped(stdout, path); - if (S_ISLNK(stab->st_mode)) { - printf(" -> "); - fn_escaped(stdout, linktarg); - } + if (foundhl) linktargpath(foundhl->path); + if (stab && S_ISLNK(stab->st_mode)) linktargpath(linktarg); + putchar('\n'); if (ferror(stdout)) { perror("summer: stdout"); exit(12); } - return 0; + + if (stab && S_ISDIR(stab->st_mode)) + recurse(path); } static void process(const char *startpoint) { - int r; if (!quiet) fprintf(stderr,"summer: processing: %s\n",startpoint); - r= nftw(startpoint, item, MAXDEPTH, FTW_MOUNT|FTW_PHYS); - if (r) { fprintf(stderr, "summer: nftw failed: %s: %s\n", - strerror(errno), startpoint); exit(4); } + node(startpoint); + tdestroy(hardlinks,free); + hardlinks= 0; +} + +static int recurse_maxlen; + +static int recurse_filter(const struct dirent *de) { + int l; + if (de->d_name[0]=='.' && + (de->d_name[1]==0 || + (de->d_name[1]=='.' && + de->d_name[2]==0))) + return 0; + l= strlen(de->d_name); + if (l > recurse_maxlen) recurse_maxlen= l; + return 1; +} + +static int recurse_compar(const void *av, const void *bv) { + const struct dirent *const *a=av, *const *b=bv; + return strcmp((*a)->d_name, (*b)->d_name); +} + +static void recurse(const char *path) { + static char *buf; + static int buf_allocd; + + struct dirent **namelist, *const *de; + char *subpathp; + int nentries, pathl, esave, buf_want, i; + + pathl= strlen(path); + recurse_maxlen= 2; + nentries= scandir(path, &namelist, recurse_filter, recurse_compar); + esave= errno; + buf_want= pathl+1+recurse_maxlen+1; + if (buf_want > buf_allocd) { + buf= mrealloc(buf, buf_want); + buf_allocd= buf_want; + } + strcpy(buf,path); + buf[pathl]= '/'; + subpathp= buf+pathl+1; + if (nentries < 0) { + strcpy(subpathp,"\\?"); errno= esave; + problem_e(buf,-1,"scandir failed"); + return; + } + for (i=0, de=namelist; id_name); + node(buf); + free(*de); + } + free(namelist); } static void from_stdin(void) { @@ -249,7 +360,7 @@ int main(int argc, const char *const *argv) { filenamefieldsep= '\t'; break; case 'D': - hidedirsizelinkcount= 1; + hidedirsize= 1; break; case 'b': hidelinkmtime= 1; diff --git a/debian/changelog b/debian/changelog index 8142387..82615ce 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +chiark-utils (4.1.1) unstable; urgency=low + + * summer sorts the output and identifies hardlink + targets instead of printing link count. + + + -- + chiark-utils (4.1.0) unstable; urgency=low New facilities: