summaryrefslogtreecommitdiffstats
path: root/file_cmds/mtree/verify.c
diff options
context:
space:
mode:
authorCameron Katri <me@cameronkatri.com>2021-05-09 14:20:58 -0400
committerCameron Katri <me@cameronkatri.com>2021-05-09 14:20:58 -0400
commit5fd83771641d15c418f747bd343ba6738d3875f7 (patch)
tree5abf0f78f680d9837dbd93d4d4c3933bb7509599 /file_cmds/mtree/verify.c
downloadapple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.gz
apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.zst
apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.zip
Import macOS userland
adv_cmds-176 basic_cmds-55 bootstrap_cmds-116.100.1 developer_cmds-66 diskdev_cmds-667.40.1 doc_cmds-53.60.1 file_cmds-321.40.3 mail_cmds-35 misc_cmds-34 network_cmds-606.40.1 patch_cmds-17 remote_cmds-63 shell_cmds-216.60.1 system_cmds-880.60.2 text_cmds-106
Diffstat (limited to 'file_cmds/mtree/verify.c')
-rw-r--r--file_cmds/mtree/verify.c341
1 files changed, 341 insertions, 0 deletions
diff --git a/file_cmds/mtree/verify.c b/file_cmds/mtree/verify.c
new file mode 100644
index 0000000..7471652
--- /dev/null
+++ b/file_cmds/mtree/verify.c
@@ -0,0 +1,341 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)verify.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/mtree/verify.c,v 1.24 2005/08/11 15:43:55 brian Exp $");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <fnmatch.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <removefile.h>
+#include "metrics.h"
+#include "mtree.h"
+#include "extern.h"
+
+static NODE *root;
+static char path[MAXPATHLEN];
+
+static int miss(NODE *, char *, size_t path_length);
+static int vwalk(void);
+
+int
+mtree_verifyspec(FILE *fi)
+{
+ int rval, mval;
+ size_t path_length = 0;
+
+ root = mtree_readspec(fi);
+ rval = vwalk();
+ mval = miss(root, path, path_length);
+
+ if (rval != 0) {
+ RECORD_FAILURE(60, WARN_MISMATCH);
+ return rval;
+ } else {
+ RECORD_FAILURE(61, WARN_MISMATCH);
+ return mval;
+ }
+}
+
+static int
+vwalk(void)
+{
+ int error = 0;
+ FTS *t;
+ FTSENT *p;
+ NODE *ep, *level;
+ int specdepth, rval;
+ char *argv[2];
+ char dot[] = ".";
+
+ argv[0] = dot;
+ argv[1] = NULL;
+ if ((t = fts_open(argv, ftsoptions, NULL)) == NULL) {
+ error = errno;
+ RECORD_FAILURE(62, error);
+ errc(1, error, "line %d: fts_open", lineno);
+ }
+ level = root;
+ specdepth = rval = 0;
+ while ((p = fts_read(t))) {
+ if (check_excludes(p->fts_name, p->fts_path)) {
+ fts_set(t, p, FTS_SKIP);
+ continue;
+ }
+ switch(p->fts_info) {
+ case FTS_D:
+ case FTS_SL:
+ break;
+ case FTS_DP:
+ if (level == NULL) {
+ RECORD_FAILURE(63, EINVAL);
+ errx(1 , "invalid root in vwalk");
+ }
+ if (specdepth > p->fts_level) {
+ for (level = level->parent; level->prev;
+ level = level->prev);
+ --specdepth;
+ }
+ continue;
+ case FTS_DNR:
+ case FTS_ERR:
+ case FTS_NS:
+ warnx("%s: %s", RP(p), strerror(p->fts_errno));
+ continue;
+ default:
+ if (dflag)
+ continue;
+ }
+
+ if (specdepth != p->fts_level)
+ goto extra;
+ for (ep = level; ep; ep = ep->next)
+ if ((ep->flags & F_MAGIC &&
+ !fnmatch(ep->name, p->fts_name, FNM_PATHNAME)) ||
+ !strcmp(ep->name, p->fts_name)) {
+ ep->flags |= F_VISIT;
+ if ((ep->flags & F_NOCHANGE) == 0 &&
+ compare(ep->name, ep, p)) {
+ RECORD_FAILURE(64, WARN_MISMATCH);
+ rval = MISMATCHEXIT;
+ }
+ if (ep->flags & F_IGN)
+ (void)fts_set(t, p, FTS_SKIP);
+ else if (ep->child && ep->type == F_DIR &&
+ p->fts_info == FTS_D) {
+ level = ep->child;
+ ++specdepth;
+ }
+ break;
+ }
+
+ if (ep)
+ continue;
+extra:
+ if (!eflag) {
+ (void)printf("%s extra", RP(p));
+
+ if (rflag) {
+ /* rflag implies: delete stuff if "extra" is observed" */
+ if (mflag) {
+ /* -mflag is used for sealing & verification -- use removefile for recursive behavior */
+ removefile_state_t rmstate;
+ rmstate = removefile_state_alloc();
+ if (removefile(p->fts_accpath, rmstate, (REMOVEFILE_RECURSIVE))) {
+ error = errno;
+ RECORD_FAILURE(65, error);
+ errx (1, "\n error deleting item (or descendant) at path %s (%s)", RP(p), strerror(error));
+ }
+ else {
+ /* removefile success */
+ (void) printf(", removed");
+ }
+ removefile_state_free(rmstate);
+
+ }
+ else {
+ /* legacy: use rmdir/unlink if "-m" not specified */
+ int syserr = 0;
+
+ if (S_ISDIR(p->fts_statp->st_mode)){
+ syserr = rmdir(p->fts_accpath);
+ }
+ else {
+ syserr = unlink(p->fts_accpath);
+ }
+
+ /* log failures */
+ if (syserr) {
+ error = errno;
+ RECORD_FAILURE(66, error);
+ (void) printf(", not removed :%s", strerror(error));
+ }
+ }
+ } else if (mflag) {
+ RECORD_FAILURE(68956, WARN_MISMATCH);
+ errx(1, "cannot generate the XML dictionary");
+ }
+ (void)putchar('\n');
+ }
+ (void)fts_set(t, p, FTS_SKIP);
+ }
+ (void)fts_close(t);
+ if (sflag) {
+ RECORD_FAILURE(67, WARN_CHECKSUM);
+ warnx("%s checksum: %lu", fullpath, (unsigned long)crc_total);
+ }
+ return (rval);
+}
+
+static int
+miss(NODE *p, char *tail, size_t path_length)
+{
+ int create;
+ char *tp;
+ const char *type, *what;
+ int serr;
+ int rval = 0;
+ int rrval = 0;
+ size_t file_name_length = 0;
+
+ for (; p; p = p->next) {
+ if (p->type != F_DIR && (dflag || p->flags & F_VISIT))
+ continue;
+ file_name_length = strnlen(p->name, MAXPATHLEN);
+ path_length += file_name_length;
+ if (path_length >= MAXPATHLEN) {
+ RECORD_FAILURE(61971, ENAMETOOLONG);
+ continue;
+ }
+ (void)strcpy(tail, p->name);
+ if (!(p->flags & F_VISIT)) {
+ /* Don't print missing message if file exists as a
+ symbolic link and the -q flag is set. */
+ struct stat statbuf;
+
+ if (qflag && stat(path, &statbuf) == 0) {
+ p->flags |= F_VISIT;
+ } else {
+ (void)printf("%s missing", path);
+ RECORD_FAILURE(68, WARN_MISMATCH);
+ rval = MISMATCHEXIT;
+ }
+ }
+ if (p->type != F_DIR && p->type != F_LINK) {
+ putchar('\n');
+ continue;
+ }
+
+ create = 0;
+ if (p->type == F_LINK)
+ type = "symlink";
+ else
+ type = "directory";
+ if (!(p->flags & F_VISIT) && uflag) {
+ if (!(p->flags & (F_UID | F_UNAME))) {
+ (void)printf(" (%s not created: user not specified)", type);
+ } else if (!(p->flags & (F_GID | F_GNAME))) {
+ (void)printf(" (%s not created: group not specified)", type);
+ } else if (p->type == F_LINK) {
+ if (symlink(p->slink, path)) {
+ serr = errno;
+ RECORD_FAILURE(69, serr);
+ (void)printf(" (symlink not created: %s)\n",
+ strerror(serr));
+ } else {
+ (void)printf(" (created)\n");
+ }
+ if (lchown(path, p->st_uid, p->st_gid) == -1) {
+ serr = errno;
+ if (p->st_uid == (uid_t)-1)
+ what = "group";
+ else if (lchown(path, (uid_t)-1,
+ p->st_gid) == -1)
+ what = "user & group";
+ else {
+ what = "user";
+ errno = serr;
+ }
+ serr = errno;
+ RECORD_FAILURE(70, serr);
+ (void)printf("%s: %s not modified: %s"
+ "\n", path, what, strerror(serr));
+ }
+ continue;
+ } else if (!(p->flags & F_MODE)) {
+ (void)printf(" (directory not created: mode not specified)");
+ } else if (mkdir(path, S_IRWXU)) {
+ serr = errno;
+ RECORD_FAILURE(71, serr);
+ (void)printf(" (directory not created: %s)",
+ strerror(serr));
+ } else {
+ create = 1;
+ (void)printf(" (created)");
+ }
+ }
+ if (!(p->flags & F_VISIT))
+ (void)putchar('\n');
+
+ for (tp = tail; *tp; ++tp);
+ *tp = '/';
+ ++path_length;
+ rrval = miss(p->child, tp + 1, path_length);
+ if (rrval != 0) {
+ RECORD_FAILURE(72, WARN_MISMATCH);
+ rval = rrval;
+ }
+ path_length -= (file_name_length + 1);
+ *tp = '\0';
+
+ if (!create)
+ continue;
+ if (chown(path, p->st_uid, p->st_gid) == -1) {
+ serr = errno;
+ if (p->st_uid == (uid_t)-1)
+ what = "group";
+ else if (chown(path, (uid_t)-1, p->st_gid) == -1)
+ what = "user & group";
+ else {
+ what = "user";
+ errno = serr;
+ }
+ serr = errno;
+ RECORD_FAILURE(73, serr);
+ (void)printf("%s: %s not modified: %s\n",
+ path, what, strerror(serr));
+ }
+ if (chmod(path, p->st_mode)) {
+ serr = errno;
+ RECORD_FAILURE(74, serr);
+ (void)printf("%s: permissions not set: %s\n",
+ path, strerror(serr));
+ }
+ if ((p->flags & F_FLAGS) && p->st_flags &&
+ chflags(path, (u_int)p->st_flags)) {
+ serr = errno;
+ RECORD_FAILURE(75, serr);
+ (void)printf("%s: file flags not set: %s\n",
+ path, strerror(serr));
+ }
+ }
+ return rval;
+}