Date: Sun, 23 Sep 2001 23:12:38 -0400 From: Garance A Drosihn <drosih@rpi.edu> To: freebsd-audit@freebsd.org Subject: Patch to sort rtn of 'lpc clean' Message-ID: <p05101001b7d44f1bb268@[128.113.24.47]>
next in thread | raw e-mail | index | archive | help
The 'lpc clean' command has a routine to sort filenames which it finds in a spool directory, which it calls when deciding which datafiles do not have a matching control-file. That sort routine makes a number of assumptions about the filenames it will see, assumptions which are usually safe to make. However, if one turns on 'LEAVE_TMPCF_FILES' in common_source/ctlinfo.c (because you're interested in debugging *that*), then the assumptions in this sort routine go haywire and 'lpc clean' can end up removing some valid user jobs. This is not good. So, here's a new improved 'sortq' routine for lpc. This does not include all the testing code that I had in here while testing it at RPI, but that testing showed that this version gets the same results as the old version, except for the cases where the old version was getting the wrong result. I did leave in the new debugging function of 'lpc tclean -d all', so you can see what the result of the sort is. While I'm pretty sure it works correctly, I thought I'd post it here in case there are any major style mixups, or subtle security issues (lpc is running as 'root' while this routine is being executed). The patch is also available at: http://people.freebsd.org/~gad/lpr/lpc-clean-sort.diff (in case it doesn't get formatted correctly here...) Index: lpc/cmds.c =================================================================== RCS file: /home/ncvs/src/usr.sbin/lpr/lpc/cmds.c,v retrieving revision 1.19 diff -r1.19 cmds.c 335,336c335,342 < * Comparison routine for scandir. Sort by job number and machine, then < * by `cf', `tf', or `df', then by the sequence letter A-Z, a-z. --- > * Comparison routine that clean_q() uses for scandir. > * > * The purpose of this sort is to have all `df' files end up immediately > * after the matching `cf' file. For files matching `cf', `df', or `tf', > * it sorts by job number and machine, then by `cf', `df', or `tf', then > * by the sequence letter A-Z, a-z. This routine may also see filenames > * which do not start with `cf', `df', or `tf' (such as `errs.*'), and > * those are simply sorted by the full filename. 341,342c347,349 < const struct dirent **d1, **d2; < int c1, c2; --- > const int a_lt_b = -1, a_gt_b = 1, cat_other = 10; > const char *fname_a, *fname_b, *jnum_a, *jnum_b; > int cat_a, cat_b, ch, res; 344,356c351,424 < d1 = (const struct dirent **)a; < d2 = (const struct dirent **)b; < if ((c1 = strcmp((*d1)->d_name + 3, (*d2)->d_name + 3))) < return(c1); < c1 = (*d1)->d_name[0]; < c2 = (*d2)->d_name[0]; < if (c1 == c2) < return((*d1)->d_name[2] - (*d2)->d_name[2]); < if (c1 == 'c') < return(-1); < if (c1 == 'd' || c2 == 'c') < return(1); < return(-1); --- > fname_a = (*(const struct dirent **)a)->d_name; > fname_b = (*(const struct dirent **)b)->d_name; > > /* > * First separate filenames into cagatories. Catagories are > * legitimate `cf', `df', & `tf' filenames, and "other" - in > * that order. It is critical that the mapping be exactly > * the same for 'a' vs 'b', so define a macro for the job. > * > * [aside: the standard `cf' file has the jobnumber start in > * in position 4, but some implementations have that as an > * extra letter, and start the job number in position 5.] > */ > #define MAP_TO_CAT(fname_X,jnum_X,cat_X) do { \ > cat_X = cat_other; \ > ch = *(fname_X + 2); \ > jnum_X = fname_X + 3; \ > if ((*(fname_X + 1) == 'f') && (isalpha(ch))) { \ > if (*fname_X == 'c') \ > cat_X = 1; \ > else if (*fname_X == 'd') \ > cat_X = 2; \ > else if (*fname_X == 't') \ > cat_X = 3; \ > if (cat_X != cat_other) { \ > ch = *jnum_X; \ > if (!isdigit(ch)) { \ > if (isalpha(ch)) { \ > jnum_X++; \ > ch = *jnum_X; \ > } \ > if (!isdigit(ch)) \ > cat_X = cat_other; \ > } \ > } \ > } \ > } while (0) > > MAP_TO_CAT(fname_a, jnum_a, cat_a); > MAP_TO_CAT(fname_b, jnum_b, cat_b); > > #undef MAP_TO_CAT > > /* First handle all cases with "other" files */ > if ((cat_a >= cat_other) || (cat_b >= cat_other)) { > /* for two "other" files, just compare the full name */ > if (cat_a == cat_b) > res = strcmp(fname_a, fname_b); > else if (cat_a < cat_b) > res = a_lt_b; > else > res = a_gt_b; > goto have_res; > } > > /* > * At this point, we know both files are legitimate `cf', `df', > * or `tf' files. Compare them by job-number and machine name. > */ > res = strcmp(jnum_a, jnum_b); > if (res != 0) > goto have_res; > > /* > * We have two files which belong to the same job. Sort based > * on the catagory of file. > */ > if (cat_a < cat_b) > res = a_lt_b; > else > res = a_gt_b; > > have_res: > return res; 386c454 < cln_debug = 1; --- > cln_debug++; 456a525,533 > if (cln_debug) { > printf("\t** ----- Sorted list of files being checked:\n"); > i = 0; > do { > cp = queue[i]->d_name; > printf("\t** [%3d] = %s\n", i, cp); > } while (++i < nitems); > printf("\t** ----- end of sorted list\n"); > } 549c626 < if (cln_debug) { --- > if (cln_debug > 1) { -- Garance Alistair Drosehn = gad@eclipse.acs.rpi.edu Senior Systems Programmer or gad@freebsd.org Rensselaer Polytechnic Institute or drosih@rpi.edu To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-audit" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?p05101001b7d44f1bb268>