17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*d1a180b0Smaheshvs * Common Development and Distribution License (the "License").
6*d1a180b0Smaheshvs * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
226451fdbcSvsakar * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
277c478bd9Sstevel@tonic-gate /* All Rights Reserved */
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988
317c478bd9Sstevel@tonic-gate * The Regents of the University of California
327c478bd9Sstevel@tonic-gate * All Rights Reserved
337c478bd9Sstevel@tonic-gate *
347c478bd9Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from
357c478bd9Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its
367c478bd9Sstevel@tonic-gate * contributors.
377c478bd9Sstevel@tonic-gate */
387c478bd9Sstevel@tonic-gate
397c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate * ncheck -- obtain file names from reading filesystem
437c478bd9Sstevel@tonic-gate */
447c478bd9Sstevel@tonic-gate
457c478bd9Sstevel@tonic-gate #define MAXNINDIR (MAXBSIZE / sizeof (daddr_t))
467c478bd9Sstevel@tonic-gate
477c478bd9Sstevel@tonic-gate #include <sys/param.h>
487c478bd9Sstevel@tonic-gate #include <sys/types.h>
497c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
507c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
517c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
527c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fsdir.h>
537c478bd9Sstevel@tonic-gate #include <stdio.h>
547c478bd9Sstevel@tonic-gate #include <stdlib.h>
557c478bd9Sstevel@tonic-gate #include <string.h>
567c478bd9Sstevel@tonic-gate #include <errno.h>
577c478bd9Sstevel@tonic-gate #include <fcntl.h>
587c478bd9Sstevel@tonic-gate #include <unistd.h>
597c478bd9Sstevel@tonic-gate #include "roll_log.h"
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate union {
627c478bd9Sstevel@tonic-gate struct fs sblk;
637c478bd9Sstevel@tonic-gate char xxx[SBSIZE]; /* because fs is variable length */
647c478bd9Sstevel@tonic-gate } real_fs;
657c478bd9Sstevel@tonic-gate #define sblock real_fs.sblk
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate struct dinode *itab;
687c478bd9Sstevel@tonic-gate unsigned itab_size;
697c478bd9Sstevel@tonic-gate
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate struct dinode *gip;
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate /* inode list */
747c478bd9Sstevel@tonic-gate struct ilist {
757c478bd9Sstevel@tonic-gate ino_t ino;
767c478bd9Sstevel@tonic-gate ushort_t mode;
777c478bd9Sstevel@tonic-gate uid_t uid;
787c478bd9Sstevel@tonic-gate gid_t gid;
797c478bd9Sstevel@tonic-gate } *ilist;
807c478bd9Sstevel@tonic-gate int ilist_size = 0; /* size of ilist[] */
817c478bd9Sstevel@tonic-gate int ilist_index = 0; /* current index for storing into ilist; */
827c478bd9Sstevel@tonic-gate #define ILIST_SZ_INCR 1000 /* initial size, amount to incr sz of ilist */
837c478bd9Sstevel@tonic-gate #define MAX_ILIST_INDEX() (ilist_size - 1)
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate struct htab
867c478bd9Sstevel@tonic-gate {
877c478bd9Sstevel@tonic-gate ino_t h_ino;
887c478bd9Sstevel@tonic-gate ino_t h_pino;
897c478bd9Sstevel@tonic-gate int h_name_index; /* index into string table */
907c478bd9Sstevel@tonic-gate } *htab;
917c478bd9Sstevel@tonic-gate unsigned htab_size; /* how much malloc'd for htab */
927c478bd9Sstevel@tonic-gate
937c478bd9Sstevel@tonic-gate /*
947c478bd9Sstevel@tonic-gate * string table: used to hold filenames.
957c478bd9Sstevel@tonic-gate */
967c478bd9Sstevel@tonic-gate char *strngtab;
977c478bd9Sstevel@tonic-gate int strngloc;
987c478bd9Sstevel@tonic-gate int strngtab_size;
997c478bd9Sstevel@tonic-gate #define STRNGTAB_INCR (1024*16) /* amount to grow strngtab */
1007c478bd9Sstevel@tonic-gate #define MAX_STRNGTAB_INDEX() (strngtab_size - 1)
1017c478bd9Sstevel@tonic-gate #define AVG_PATH_LEN 30 /* average (?) length of name */
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate long hsize;
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate struct dirstuff {
1067c478bd9Sstevel@tonic-gate int loc;
1077c478bd9Sstevel@tonic-gate struct dinode *ip;
1087c478bd9Sstevel@tonic-gate char dbuf[MAXBSIZE];
1097c478bd9Sstevel@tonic-gate };
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gate int aflg = 0;
1137c478bd9Sstevel@tonic-gate int sflg = 0;
1147c478bd9Sstevel@tonic-gate int iflg = 0; /* number of inodes being searched for */
1157c478bd9Sstevel@tonic-gate int mflg = 0;
1167c478bd9Sstevel@tonic-gate int fi;
1177c478bd9Sstevel@tonic-gate ino_t ino;
1187c478bd9Sstevel@tonic-gate int nhent;
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate int nerror;
1217c478bd9Sstevel@tonic-gate
1227c478bd9Sstevel@tonic-gate long atol();
123*d1a180b0Smaheshvs daddr_t bmap(daddr_t);
1247c478bd9Sstevel@tonic-gate void bread(diskaddr_t bno, char *buf, int cnt);
1257c478bd9Sstevel@tonic-gate void check(char *file);
1267c478bd9Sstevel@tonic-gate int dotname(struct direct *dp);
1277c478bd9Sstevel@tonic-gate offset_t llseek();
1287c478bd9Sstevel@tonic-gate struct htab *lookup(ino_t i, int ef);
1297c478bd9Sstevel@tonic-gate void pass1(struct dinode *ip);
1307c478bd9Sstevel@tonic-gate void pass2(struct dinode *ip);
1317c478bd9Sstevel@tonic-gate void pass3(struct dinode *ip);
1327c478bd9Sstevel@tonic-gate void pname(ino_t i, int lev);
1337c478bd9Sstevel@tonic-gate char *strcpy();
1347c478bd9Sstevel@tonic-gate void usage();
1357c478bd9Sstevel@tonic-gate struct direct *dreaddir();
1367c478bd9Sstevel@tonic-gate void extend_ilist();
1377c478bd9Sstevel@tonic-gate int extend_strngtab(unsigned int size);
1387c478bd9Sstevel@tonic-gate uchar_t *extend_tbl(uchar_t *tbl, unsigned int *current_size,
1397c478bd9Sstevel@tonic-gate unsigned int new_size);
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate extern int optind;
1427c478bd9Sstevel@tonic-gate extern char *optarg;
1437c478bd9Sstevel@tonic-gate
1447c478bd9Sstevel@tonic-gate char *subopts [] = {
1457c478bd9Sstevel@tonic-gate #define M_FLAG 0
1467c478bd9Sstevel@tonic-gate "m",
1477c478bd9Sstevel@tonic-gate NULL
1487c478bd9Sstevel@tonic-gate };
1497c478bd9Sstevel@tonic-gate
150*d1a180b0Smaheshvs int
main(int argc,char * argv[])151*d1a180b0Smaheshvs main(int argc, char *argv[])
1527c478bd9Sstevel@tonic-gate {
1537c478bd9Sstevel@tonic-gate long n;
1547c478bd9Sstevel@tonic-gate int opt;
1557c478bd9Sstevel@tonic-gate char *suboptions, *value;
1567c478bd9Sstevel@tonic-gate int suboption;
1577c478bd9Sstevel@tonic-gate char *p;
1587c478bd9Sstevel@tonic-gate int first = 0;
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate extend_ilist();
1617c478bd9Sstevel@tonic-gate while ((opt = getopt(argc, argv, "ao:i:s")) != EOF) {
1627c478bd9Sstevel@tonic-gate switch (opt) {
1637c478bd9Sstevel@tonic-gate
1647c478bd9Sstevel@tonic-gate case 'a':
1657c478bd9Sstevel@tonic-gate aflg++;
1667c478bd9Sstevel@tonic-gate break;
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate case 'o':
1697c478bd9Sstevel@tonic-gate /*
1707c478bd9Sstevel@tonic-gate * ufs specific options.
1717c478bd9Sstevel@tonic-gate */
1727c478bd9Sstevel@tonic-gate suboptions = optarg;
1737c478bd9Sstevel@tonic-gate while (*suboptions != '\0') {
1747c478bd9Sstevel@tonic-gate suboption = getsubopt(&suboptions,
1757c478bd9Sstevel@tonic-gate subopts, &value);
1767c478bd9Sstevel@tonic-gate switch (suboption) {
1777c478bd9Sstevel@tonic-gate
1787c478bd9Sstevel@tonic-gate case M_FLAG:
1797c478bd9Sstevel@tonic-gate mflg++;
1807c478bd9Sstevel@tonic-gate break;
1817c478bd9Sstevel@tonic-gate
1827c478bd9Sstevel@tonic-gate default:
1837c478bd9Sstevel@tonic-gate usage();
1847c478bd9Sstevel@tonic-gate }
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate break;
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate case 'i':
1897c478bd9Sstevel@tonic-gate while ((p = (char *)strtok((first++ == 0 ? optarg : 0),
1907c478bd9Sstevel@tonic-gate ", ")) != NULL) {
1917c478bd9Sstevel@tonic-gate if ((n = atoi(p)) == 0)
1927c478bd9Sstevel@tonic-gate break;
1937c478bd9Sstevel@tonic-gate ilist[iflg].ino = n;
1947c478bd9Sstevel@tonic-gate iflg++;
1957c478bd9Sstevel@tonic-gate ilist_index = iflg;
1967c478bd9Sstevel@tonic-gate if (iflg > MAX_ILIST_INDEX())
1977c478bd9Sstevel@tonic-gate extend_ilist();
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate break;
2007c478bd9Sstevel@tonic-gate
2017c478bd9Sstevel@tonic-gate case 's':
2027c478bd9Sstevel@tonic-gate sflg++;
2037c478bd9Sstevel@tonic-gate break;
2047c478bd9Sstevel@tonic-gate #if 0
2057c478bd9Sstevel@tonic-gate case 'V':
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate int opt_count;
2087c478bd9Sstevel@tonic-gate char *opt_text;
2097c478bd9Sstevel@tonic-gate
2107c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "ncheck -F ufs ");
2117c478bd9Sstevel@tonic-gate for (opt_count = 1; opt_count < argc;
2127c478bd9Sstevel@tonic-gate opt_count++) {
2137c478bd9Sstevel@tonic-gate opt_text = argv[opt_count];
2147c478bd9Sstevel@tonic-gate if (opt_text)
2157c478bd9Sstevel@tonic-gate (void) fprintf(stdout, " %s ",
2167c478bd9Sstevel@tonic-gate opt_text);
2177c478bd9Sstevel@tonic-gate }
2187c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "\n");
2197c478bd9Sstevel@tonic-gate }
2207c478bd9Sstevel@tonic-gate break;
2217c478bd9Sstevel@tonic-gate #endif
2227c478bd9Sstevel@tonic-gate case '?':
2237c478bd9Sstevel@tonic-gate usage();
2247c478bd9Sstevel@tonic-gate }
2257c478bd9Sstevel@tonic-gate }
2267c478bd9Sstevel@tonic-gate argc -= optind;
2277c478bd9Sstevel@tonic-gate argv = &argv[optind];
2287c478bd9Sstevel@tonic-gate while (argc--) {
2297c478bd9Sstevel@tonic-gate check(*argv);
2307c478bd9Sstevel@tonic-gate argv++;
2317c478bd9Sstevel@tonic-gate }
2327c478bd9Sstevel@tonic-gate return (nerror);
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate
2357c478bd9Sstevel@tonic-gate void
check(char * file)236*d1a180b0Smaheshvs check(char *file)
2377c478bd9Sstevel@tonic-gate {
238*d1a180b0Smaheshvs int i, j, c;
2397c478bd9Sstevel@tonic-gate
2407c478bd9Sstevel@tonic-gate fi = open64(file, 0);
2417c478bd9Sstevel@tonic-gate if (fi < 0) {
2427c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "ncheck: cannot open %s\n", file);
2437c478bd9Sstevel@tonic-gate nerror++;
2447c478bd9Sstevel@tonic-gate return;
2457c478bd9Sstevel@tonic-gate }
2467c478bd9Sstevel@tonic-gate nhent = 0;
2477c478bd9Sstevel@tonic-gate (void) printf("%s:\n", file);
2487c478bd9Sstevel@tonic-gate sync();
2497c478bd9Sstevel@tonic-gate bread((diskaddr_t)SBLOCK, (char *)&sblock, SBSIZE);
2507c478bd9Sstevel@tonic-gate if ((sblock.fs_magic != FS_MAGIC) &&
2517c478bd9Sstevel@tonic-gate (sblock.fs_magic != MTB_UFS_MAGIC)) {
2527c478bd9Sstevel@tonic-gate (void) printf("%s: not a ufs file system\n", file);
2537c478bd9Sstevel@tonic-gate nerror++;
2547c478bd9Sstevel@tonic-gate return;
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate
2576451fdbcSvsakar if ((sblock.fs_magic == FS_MAGIC) &&
2586451fdbcSvsakar ((sblock.fs_version != UFS_EFISTYLE4NONEFI_VERSION_2) &&
2596451fdbcSvsakar (sblock.fs_version != UFS_VERSION_MIN))) {
2606451fdbcSvsakar (void) printf("%s: unrecognized ufs version number %d\n",
2616451fdbcSvsakar file, sblock.fs_version);
2626451fdbcSvsakar nerror++;
2636451fdbcSvsakar return;
2646451fdbcSvsakar }
2656451fdbcSvsakar
2667c478bd9Sstevel@tonic-gate if ((sblock.fs_magic == MTB_UFS_MAGIC) &&
2677c478bd9Sstevel@tonic-gate ((sblock.fs_version > MTB_UFS_VERSION_1) ||
2687c478bd9Sstevel@tonic-gate (sblock.fs_version < MTB_UFS_VERSION_MIN))) {
2697c478bd9Sstevel@tonic-gate (void) printf("%s: unrecognized ufs version number %d\n",
2707c478bd9Sstevel@tonic-gate file, sblock.fs_version);
2717c478bd9Sstevel@tonic-gate nerror++;
2727c478bd9Sstevel@tonic-gate return;
2737c478bd9Sstevel@tonic-gate }
2747c478bd9Sstevel@tonic-gate
2757c478bd9Sstevel@tonic-gate /* If fs is logged, roll the log. */
2767c478bd9Sstevel@tonic-gate if (sblock.fs_logbno) {
2777c478bd9Sstevel@tonic-gate switch (rl_roll_log(file)) {
2787c478bd9Sstevel@tonic-gate case RL_SUCCESS:
2797c478bd9Sstevel@tonic-gate /*
2807c478bd9Sstevel@tonic-gate * Reread the superblock. Rolling the log may have
2817c478bd9Sstevel@tonic-gate * changed it.
2827c478bd9Sstevel@tonic-gate */
2837c478bd9Sstevel@tonic-gate bread((diskaddr_t)SBLOCK, (char *)&sblock, SBSIZE);
2847c478bd9Sstevel@tonic-gate break;
2857c478bd9Sstevel@tonic-gate case RL_SYSERR:
2867c478bd9Sstevel@tonic-gate (void) printf("Warning: cannot roll log for %s. %s\n",
2877c478bd9Sstevel@tonic-gate file, strerror(errno));
2887c478bd9Sstevel@tonic-gate break;
2897c478bd9Sstevel@tonic-gate default:
2907c478bd9Sstevel@tonic-gate (void) printf("Warning: cannot roll log for %s.\n",
2917c478bd9Sstevel@tonic-gate file);
2927c478bd9Sstevel@tonic-gate break;
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate
2967c478bd9Sstevel@tonic-gate itab = (struct dinode *)extend_tbl((uchar_t *)itab, &itab_size,
2977c478bd9Sstevel@tonic-gate (unsigned)(sblock.fs_ipg * sizeof (struct dinode)));
2987c478bd9Sstevel@tonic-gate if (itab == 0) {
2997c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
3007c478bd9Sstevel@tonic-gate "ncheck: not enough memory for itab table\n");
3017c478bd9Sstevel@tonic-gate nerror++;
3027c478bd9Sstevel@tonic-gate return;
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate
3057c478bd9Sstevel@tonic-gate hsize = sblock.fs_ipg * sblock.fs_ncg - sblock.fs_cstotal.cs_nifree + 1;
3067c478bd9Sstevel@tonic-gate
3077c478bd9Sstevel@tonic-gate htab = (struct htab *)extend_tbl((uchar_t *)htab, &htab_size,
3087c478bd9Sstevel@tonic-gate (unsigned)(hsize * sizeof (struct htab)));
3097c478bd9Sstevel@tonic-gate if (htab == 0) {
3107c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
3117c478bd9Sstevel@tonic-gate "ncheck: not enough memory for htab table\n");
3127c478bd9Sstevel@tonic-gate nerror++;
3137c478bd9Sstevel@tonic-gate return;
3147c478bd9Sstevel@tonic-gate }
3157c478bd9Sstevel@tonic-gate
3167c478bd9Sstevel@tonic-gate if (!extend_strngtab(AVG_PATH_LEN * hsize)) {
3177c478bd9Sstevel@tonic-gate (void) printf("not enough memory to allocate tables\n");
3187c478bd9Sstevel@tonic-gate nerror++;
3197c478bd9Sstevel@tonic-gate return;
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate strngloc = 0;
3227c478bd9Sstevel@tonic-gate
3237c478bd9Sstevel@tonic-gate ino = 0;
3247c478bd9Sstevel@tonic-gate for (c = 0; c < sblock.fs_ncg; c++) {
3257c478bd9Sstevel@tonic-gate bread(fsbtodb(&sblock, cgimin(&sblock, c)), (char *)itab,
3267c478bd9Sstevel@tonic-gate (int)(sblock.fs_ipg * sizeof (struct dinode)));
3277c478bd9Sstevel@tonic-gate for (j = 0; j < sblock.fs_ipg; j++) {
3287c478bd9Sstevel@tonic-gate if (itab[j].di_smode != 0) {
3297c478bd9Sstevel@tonic-gate itab[j].di_mode = itab[j].di_smode;
3307c478bd9Sstevel@tonic-gate if (itab[j].di_suid != UID_LONG)
3317c478bd9Sstevel@tonic-gate itab[j].di_uid = itab[j].di_suid;
3327c478bd9Sstevel@tonic-gate if (itab[j].di_sgid != GID_LONG)
3337c478bd9Sstevel@tonic-gate itab[j].di_gid = itab[j].di_sgid;
3347c478bd9Sstevel@tonic-gate pass1(&itab[j]);
3357c478bd9Sstevel@tonic-gate }
3367c478bd9Sstevel@tonic-gate ino++;
3377c478bd9Sstevel@tonic-gate }
3387c478bd9Sstevel@tonic-gate }
3397c478bd9Sstevel@tonic-gate ilist[ilist_index++].ino = 0;
3407c478bd9Sstevel@tonic-gate if (ilist_index > MAX_ILIST_INDEX())
3417c478bd9Sstevel@tonic-gate extend_ilist();
3427c478bd9Sstevel@tonic-gate ino = 0;
3437c478bd9Sstevel@tonic-gate for (c = 0; c < sblock.fs_ncg; c++) {
3447c478bd9Sstevel@tonic-gate bread(fsbtodb(&sblock, cgimin(&sblock, c)), (char *)itab,
3457c478bd9Sstevel@tonic-gate (int)(sblock.fs_ipg * sizeof (struct dinode)));
3467c478bd9Sstevel@tonic-gate for (j = 0; j < sblock.fs_ipg; j++) {
3477c478bd9Sstevel@tonic-gate
3487c478bd9Sstevel@tonic-gate if (itab[j].di_smode != 0) {
3497c478bd9Sstevel@tonic-gate itab[j].di_mode = itab[j].di_smode;
3507c478bd9Sstevel@tonic-gate pass2(&itab[j]);
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate ino++;
3537c478bd9Sstevel@tonic-gate }
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate ino = 0;
3567c478bd9Sstevel@tonic-gate for (c = 0; c < sblock.fs_ncg; c++) {
3577c478bd9Sstevel@tonic-gate bread(fsbtodb(&sblock, cgimin(&sblock, c)), (char *)itab,
3587c478bd9Sstevel@tonic-gate (int)(sblock.fs_ipg * sizeof (struct dinode)));
3597c478bd9Sstevel@tonic-gate for (j = 0; j < sblock.fs_ipg; j++) {
3607c478bd9Sstevel@tonic-gate if (itab[j].di_smode != 0) {
3617c478bd9Sstevel@tonic-gate itab[j].di_mode = itab[j].di_smode;
3627c478bd9Sstevel@tonic-gate pass3(&itab[j]);
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate ino++;
3657c478bd9Sstevel@tonic-gate }
3667c478bd9Sstevel@tonic-gate }
3677c478bd9Sstevel@tonic-gate (void) close(fi);
3687c478bd9Sstevel@tonic-gate
3697c478bd9Sstevel@tonic-gate /*
3707c478bd9Sstevel@tonic-gate * Clear those elements after inodes specified by "-i" out of
3717c478bd9Sstevel@tonic-gate * ilist.
3727c478bd9Sstevel@tonic-gate */
3737c478bd9Sstevel@tonic-gate for (i = iflg; i < ilist_index; i++) {
3747c478bd9Sstevel@tonic-gate ilist[i].ino = 0;
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate ilist_index = iflg;
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate
3797c478bd9Sstevel@tonic-gate void
pass1(struct dinode * ip)380*d1a180b0Smaheshvs pass1(struct dinode *ip)
3817c478bd9Sstevel@tonic-gate {
3827c478bd9Sstevel@tonic-gate int i;
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate if (mflg) {
3857c478bd9Sstevel@tonic-gate for (i = 0; i < iflg; i++)
3867c478bd9Sstevel@tonic-gate if (ino == ilist[i].ino) {
3877c478bd9Sstevel@tonic-gate ilist[i].mode = ip->di_mode;
3887c478bd9Sstevel@tonic-gate ilist[i].uid = ip->di_uid;
3897c478bd9Sstevel@tonic-gate ilist[i].gid = ip->di_gid;
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate }
3927c478bd9Sstevel@tonic-gate if ((ip->di_mode & IFMT) != IFDIR) {
3937c478bd9Sstevel@tonic-gate if (sflg == 0)
3947c478bd9Sstevel@tonic-gate return;
3957c478bd9Sstevel@tonic-gate if ((ip->di_mode & IFMT) == IFBLK ||
3967c478bd9Sstevel@tonic-gate (ip->di_mode & IFMT) == IFCHR ||
3977c478bd9Sstevel@tonic-gate ip->di_mode&(ISUID|ISGID)) {
3987c478bd9Sstevel@tonic-gate ilist[ilist_index].ino = ino;
3997c478bd9Sstevel@tonic-gate ilist[ilist_index].mode = ip->di_mode;
4007c478bd9Sstevel@tonic-gate ilist[ilist_index].uid = ip->di_uid;
4017c478bd9Sstevel@tonic-gate ilist[ilist_index].gid = ip->di_gid;
4027c478bd9Sstevel@tonic-gate if (++ilist_index > MAX_ILIST_INDEX())
4037c478bd9Sstevel@tonic-gate extend_ilist();
4047c478bd9Sstevel@tonic-gate return;
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate }
4077c478bd9Sstevel@tonic-gate (void) lookup(ino, 1);
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate
4107c478bd9Sstevel@tonic-gate void
pass2(struct dinode * ip)411*d1a180b0Smaheshvs pass2(struct dinode *ip)
4127c478bd9Sstevel@tonic-gate {
413*d1a180b0Smaheshvs struct direct *dp;
4147c478bd9Sstevel@tonic-gate struct dirstuff dirp;
4157c478bd9Sstevel@tonic-gate struct htab *hp;
4167c478bd9Sstevel@tonic-gate
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate if ((ip->di_mode&IFMT) != IFDIR)
4197c478bd9Sstevel@tonic-gate return;
4207c478bd9Sstevel@tonic-gate dirp.loc = 0;
4217c478bd9Sstevel@tonic-gate dirp.ip = ip;
4227c478bd9Sstevel@tonic-gate gip = ip;
4237c478bd9Sstevel@tonic-gate for (dp = dreaddir(&dirp); dp != NULL; dp = dreaddir(&dirp)) {
4247c478bd9Sstevel@tonic-gate int nmlen;
4257c478bd9Sstevel@tonic-gate
4267c478bd9Sstevel@tonic-gate if (dp->d_ino == 0)
4277c478bd9Sstevel@tonic-gate continue;
4287c478bd9Sstevel@tonic-gate
4297c478bd9Sstevel@tonic-gate hp = lookup(dp->d_ino, 0);
4307c478bd9Sstevel@tonic-gate if (hp == 0)
4317c478bd9Sstevel@tonic-gate continue;
4327c478bd9Sstevel@tonic-gate
4337c478bd9Sstevel@tonic-gate if (dotname(dp))
4347c478bd9Sstevel@tonic-gate continue;
4357c478bd9Sstevel@tonic-gate hp->h_pino = ino;
4367c478bd9Sstevel@tonic-gate nmlen = strlen(dp->d_name);
4377c478bd9Sstevel@tonic-gate
4387c478bd9Sstevel@tonic-gate if (strngloc + nmlen + 1 > MAX_STRNGTAB_INDEX()) {
4397c478bd9Sstevel@tonic-gate if (!extend_strngtab(STRNGTAB_INCR)) {
4407c478bd9Sstevel@tonic-gate perror("ncheck: can't grow string table\n");
4417c478bd9Sstevel@tonic-gate exit(32);
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate }
4447c478bd9Sstevel@tonic-gate
4457c478bd9Sstevel@tonic-gate hp->h_name_index = strngloc;
4467c478bd9Sstevel@tonic-gate (void) strcpy(&strngtab[strngloc], dp->d_name);
4477c478bd9Sstevel@tonic-gate strngloc += nmlen + 1;
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate
4517c478bd9Sstevel@tonic-gate void
pass3(struct dinode * ip)452*d1a180b0Smaheshvs pass3(struct dinode *ip)
4537c478bd9Sstevel@tonic-gate {
454*d1a180b0Smaheshvs struct direct *dp;
4557c478bd9Sstevel@tonic-gate struct dirstuff dirp;
4567c478bd9Sstevel@tonic-gate int k;
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gate if ((ip->di_mode&IFMT) != IFDIR)
4597c478bd9Sstevel@tonic-gate return;
4607c478bd9Sstevel@tonic-gate dirp.loc = 0;
4617c478bd9Sstevel@tonic-gate dirp.ip = ip;
4627c478bd9Sstevel@tonic-gate gip = ip;
4637c478bd9Sstevel@tonic-gate for (dp = dreaddir(&dirp); dp != NULL; dp = dreaddir(&dirp)) {
4647c478bd9Sstevel@tonic-gate if (aflg == 0 && dotname(dp))
4657c478bd9Sstevel@tonic-gate continue;
4667c478bd9Sstevel@tonic-gate
4677c478bd9Sstevel@tonic-gate if (sflg == 0 && iflg == 0)
4687c478bd9Sstevel@tonic-gate goto pr;
4697c478bd9Sstevel@tonic-gate for (k = 0; k < ilist_index && ilist[k].ino != 0; k++) {
4707c478bd9Sstevel@tonic-gate if (ilist[k].ino == dp->d_ino) {
4717c478bd9Sstevel@tonic-gate break;
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate if (ilist[k].ino == 0)
4757c478bd9Sstevel@tonic-gate continue;
4767c478bd9Sstevel@tonic-gate if (mflg)
4777c478bd9Sstevel@tonic-gate (void) printf("mode %-6o uid %-5ld gid %-5ld ino ",
4787c478bd9Sstevel@tonic-gate ilist[k].mode, ilist[k].uid, ilist[k].gid);
4797c478bd9Sstevel@tonic-gate pr:
4807c478bd9Sstevel@tonic-gate (void) printf("%-5u\t", dp->d_ino);
4817c478bd9Sstevel@tonic-gate pname(ino, 0);
4827c478bd9Sstevel@tonic-gate (void) printf("/%s", dp->d_name);
4837c478bd9Sstevel@tonic-gate if (lookup(dp->d_ino, 0))
4847c478bd9Sstevel@tonic-gate (void) printf("/.");
4857c478bd9Sstevel@tonic-gate (void) printf("\n");
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate }
4887c478bd9Sstevel@tonic-gate
4897c478bd9Sstevel@tonic-gate /*
4907c478bd9Sstevel@tonic-gate * get next entry in a directory.
4917c478bd9Sstevel@tonic-gate */
4927c478bd9Sstevel@tonic-gate struct direct *
dreaddir(struct dirstuff * dirp)493*d1a180b0Smaheshvs dreaddir(struct dirstuff *dirp)
4947c478bd9Sstevel@tonic-gate {
495*d1a180b0Smaheshvs struct direct *dp;
4967c478bd9Sstevel@tonic-gate daddr_t lbn, d;
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate for (;;) {
4997c478bd9Sstevel@tonic-gate
5007c478bd9Sstevel@tonic-gate if (dirp->loc >= (int)dirp->ip->di_size)
5017c478bd9Sstevel@tonic-gate return (NULL);
5027c478bd9Sstevel@tonic-gate if (blkoff(&sblock, dirp->loc) == 0) {
5037c478bd9Sstevel@tonic-gate
5047c478bd9Sstevel@tonic-gate lbn = lblkno(&sblock, dirp->loc);
5057c478bd9Sstevel@tonic-gate
5067c478bd9Sstevel@tonic-gate d = bmap(lbn);
5077c478bd9Sstevel@tonic-gate if (d == 0)
5087c478bd9Sstevel@tonic-gate return (NULL);
5097c478bd9Sstevel@tonic-gate
5107c478bd9Sstevel@tonic-gate bread(fsbtodb(&sblock, d), dirp->dbuf,
5117c478bd9Sstevel@tonic-gate (int)dblksize(&sblock, dirp->ip, (int)lbn));
5127c478bd9Sstevel@tonic-gate
5137c478bd9Sstevel@tonic-gate }
5147c478bd9Sstevel@tonic-gate dp = (struct direct *)
5157c478bd9Sstevel@tonic-gate (dirp->dbuf + blkoff(&sblock, dirp->loc));
5167c478bd9Sstevel@tonic-gate dirp->loc += dp->d_reclen;
5177c478bd9Sstevel@tonic-gate if (dp->d_ino == 0) {
5187c478bd9Sstevel@tonic-gate continue;
5197c478bd9Sstevel@tonic-gate }
5207c478bd9Sstevel@tonic-gate return (dp);
5217c478bd9Sstevel@tonic-gate }
5227c478bd9Sstevel@tonic-gate }
5237c478bd9Sstevel@tonic-gate
524*d1a180b0Smaheshvs int
dotname(struct direct * dp)525*d1a180b0Smaheshvs dotname(struct direct *dp)
5267c478bd9Sstevel@tonic-gate {
5277c478bd9Sstevel@tonic-gate
5287c478bd9Sstevel@tonic-gate if (dp->d_name[0] == '.') {
5297c478bd9Sstevel@tonic-gate if (dp->d_name[1] == 0 ||
5307c478bd9Sstevel@tonic-gate (dp->d_name[1] == '.' && dp->d_name[2] == 0))
5317c478bd9Sstevel@tonic-gate return (1);
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate return (0);
5347c478bd9Sstevel@tonic-gate }
5357c478bd9Sstevel@tonic-gate
5367c478bd9Sstevel@tonic-gate void
pname(ino_t i,int lev)537*d1a180b0Smaheshvs pname(ino_t i, int lev)
5387c478bd9Sstevel@tonic-gate {
539*d1a180b0Smaheshvs struct htab *hp;
5407c478bd9Sstevel@tonic-gate
5417c478bd9Sstevel@tonic-gate if (i == UFSROOTINO)
5427c478bd9Sstevel@tonic-gate return;
5437c478bd9Sstevel@tonic-gate
5447c478bd9Sstevel@tonic-gate if ((hp = lookup(i, 0)) == 0) {
5457c478bd9Sstevel@tonic-gate (void) printf("???");
5467c478bd9Sstevel@tonic-gate return;
5477c478bd9Sstevel@tonic-gate }
5487c478bd9Sstevel@tonic-gate if (lev > 10) {
5497c478bd9Sstevel@tonic-gate (void) printf("...");
5507c478bd9Sstevel@tonic-gate return;
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate pname(hp->h_pino, ++lev);
5537c478bd9Sstevel@tonic-gate (void) printf("/%s", &(strngtab[hp->h_name_index]));
5547c478bd9Sstevel@tonic-gate
5557c478bd9Sstevel@tonic-gate }
5567c478bd9Sstevel@tonic-gate
5577c478bd9Sstevel@tonic-gate struct htab *
lookup(ino_t i,int ef)558*d1a180b0Smaheshvs lookup(ino_t i, int ef)
5597c478bd9Sstevel@tonic-gate {
560*d1a180b0Smaheshvs struct htab *hp;
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate for (hp = &htab[(int)i%hsize]; hp->h_ino; ) {
5637c478bd9Sstevel@tonic-gate if (hp->h_ino == i)
5647c478bd9Sstevel@tonic-gate return (hp);
5657c478bd9Sstevel@tonic-gate if (++hp >= &htab[hsize])
5667c478bd9Sstevel@tonic-gate hp = htab;
5677c478bd9Sstevel@tonic-gate }
5687c478bd9Sstevel@tonic-gate
5697c478bd9Sstevel@tonic-gate if (ef == 0)
5707c478bd9Sstevel@tonic-gate return (0);
5717c478bd9Sstevel@tonic-gate if (++nhent >= hsize) {
5727c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "ncheck: hsize of %ld is too small\n",
5737c478bd9Sstevel@tonic-gate hsize);
5747c478bd9Sstevel@tonic-gate exit(32);
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate hp->h_ino = i;
5777c478bd9Sstevel@tonic-gate return (hp);
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate
5807c478bd9Sstevel@tonic-gate void
bread(diskaddr_t bno,char * buf,int cnt)581*d1a180b0Smaheshvs bread(diskaddr_t bno, char *buf, int cnt)
5827c478bd9Sstevel@tonic-gate {
583*d1a180b0Smaheshvs int i;
5847c478bd9Sstevel@tonic-gate int got;
5857c478bd9Sstevel@tonic-gate
5867c478bd9Sstevel@tonic-gate if (llseek(fi, (offset_t)bno * DEV_BSIZE, 0) == -1) {
5877c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "ncheck: lseek error %lld\n",
5887c478bd9Sstevel@tonic-gate (offset_t)bno * DEV_BSIZE);
5897c478bd9Sstevel@tonic-gate
5907c478bd9Sstevel@tonic-gate for (i = 0; i < cnt; i++) {
5917c478bd9Sstevel@tonic-gate buf[i] = 0;
5927c478bd9Sstevel@tonic-gate }
5937c478bd9Sstevel@tonic-gate
5947c478bd9Sstevel@tonic-gate return;
5957c478bd9Sstevel@tonic-gate }
5967c478bd9Sstevel@tonic-gate
5977c478bd9Sstevel@tonic-gate got = read((int)fi, buf, cnt);
5987c478bd9Sstevel@tonic-gate
5997c478bd9Sstevel@tonic-gate if (got != cnt) {
6007c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
6017c478bd9Sstevel@tonic-gate "ncheck: read error at block %lld (wanted %d got %d)\n",
6027c478bd9Sstevel@tonic-gate bno, cnt, got);
6037c478bd9Sstevel@tonic-gate
6047c478bd9Sstevel@tonic-gate for (i = 0; i < cnt; i++)
6057c478bd9Sstevel@tonic-gate buf[i] = 0;
6067c478bd9Sstevel@tonic-gate }
6077c478bd9Sstevel@tonic-gate }
6087c478bd9Sstevel@tonic-gate
6097c478bd9Sstevel@tonic-gate daddr_t
bmap(daddr_t i)610*d1a180b0Smaheshvs bmap(daddr_t i)
6117c478bd9Sstevel@tonic-gate {
6127c478bd9Sstevel@tonic-gate daddr_t ibuf[MAXNINDIR];
6137c478bd9Sstevel@tonic-gate
6147c478bd9Sstevel@tonic-gate if (i < NDADDR)
6157c478bd9Sstevel@tonic-gate return (gip->di_db[i]);
6167c478bd9Sstevel@tonic-gate i -= NDADDR;
6177c478bd9Sstevel@tonic-gate if (i > NINDIR(&sblock)) {
6187c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "ncheck: %lu - huge directory\n", ino);
6197c478bd9Sstevel@tonic-gate return ((daddr_t)0);
6207c478bd9Sstevel@tonic-gate }
6217c478bd9Sstevel@tonic-gate
6227c478bd9Sstevel@tonic-gate bread(fsbtodb(&sblock, gip->di_ib[0]), (char *)ibuf, sizeof (ibuf));
6237c478bd9Sstevel@tonic-gate
6247c478bd9Sstevel@tonic-gate return (ibuf[i]);
6257c478bd9Sstevel@tonic-gate }
6267c478bd9Sstevel@tonic-gate
6277c478bd9Sstevel@tonic-gate void
usage()6287c478bd9Sstevel@tonic-gate usage()
6297c478bd9Sstevel@tonic-gate {
6307c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
6317c478bd9Sstevel@tonic-gate /*CSTYLED*/
6327c478bd9Sstevel@tonic-gate "ufs usage: ncheck [-F ufs] [generic options] [-a -i #list -s] [-o m] special\n");
6337c478bd9Sstevel@tonic-gate exit(32);
6347c478bd9Sstevel@tonic-gate }
6357c478bd9Sstevel@tonic-gate
6367c478bd9Sstevel@tonic-gate
6377c478bd9Sstevel@tonic-gate /*
6387c478bd9Sstevel@tonic-gate * Extend or create the inode list;
6397c478bd9Sstevel@tonic-gate * this is used to contains the list of inodes we've been
6407c478bd9Sstevel@tonic-gate * asked to check using the "-i" flag and to hold the
6417c478bd9Sstevel@tonic-gate * inode numbers of files which we detect as being
6427c478bd9Sstevel@tonic-gate * blk|char|setuid|setgid ("-s" flag support).
6437c478bd9Sstevel@tonic-gate * Preserves contents.
6447c478bd9Sstevel@tonic-gate */
6457c478bd9Sstevel@tonic-gate void
extend_ilist()6467c478bd9Sstevel@tonic-gate extend_ilist()
6477c478bd9Sstevel@tonic-gate {
6487c478bd9Sstevel@tonic-gate ilist_size += ILIST_SZ_INCR;
6497c478bd9Sstevel@tonic-gate ilist = (struct ilist *)realloc(ilist,
6507c478bd9Sstevel@tonic-gate (ilist_size * sizeof (struct ilist)));
6517c478bd9Sstevel@tonic-gate
6527c478bd9Sstevel@tonic-gate if (ilist == NULL) {
6537c478bd9Sstevel@tonic-gate perror("ncheck: not enough memory to grow ilist\n");
6547c478bd9Sstevel@tonic-gate exit(32);
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate }
6577c478bd9Sstevel@tonic-gate
6587c478bd9Sstevel@tonic-gate /*
6597c478bd9Sstevel@tonic-gate * Extend or create the string table.
6607c478bd9Sstevel@tonic-gate * Preserves contents.
6617c478bd9Sstevel@tonic-gate * Return non-zero for success.
6627c478bd9Sstevel@tonic-gate */
6637c478bd9Sstevel@tonic-gate int
extend_strngtab(unsigned int size)664*d1a180b0Smaheshvs extend_strngtab(unsigned int size)
6657c478bd9Sstevel@tonic-gate {
6667c478bd9Sstevel@tonic-gate strngtab_size += size;
6677c478bd9Sstevel@tonic-gate strngtab = (char *)realloc(strngtab, strngtab_size);
6687c478bd9Sstevel@tonic-gate
6697c478bd9Sstevel@tonic-gate return ((int)strngtab);
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate
6727c478bd9Sstevel@tonic-gate /*
6737c478bd9Sstevel@tonic-gate * Extend or create a table, throwing away previous
6747c478bd9Sstevel@tonic-gate * contents.
6757c478bd9Sstevel@tonic-gate * Return null on failure.
6767c478bd9Sstevel@tonic-gate */
6777c478bd9Sstevel@tonic-gate uchar_t *
extend_tbl(uchar_t * tbl,unsigned int * current_size,unsigned int new_size)678*d1a180b0Smaheshvs extend_tbl(uchar_t *tbl, unsigned int *current_size, unsigned int new_size)
6797c478bd9Sstevel@tonic-gate {
6807c478bd9Sstevel@tonic-gate /*
6817c478bd9Sstevel@tonic-gate * if we've already allocated tbl,
6827c478bd9Sstevel@tonic-gate * but it is too small, free it.
6837c478bd9Sstevel@tonic-gate * we don't realloc because we are throwing
6847c478bd9Sstevel@tonic-gate * away its contents.
6857c478bd9Sstevel@tonic-gate */
6867c478bd9Sstevel@tonic-gate
6877c478bd9Sstevel@tonic-gate if (tbl && (*current_size < new_size)) {
6887c478bd9Sstevel@tonic-gate free(tbl);
6897c478bd9Sstevel@tonic-gate tbl = NULL;
6907c478bd9Sstevel@tonic-gate }
6917c478bd9Sstevel@tonic-gate
6927c478bd9Sstevel@tonic-gate if (tbl == NULL) {
6937c478bd9Sstevel@tonic-gate tbl = (uchar_t *)malloc(new_size);
6947c478bd9Sstevel@tonic-gate if (tbl == 0)
6957c478bd9Sstevel@tonic-gate return ((uchar_t *)0);
6967c478bd9Sstevel@tonic-gate
6977c478bd9Sstevel@tonic-gate *current_size = new_size;
6987c478bd9Sstevel@tonic-gate }
6997c478bd9Sstevel@tonic-gate (void) memset(tbl, 0, new_size);
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate return (tbl);
7027c478bd9Sstevel@tonic-gate }
703