Skip site navigation (1)Skip section navigation (2)
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>