12334Scsgr/*
22334Scsgr * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
32334Scsgr * unrestricted use provided that this legend is included on all tape
42334Scsgr * media and as a part of the software program in whole or part.  Users
52334Scsgr * may copy or modify Sun RPC without charge, but are not authorized
62334Scsgr * to license or distribute it to anyone else except as part of a product or
72334Scsgr * program developed by the user.
82334Scsgr *
92334Scsgr * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
102334Scsgr * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
112334Scsgr * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
122334Scsgr *
132334Scsgr * Sun RPC is provided with no support and without any obligation on the
142334Scsgr * part of Sun Microsystems, Inc. to assist in its use, correction,
152334Scsgr * modification or enhancement.
162334Scsgr *
172334Scsgr * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
182334Scsgr * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
192334Scsgr * OR ANY PART THEREOF.
202334Scsgr *
212334Scsgr * In no event will Sun Microsystems, Inc. be liable for any lost revenue
222334Scsgr * or profits or other special, indirect and consequential damages, even if
232334Scsgr * Sun has been advised of the possibility of such damages.
242334Scsgr *
252334Scsgr * Sun Microsystems, Inc.
262334Scsgr * 2550 Garcia Avenue
272334Scsgr * Mountain View, California  94043
282334Scsgr */
2931421Scharnier
302334Scsgr#ifndef lint
3131421Scharnier#if 0
3231421Scharnierstatic char sccsid[] = "from: @(#)rpc.rstatd.c 1.1 86/09/25 Copyr 1984 Sun Micro";
3331421Scharnierstatic char sccsid[] = "from: @(#)rstat_proc.c	2.2 88/08/01 4.0 RPCSRC";
342334Scsgr#endif
3531421Scharnierstatic const char rcsid[] =
3650476Speter  "$FreeBSD$";
3731421Scharnier#endif
382334Scsgr
392334Scsgr/*
402334Scsgr * rstat service:  built with rstat.x and derived from rpc.rstatd.c
412334Scsgr *
422334Scsgr * Copyright (c) 1984 by Sun Microsystems, Inc.
432334Scsgr */
442334Scsgr
4520333Swollman#include <sys/types.h>
4620333Swollman#include <sys/socket.h>
4720333Swollman#include <sys/sysctl.h>
4820333Swollman#include <sys/time.h>
49111005Sphk#include <sys/resource.h>
5020333Swollman#include <sys/vmmeter.h>
5139228Sgibbs#include <sys/param.h>
5220333Swollman
5331421Scharnier#include <err.h>
5485040Sfenner#include <errno.h>
552334Scsgr#include <fcntl.h>
562334Scsgr#include <limits.h>
572334Scsgr#include <signal.h>
582334Scsgr#include <stdio.h>
592334Scsgr#include <stdlib.h>
602334Scsgr#include <string.h>
612334Scsgr#include <syslog.h>
6231421Scharnier#include <unistd.h>
6339228Sgibbs#include <devstat.h>
642334Scsgr
652334Scsgr#include <net/if.h>
6620333Swollman#include <net/if_mib.h>
672334Scsgr
682334Scsgr#undef FSHIFT			 /* Use protocol's shift and scale values */
692334Scsgr#undef FSCALE
702334Scsgr#undef if_ipackets
712334Scsgr#undef if_ierrors
722334Scsgr#undef if_opackets
732334Scsgr#undef if_oerrors
742334Scsgr#undef if_collisions
752334Scsgr#include <rpcsvc/rstat.h>
762334Scsgr
77104384Smikeint haveadisk(void);
7890336Simpvoid updatexfers(int, int *);
7990336Simpint stats_service(void);
802334Scsgr
812334Scsgrextern int from_inetd;
822334Scsgrint sincelastreq = 0;		/* number of alarms since last request */
832334Scsgrextern int closedown;
842334Scsgr
852334Scsgrunion {
862334Scsgr    struct stats s1;
872334Scsgr    struct statsswtch s2;
882334Scsgr    struct statstime s3;
892334Scsgr} stats_all;
902334Scsgr
912334Scsgrvoid updatestat();
92115667Sobrienstatic int stat_is_init = 0;
932334Scsgr
948870Srgrimesstatic int	cp_time_xlat[RSTAT_CPUSTATES] = { CP_USER, CP_NICE, CP_SYS,
952334Scsgr							CP_IDLE };
962334Scsgrstatic long	bsd_cp_time[CPUSTATES];
972334Scsgr
982334Scsgr
992334Scsgr#ifndef FSCALE
1002334Scsgr#define FSCALE (1 << 8)
1012334Scsgr#endif
1022334Scsgr
10331421Scharniervoid
10490336Simpstat_init(void)
1052334Scsgr{
1062334Scsgr    stat_is_init = 1;
10781080Sjon    alarm(0);
1082334Scsgr    updatestat();
1092334Scsgr    (void) signal(SIGALRM, updatestat);
1102334Scsgr    alarm(1);
1112334Scsgr}
1122334Scsgr
1132334Scsgrstatstime *
11490336Simprstatproc_stats_3_svc(void *argp, struct svc_req *rqstp)
1152334Scsgr{
1162334Scsgr    if (! stat_is_init)
1172334Scsgr        stat_init();
1182334Scsgr    sincelastreq = 0;
1192334Scsgr    return(&stats_all.s3);
1202334Scsgr}
1212334Scsgr
1222334Scsgrstatsswtch *
12390336Simprstatproc_stats_2_svc(void *argp, struct svc_req *rqstp)
1242334Scsgr{
1252334Scsgr    if (! stat_is_init)
1262334Scsgr        stat_init();
1272334Scsgr    sincelastreq = 0;
1282334Scsgr    return(&stats_all.s2);
1292334Scsgr}
1302334Scsgr
1312334Scsgrstats *
13290336Simprstatproc_stats_1_svc(void *argp, struct svc_req *rqstp)
1332334Scsgr{
1342334Scsgr    if (! stat_is_init)
1352334Scsgr        stat_init();
1362334Scsgr    sincelastreq = 0;
1372334Scsgr    return(&stats_all.s1);
1382334Scsgr}
1392334Scsgr
1402334Scsgru_int *
14190336Simprstatproc_havedisk_3_svc(void *argp, struct svc_req *rqstp)
1422334Scsgr{
1432334Scsgr    static u_int have;
1442334Scsgr
1452334Scsgr    if (! stat_is_init)
1462334Scsgr        stat_init();
1472334Scsgr    sincelastreq = 0;
148104384Smike    have = haveadisk();
1492334Scsgr	return(&have);
1502334Scsgr}
1512334Scsgr
1522334Scsgru_int *
15390336Simprstatproc_havedisk_2_svc(void *argp, struct svc_req *rqstp)
1542334Scsgr{
15532629Swpaul    return(rstatproc_havedisk_3_svc(argp, rqstp));
1562334Scsgr}
1572334Scsgr
1582334Scsgru_int *
15990336Simprstatproc_havedisk_1_svc(void *argp, struct svc_req *rqstp)
1602334Scsgr{
16132629Swpaul    return(rstatproc_havedisk_3_svc(argp, rqstp));
1622334Scsgr}
1632334Scsgr
1642334Scsgrvoid
16590336Simpupdatestat(void)
1662334Scsgr{
16731421Scharnier	int i, hz;
16820333Swollman	struct clockinfo clockrate;
1692334Scsgr	struct vmmeter cnt;
17020333Swollman	struct ifmibdata ifmd;
1712334Scsgr	double avrun[3];
1722334Scsgr	struct timeval tm, btm;
17320333Swollman	int mib[6];
17420333Swollman	size_t len;
17520333Swollman	int ifcount;
1762334Scsgr
1772334Scsgr#ifdef DEBUG
1782334Scsgr	fprintf(stderr, "entering updatestat\n");
1792334Scsgr#endif
1802334Scsgr	if (sincelastreq >= closedown) {
1812334Scsgr#ifdef DEBUG
1822334Scsgr                fprintf(stderr, "about to closedown\n");
1832334Scsgr#endif
1842334Scsgr                if (from_inetd)
1852334Scsgr                        exit(0);
1862334Scsgr                else {
1872334Scsgr                        stat_is_init = 0;
1882334Scsgr                        return;
1892334Scsgr                }
1902334Scsgr	}
1912334Scsgr	sincelastreq++;
1922334Scsgr
19320333Swollman	mib[0] = CTL_KERN;
19420333Swollman	mib[1] = KERN_CLOCKRATE;
19520333Swollman	len = sizeof clockrate;
19620333Swollman	if (sysctl(mib, 2, &clockrate, &len, 0, 0) < 0) {
19720333Swollman		syslog(LOG_ERR, "sysctl(kern.clockrate): %m");
1982334Scsgr		exit(1);
1992334Scsgr	}
20020333Swollman	hz = clockrate.hz;
20120333Swollman
202179710Sjhb	len = sizeof(bsd_cp_time);
203179710Sjhb	if (sysctlbyname("kern.cp_time", bsd_cp_time, &len, 0, 0) < 0) {
204179710Sjhb		syslog(LOG_ERR, "sysctl(kern.cp_time): %m");
2052334Scsgr		exit(1);
2062334Scsgr	}
2072334Scsgr	for(i = 0; i < RSTAT_CPUSTATES ; i++)
2082334Scsgr		stats_all.s1.cp_time[i] = bsd_cp_time[cp_time_xlat[i]];
20920333Swollman
2102334Scsgr        (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0]));
21120333Swollman
2122334Scsgr	stats_all.s2.avenrun[0] = avrun[0] * FSCALE;
2132334Scsgr	stats_all.s2.avenrun[1] = avrun[1] * FSCALE;
2142334Scsgr	stats_all.s2.avenrun[2] = avrun[2] * FSCALE;
21520333Swollman
21620333Swollman	mib[0] = CTL_KERN;
21720333Swollman	mib[1] = KERN_BOOTTIME;
21820333Swollman	len = sizeof btm;
21920333Swollman	if (sysctl(mib, 2, &btm, &len, 0, 0) < 0) {
22020333Swollman		syslog(LOG_ERR, "sysctl(kern.boottime): %m");
2212334Scsgr		exit(1);
2222334Scsgr	}
22320333Swollman
2242334Scsgr	stats_all.s2.boottime.tv_sec = btm.tv_sec;
2252334Scsgr	stats_all.s2.boottime.tv_usec = btm.tv_usec;
2262334Scsgr
2272334Scsgr
2282334Scsgr#ifdef DEBUG
2292334Scsgr	fprintf(stderr, "%d %d %d %d\n", stats_all.s1.cp_time[0],
2302334Scsgr	    stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]);
2312334Scsgr#endif
2322334Scsgr
233179710Sjhb#define	FETCH_CNT(stat, cnt) do {					\
234179710Sjhb	len = sizeof((stat));						\
235179710Sjhb	if (sysctlbyname("vm.stats." #cnt , &(stat), &len, 0, 0) < 0) { \
236179710Sjhb		syslog(LOG_ERR, "sysctl(vm.stats." #cnt "): %m"); \
237179710Sjhb		exit(1);						\
238179710Sjhb	}								\
239179710Sjhb} while (0)
240179710Sjhb
241179710Sjhb	FETCH_CNT(stats_all.s1.v_pgpgin, vm.v_vnodepgsin);
242179710Sjhb	FETCH_CNT(stats_all.s1.v_pgpgout, vm.v_vnodepgsout);
243179710Sjhb	FETCH_CNT(stats_all.s1.v_pswpin, vm.v_swappgsin);
244179710Sjhb	FETCH_CNT(stats_all.s1.v_pswpout, vm.v_swappgsout);
245179710Sjhb	FETCH_CNT(stats_all.s1.v_intr, sys.v_intr);
246179710Sjhb	FETCH_CNT(stats_all.s2.v_swtch, sys.v_swtch);
247239991Sed	(void)gettimeofday(&tm, NULL);
2482334Scsgr	stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) +
2492334Scsgr	    hz*(tm.tv_usec - btm.tv_usec)/1000000;
2502334Scsgr
25139228Sgibbs	/* update disk transfers */
25239228Sgibbs	updatexfers(RSTAT_DK_NDRIVE, stats_all.s1.dk_xfer);
2532334Scsgr
25420333Swollman	mib[0] = CTL_NET;
25520333Swollman	mib[1] = PF_LINK;
25620333Swollman	mib[2] = NETLINK_GENERIC;
25720333Swollman	mib[3] = IFMIB_SYSTEM;
25820333Swollman	mib[4] = IFMIB_IFCOUNT;
25920333Swollman	len = sizeof ifcount;
26020333Swollman	if (sysctl(mib, 5, &ifcount, &len, 0, 0) < 0) {
26120333Swollman		syslog(LOG_ERR, "sysctl(net.link.generic.system.ifcount): %m");
26220333Swollman		exit(1);
26320333Swollman	}
26420333Swollman
2652334Scsgr	stats_all.s1.if_ipackets = 0;
2662334Scsgr	stats_all.s1.if_opackets = 0;
2672334Scsgr	stats_all.s1.if_ierrors = 0;
2682334Scsgr	stats_all.s1.if_oerrors = 0;
2692334Scsgr	stats_all.s1.if_collisions = 0;
27020333Swollman	for (i = 1; i <= ifcount; i++) {
27120333Swollman		len = sizeof ifmd;
27220333Swollman		mib[3] = IFMIB_IFDATA;
27320333Swollman		mib[4] = i;
27420333Swollman		mib[5] = IFDATA_GENERAL;
27520333Swollman		if (sysctl(mib, 6, &ifmd, &len, 0, 0) < 0) {
27685040Sfenner			if (errno == ENOENT)
27785040Sfenner				continue;
27885040Sfenner
27920333Swollman			syslog(LOG_ERR, "sysctl(net.link.ifdata.%d.general)"
28020333Swollman			       ": %m", i);
2812334Scsgr			exit(1);
2822334Scsgr		}
28320333Swollman
28420333Swollman		stats_all.s1.if_ipackets += ifmd.ifmd_data.ifi_ipackets;
28520333Swollman		stats_all.s1.if_opackets += ifmd.ifmd_data.ifi_opackets;
28620333Swollman		stats_all.s1.if_ierrors += ifmd.ifmd_data.ifi_ierrors;
28720333Swollman		stats_all.s1.if_oerrors += ifmd.ifmd_data.ifi_oerrors;
28820333Swollman		stats_all.s1.if_collisions += ifmd.ifmd_data.ifi_collisions;
2892334Scsgr	}
290239991Sed	(void)gettimeofday(&tm, NULL);
291239991Sed	stats_all.s3.curtime.tv_sec = tm.tv_sec;
292239991Sed	stats_all.s3.curtime.tv_usec = tm.tv_usec;
2932334Scsgr	alarm(1);
2942334Scsgr}
2952334Scsgr
2962334Scsgr/*
2972334Scsgr * returns true if have a disk
2982334Scsgr */
29931421Scharnierint
300104384Smikehaveadisk(void)
3012334Scsgr{
30239228Sgibbs	register int i;
30339228Sgibbs	struct statinfo stats;
30439228Sgibbs	int num_devices, retval = 0;
3052334Scsgr
306112283Sphk	if ((num_devices = devstat_getnumdevs(NULL)) < 0) {
30739228Sgibbs		syslog(LOG_ERR, "rstatd: can't get number of devices: %s",
30839228Sgibbs		       devstat_errbuf);
30939228Sgibbs		exit(1);
31039228Sgibbs	}
3112334Scsgr
312112283Sphk	if (devstat_checkversion(NULL) < 0) {
31339228Sgibbs		syslog(LOG_ERR, "rstatd: %s", devstat_errbuf);
3142334Scsgr		exit(1);
3152334Scsgr	}
31639228Sgibbs
31739228Sgibbs	stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
31839228Sgibbs	bzero(stats.dinfo, sizeof(struct devinfo));
31939228Sgibbs
320112283Sphk	if (devstat_getdevs(NULL, &stats) == -1) {
32139228Sgibbs		syslog(LOG_ERR, "rstatd: can't get device list: %s",
32239228Sgibbs		       devstat_errbuf);
32339228Sgibbs		exit(1);
32439228Sgibbs	}
32539228Sgibbs	for (i = 0; i < stats.dinfo->numdevs; i++) {
32639228Sgibbs		if (((stats.dinfo->devices[i].device_type
32739228Sgibbs		      & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT)
32839228Sgibbs		 && ((stats.dinfo->devices[i].device_type
32939228Sgibbs		      & DEVSTAT_TYPE_PASS) == 0)) {
33039228Sgibbs			retval = 1;
33139228Sgibbs			break;
33239228Sgibbs		}
33339228Sgibbs	}
33439228Sgibbs
33540078Sken	if (stats.dinfo->mem_ptr)
33640078Sken		free(stats.dinfo->mem_ptr);
33740078Sken
33839228Sgibbs	free(stats.dinfo);
33939228Sgibbs	return(retval);
3402334Scsgr}
3412334Scsgr
3422334Scsgrvoid
34390336Simpupdatexfers(int numdevs, int *devs)
34439228Sgibbs{
345112288Sphk	register int i, j, k, t;
34639228Sgibbs	struct statinfo stats;
34739228Sgibbs	int num_devices = 0;
34839228Sgibbs	u_int64_t total_transfers;
34939228Sgibbs
350112283Sphk	if ((num_devices = devstat_getnumdevs(NULL)) < 0) {
35139228Sgibbs		syslog(LOG_ERR, "rstatd: can't get number of devices: %s",
35239228Sgibbs		       devstat_errbuf);
35339228Sgibbs		exit(1);
35439228Sgibbs	}
35539228Sgibbs
356112283Sphk	if (devstat_checkversion(NULL) < 0) {
35739228Sgibbs		syslog(LOG_ERR, "rstatd: %s", devstat_errbuf);
35839228Sgibbs		exit(1);
35939228Sgibbs	}
36039228Sgibbs
36139228Sgibbs	stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
36239228Sgibbs	bzero(stats.dinfo, sizeof(struct devinfo));
36339228Sgibbs
364112283Sphk	if (devstat_getdevs(NULL, &stats) == -1) {
36539228Sgibbs		syslog(LOG_ERR, "rstatd: can't get device list: %s",
36639228Sgibbs		       devstat_errbuf);
36739228Sgibbs		exit(1);
36839228Sgibbs	}
36939228Sgibbs
37039228Sgibbs	for (i = 0, j = 0; i < stats.dinfo->numdevs && j < numdevs; i++) {
37139228Sgibbs		if (((stats.dinfo->devices[i].device_type
37239228Sgibbs		      & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT)
37339228Sgibbs		 && ((stats.dinfo->devices[i].device_type
37439228Sgibbs		      & DEVSTAT_TYPE_PASS) == 0)) {
375112288Sphk			total_transfers = 0;
376112288Sphk			for (k = 0; k < DEVSTAT_N_TRANS_FLAGS; k++)
377112288Sphk				total_transfers +=
378112288Sphk				    stats.dinfo->devices[i].operations[k];
37939228Sgibbs			/*
38039228Sgibbs			 * XXX KDM If the total transfers for this device
38139228Sgibbs			 * are greater than the amount we can fit in a
38239228Sgibbs			 * signed integer, just set them to the maximum
38339228Sgibbs			 * amount we can fit in a signed integer.  I have a
38439228Sgibbs			 * feeling that the rstat protocol assumes 32-bit
38539228Sgibbs			 * integers, so this could well break on a 64-bit
38639228Sgibbs			 * architecture like the Alpha.
38739228Sgibbs			 */
38839228Sgibbs			if (total_transfers > INT_MAX)
38939383Sdfr				t = INT_MAX;
39039228Sgibbs			else
39139383Sdfr				t = total_transfers;
39239383Sdfr			devs[j] = t;
39339228Sgibbs			j++;
39439228Sgibbs		}
39539228Sgibbs	}
39639228Sgibbs
39740078Sken	if (stats.dinfo->mem_ptr)
39840078Sken		free(stats.dinfo->mem_ptr);
39940078Sken
40039228Sgibbs	free(stats.dinfo);
40139228Sgibbs}
40239228Sgibbs
40339228Sgibbsvoid
40490336Simprstat_service(struct svc_req *rqstp, SVCXPRT *transp)
4052334Scsgr{
4062334Scsgr	union {
4072334Scsgr		int fill;
4082334Scsgr	} argument;
4092334Scsgr	char *result;
4102334Scsgr	bool_t (*xdr_argument)(), (*xdr_result)();
4112334Scsgr	char *(*local)();
4122334Scsgr
4132334Scsgr	switch (rqstp->rq_proc) {
4142334Scsgr	case NULLPROC:
41595658Sdes		(void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL);
4162334Scsgr		goto leave;
4172334Scsgr
4182334Scsgr	case RSTATPROC_STATS:
4192334Scsgr		xdr_argument = xdr_void;
4202334Scsgr		xdr_result = xdr_statstime;
4212334Scsgr                switch (rqstp->rq_vers) {
4222334Scsgr                case RSTATVERS_ORIG:
42332629Swpaul                        local = (char *(*)()) rstatproc_stats_1_svc;
4242334Scsgr                        break;
4252334Scsgr                case RSTATVERS_SWTCH:
42632629Swpaul                        local = (char *(*)()) rstatproc_stats_2_svc;
4272334Scsgr                        break;
4282334Scsgr                case RSTATVERS_TIME:
42932629Swpaul                        local = (char *(*)()) rstatproc_stats_3_svc;
4302334Scsgr                        break;
4312334Scsgr                default:
4322334Scsgr                        svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
4332334Scsgr                        goto leave;
4342334Scsgr                        /*NOTREACHED*/
4352334Scsgr                }
4362334Scsgr		break;
4372334Scsgr
4382334Scsgr	case RSTATPROC_HAVEDISK:
4392334Scsgr		xdr_argument = xdr_void;
4402334Scsgr		xdr_result = xdr_u_int;
4412334Scsgr                switch (rqstp->rq_vers) {
4422334Scsgr                case RSTATVERS_ORIG:
44332629Swpaul                        local = (char *(*)()) rstatproc_havedisk_1_svc;
4442334Scsgr                        break;
4452334Scsgr                case RSTATVERS_SWTCH:
44632629Swpaul                        local = (char *(*)()) rstatproc_havedisk_2_svc;
4472334Scsgr                        break;
4482334Scsgr                case RSTATVERS_TIME:
44932629Swpaul                        local = (char *(*)()) rstatproc_havedisk_3_svc;
4502334Scsgr                        break;
4512334Scsgr                default:
4522334Scsgr                        svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
4532334Scsgr                        goto leave;
4542334Scsgr                        /*NOTREACHED*/
4552334Scsgr                }
4562334Scsgr		break;
4572334Scsgr
4582334Scsgr	default:
4592334Scsgr		svcerr_noproc(transp);
4602334Scsgr		goto leave;
4612334Scsgr	}
4622334Scsgr	bzero((char *)&argument, sizeof(argument));
46395658Sdes	if (!svc_getargs(transp, (xdrproc_t)xdr_argument, &argument)) {
4642334Scsgr		svcerr_decode(transp);
4652334Scsgr		goto leave;
4662334Scsgr	}
4672334Scsgr	result = (*local)(&argument, rqstp);
46895658Sdes	if (result != NULL &&
46995658Sdes	    !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) {
4702334Scsgr		svcerr_systemerr(transp);
4712334Scsgr	}
47295658Sdes	if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, &argument))
47331421Scharnier		errx(1, "unable to free arguments");
4742334Scsgrleave:
4752334Scsgr        if (from_inetd)
4762334Scsgr                exit(0);
4772334Scsgr}
478