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