/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1992-2012 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* David Korn <dgk@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* Glenn Fowler
* AT&T Research
*
* sum -- list file checksum and size
*/
static const char usage[] =
"[-?\n@(#)$Id: sum (AT&T Research) 2012-04-20 $\n]"
"[+NAME?cksum,md5sum,sum - print file checksum and block count]"
"[+DESCRIPTION?\bsum\b lists the checksum, and for most methods the block"
" count, for each file argument. The standard input is read if there are"
" no \afile\a arguments. \bgetconf UNIVERSE\b determines the default"
" \bsum\b method: \batt\b for the \batt\b universe, \bbsd\b otherwise."
" The default for the other commands is the command name itself. The"
" \batt\b method is a true sum, all others are order dependent.]"
"[+?Method names consist of a leading identifier and 0 or more options"
" separated by -.]"
"[+?\bgetconf PATH_RESOLVE\b determines how symbolic links are handled. This"
" can be explicitly overridden by the \b--logical\b, \b--metaphysical\b,"
" and \b--physical\b options below. \bPATH_RESOLVE\b can be one of:]{"
" [+logical?Follow all symbolic links.]"
" [+metaphysical?Follow command argument symbolic links,"
" otherwise don't follow.]"
" [+physical?Don't follow symbolic links.]"
"}"
"[a:all?List the checksum for all files. Use with \b--total\b to list both"
" individual and total checksums and block counts.]"
"[b:binary?Read files in binary mode. This is the default.]"
"[B:scale?Block count scale (bytes per block) override for methods that"
" include size in the output. The default is method specific.]#[scale]"
"[c:check?Each \afile\a is interpreted as the output from a previous \bsum\b."
" If \b--header\b or \b--permissions\b was specified in the previous"
" \bsum\b then the checksum method is automatically determined,"
" otherwise \b--method\b must be specified. The listed checksum is"
" compared with the current value and a warning is issued for each file"
" that does not match. If \afile\a was generated by \b--permissions\b"
" then the file mode, user and group are also checked. Empty lines,"
" lines starting with \b#<space>\b, or the line \b#\b are ignored. Lines"
" containing no blanks are interpreted as [no]]\aname\a[=\avalue\a]]"
" options:]{"
" [+method=name?Checksum method to apply to subsequent lines.]"
" [+permissions?Subsequent lines were generated with"
" \b--permissions\b.]"
"}"
"[h:header?Print the checksum method as the first output line. Used with"
" \b--check\b and \b--permissions\b.]"
"[l:list?Each \afile\a is interpreted as a list of files, one per line,"
" that is checksummed.]"
"[p:permissions?If \b--check\b is not specified then list the file"
" mode, user and group between the checksum and path. User and group"
" matching the caller are output as \b-\b. If \b--check\b is"
" specified then the mode, user and group for each path in \afile\a"
" are updated if necessary to match those in \afile\a. A warning is"
" printed on the standard error for each changed file.]"
"[R:recursive?Recursively checksum the contents of directories.]"
"[S:silent|status?No output for \b--check\b; 0 exit status means all sums"
" matched, non-0 means at least one sum failed to match. Ignored for"
" \b--permissions\b.]"
"[t:total?List only the total checksum and block count of all files."
" \b--all\b \b--total\b lists each checksum and the total. The"
" total checksum and block count may be different from the checksum"
" and block count of the catenation of all files due to partial"
" blocks that may occur when the files are treated separately.]"
"[T:text?Read files in text mode (i.e., treat \b\\r\\n\b as \b\\n\b).]"
"[w!:warn?Warn about invalid \b--check\b lines.]"
"[x:method|algorithm?Specifies the checksum \amethod\a to"
" apply. Parenthesized method options are readonly implementation"
" details.]:[method]{\fmethods\f}"
"[L:logical|follow?Follow symbolic links when traversing directories. The"
" default is determined by \bgetconf PATH_RESOLVE\b.]"
"[H:metaphysical?Follow command argument symbolic links, otherwise don't"
" follow symbolic links when traversing directories. The default is"
" determined by \bgetconf PATH_RESOLVE\b.]"
"[P:physical?Don't follow symbolic links when traversing directories. The"
" default is determined by \bgetconf PATH_RESOLVE\b.]"
"[r:bsd?Equivalent to \b--method=bsd --scale=512\b for compatibility with"
" other \bsum\b(1) implementations.]"
"[s:sysv?Equivalent to \b--method=sys5\b for compatibility with other"
" \bsum\b(1) implementations.]"
"\n"
"\n[ file ... ]\n"
"\n"
"[+SEE ALSO?\bgetconf\b(1), \btw\b(1), \buuencode\b(1)]"
;
#include <cmd.h>
#include <sum.h>
#include <ls.h>
#include <modex.h>
#include <fts_fix.h>
#include <error.h>
{
} State_t;
/*
* open path for read mode
*/
static Sfio_t*
{
{
}
return sp;
}
/*
* close an openfile() stream
*/
static int
{
}
/*
* compute and print sum on an open file
*/
static void
{
register char* p;
register char* r;
register char* e;
register int peek;
if (check)
{
return;
}
{
peek = 0;
{
if (peek)
{
peek = 0;
if (*p != '\n')
}
while (r = memchr(p, '\r', e - p))
{
if (++r >= e)
{
e--;
peek = 1;
break;
}
p = r;
}
}
if (peek)
}
else
{
if (perm >= 0)
{
if (perm)
{
else
(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) : "-",
(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) : "-");
}
}
}
}
/*
* verify previous sum output
*/
static void
{
register char* t;
char* e;
char* file;
int attr;
int mode;
int uid;
int gid;
if (!*s || *s == '#' && (!*(s + 1) || *(s + 1) == ' ' || *(s + 1) == '\t'))
return;
if (t = strchr(s, ' '))
{
file = t;
*file++ = 0;
attr = 0;
{
if (t = strchr(++e, ' '))
{
if (*e == '-' && (t - e) == 1)
uid = -1;
else
{
*t = 0;
*t = ' ';
}
if (e = strchr(++t, ' '))
{
if (*t == '-' && (e - t) == 1)
gid = -1;
else
{
*e = 0;
*e = ' ';
}
file = e + 1;
attr = 1;
}
}
}
{
if (!streq(s, t))
{
error_info.errors++;
else
}
else if (attr)
{
{
error_info.errors++;
else
}
else
{
uid = -1;
else if (!state->permissions)
{
error_info.errors++;
else
}
gid = -1;
else if (!state->permissions)
{
error_info.errors++;
else
}
{
{
if (uid < 0)
else if (gid < 0)
else
error(ERROR_SYSTEM|2, "%s: cannot change user to %s and group to %s", file, fmtuid(uid), fmtgid(gid));
}
else
{
if (uid < 0)
else if (gid < 0)
else
}
}
{
if (state->permissions)
{
else
}
error_info.errors++;
else
}
}
}
}
}
{
s += 7;
}
else if (streq(s, "permissions"))
else
}
/*
* sum the list of files in lp
*/
static void
{
register char* file;
{
}
}
/*
* order child entries
*/
static int
{
}
/*
* optget() info discipline function
*/
static int
{
if (streq(s, "methods"))
return 0;
}
int
{
register int flags;
char* file;
char* method;
int logical;
logical = 1;
method = 0;
for (;;)
{
{
case 'a':
continue;
case 'b':
continue;
case 'B':
continue;
case 'c':
continue;
case 'h':
continue;
case 'l':
continue;
case 'p':
continue;
case 'r':
method = "bsd";
continue;
case 'R':
logical = 0;
continue;
case 's':
method = "sys5";
continue;
case 'S':
continue;
case 't':
continue;
case 'w':
continue;
case 'x':
continue;
case 'H':
logical = 0;
continue;
case 'L':
logical = 0;
continue;
case 'P':
flags |= FTS_PHYSICAL;
logical = 0;
continue;
case 'T':
continue;
case '?':
break;
case ':':
break;
}
break;
}
if (error_info.errors)
/*
* check the method
*/
if (!state.sum && !(state.sum = sumopen(error_info.id)) && !(state.sum = sumopen(astconf("UNIVERSE", NiL, NiL))))
/*
* do it
*/
if (logical)
{
flags |= FTS_SEEDOTDIR;
}
if (state.permissions)
{
}
{
if (state.permissions)
}
{
if (*argv)
{
{
}
}
{
}
}
else
{
{
case FTS_SL:
break;
case FTS_F:
{
}
break;
case FTS_DC:
break;
case FTS_DNR:
break;
case FTS_DNX:
break;
case FTS_NS:
break;
}
}
{
}
return error_info.errors != 0;
}