13125Sdg/*
23125Sdg * Copyright (c) 1994 Christopher G. Demetriou
33125Sdg * All rights reserved.
43125Sdg *
53125Sdg * Redistribution and use in source and binary forms, with or without
63125Sdg * modification, are permitted provided that the following conditions
73125Sdg * are met:
83125Sdg * 1. Redistributions of source code must retain the above copyright
93125Sdg *    notice, this list of conditions and the following disclaimer.
103125Sdg * 2. Redistributions in binary form must reproduce the above copyright
113125Sdg *    notice, this list of conditions and the following disclaimer in the
123125Sdg *    documentation and/or other materials provided with the distribution.
133125Sdg * 3. All advertising materials mentioning features or use of this software
143125Sdg *    must display the following acknowledgement:
153125Sdg *      This product includes software developed by Christopher G. Demetriou.
163125Sdg * 4. The name of the author may not be used to endorse or promote products
173125Sdg *    derived from this software without specific prior written permission
183125Sdg *
193125Sdg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
203125Sdg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
213125Sdg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
223125Sdg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
233125Sdg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
243125Sdg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
253125Sdg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
263125Sdg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
273125Sdg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
283125Sdg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
293125Sdg */
303125Sdg
31114601Sobrien#if 0
3230425Scharnier#ifndef lint
3330425Scharnierstatic const char copyright[] =
343125Sdg"@(#) Copyright (c) 1994 Christopher G. Demetriou\n\
353125Sdg All rights reserved.\n";
363125Sdg#endif
37114601Sobrien#endif
38114601Sobrien#include <sys/cdefs.h>
39114601Sobrien__FBSDID("$FreeBSD$");
403125Sdg
413125Sdg/*
423125Sdg * sa:	system accounting
433125Sdg */
443125Sdg
453125Sdg#include <sys/types.h>
463125Sdg#include <sys/acct.h>
473125Sdg#include <ctype.h>
483125Sdg#include <err.h>
49169857Sdds#include <errno.h>
503125Sdg#include <fcntl.h>
513125Sdg#include <signal.h>
52100107Sdes#include <stdint.h>
533125Sdg#include <stdio.h>
543125Sdg#include <stdlib.h>
5513558Smpp#include <string.h>
563125Sdg#include <unistd.h>
573125Sdg#include "extern.h"
583125Sdg#include "pathnames.h"
593125Sdg
60169857Sddsstatic FILE	*acct_load(const char *, int);
61169857Sddsstatic int	 cmp_comm(const char *, const char *);
62169857Sddsstatic int	 cmp_usrsys(const DBT *, const DBT *);
63169857Sddsstatic int	 cmp_avgusrsys(const DBT *, const DBT *);
64169857Sddsstatic int	 cmp_dkio(const DBT *, const DBT *);
65169857Sddsstatic int	 cmp_avgdkio(const DBT *, const DBT *);
66169857Sddsstatic int	 cmp_cpumem(const DBT *, const DBT *);
67169857Sddsstatic int	 cmp_avgcpumem(const DBT *, const DBT *);
68169857Sddsstatic int	 cmp_calls(const DBT *, const DBT *);
69169857Sddsstatic void	 usage(void);
703125Sdg
713125Sdgint aflag, bflag, cflag, dflag, Dflag, fflag, iflag, jflag, kflag;
723125Sdgint Kflag, lflag, mflag, qflag, rflag, sflag, tflag, uflag, vflag;
7399829Salfredu_quad_t cutoff = 1;
74169670Sddsconst char *pdb_file = _PATH_SAVACCT;
75169670Sddsconst char *usrdb_file = _PATH_USRACCT;
763125Sdg
7799829Salfredstatic char	*dfltargv[] = { NULL };
783125Sdgstatic int	dfltargc = (sizeof dfltargv/sizeof(char *));
793125Sdg
803125Sdg/* default to comparing by sum of user + system time */
813125Sdgcmpf_t   sa_cmp = cmp_usrsys;
823125Sdg
833125Sdgint
8499829Salfredmain(int argc, char **argv)
853125Sdg{
86169857Sdds	FILE *f;
8799829Salfred	char pathacct[] = _PATH_ACCT;
88124830Sgrehan	int ch, error = 0;
893125Sdg
9099829Salfred	dfltargv[0] = pathacct;
9199829Salfred
92169670Sdds	while ((ch = getopt(argc, argv, "abcdDfijkKlmnP:qrstuU:v:")) != -1)
933125Sdg		switch (ch) {
943125Sdg			case 'a':
953125Sdg				/* print all commands */
963125Sdg				aflag = 1;
973125Sdg				break;
983125Sdg			case 'b':
993125Sdg				/* sort by per-call user/system time average */
1003125Sdg				bflag = 1;
1013125Sdg				sa_cmp = cmp_avgusrsys;
1023125Sdg				break;
1033125Sdg			case 'c':
1043125Sdg				/* print percentage total time */
1053125Sdg				cflag = 1;
1063125Sdg				break;
1073125Sdg			case 'd':
1083125Sdg				/* sort by averge number of disk I/O ops */
1093125Sdg				dflag = 1;
1103125Sdg				sa_cmp = cmp_avgdkio;
1113125Sdg				break;
1123125Sdg			case 'D':
1133125Sdg				/* print and sort by total disk I/O ops */
1143125Sdg				Dflag = 1;
1153125Sdg				sa_cmp = cmp_dkio;
1163125Sdg				break;
1173125Sdg			case 'f':
1183125Sdg				/* force no interactive threshold comprison */
1193125Sdg				fflag = 1;
1203125Sdg				break;
1213125Sdg			case 'i':
1223125Sdg				/* do not read in summary file */
1233125Sdg				iflag = 1;
1243125Sdg				break;
1253125Sdg			case 'j':
1263125Sdg				/* instead of total minutes, give sec/call */
1273125Sdg				jflag = 1;
1283125Sdg				break;
1293125Sdg			case 'k':
1303125Sdg				/* sort by cpu-time average memory usage */
1313125Sdg				kflag = 1;
1323125Sdg				sa_cmp = cmp_avgcpumem;
1333125Sdg				break;
1343125Sdg			case 'K':
1353125Sdg				/* print and sort by cpu-storage integral */
1363125Sdg				sa_cmp = cmp_cpumem;
1373125Sdg				Kflag = 1;
1383125Sdg				break;
1393125Sdg			case 'l':
14072091Sasmodai				/* separate system and user time */
1413125Sdg				lflag = 1;
1423125Sdg				break;
1433125Sdg			case 'm':
1443125Sdg				/* print procs and time per-user */
1453125Sdg				mflag = 1;
1463125Sdg				break;
1473125Sdg			case 'n':
1483125Sdg				/* sort by number of calls */
1493125Sdg				sa_cmp = cmp_calls;
1503125Sdg				break;
151169670Sdds			case 'P':
152169670Sdds				/* specify program database summary file */
153169670Sdds				pdb_file = optarg;
154169670Sdds				break;
1553125Sdg			case 'q':
1563125Sdg				/* quiet; error messages only */
1573125Sdg				qflag = 1;
1583125Sdg				break;
1593125Sdg			case 'r':
1603125Sdg				/* reverse order of sort */
1613125Sdg				rflag = 1;
1623125Sdg				break;
1633125Sdg			case 's':
1643125Sdg				/* merge accounting file into summaries */
1653125Sdg				sflag = 1;
1663125Sdg				break;
1673125Sdg			case 't':
1683125Sdg				/* report ratio of user and system times */
1693125Sdg				tflag = 1;
1703125Sdg				break;
1713125Sdg			case 'u':
1723125Sdg				/* first, print uid and command name */
1733125Sdg				uflag = 1;
1743125Sdg				break;
175169670Sdds			case 'U':
176169670Sdds				/* specify user database summary file */
177169670Sdds				usrdb_file = optarg;
178169670Sdds				break;
1793125Sdg			case 'v':
1803125Sdg				/* cull junk */
1813125Sdg				vflag = 1;
1823125Sdg				cutoff = atoi(optarg);
1833125Sdg				break;
1843125Sdg			case '?':
1853125Sdg	                default:
18630425Scharnier				usage();
1873125Sdg		}
1883125Sdg
1893125Sdg	argc -= optind;
1903125Sdg	argv += optind;
1913125Sdg
1923125Sdg	/* various argument checking */
1933125Sdg	if (fflag && !vflag)
1943125Sdg		errx(1, "only one of -f requires -v");
1953125Sdg	if (fflag && aflag)
1963125Sdg		errx(1, "only one of -a and -v may be specified");
1973125Sdg	/* XXX need more argument checking */
1983125Sdg
1993125Sdg	if (!uflag) {
2003125Sdg		/* initialize tables */
2013125Sdg		if ((sflag || (!mflag && !qflag)) && pacct_init() != 0)
2023125Sdg			errx(1, "process accounting initialization failed");
2033125Sdg		if ((sflag || (mflag && !qflag)) && usracct_init() != 0)
2043125Sdg			errx(1, "user accounting initialization failed");
2053125Sdg	}
2063125Sdg
2073125Sdg	if (argc == 0) {
2083125Sdg		argc = dfltargc;
2093125Sdg		argv = dfltargv;
2103125Sdg	}
2113125Sdg
2123125Sdg	/* for each file specified */
2133125Sdg	for (; argc > 0; argc--, argv++) {
2143125Sdg		/*
2153125Sdg		 * load the accounting data from the file.
2163125Sdg		 * if it fails, go on to the next file.
2173125Sdg		 */
218169857Sdds		f = acct_load(argv[0], sflag);
219169857Sdds		if (f == NULL)
2203125Sdg			continue;
2213125Sdg
2223125Sdg		if (!uflag && sflag) {
2233125Sdg#ifndef DEBUG
2243125Sdg			sigset_t nmask, omask;
2253125Sdg			int unmask = 1;
2263125Sdg
2273125Sdg			/*
2283125Sdg			 * block most signals so we aren't interrupted during
2293125Sdg			 * the update.
2303125Sdg			 */
2313125Sdg			if (sigfillset(&nmask) == -1) {
2323125Sdg				warn("sigfillset");
2333125Sdg				unmask = 0;
2343125Sdg				error = 1;
2353125Sdg			}
2368857Srgrimes			if (unmask &&
2373125Sdg			    (sigprocmask(SIG_BLOCK, &nmask, &omask) == -1)) {
23830425Scharnier				warn("couldn't set signal mask");
2393125Sdg				unmask = 0;
2403125Sdg				error = 1;
2413125Sdg			}
2423125Sdg#endif /* DEBUG */
2433125Sdg
2443125Sdg			/*
2453125Sdg			 * truncate the accounting data file ASAP, to avoid
2463125Sdg			 * losing data.  don't worry about errors in updating
2473125Sdg			 * the saved stats; better to underbill than overbill,
2483125Sdg			 * but we want every accounting record intact.
2493125Sdg			 */
250169857Sdds			if (ftruncate(fileno(f), 0) == -1) {
25199829Salfred				warn("couldn't truncate %s", *argv);
2523125Sdg				error = 1;
2533125Sdg			}
2543125Sdg
2553125Sdg			/*
2563125Sdg			 * update saved user and process accounting data.
2573125Sdg			 * note errors for later.
2583125Sdg			 */
2593125Sdg			if (pacct_update() != 0 || usracct_update() != 0)
2603125Sdg				error = 1;
2613125Sdg
2623125Sdg#ifndef DEBUG
2633125Sdg			/*
2643125Sdg			 * restore signals
2653125Sdg			 */
2663125Sdg			if (unmask &&
2673125Sdg			    (sigprocmask(SIG_SETMASK, &omask, NULL) == -1)) {
2683125Sdg				warn("couldn't restore signal mask");
2693125Sdg				error = 1;
2703125Sdg			}
2713125Sdg#endif /* DEBUG */
2723125Sdg		}
2733125Sdg
2743125Sdg		/*
2753125Sdg		 * close the opened accounting file
2763125Sdg		 */
277169857Sdds		if (fclose(f) == EOF) {
278169857Sdds			warn("fclose %s", *argv);
2793125Sdg			error = 1;
2803125Sdg		}
2813125Sdg	}
2823125Sdg
2833125Sdg	if (!uflag && !qflag) {
2843125Sdg		/* print any results we may have obtained. */
2853125Sdg		if (!mflag)
2863125Sdg			pacct_print();
2873125Sdg		else
2883125Sdg			usracct_print();
2893125Sdg	}
2903125Sdg
2913125Sdg	if (!uflag) {
2923125Sdg		/* finally, deallocate databases */
2933125Sdg		if (sflag || (!mflag && !qflag))
2943125Sdg			pacct_destroy();
2953125Sdg		if (sflag || (mflag && !qflag))
2963125Sdg			usracct_destroy();
2973125Sdg	}
2983125Sdg
2993125Sdg	exit(error);
3003125Sdg}
3013125Sdg
30230425Scharnierstatic void
303201227Sedusage(void)
30430425Scharnier{
30530425Scharnier	(void)fprintf(stderr,
306169670Sdds		"usage: sa [-abcdDfijkKlmnqrstu] [-P file] [-U file] [-v cutoff] [file ...]\n");
30730425Scharnier	exit(1);
30830425Scharnier}
30930425Scharnier
310169857Sddsstatic FILE *
311141638Sdelphijacct_load(const char *pn, int wr)
3123125Sdg{
313169857Sdds	struct acctv2 ac;
3143125Sdg	struct cmdinfo ci;
3153125Sdg	ssize_t rv;
316169857Sdds	FILE *f;
317169857Sdds	int i;
3183125Sdg
3193125Sdg	/*
3203125Sdg	 * open the file
3213125Sdg	 */
322169857Sdds	f = fopen(pn, wr ? "r+" : "r");
323169857Sdds	if (f == NULL) {
3243125Sdg		warn("open %s %s", pn, wr ? "for read/write" : "read-only");
325169857Sdds		return (NULL);
3263125Sdg	}
3273125Sdg
3283125Sdg	/*
3293125Sdg	 * read all we can; don't stat and open because more processes
3303125Sdg	 * could exit, and we'd miss them
3313125Sdg	 */
3323125Sdg	while (1) {
3333125Sdg		/* get one accounting entry and punt if there's an error */
334169857Sdds		rv = readrec_forward(f, &ac);
335169857Sdds		if (rv != 1) {
336169857Sdds			if (rv == EOF)
337169857Sdds				warn("error reading %s", pn);
3383125Sdg			break;
339169857Sdds		}
3403125Sdg
3413125Sdg		/* decode it */
3423125Sdg		ci.ci_calls = 1;
34399829Salfred		for (i = 0; i < (int)sizeof ac.ac_comm && ac.ac_comm[i] != '\0';
3443125Sdg		    i++) {
3453125Sdg			char c = ac.ac_comm[i];
3463125Sdg
3473125Sdg			if (!isascii(c) || iscntrl(c)) {
3483125Sdg				ci.ci_comm[i] = '?';
3493125Sdg				ci.ci_flags |= CI_UNPRINTABLE;
3503125Sdg			} else
3513125Sdg				ci.ci_comm[i] = c;
3523125Sdg		}
353169857Sdds		if (ac.ac_flagx & AFORK)
3543125Sdg			ci.ci_comm[i++] = '*';
3553125Sdg		ci.ci_comm[i++] = '\0';
356169857Sdds		ci.ci_etime = ac.ac_etime;
357169857Sdds		ci.ci_utime = ac.ac_utime;
358169857Sdds		ci.ci_stime = ac.ac_stime;
3593125Sdg		ci.ci_uid = ac.ac_uid;
3603125Sdg		ci.ci_mem = ac.ac_mem;
361169857Sdds		ci.ci_io = ac.ac_io;
3623125Sdg
3633125Sdg		if (!uflag) {
3643125Sdg			/* and enter it into the usracct and pacct databases */
3653125Sdg			if (sflag || (!mflag && !qflag))
3663125Sdg				pacct_add(&ci);
3673125Sdg			if (sflag || (mflag && !qflag))
3683125Sdg				usracct_add(&ci);
3693125Sdg		} else if (!qflag)
370169857Sdds			printf("%6u %12.3lf cpu %12.0lfk mem %12.0lf io %s\n",
3713125Sdg			    ci.ci_uid,
372169857Sdds			    (ci.ci_utime + ci.ci_stime) / 1000000,
373169857Sdds			    ci.ci_mem, ci.ci_io,
374100107Sdes			    ci.ci_comm);
3753125Sdg	}
3763125Sdg
377169857Sdds	/* Finally, return the file stream for possible truncation. */
378169857Sdds	return (f);
3793125Sdg}
3803125Sdg
3813125Sdg/* sort commands, doing the right thing in terms of reversals */
3823125Sdgstatic int
383141638Sdelphijcmp_comm(const char *s1, const char *s2)
3843125Sdg{
3853125Sdg	int rv;
3863125Sdg
3873125Sdg	rv = strcmp(s1, s2);
3883125Sdg	if (rv == 0)
3893125Sdg		rv = -1;
3903125Sdg	return (rflag ? rv : -rv);
3913125Sdg}
3923125Sdg
3933125Sdg/* sort by total user and system time */
3943125Sdgstatic int
395141638Sdelphijcmp_usrsys(const DBT *d1, const DBT *d2)
3963125Sdg{
39767642Sgallatin	struct cmdinfo c1, c2;
398169857Sdds	double t1, t2;
3993125Sdg
40067642Sgallatin	memcpy(&c1, d1->data, sizeof(c1));
40167642Sgallatin	memcpy(&c2, d2->data, sizeof(c2));
4023125Sdg
40367642Sgallatin	t1 = c1.ci_utime + c1.ci_stime;
40467642Sgallatin	t2 = c2.ci_utime + c2.ci_stime;
4053125Sdg
4063125Sdg	if (t1 < t2)
4073125Sdg		return -1;
4083125Sdg	else if (t1 == t2)
40967642Sgallatin		return (cmp_comm(c1.ci_comm, c2.ci_comm));
4103125Sdg	else
4113125Sdg		return 1;
4123125Sdg}
4133125Sdg
4143125Sdg/* sort by average user and system time */
4153125Sdgstatic int
416141638Sdelphijcmp_avgusrsys(const DBT *d1, const DBT *d2)
4173125Sdg{
41867642Sgallatin	struct cmdinfo c1, c2;
4193125Sdg	double t1, t2;
4203125Sdg
42167642Sgallatin	memcpy(&c1, d1->data, sizeof(c1));
42267642Sgallatin	memcpy(&c2, d2->data, sizeof(c2));
4233125Sdg
42467642Sgallatin	t1 = c1.ci_utime + c1.ci_stime;
42567642Sgallatin	t1 /= (double) (c1.ci_calls ? c1.ci_calls : 1);
4263125Sdg
42767642Sgallatin	t2 = c2.ci_utime + c2.ci_stime;
42867642Sgallatin	t2 /= (double) (c2.ci_calls ? c2.ci_calls : 1);
4293125Sdg
4303125Sdg	if (t1 < t2)
4313125Sdg		return -1;
4323125Sdg	else if (t1 == t2)
43367642Sgallatin		return (cmp_comm(c1.ci_comm, c2.ci_comm));
4343125Sdg	else
4353125Sdg		return 1;
4363125Sdg}
4373125Sdg
4383125Sdg/* sort by total number of disk I/O operations */
4393125Sdgstatic int
440141638Sdelphijcmp_dkio(const DBT *d1, const DBT *d2)
4413125Sdg{
44267642Sgallatin	struct cmdinfo c1, c2;
4433125Sdg
44467642Sgallatin	memcpy(&c1, d1->data, sizeof(c1));
44567642Sgallatin	memcpy(&c2, d2->data, sizeof(c2));
4463125Sdg
44767642Sgallatin	if (c1.ci_io < c2.ci_io)
4483125Sdg		return -1;
44967642Sgallatin	else if (c1.ci_io == c2.ci_io)
45067642Sgallatin		return (cmp_comm(c1.ci_comm, c2.ci_comm));
4513125Sdg	else
4523125Sdg		return 1;
4533125Sdg}
4543125Sdg
4553125Sdg/* sort by average number of disk I/O operations */
4563125Sdgstatic int
457141638Sdelphijcmp_avgdkio(const DBT *d1, const DBT *d2)
4583125Sdg{
45967642Sgallatin	struct cmdinfo c1, c2;
4603125Sdg	double n1, n2;
4613125Sdg
46267642Sgallatin	memcpy(&c1, d1->data, sizeof(c1));
46367642Sgallatin	memcpy(&c2, d2->data, sizeof(c2));
4643125Sdg
465169857Sdds	n1 = c1.ci_io / (double) (c1.ci_calls ? c1.ci_calls : 1);
466169857Sdds	n2 = c2.ci_io / (double) (c2.ci_calls ? c2.ci_calls : 1);
4673125Sdg
4683125Sdg	if (n1 < n2)
4693125Sdg		return -1;
4703125Sdg	else if (n1 == n2)
47167642Sgallatin		return (cmp_comm(c1.ci_comm, c2.ci_comm));
4723125Sdg	else
4733125Sdg		return 1;
4743125Sdg}
4753125Sdg
4763125Sdg/* sort by the cpu-storage integral */
4773125Sdgstatic int
478141638Sdelphijcmp_cpumem(const DBT *d1, const DBT *d2)
4793125Sdg{
48067642Sgallatin	struct cmdinfo c1, c2;
4813125Sdg
48267642Sgallatin	memcpy(&c1, d1->data, sizeof(c1));
48367642Sgallatin	memcpy(&c2, d2->data, sizeof(c2));
4843125Sdg
48567642Sgallatin	if (c1.ci_mem < c2.ci_mem)
4863125Sdg		return -1;
48767642Sgallatin	else if (c1.ci_mem == c2.ci_mem)
48867642Sgallatin		return (cmp_comm(c1.ci_comm, c2.ci_comm));
4893125Sdg	else
4903125Sdg		return 1;
4913125Sdg}
4923125Sdg
4933125Sdg/* sort by the cpu-time average memory usage */
4943125Sdgstatic int
495141638Sdelphijcmp_avgcpumem(const DBT *d1, const DBT *d2)
4963125Sdg{
49767642Sgallatin	struct cmdinfo c1, c2;
498169857Sdds	double t1, t2;
4993125Sdg	double n1, n2;
5003125Sdg
50167642Sgallatin	memcpy(&c1, d1->data, sizeof(c1));
50267642Sgallatin	memcpy(&c2, d2->data, sizeof(c2));
5033125Sdg
50467642Sgallatin	t1 = c1.ci_utime + c1.ci_stime;
50567642Sgallatin	t2 = c2.ci_utime + c2.ci_stime;
5063125Sdg
507169857Sdds	n1 = c1.ci_mem / (t1 ? t1 : 1);
508169857Sdds	n2 = c2.ci_mem / (t2 ? t2 : 1);
5093125Sdg
5103125Sdg	if (n1 < n2)
5113125Sdg		return -1;
5123125Sdg	else if (n1 == n2)
51367642Sgallatin		return (cmp_comm(c1.ci_comm, c2.ci_comm));
5143125Sdg	else
5153125Sdg		return 1;
5163125Sdg}
5173125Sdg
5183125Sdg/* sort by the number of invocations */
5193125Sdgstatic int
520141638Sdelphijcmp_calls(const DBT *d1, const DBT *d2)
5213125Sdg{
52267642Sgallatin	struct cmdinfo c1, c2;
5233125Sdg
52467642Sgallatin	memcpy(&c1, d1->data, sizeof(c1));
52567642Sgallatin	memcpy(&c2, d2->data, sizeof(c2));
5263125Sdg
52767642Sgallatin	if (c1.ci_calls < c2.ci_calls)
5283125Sdg		return -1;
52967642Sgallatin	else if (c1.ci_calls == c2.ci_calls)
53067642Sgallatin		return (cmp_comm(c1.ci_comm, c2.ci_comm));
5313125Sdg	else
5323125Sdg		return 1;
5333125Sdg}
534