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);
2472334Scsgr	gettimeofday(&tm, (struct timezone *) 0);
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	}
2902334Scsgr	gettimeofday((struct timeval *)&stats_all.s3.curtime,
2912334Scsgr		(struct timezone *) 0);
2922334Scsgr	alarm(1);
2932334Scsgr}
2942334Scsgr
2952334Scsgr/*
2962334Scsgr * returns true if have a disk
2972334Scsgr */
29831421Scharnierint
299104384Smikehaveadisk(void)
3002334Scsgr{
30139228Sgibbs	register int i;
30239228Sgibbs	struct statinfo stats;
30339228Sgibbs	int num_devices, retval = 0;
3042334Scsgr
305112283Sphk	if ((num_devices = devstat_getnumdevs(NULL)) < 0) {
30639228Sgibbs		syslog(LOG_ERR, "rstatd: can't get number of devices: %s",
30739228Sgibbs		       devstat_errbuf);
30839228Sgibbs		exit(1);
30939228Sgibbs	}
3102334Scsgr
311112283Sphk	if (devstat_checkversion(NULL) < 0) {
31239228Sgibbs		syslog(LOG_ERR, "rstatd: %s", devstat_errbuf);
3132334Scsgr		exit(1);
3142334Scsgr	}
31539228Sgibbs
31639228Sgibbs	stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
31739228Sgibbs	bzero(stats.dinfo, sizeof(struct devinfo));
31839228Sgibbs
319112283Sphk	if (devstat_getdevs(NULL, &stats) == -1) {
32039228Sgibbs		syslog(LOG_ERR, "rstatd: can't get device list: %s",
32139228Sgibbs		       devstat_errbuf);
32239228Sgibbs		exit(1);
32339228Sgibbs	}
32439228Sgibbs	for (i = 0; i < stats.dinfo->numdevs; i++) {
32539228Sgibbs		if (((stats.dinfo->devices[i].device_type
32639228Sgibbs		      & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT)
32739228Sgibbs		 && ((stats.dinfo->devices[i].device_type
32839228Sgibbs		      & DEVSTAT_TYPE_PASS) == 0)) {
32939228Sgibbs			retval = 1;
33039228Sgibbs			break;
33139228Sgibbs		}
33239228Sgibbs	}
33339228Sgibbs
33440078Sken	if (stats.dinfo->mem_ptr)
33540078Sken		free(stats.dinfo->mem_ptr);
33640078Sken
33739228Sgibbs	free(stats.dinfo);
33839228Sgibbs	return(retval);
3392334Scsgr}
3402334Scsgr
3412334Scsgrvoid
34290336Simpupdatexfers(int numdevs, int *devs)
34339228Sgibbs{
344112288Sphk	register int i, j, k, t;
34539228Sgibbs	struct statinfo stats;
34639228Sgibbs	int num_devices = 0;
34739228Sgibbs	u_int64_t total_transfers;
34839228Sgibbs
349112283Sphk	if ((num_devices = devstat_getnumdevs(NULL)) < 0) {
35039228Sgibbs		syslog(LOG_ERR, "rstatd: can't get number of devices: %s",
35139228Sgibbs		       devstat_errbuf);
35239228Sgibbs		exit(1);
35339228Sgibbs	}
35439228Sgibbs
355112283Sphk	if (devstat_checkversion(NULL) < 0) {
35639228Sgibbs		syslog(LOG_ERR, "rstatd: %s", devstat_errbuf);
35739228Sgibbs		exit(1);
35839228Sgibbs	}
35939228Sgibbs
36039228Sgibbs	stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
36139228Sgibbs	bzero(stats.dinfo, sizeof(struct devinfo));
36239228Sgibbs
363112283Sphk	if (devstat_getdevs(NULL, &stats) == -1) {
36439228Sgibbs		syslog(LOG_ERR, "rstatd: can't get device list: %s",
36539228Sgibbs		       devstat_errbuf);
36639228Sgibbs		exit(1);
36739228Sgibbs	}
36839228Sgibbs
36939228Sgibbs	for (i = 0, j = 0; i < stats.dinfo->numdevs && j < numdevs; i++) {
37039228Sgibbs		if (((stats.dinfo->devices[i].device_type
37139228Sgibbs		      & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT)
37239228Sgibbs		 && ((stats.dinfo->devices[i].device_type
37339228Sgibbs		      & DEVSTAT_TYPE_PASS) == 0)) {
374112288Sphk			total_transfers = 0;
375112288Sphk			for (k = 0; k < DEVSTAT_N_TRANS_FLAGS; k++)
376112288Sphk				total_transfers +=
377112288Sphk				    stats.dinfo->devices[i].operations[k];
37839228Sgibbs			/*
37939228Sgibbs			 * XXX KDM If the total transfers for this device
38039228Sgibbs			 * are greater than the amount we can fit in a
38139228Sgibbs			 * signed integer, just set them to the maximum
38239228Sgibbs			 * amount we can fit in a signed integer.  I have a
38339228Sgibbs			 * feeling that the rstat protocol assumes 32-bit
38439228Sgibbs			 * integers, so this could well break on a 64-bit
38539228Sgibbs			 * architecture like the Alpha.
38639228Sgibbs			 */
38739228Sgibbs			if (total_transfers > INT_MAX)
38839383Sdfr				t = INT_MAX;
38939228Sgibbs			else
39039383Sdfr				t = total_transfers;
39139383Sdfr			devs[j] = t;
39239228Sgibbs			j++;
39339228Sgibbs		}
39439228Sgibbs	}
39539228Sgibbs
39640078Sken	if (stats.dinfo->mem_ptr)
39740078Sken		free(stats.dinfo->mem_ptr);
39840078Sken
39939228Sgibbs	free(stats.dinfo);
40039228Sgibbs}
40139228Sgibbs
40239228Sgibbsvoid
40390336Simprstat_service(struct svc_req *rqstp, SVCXPRT *transp)
4042334Scsgr{
4052334Scsgr	union {
4062334Scsgr		int fill;
4072334Scsgr	} argument;
4082334Scsgr	char *result;
4092334Scsgr	bool_t (*xdr_argument)(), (*xdr_result)();
4102334Scsgr	char *(*local)();
4112334Scsgr
4122334Scsgr	switch (rqstp->rq_proc) {
4132334Scsgr	case NULLPROC:
41495658Sdes		(void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL);
4152334Scsgr		goto leave;
4162334Scsgr
4172334Scsgr	case RSTATPROC_STATS:
4182334Scsgr		xdr_argument = xdr_void;
4192334Scsgr		xdr_result = xdr_statstime;
4202334Scsgr                switch (rqstp->rq_vers) {
4212334Scsgr                case RSTATVERS_ORIG:
42232629Swpaul                        local = (char *(*)()) rstatproc_stats_1_svc;
4232334Scsgr                        break;
4242334Scsgr                case RSTATVERS_SWTCH:
42532629Swpaul                        local = (char *(*)()) rstatproc_stats_2_svc;
4262334Scsgr                        break;
4272334Scsgr                case RSTATVERS_TIME:
42832629Swpaul                        local = (char *(*)()) rstatproc_stats_3_svc;
4292334Scsgr                        break;
4302334Scsgr                default:
4312334Scsgr                        svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
4322334Scsgr                        goto leave;
4332334Scsgr                        /*NOTREACHED*/
4342334Scsgr                }
4352334Scsgr		break;
4362334Scsgr
4372334Scsgr	case RSTATPROC_HAVEDISK:
4382334Scsgr		xdr_argument = xdr_void;
4392334Scsgr		xdr_result = xdr_u_int;
4402334Scsgr                switch (rqstp->rq_vers) {
4412334Scsgr                case RSTATVERS_ORIG:
44232629Swpaul                        local = (char *(*)()) rstatproc_havedisk_1_svc;
4432334Scsgr                        break;
4442334Scsgr                case RSTATVERS_SWTCH:
44532629Swpaul                        local = (char *(*)()) rstatproc_havedisk_2_svc;
4462334Scsgr                        break;
4472334Scsgr                case RSTATVERS_TIME:
44832629Swpaul                        local = (char *(*)()) rstatproc_havedisk_3_svc;
4492334Scsgr                        break;
4502334Scsgr                default:
4512334Scsgr                        svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
4522334Scsgr                        goto leave;
4532334Scsgr                        /*NOTREACHED*/
4542334Scsgr                }
4552334Scsgr		break;
4562334Scsgr
4572334Scsgr	default:
4582334Scsgr		svcerr_noproc(transp);
4592334Scsgr		goto leave;
4602334Scsgr	}
4612334Scsgr	bzero((char *)&argument, sizeof(argument));
46295658Sdes	if (!svc_getargs(transp, (xdrproc_t)xdr_argument, &argument)) {
4632334Scsgr		svcerr_decode(transp);
4642334Scsgr		goto leave;
4652334Scsgr	}
4662334Scsgr	result = (*local)(&argument, rqstp);
46795658Sdes	if (result != NULL &&
46895658Sdes	    !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) {
4692334Scsgr		svcerr_systemerr(transp);
4702334Scsgr	}
47195658Sdes	if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, &argument))
47231421Scharnier		errx(1, "unable to free arguments");
4732334Scsgrleave:
4742334Scsgr        if (from_inetd)
4752334Scsgr                exit(0);
4762334Scsgr}
477