xref: /onnv-gate/usr/src/lib/libcmd/common/cksum.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1992-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                                                                      *
204887Schin ***********************************************************************/
214887Schin #pragma prototyped
224887Schin /*
234887Schin  * Glenn Fowler
244887Schin  * AT&T Research
254887Schin  *
264887Schin  * sum -- list file checksum and size
274887Schin  */
284887Schin 
294887Schin static const char usage[] =
30*12068SRoger.Faulkner@Oracle.COM "[-?\n@(#)$Id: sum (AT&T Research) 2009-11-28 $\n]"
314887Schin USAGE_LICENSE
324887Schin "[+NAME?cksum,md5sum,sum - print file checksum and block count]"
334887Schin "[+DESCRIPTION?\bsum\b lists the checksum, and for most methods the block"
344887Schin "	count, for each file argument. The standard input is read if there are"
354887Schin "	no \afile\a arguments. \bgetconf UNIVERSE\b determines the default"
364887Schin "	\bsum\b method: \batt\b for the \batt\b universe, \bbsd\b otherwise."
374887Schin "	The default for the other commands is the command name itself. The"
384887Schin "	\batt\b method is a true sum, all others are order dependent.]"
394887Schin "[+?Method names consist of a leading identifier and 0 or more options"
404887Schin "	separated by -.]"
414887Schin "[+?\bgetconf PATH_RESOLVE\b determines how symbolic links are handled. This"
424887Schin "	can be explicitly overridden by the \b--logical\b, \b--metaphysical\b,"
434887Schin "	and \b--physical\b options below. \bPATH_RESOLVE\b can be one of:]{"
444887Schin "		[+logical?Follow all symbolic links.]"
454887Schin "		[+metaphysical?Follow command argument symbolic links,"
464887Schin "			otherwise don't follow.]"
474887Schin "		[+physical?Don't follow symbolic links.]"
484887Schin "}"
494887Schin 
504887Schin "[a:all?List the checksum for all files. Use with \b--total\b to list both"
514887Schin "	individual and total checksums and block counts.]"
524887Schin "[b:binary?Read files in binary mode. This is the default.]"
538462SApril.Chin@Sun.COM "[B:scale?Block count scale (bytes per block) override for methods that"
548462SApril.Chin@Sun.COM "	include size in the output.  The default is method specific.]#[scale]"
554887Schin "[c:check?Each \afile\a is interpreted as the output from a previous \bsum\b."
564887Schin "	If \b--header\b or \b--permissions\b was specified in the previous"
574887Schin "	\bsum\b then the checksum method is automatically determined,"
584887Schin "	otherwise \b--method\b must be specified. The listed checksum is"
594887Schin "	compared with the current value and a warning is issued for each file"
604887Schin "	that does not match. If \afile\a was generated by \b--permissions\b"
614887Schin "	then the file mode, user and group are also checked. Empty lines,"
624887Schin "	lines starting with \b#<space>\b, or the line \b#\b are ignored. Lines"
634887Schin "	containing no blanks are interpreted as [no]]\aname\a[=\avalue\a]]"
644887Schin "	options:]{"
654887Schin "		[+method=name?Checksum method to apply to subsequent lines.]"
664887Schin "		[+permissions?Subsequent lines were generated with"
674887Schin "			\b--permissions\b.]"
684887Schin "}"
694887Schin "[h:header?Print the checksum method as the first output line. Used with"
704887Schin "	\b--check\b and \b--permissions\b.]"
714887Schin "[l:list?Each \afile\a is interpreted as a list of files, one per line,"
724887Schin "	that is checksummed.]"
734887Schin "[p:permissions?If \b--check\b is not specified then list the file"
744887Schin "	mode, user and group between the checksum and path. User and group"
754887Schin "	matching the caller are output as \b-\b. If \b--check\b is"
764887Schin "	specified then the mode, user and group for each path in \afile\a"
774887Schin "	are updated if necessary to match those in \afile\a. A warning is"
784887Schin "	printed on the standard error for each changed file.]"
798462SApril.Chin@Sun.COM "[R:recursive?Recursively checksum the contents of directories.]"
808462SApril.Chin@Sun.COM "[S:silent|status?No output for \b--check\b; 0 exit status means all sums"
814887Schin "	matched, non-0 means at least one sum failed to match. Ignored for"
824887Schin "	\b--permissions\b.]"
834887Schin "[t:total?List only the total checksum and block count of all files."
844887Schin "	\b--all\b \b--total\b lists each checksum and the total. The"
854887Schin "	total checksum and block count may be different from the checksum"
864887Schin "	and block count of the catenation of all files due to partial"
874887Schin "	blocks that may occur when the files are treated separately.]"
884887Schin "[T:text?Read files in text mode (i.e., treat \b\\r\\n\b as \b\\n\b).]"
894887Schin "[w!:warn?Warn about invalid \b--check\b lines.]"
904887Schin "[x:method|algorithm?Specifies the checksum \amethod\a to"
914887Schin "	apply. Parenthesized method options are readonly implementation"
924887Schin "	details.]:[method]{\fmethods\f}"
934887Schin "[L:logical|follow?Follow symbolic links when traversing directories. The"
944887Schin "	default is determined by \bgetconf PATH_RESOLVE\b.]"
954887Schin "[H:metaphysical?Follow command argument symbolic links, otherwise don't"
964887Schin "	follow symbolic links when traversing directories. The default is"
974887Schin "	determined by \bgetconf PATH_RESOLVE\b.]"
984887Schin "[P:physical?Don't follow symbolic links when traversing directories. The"
994887Schin "	default is determined by \bgetconf PATH_RESOLVE\b.]"
1008462SApril.Chin@Sun.COM "[r:bsd?Equivalent to \b--method=bsd --scale=512\b for compatibility with"
1018462SApril.Chin@Sun.COM "	other \bsum\b(1) implementations.]"
1028462SApril.Chin@Sun.COM "[s:sysv?Equivalent to \b--method=sys5\b for compatibility with other"
1038462SApril.Chin@Sun.COM "	\bsum\b(1) implementations.]"
1044887Schin 
1054887Schin "\n"
1064887Schin "\n[ file ... ]\n"
1074887Schin "\n"
1084887Schin 
1094887Schin "[+SEE ALSO?\bgetconf\b(1), \btw\b(1), \buuencode\b(1)]"
1104887Schin ;
1114887Schin 
1124887Schin #include <cmd.h>
1134887Schin #include <sum.h>
1144887Schin #include <ls.h>
1158462SApril.Chin@Sun.COM #include <modex.h>
116*12068SRoger.Faulkner@Oracle.COM #include <fts_fix.h>
1174887Schin #include <error.h>
1184887Schin 
1194887Schin typedef struct State_s			/* program state		*/
1204887Schin {
1214887Schin 	int		all;		/* list all items		*/
1224887Schin 	Sfio_t*		check;		/* check previous output	*/
1238462SApril.Chin@Sun.COM 	int		flags;		/* sumprint() SUM_* flags	*/
1244887Schin 	gid_t		gid;		/* caller gid			*/
1254887Schin 	int		header;		/* list method on output	*/
1264887Schin 	int		list;		/* list file name too		*/
1274887Schin 	Sum_t*		oldsum;		/* previous sum method		*/
1284887Schin 	int		permissions;	/* include mode,uer,group	*/
1294887Schin 	int		haveperm;	/* permissions in the input	*/
1304887Schin 	int		recursive;	/* recursively descend dirs	*/
1318462SApril.Chin@Sun.COM 	size_t		scale;		/* scale override		*/
1324887Schin 	unsigned long	size;		/* combined size of all files	*/
1334887Schin 	int		silent;		/* silent check, 0 exit if ok	*/
1344887Schin 	int		(*sort)(FTSENT* const*, FTSENT* const*);
1354887Schin 	Sum_t*		sum;		/* sum method			*/
1364887Schin 	int		text;		/* \r\n == \n			*/
1374887Schin 	int		total;		/* list totals only		*/
1384887Schin 	uid_t		uid;		/* caller uid			*/
1394887Schin 	int		warn;		/* invalid check line warnings	*/
1404887Schin } State_t;
1414887Schin 
1424887Schin static void	verify(State_t*, char*, char*, Sfio_t*);
1434887Schin 
1444887Schin /*
1454887Schin  * open path for read mode
1464887Schin  */
1474887Schin 
1484887Schin static Sfio_t*
openfile(const char * path,const char * mode)1494887Schin openfile(const char* path, const char* mode)
1504887Schin {
1514887Schin 	Sfio_t*		sp;
1524887Schin 
1534887Schin 	if (!path || streq(path, "-") || streq(path, "/dev/stdin") || streq(path, "/dev/fd/0"))
1544887Schin 	{
1554887Schin 		sp = sfstdin;
1564887Schin 		sfopen(sp, NiL, mode);
1574887Schin 	}
1584887Schin 	else if (!(sp = sfopen(NiL, path, mode)))
1594887Schin 		error(ERROR_SYSTEM|2, "%s: cannot read", path);
1604887Schin 	return sp;
1614887Schin }
1624887Schin 
1634887Schin /*
1644887Schin  * close an openfile() stream
1654887Schin  */
1664887Schin 
1674887Schin static int
closefile(Sfio_t * sp)1684887Schin closefile(Sfio_t* sp)
1694887Schin {
1704887Schin 	return sp == sfstdin ? 0 : sfclose(sp);
1714887Schin }
1724887Schin 
1734887Schin /*
1744887Schin  * compute and print sum on an open file
1754887Schin  */
1764887Schin 
1774887Schin static void
pr(State_t * state,Sfio_t * op,Sfio_t * ip,char * file,int perm,struct stat * st,Sfio_t * check)1784887Schin pr(State_t* state, Sfio_t* op, Sfio_t* ip, char* file, int perm, struct stat* st, Sfio_t* check)
1794887Schin {
1804887Schin 	register char*	p;
1814887Schin 	register char*	r;
1824887Schin 	register char*	e;
1834887Schin 	register int	peek;
1844887Schin 	struct stat	ss;
1854887Schin 
1864887Schin 	if (check)
1874887Schin 	{
1884887Schin 		state->oldsum = state->sum;
1894887Schin 		while (p = sfgetr(ip, '\n', 1))
1904887Schin 			verify(state, p, file, check);
1914887Schin 		state->sum = state->oldsum;
1924887Schin 		if (state->warn && !sfeof(ip))
1934887Schin 			error(2, "%s: last line incomplete", file);
1944887Schin 		return;
1954887Schin 	}
1964887Schin 	suminit(state->sum);
1974887Schin 	if (state->text)
1984887Schin 	{
1994887Schin 		peek = 0;
2004887Schin 		while (p = sfreserve(ip, SF_UNBOUND, 0))
2014887Schin 		{
2024887Schin 			e = p + sfvalue(ip);
2034887Schin 			if (peek)
2044887Schin 			{
2054887Schin 				peek = 0;
2064887Schin 				if (*p != '\n')
2074887Schin 					sumblock(state->sum, "\r", 1);
2084887Schin 			}
2094887Schin 			while (r = memchr(p, '\r', e - p))
2104887Schin 			{
2114887Schin 				if (++r >= e)
2124887Schin 				{
2134887Schin 					e--;
2144887Schin 					peek = 1;
2154887Schin 					break;
2164887Schin 				}
2174887Schin 				sumblock(state->sum, p, r - p - (*r == '\n'));
2184887Schin 				p = r;
2194887Schin 			}
2204887Schin 			sumblock(state->sum, p, e - p);
2214887Schin 		}
2224887Schin 		if (peek)
2234887Schin 			sumblock(state->sum, "\r", 1);
2244887Schin 	}
2254887Schin 	else
2264887Schin 		while (p = sfreserve(ip, SF_UNBOUND, 0))
2274887Schin 			sumblock(state->sum, p, sfvalue(ip));
2284887Schin 	if (sfvalue(ip))
2294887Schin 		error(ERROR_SYSTEM|2, "%s: read error", file);
2304887Schin 	sumdone(state->sum);
2314887Schin 	if (!state->total || state->all)
2324887Schin 	{
2338462SApril.Chin@Sun.COM 		sumprint(state->sum, op, state->flags|SUM_SCALE, state->scale);
2344887Schin 		if (perm >= 0)
2354887Schin 		{
2364887Schin 			if (perm)
2374887Schin 			{
2384887Schin 				if (!st && fstat(sffileno(ip), st = &ss))
2394887Schin 					error(ERROR_SYSTEM|2, "%s: cannot stat", file);
2404887Schin 				else
2414887Schin 					sfprintf(sfstdout, " %04o %s %s",
2424887Schin 						modex(st->st_mode & S_IPERM),
2434887Schin 						(st->st_uid != state->uid && ((st->st_mode & S_ISUID) || (st->st_mode & S_IRUSR) && !(st->st_mode & (S_IRGRP|S_IROTH)) || (st->st_mode & S_IXUSR) && !(st->st_mode & (S_IXGRP|S_IXOTH)))) ? fmtuid(st->st_uid) : "-",
2444887Schin 						(st->st_gid != state->gid && ((st->st_mode & S_ISGID) || (st->st_mode & S_IRGRP) && !(st->st_mode & S_IROTH) || (st->st_mode & S_IXGRP) && !(st->st_mode & S_IXOTH))) ? fmtgid(st->st_gid) : "-");
2454887Schin 			}
2464887Schin 			if (ip != sfstdin)
2474887Schin 				sfprintf(op, " %s", file);
2484887Schin 			sfputc(op, '\n');
2494887Schin 		}
2504887Schin 	}
2514887Schin }
2524887Schin 
2534887Schin /*
2544887Schin  * verify previous sum output
2554887Schin  */
2564887Schin 
2574887Schin static void
verify(State_t * state,register char * s,char * check,Sfio_t * rp)2584887Schin verify(State_t* state, register char* s, char* check, Sfio_t* rp)
2594887Schin {
2604887Schin 	register char*	t;
2614887Schin 	char*		e;
2624887Schin 	char*		file;
2634887Schin 	int		attr;
2644887Schin 	int		mode;
2654887Schin 	int		uid;
2664887Schin 	int		gid;
2674887Schin 	Sfio_t*		sp;
2684887Schin 	struct stat	st;
2694887Schin 
2704887Schin 	if (!*s || *s == '#' && (!*(s + 1) || *(s + 1) == ' ' || *(s + 1) == '\t'))
2714887Schin 		return;
2724887Schin 	if (t = strchr(s, ' '))
2734887Schin 	{
2744887Schin 		if ((t - s) > 10 || !(file = strchr(t + 1, ' ')))
2754887Schin 			file = t;
2764887Schin 		*file++ = 0;
2774887Schin 		attr = 0;
2784887Schin 		if ((mode = strtol(file, &e, 8)) && *e == ' ' && (e - file) == 4)
2794887Schin 		{
2804887Schin 			mode = modei(mode);
2814887Schin 			if (t = strchr(++e, ' '))
2824887Schin 			{
2834887Schin 				if (*e == '-' && (t - e) == 1)
2844887Schin 					uid = -1;
2854887Schin 				else
2864887Schin 				{
2874887Schin 					*t = 0;
2884887Schin 					uid = struid(e);
2894887Schin 					*t = ' ';
2904887Schin 				}
2914887Schin 				if (e = strchr(++t, ' '))
2924887Schin 				{
2934887Schin 					if (*t == '-' && (e - t) == 1)
2944887Schin 						gid = -1;
2954887Schin 					else
2964887Schin 					{
2974887Schin 						*e = 0;
2984887Schin 						gid = struid(t);
2994887Schin 						*e = ' ';
3004887Schin 					}
3014887Schin 					file = e + 1;
3024887Schin 					attr = 1;
3034887Schin 				}
3044887Schin 			}
3054887Schin 		}
3064887Schin 		if (sp = openfile(file, "rb"))
3074887Schin 		{
3084887Schin 			pr(state, rp, sp, file, -1, NiL, NiL);
3094887Schin 			if (!(t = sfstruse(rp)))
3104887Schin 				error(ERROR_SYSTEM|3, "out of space");
3114887Schin 			if (!streq(s, t))
3124887Schin 			{
3134887Schin 				if (state->silent)
3144887Schin 					error_info.errors++;
3154887Schin 				else
3164887Schin 					error(2, "%s: checksum changed", file);
3174887Schin 			}
3184887Schin 			else if (attr)
3194887Schin 			{
3204887Schin 				if (fstat(sffileno(sp), &st))
3214887Schin 				{
3224887Schin 					if (state->silent)
3234887Schin 						error_info.errors++;
3244887Schin 					else
3254887Schin 						error(ERROR_SYSTEM|2, "%s: cannot stat", file);
3264887Schin 				}
3274887Schin 				else
3284887Schin 				{
3294887Schin 					if (uid < 0 || uid == st.st_uid)
3304887Schin 						uid = -1;
3314887Schin 					else if (!state->permissions)
3324887Schin 					{
3334887Schin 						if (state->silent)
3344887Schin 							error_info.errors++;
3354887Schin 						else
3364887Schin 							error(2, "%s: uid should be %s", file, fmtuid(uid));
3374887Schin 					}
3384887Schin 					if (gid < 0 || gid == st.st_gid)
3394887Schin 						gid = -1;
3404887Schin 					else if (!state->permissions)
3414887Schin 					{
3424887Schin 						if (state->silent)
3434887Schin 							error_info.errors++;
3444887Schin 						else
3454887Schin 							error(2, "%s: gid should be %s", file, fmtgid(gid));
3464887Schin 					}
3474887Schin 					if (state->permissions && (uid >= 0 || gid >= 0))
3484887Schin 					{
3494887Schin 						if (chown(file, uid, gid) < 0)
3504887Schin 						{
3514887Schin 							if (uid < 0)
3524887Schin 								error(ERROR_SYSTEM|2, "%s: cannot change group to %s", file, fmtgid(gid));
3534887Schin 							else if (gid < 0)
3544887Schin 								error(ERROR_SYSTEM|2, "%s: cannot change user to %s", file, fmtuid(uid));
3554887Schin 							else
3564887Schin 								error(ERROR_SYSTEM|2, "%s: cannot change user to %s and group to %s", file, fmtuid(uid), fmtgid(gid));
3574887Schin 						}
3584887Schin 						else
3594887Schin 						{
3604887Schin 							if (uid < 0)
3614887Schin 								error(1, "%s: changed group to %s", file, fmtgid(gid));
3624887Schin 							else if (gid < 0)
3634887Schin 								error(1, "%s: changed user to %s", file, fmtuid(uid));
3644887Schin 							else
3654887Schin 								error(1, "%s: changed user to %s and group to %s", file, fmtuid(uid), fmtgid(gid));
3664887Schin 						}
3674887Schin 					}
3684887Schin 					if ((st.st_mode & S_IPERM) ^ mode)
3694887Schin 					{
3704887Schin 						if (state->permissions)
3714887Schin 						{
3724887Schin 							if (chmod(file, mode) < 0)
3734887Schin 								error(ERROR_SYSTEM|2, "%s: cannot change mode to %s", file, fmtmode(mode, 0));
3744887Schin 							else
3754887Schin 								error(ERROR_SYSTEM|1, "%s: changed mode to %s", file, fmtmode(mode, 0));
3764887Schin 						}
3774887Schin 						else if (state->silent)
3784887Schin 							error_info.errors++;
3794887Schin 						else
3804887Schin 							error(2, "%s: mode should be %s", file, fmtmode(mode, 0));
3814887Schin 					}
3824887Schin 				}
3834887Schin 			}
3844887Schin 			closefile(sp);
3854887Schin 		}
3864887Schin 	}
3874887Schin 	else if (strneq(s, "method=", 7))
3884887Schin 	{
3894887Schin 		s += 7;
3904887Schin 		if (state->sum != state->oldsum)
3914887Schin 			sumclose(state->sum);
3924887Schin 		if (!(state->sum = sumopen(s)))
3934887Schin 			error(3, "%s: %s: unknown checksum method", check, s);
3944887Schin 	}
3954887Schin 	else if (streq(s, "permissions"))
3964887Schin 		state->haveperm = 1;
3974887Schin 	else
3984887Schin 		error(1, "%s: %s: unknown option", check, s);
3994887Schin }
4004887Schin 
4014887Schin /*
4024887Schin  * sum the list of files in lp
4034887Schin  */
4044887Schin 
4054887Schin static void
list(State_t * state,register Sfio_t * lp)4064887Schin list(State_t* state, register Sfio_t* lp)
4074887Schin {
4084887Schin 	register char*		file;
4094887Schin 	register Sfio_t*	sp;
4104887Schin 
4114887Schin 	while (file = sfgetr(lp, '\n', 1))
4124887Schin 		if (sp = openfile(file, state->check ? "rt" : "rb"))
4134887Schin 		{
4144887Schin 			pr(state, sfstdout, sp, file, state->permissions, NiL, state->check);
4154887Schin 			closefile(sp);
4164887Schin 		}
4174887Schin }
4184887Schin 
4194887Schin /*
4204887Schin  * order child entries
4214887Schin  */
4224887Schin 
4234887Schin static int
order(FTSENT * const * f1,FTSENT * const * f2)4244887Schin order(FTSENT* const* f1, FTSENT* const* f2)
4254887Schin {
4264887Schin 	return strcoll((*f1)->fts_name, (*f2)->fts_name);
4274887Schin }
4284887Schin 
4294887Schin /*
4304887Schin  * optget() info discipline function
4314887Schin  */
4324887Schin 
4334887Schin static int
optinfo(Opt_t * op,Sfio_t * sp,const char * s,Optdisc_t * dp)4344887Schin optinfo(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp)
4354887Schin {
4364887Schin 	if (streq(s, "methods"))
4374887Schin 		return sumusage(sp);
4384887Schin 	return 0;
4394887Schin }
4404887Schin 
4414887Schin int
b_cksum(int argc,register char ** argv,void * context)4424887Schin b_cksum(int argc, register char** argv, void* context)
4434887Schin {
4444887Schin 	register int	flags;
4454887Schin 	char*		file;
4468462SApril.Chin@Sun.COM 	char*		method;
4474887Schin 	Sfio_t*		sp;
4484887Schin 	FTS*		fts;
4494887Schin 	FTSENT*		ent;
45010898Sroland.mainz@nrubsig.org 	int		logical;
4514887Schin 	Optdisc_t	optdisc;
4524887Schin 	State_t		state;
4534887Schin 
4544887Schin 	cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_NOTIFY);
4554887Schin 	memset(&state, 0, sizeof(state));
456*12068SRoger.Faulkner@Oracle.COM 	flags = fts_flags() | FTS_TOP | FTS_NOPOSTORDER;
4578462SApril.Chin@Sun.COM 	state.flags = SUM_SIZE;
4584887Schin 	state.warn = 1;
45910898Sroland.mainz@nrubsig.org 	logical = 1;
4608462SApril.Chin@Sun.COM 	method = 0;
4614887Schin 	optinit(&optdisc, optinfo);
4624887Schin 	for (;;)
4634887Schin 	{
4644887Schin 		switch (optget(argv, usage))
4654887Schin 		{
4664887Schin 		case 'a':
4674887Schin 			state.all = 1;
4684887Schin 			continue;
4694887Schin 		case 'b':
4704887Schin 			state.text = 0;
4714887Schin 			continue;
4728462SApril.Chin@Sun.COM 		case 'B':
4738462SApril.Chin@Sun.COM 			state.scale = opt_info.num;
4748462SApril.Chin@Sun.COM 			continue;
4754887Schin 		case 'c':
4764887Schin 			if (!(state.check = sfstropen()))
4774887Schin 				error(3, "out of space [check]");
4784887Schin 			continue;
4794887Schin 		case 'h':
4804887Schin 			state.header = 1;
4814887Schin 			continue;
4824887Schin 		case 'l':
4834887Schin 			state.list = 1;
4844887Schin 			continue;
4854887Schin 		case 'p':
4864887Schin 			state.permissions = 1;
4874887Schin 			continue;
4884887Schin 		case 'r':
4898462SApril.Chin@Sun.COM 			method = "bsd";
4908462SApril.Chin@Sun.COM 			state.scale = 512;
4918462SApril.Chin@Sun.COM 			state.flags |= SUM_LEGACY;
4928462SApril.Chin@Sun.COM 			continue;
4938462SApril.Chin@Sun.COM 		case 'R':
4944887Schin 			flags &= ~FTS_TOP;
4954887Schin 			state.recursive = 1;
4964887Schin 			state.sort = order;
49710898Sroland.mainz@nrubsig.org 			logical = 0;
4984887Schin 			continue;
4994887Schin 		case 's':
5008462SApril.Chin@Sun.COM 			method = "sys5";
5018462SApril.Chin@Sun.COM 			continue;
5028462SApril.Chin@Sun.COM 		case 'S':
5034887Schin 			state.silent = opt_info.num;
5044887Schin 			continue;
5054887Schin 		case 't':
5064887Schin 			state.total = 1;
5074887Schin 			continue;
5084887Schin 		case 'w':
5094887Schin 			state.warn = opt_info.num;
5104887Schin 			continue;
5114887Schin 		case 'x':
5128462SApril.Chin@Sun.COM 			method = opt_info.arg;
5134887Schin 			continue;
5144887Schin 		case 'H':
5154887Schin 			flags |= FTS_META|FTS_PHYSICAL;
51610898Sroland.mainz@nrubsig.org 			logical = 0;
5174887Schin 			continue;
5184887Schin 		case 'L':
5194887Schin 			flags &= ~(FTS_META|FTS_PHYSICAL);
52010898Sroland.mainz@nrubsig.org 			logical = 0;
5214887Schin 			continue;
5224887Schin 		case 'P':
5234887Schin 			flags &= ~FTS_META;
5244887Schin 			flags |= FTS_PHYSICAL;
52510898Sroland.mainz@nrubsig.org 			logical = 0;
5264887Schin 			continue;
5274887Schin 		case 'T':
5284887Schin 			state.text = 1;
5294887Schin 			continue;
5304887Schin 		case '?':
5314887Schin 			error(ERROR_USAGE|4, "%s", opt_info.arg);
5324887Schin 			break;
5334887Schin 		case ':':
5344887Schin 			error(2, "%s", opt_info.arg);
5354887Schin 			break;
5364887Schin 		}
5374887Schin 		break;
5384887Schin 	}
5394887Schin 	argv += opt_info.index;
5404887Schin 	if (error_info.errors)
5414887Schin 		error(ERROR_USAGE|4, "%s", optusage(NiL));
5424887Schin 
5434887Schin 	/*
5444887Schin 	 * check the method
5454887Schin 	 */
5464887Schin 
5478462SApril.Chin@Sun.COM 	if (method && !(state.sum = sumopen(method)))
5488462SApril.Chin@Sun.COM 		error(3, "%s: unknown checksum method", method);
5494887Schin 	if (!state.sum && !(state.sum = sumopen(error_info.id)) && !(state.sum = sumopen(astconf("UNIVERSE", NiL, NiL))))
5504887Schin 		state.sum = sumopen(NiL);
5514887Schin 
5524887Schin 	/*
5534887Schin 	 * do it
5544887Schin 	 */
5554887Schin 
55610898Sroland.mainz@nrubsig.org 	if (logical)
557*12068SRoger.Faulkner@Oracle.COM 	{
55810898Sroland.mainz@nrubsig.org 		flags &= ~(FTS_META|FTS_PHYSICAL);
559*12068SRoger.Faulkner@Oracle.COM 		flags |= FTS_SEEDOTDIR;
560*12068SRoger.Faulkner@Oracle.COM 	}
5614887Schin 	if (state.permissions)
5624887Schin 	{
5634887Schin 		state.uid = geteuid();
5644887Schin 		state.gid = getegid();
5654887Schin 		state.silent = 0;
5664887Schin 	}
5674887Schin 	if (!state.check && (state.header || state.permissions))
5684887Schin 	{
5694887Schin 		sfprintf(sfstdout, "method=%s\n", state.sum->name);
5704887Schin 		if (state.permissions)
5714887Schin 			sfprintf(sfstdout, "permissions\n");
5724887Schin 	}
5734887Schin 	if (state.list)
5744887Schin 	{
5754887Schin 		if (*argv)
5764887Schin 		{
5774887Schin 			while (file = *argv++)
5784887Schin 				if (sp = openfile(file, "rt"))
5794887Schin 				{
5804887Schin 					list(&state, sp);
5814887Schin 					closefile(sp);
5824887Schin 				}
5834887Schin 		}
5844887Schin 		else if (sp = openfile(NiL, "rt"))
5854887Schin 		{
5864887Schin 			list(&state, sp);
5874887Schin 			closefile(sp);
5884887Schin 		}
5894887Schin 	}
5904887Schin 	else if (!*argv && !state.recursive)
5914887Schin 		pr(&state, sfstdout, sfstdin, "/dev/stdin", state.permissions, NiL, state.check);
5924887Schin 	else if (!(fts = fts_open(argv, flags, state.sort)))
5934887Schin 		error(ERROR_system(1), "%s: not found", *argv);
5944887Schin 	else
5954887Schin 	{
5968462SApril.Chin@Sun.COM 		while (!sh_checksig(context) && (ent = fts_read(fts)))
5974887Schin 			switch (ent->fts_info)
5984887Schin 			{
5994887Schin 			case FTS_SL:
6004887Schin 				if (!(flags & FTS_PHYSICAL) || (flags & FTS_META) && ent->fts_level == 1)
6014887Schin 					fts_set(NiL, ent, FTS_FOLLOW);
6024887Schin 				break;
6034887Schin 			case FTS_F:
6044887Schin 				if (sp = openfile(ent->fts_accpath, "rb"))
6054887Schin 				{
6064887Schin 					pr(&state, sfstdout, sp, ent->fts_path, state.permissions, ent->fts_statp, state.check);
6074887Schin 					closefile(sp);
6084887Schin 				}
6094887Schin 				break;
6104887Schin 			case FTS_DC:
6114887Schin 				error(ERROR_warn(0), "%s: directory causes cycle", ent->fts_accpath);
6124887Schin 				break;
6134887Schin 			case FTS_DNR:
6144887Schin 				error(ERROR_system(0), "%s: cannot read directory", ent->fts_accpath);
6154887Schin 				break;
6164887Schin 			case FTS_DNX:
6174887Schin 				error(ERROR_system(0), "%s: cannot search directory", ent->fts_accpath);
6184887Schin 				break;
6194887Schin 			case FTS_NS:
6204887Schin 				error(ERROR_system(0), "%s: not found", ent->fts_accpath);
6214887Schin 				break;
6224887Schin 			}
6234887Schin 		fts_close(fts);
6244887Schin 	}
6254887Schin 	if (state.total)
6264887Schin 	{
6278462SApril.Chin@Sun.COM 		sumprint(state.sum, sfstdout, state.flags|SUM_TOTAL|SUM_SCALE, state.scale);
6284887Schin 		sfputc(sfstdout, '\n');
6294887Schin 	}
6304887Schin 	sumclose(state.sum);
6314887Schin 	return error_info.errors != 0;
6324887Schin }
633