1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * CDDL HEADER START
3*0Sstevel@tonic-gate *
4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*0Sstevel@tonic-gate * with the License.
8*0Sstevel@tonic-gate *
9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate * and limitations under the License.
13*0Sstevel@tonic-gate *
14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate *
20*0Sstevel@tonic-gate * CDDL HEADER END
21*0Sstevel@tonic-gate */
22*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
23*0Sstevel@tonic-gate
24*0Sstevel@tonic-gate /*
25*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
26*0Sstevel@tonic-gate * Use is subject to license terms.
27*0Sstevel@tonic-gate */
28*0Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
29*0Sstevel@tonic-gate /* All Rights Reserved */
30*0Sstevel@tonic-gate /*
31*0Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988
32*0Sstevel@tonic-gate * The Regents of the University of California
33*0Sstevel@tonic-gate * All Rights Reserved
34*0Sstevel@tonic-gate *
35*0Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from
36*0Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its
37*0Sstevel@tonic-gate * contributors.
38*0Sstevel@tonic-gate */
39*0Sstevel@tonic-gate
40*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
41*0Sstevel@tonic-gate
42*0Sstevel@tonic-gate #include <stdlib.h>
43*0Sstevel@tonic-gate #include <stdio.h>
44*0Sstevel@tonic-gate #include <unistd.h>
45*0Sstevel@tonic-gate #include <sys/types.h>
46*0Sstevel@tonic-gate #include <netconfig.h>
47*0Sstevel@tonic-gate #include <netdir.h>
48*0Sstevel@tonic-gate #include <rpc/rpc.h>
49*0Sstevel@tonic-gate #include <rpcsvc/rusers.h>
50*0Sstevel@tonic-gate #include <string.h>
51*0Sstevel@tonic-gate #include <limits.h>
52*0Sstevel@tonic-gate
53*0Sstevel@tonic-gate #define NMAX 12 /* These are used as field width specifiers */
54*0Sstevel@tonic-gate #define LMAX 8 /* when printing. */
55*0Sstevel@tonic-gate #define HMAX 16 /* "Logged in" host name. */
56*0Sstevel@tonic-gate
57*0Sstevel@tonic-gate #define MACHINELEN 16 /* length of machine name printed out */
58*0Sstevel@tonic-gate #define NUMENTRIES 256
59*0Sstevel@tonic-gate #define min(a, b) ((a) < (b) ? (a) : (b))
60*0Sstevel@tonic-gate
61*0Sstevel@tonic-gate struct entry {
62*0Sstevel@tonic-gate int cnt;
63*0Sstevel@tonic-gate int idle; /* set to INT_MAX if not present */
64*0Sstevel@tonic-gate char *machine;
65*0Sstevel@tonic-gate utmp_array users;
66*0Sstevel@tonic-gate };
67*0Sstevel@tonic-gate
68*0Sstevel@tonic-gate static int curentry;
69*0Sstevel@tonic-gate static int total_entries;
70*0Sstevel@tonic-gate static struct entry *entry;
71*0Sstevel@tonic-gate static int hflag; /* host: sort by machine name */
72*0Sstevel@tonic-gate static int iflag; /* idle: sort by idle time */
73*0Sstevel@tonic-gate static int uflag; /* users: sort by number of users */
74*0Sstevel@tonic-gate static int lflag; /* print out long form */
75*0Sstevel@tonic-gate static int aflag; /* all: list all machines */
76*0Sstevel@tonic-gate static int dflag; /* debug: list only first n machines */
77*0Sstevel@tonic-gate static int sorted;
78*0Sstevel@tonic-gate static int debug;
79*0Sstevel@tonic-gate static int debugcnt;
80*0Sstevel@tonic-gate static char *nettype;
81*0Sstevel@tonic-gate
82*0Sstevel@tonic-gate static int hcompare(const struct entry *, const struct entry *);
83*0Sstevel@tonic-gate static int icompare(const struct entry *, const struct entry *);
84*0Sstevel@tonic-gate static int ucompare(const struct entry *, const struct entry *);
85*0Sstevel@tonic-gate static int print_info(struct utmpidlearr *, const char *);
86*0Sstevel@tonic-gate static int print_info_3(utmp_array *, const char *);
87*0Sstevel@tonic-gate static int collectnames(void *, struct netbuf *, struct netconfig *);
88*0Sstevel@tonic-gate static int collectnames_3(void *, struct netbuf *, struct netconfig *);
89*0Sstevel@tonic-gate static void singlehost(char *);
90*0Sstevel@tonic-gate static void printnames(void);
91*0Sstevel@tonic-gate static void putline_2(char *, struct utmpidle *);
92*0Sstevel@tonic-gate static void putline_3(char *, rusers_utmp *);
93*0Sstevel@tonic-gate static void prttime(uint_t, char *);
94*0Sstevel@tonic-gate static void usage(void);
95*0Sstevel@tonic-gate
96*0Sstevel@tonic-gate /*
97*0Sstevel@tonic-gate * rusers [-ahilu] [host...]
98*0Sstevel@tonic-gate */
99*0Sstevel@tonic-gate int
main(int argc,char * argv[])100*0Sstevel@tonic-gate main(int argc, char *argv[])
101*0Sstevel@tonic-gate {
102*0Sstevel@tonic-gate int c;
103*0Sstevel@tonic-gate uint_t errflag = 0;
104*0Sstevel@tonic-gate uint_t single = 0;
105*0Sstevel@tonic-gate struct utmpidlearr utmpidlearr;
106*0Sstevel@tonic-gate utmp_array utmp_array_res;
107*0Sstevel@tonic-gate
108*0Sstevel@tonic-gate curentry = 0;
109*0Sstevel@tonic-gate total_entries = NUMENTRIES;
110*0Sstevel@tonic-gate entry = malloc(sizeof (struct entry) * total_entries);
111*0Sstevel@tonic-gate
112*0Sstevel@tonic-gate while ((c = getopt(argc, argv, ":ad:hilun:")) != -1) {
113*0Sstevel@tonic-gate switch (c) {
114*0Sstevel@tonic-gate case 'a':
115*0Sstevel@tonic-gate aflag++;
116*0Sstevel@tonic-gate break;
117*0Sstevel@tonic-gate case 'd':
118*0Sstevel@tonic-gate dflag++;
119*0Sstevel@tonic-gate debug = atoi(optarg);
120*0Sstevel@tonic-gate (void) printf("Will collect %d responses.\n", debug);
121*0Sstevel@tonic-gate break;
122*0Sstevel@tonic-gate case 'h':
123*0Sstevel@tonic-gate hflag++;
124*0Sstevel@tonic-gate sorted++;
125*0Sstevel@tonic-gate if (iflag || uflag)
126*0Sstevel@tonic-gate errflag++;
127*0Sstevel@tonic-gate break;
128*0Sstevel@tonic-gate case 'i':
129*0Sstevel@tonic-gate iflag++;
130*0Sstevel@tonic-gate sorted++;
131*0Sstevel@tonic-gate if (hflag || uflag)
132*0Sstevel@tonic-gate errflag++;
133*0Sstevel@tonic-gate break;
134*0Sstevel@tonic-gate case 'u':
135*0Sstevel@tonic-gate uflag++;
136*0Sstevel@tonic-gate sorted++;
137*0Sstevel@tonic-gate if (hflag || iflag)
138*0Sstevel@tonic-gate errflag++;
139*0Sstevel@tonic-gate break;
140*0Sstevel@tonic-gate case 'l':
141*0Sstevel@tonic-gate lflag++;
142*0Sstevel@tonic-gate break;
143*0Sstevel@tonic-gate case ':': /* required operand missing */
144*0Sstevel@tonic-gate errflag++;
145*0Sstevel@tonic-gate break;
146*0Sstevel@tonic-gate case 'n':
147*0Sstevel@tonic-gate nettype = optarg;
148*0Sstevel@tonic-gate break;
149*0Sstevel@tonic-gate default:
150*0Sstevel@tonic-gate case '?': /* Unrecognized option */
151*0Sstevel@tonic-gate errflag++;
152*0Sstevel@tonic-gate break;
153*0Sstevel@tonic-gate }
154*0Sstevel@tonic-gate }
155*0Sstevel@tonic-gate if (errflag)
156*0Sstevel@tonic-gate usage();
157*0Sstevel@tonic-gate
158*0Sstevel@tonic-gate for (; optind < argc; optind++) {
159*0Sstevel@tonic-gate single++;
160*0Sstevel@tonic-gate singlehost(argv[optind]);
161*0Sstevel@tonic-gate }
162*0Sstevel@tonic-gate if (single) {
163*0Sstevel@tonic-gate if (sorted)
164*0Sstevel@tonic-gate printnames();
165*0Sstevel@tonic-gate free(entry);
166*0Sstevel@tonic-gate exit(0);
167*0Sstevel@tonic-gate }
168*0Sstevel@tonic-gate
169*0Sstevel@tonic-gate if (sorted) {
170*0Sstevel@tonic-gate (void) printf("Collecting responses...\n");
171*0Sstevel@tonic-gate (void) fflush(stdout);
172*0Sstevel@tonic-gate }
173*0Sstevel@tonic-gate utmp_array_res.utmp_array_val = NULL;
174*0Sstevel@tonic-gate utmp_array_res.utmp_array_len = 0;
175*0Sstevel@tonic-gate (void) printf("Sending broadcast for rusersd protocol version 3...\n");
176*0Sstevel@tonic-gate (void) rpc_broadcast(RUSERSPROG, RUSERSVERS_3,
177*0Sstevel@tonic-gate RUSERSPROC_NAMES, (xdrproc_t)xdr_void, NULL,
178*0Sstevel@tonic-gate (xdrproc_t)xdr_utmp_array, (char *)&utmp_array_res,
179*0Sstevel@tonic-gate (resultproc_t)collectnames_3, nettype);
180*0Sstevel@tonic-gate utmpidlearr.uia_arr = NULL;
181*0Sstevel@tonic-gate (void) printf("Sending broadcast for rusersd protocol version 2...\n");
182*0Sstevel@tonic-gate (void) rpc_broadcast(RUSERSPROG, RUSERSVERS_IDLE,
183*0Sstevel@tonic-gate RUSERSPROC_NAMES, (xdrproc_t)xdr_void, NULL,
184*0Sstevel@tonic-gate (xdrproc_t)xdr_utmpidlearr, (char *)&utmpidlearr,
185*0Sstevel@tonic-gate (resultproc_t)collectnames, nettype);
186*0Sstevel@tonic-gate
187*0Sstevel@tonic-gate if (sorted)
188*0Sstevel@tonic-gate printnames();
189*0Sstevel@tonic-gate
190*0Sstevel@tonic-gate free(entry);
191*0Sstevel@tonic-gate return (0);
192*0Sstevel@tonic-gate }
193*0Sstevel@tonic-gate
194*0Sstevel@tonic-gate static void
singlehost(char * name)195*0Sstevel@tonic-gate singlehost(char *name)
196*0Sstevel@tonic-gate {
197*0Sstevel@tonic-gate enum clnt_stat err;
198*0Sstevel@tonic-gate struct utmpidlearr utmpidlearr;
199*0Sstevel@tonic-gate utmp_array utmp_array_res;
200*0Sstevel@tonic-gate
201*0Sstevel@tonic-gate if (curentry >= total_entries) {
202*0Sstevel@tonic-gate struct entry *tmp;
203*0Sstevel@tonic-gate
204*0Sstevel@tonic-gate total_entries += NUMENTRIES;
205*0Sstevel@tonic-gate if ((tmp = realloc(entry, sizeof (struct entry)
206*0Sstevel@tonic-gate * total_entries)) == NULL)
207*0Sstevel@tonic-gate return;
208*0Sstevel@tonic-gate entry = tmp;
209*0Sstevel@tonic-gate }
210*0Sstevel@tonic-gate utmp_array_res.utmp_array_val = NULL;
211*0Sstevel@tonic-gate utmp_array_res.utmp_array_len = 0;
212*0Sstevel@tonic-gate err = rpc_call(name, RUSERSPROG, RUSERSVERS_3,
213*0Sstevel@tonic-gate RUSERSPROC_NAMES, (xdrproc_t)xdr_void, 0,
214*0Sstevel@tonic-gate (xdrproc_t)xdr_utmp_array, (char *)&utmp_array_res,
215*0Sstevel@tonic-gate nettype);
216*0Sstevel@tonic-gate if (err == RPC_SUCCESS) {
217*0Sstevel@tonic-gate (void) print_info_3(&utmp_array_res, name);
218*0Sstevel@tonic-gate return;
219*0Sstevel@tonic-gate }
220*0Sstevel@tonic-gate if (err == RPC_PROGVERSMISMATCH) {
221*0Sstevel@tonic-gate utmpidlearr.uia_arr = NULL;
222*0Sstevel@tonic-gate err = rpc_call(name, RUSERSPROG, RUSERSVERS_IDLE,
223*0Sstevel@tonic-gate RUSERSPROC_NAMES, (xdrproc_t)xdr_void, 0,
224*0Sstevel@tonic-gate (xdrproc_t)xdr_utmpidlearr,
225*0Sstevel@tonic-gate (char *)&utmpidlearr, nettype);
226*0Sstevel@tonic-gate }
227*0Sstevel@tonic-gate if (err != RPC_SUCCESS) {
228*0Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", name);
229*0Sstevel@tonic-gate clnt_perrno(err);
230*0Sstevel@tonic-gate return;
231*0Sstevel@tonic-gate }
232*0Sstevel@tonic-gate (void) print_info(&utmpidlearr, name);
233*0Sstevel@tonic-gate }
234*0Sstevel@tonic-gate
235*0Sstevel@tonic-gate /*
236*0Sstevel@tonic-gate * Collect responses from RUSERSVERS_IDLE broadcast, convert to
237*0Sstevel@tonic-gate * RUSERSVERS_3 format, and store in entry database.
238*0Sstevel@tonic-gate */
239*0Sstevel@tonic-gate static int
collectnames(void * resultsp,struct netbuf * raddrp,struct netconfig * nconf)240*0Sstevel@tonic-gate collectnames(void *resultsp, struct netbuf *raddrp, struct netconfig *nconf)
241*0Sstevel@tonic-gate {
242*0Sstevel@tonic-gate struct utmpidlearr utmpidlearr;
243*0Sstevel@tonic-gate struct entry *entryp, *lim;
244*0Sstevel@tonic-gate struct nd_hostservlist *hs;
245*0Sstevel@tonic-gate char host[MACHINELEN + 1];
246*0Sstevel@tonic-gate
247*0Sstevel@tonic-gate utmpidlearr = *(struct utmpidlearr *)resultsp;
248*0Sstevel@tonic-gate if (utmpidlearr.uia_cnt < 1 && !aflag)
249*0Sstevel@tonic-gate return (0);
250*0Sstevel@tonic-gate
251*0Sstevel@tonic-gate if (netdir_getbyaddr(nconf, &hs, raddrp)) {
252*0Sstevel@tonic-gate #ifdef DEBUG
253*0Sstevel@tonic-gate netdir_perror("netdir_getbyaddr");
254*0Sstevel@tonic-gate #endif
255*0Sstevel@tonic-gate /* netdir routine couldn't resolve addr;just print out uaddr */
256*0Sstevel@tonic-gate (void) sprintf(host, "%.*s", MACHINELEN,
257*0Sstevel@tonic-gate taddr2uaddr(nconf, raddrp));
258*0Sstevel@tonic-gate } else {
259*0Sstevel@tonic-gate (void) sprintf(host, "%.*s", MACHINELEN,
260*0Sstevel@tonic-gate hs->h_hostservs->h_host);
261*0Sstevel@tonic-gate netdir_free((char *)hs, ND_HOSTSERVLIST);
262*0Sstevel@tonic-gate }
263*0Sstevel@tonic-gate /*
264*0Sstevel@tonic-gate * need to realloc more space if we have more than 256 machines
265*0Sstevel@tonic-gate * that respond to broadcast
266*0Sstevel@tonic-gate */
267*0Sstevel@tonic-gate if (curentry >= total_entries) {
268*0Sstevel@tonic-gate struct entry *tmp;
269*0Sstevel@tonic-gate
270*0Sstevel@tonic-gate total_entries += NUMENTRIES;
271*0Sstevel@tonic-gate if ((tmp = realloc(entry, sizeof (struct entry)
272*0Sstevel@tonic-gate * total_entries)) == NULL)
273*0Sstevel@tonic-gate return (1);
274*0Sstevel@tonic-gate entry = tmp;
275*0Sstevel@tonic-gate }
276*0Sstevel@tonic-gate
277*0Sstevel@tonic-gate
278*0Sstevel@tonic-gate /*
279*0Sstevel@tonic-gate * weed out duplicates
280*0Sstevel@tonic-gate */
281*0Sstevel@tonic-gate lim = entry + curentry;
282*0Sstevel@tonic-gate for (entryp = entry; entryp < lim; entryp++) {
283*0Sstevel@tonic-gate if (strcmp(entryp->machine, host) == 0)
284*0Sstevel@tonic-gate return (0);
285*0Sstevel@tonic-gate }
286*0Sstevel@tonic-gate return (print_info((struct utmpidlearr *)resultsp, host));
287*0Sstevel@tonic-gate }
288*0Sstevel@tonic-gate
289*0Sstevel@tonic-gate static int
print_info(struct utmpidlearr * utmpidlearrp,const char * name)290*0Sstevel@tonic-gate print_info(struct utmpidlearr *utmpidlearrp, const char *name)
291*0Sstevel@tonic-gate {
292*0Sstevel@tonic-gate utmp_array *iconvert;
293*0Sstevel@tonic-gate int i, cnt, minidle;
294*0Sstevel@tonic-gate char host[MACHINELEN + 1];
295*0Sstevel@tonic-gate char username[NMAX + 1];
296*0Sstevel@tonic-gate
297*0Sstevel@tonic-gate cnt = utmpidlearrp->uia_cnt;
298*0Sstevel@tonic-gate (void) sprintf(host, "%.*s", MACHINELEN, name);
299*0Sstevel@tonic-gate
300*0Sstevel@tonic-gate /*
301*0Sstevel@tonic-gate * if raw, print this entry out immediately
302*0Sstevel@tonic-gate * otherwise store for later sorting
303*0Sstevel@tonic-gate */
304*0Sstevel@tonic-gate if (!sorted) {
305*0Sstevel@tonic-gate if (lflag && (cnt > 0))
306*0Sstevel@tonic-gate for (i = 0; i < cnt; i++)
307*0Sstevel@tonic-gate putline_2(host, utmpidlearrp->uia_arr[i]);
308*0Sstevel@tonic-gate else {
309*0Sstevel@tonic-gate (void) printf("%-*.*s", MACHINELEN, MACHINELEN, host);
310*0Sstevel@tonic-gate for (i = 0; i < cnt; i++) {
311*0Sstevel@tonic-gate (void) strlcpy(username,
312*0Sstevel@tonic-gate utmpidlearrp->uia_arr[i]->ui_utmp.ut_name,
313*0Sstevel@tonic-gate NMAX + 1);
314*0Sstevel@tonic-gate (void) printf(" %.*s", NMAX, username);
315*0Sstevel@tonic-gate }
316*0Sstevel@tonic-gate (void) printf("\n");
317*0Sstevel@tonic-gate }
318*0Sstevel@tonic-gate /* store just the name */
319*0Sstevel@tonic-gate entry[curentry].machine = malloc(MACHINELEN + 1);
320*0Sstevel@tonic-gate if (entry[curentry].machine == NULL) {
321*0Sstevel@tonic-gate (void) fprintf(stderr, "Ran out of memory - exiting\n");
322*0Sstevel@tonic-gate exit(1);
323*0Sstevel@tonic-gate }
324*0Sstevel@tonic-gate (void) strlcpy(entry[curentry].machine, name, MACHINELEN + 1);
325*0Sstevel@tonic-gate entry[curentry++].cnt = 0;
326*0Sstevel@tonic-gate if (dflag && (++debugcnt >= debug))
327*0Sstevel@tonic-gate return (1);
328*0Sstevel@tonic-gate return (0);
329*0Sstevel@tonic-gate }
330*0Sstevel@tonic-gate entry[curentry].machine = malloc(MACHINELEN + 1);
331*0Sstevel@tonic-gate if (entry[curentry].machine == NULL) {
332*0Sstevel@tonic-gate (void) fprintf(stderr, "Ran out of memory - exiting\n");
333*0Sstevel@tonic-gate exit(1);
334*0Sstevel@tonic-gate }
335*0Sstevel@tonic-gate (void) strlcpy(entry[curentry].machine, name, MACHINELEN + 1);
336*0Sstevel@tonic-gate entry[curentry].cnt = cnt;
337*0Sstevel@tonic-gate iconvert = &entry[curentry].users;
338*0Sstevel@tonic-gate iconvert->utmp_array_len = cnt;
339*0Sstevel@tonic-gate iconvert->utmp_array_val = malloc(cnt * sizeof (rusers_utmp));
340*0Sstevel@tonic-gate minidle = INT_MAX;
341*0Sstevel@tonic-gate for (i = 0; i < cnt; i++) {
342*0Sstevel@tonic-gate iconvert->utmp_array_val[i].ut_user =
343*0Sstevel@tonic-gate strdup(utmpidlearrp->uia_arr[i]->ui_utmp.ut_name);
344*0Sstevel@tonic-gate iconvert->utmp_array_val[i].ut_line =
345*0Sstevel@tonic-gate strdup(utmpidlearrp->uia_arr[i]->ui_utmp.ut_line);
346*0Sstevel@tonic-gate iconvert->utmp_array_val[i].ut_host =
347*0Sstevel@tonic-gate strdup(utmpidlearrp->uia_arr[i]->ui_utmp.ut_host);
348*0Sstevel@tonic-gate iconvert->utmp_array_val[i].ut_time =
349*0Sstevel@tonic-gate utmpidlearrp->uia_arr[i]->ui_utmp.ut_time;
350*0Sstevel@tonic-gate iconvert->utmp_array_val[i].ut_idle =
351*0Sstevel@tonic-gate utmpidlearrp->uia_arr[i]->ui_idle;
352*0Sstevel@tonic-gate minidle = min(minidle, utmpidlearrp->uia_arr[i]->ui_idle);
353*0Sstevel@tonic-gate }
354*0Sstevel@tonic-gate entry[curentry].idle = minidle;
355*0Sstevel@tonic-gate curentry++;
356*0Sstevel@tonic-gate if (dflag && (++debugcnt >= debug))
357*0Sstevel@tonic-gate return (1);
358*0Sstevel@tonic-gate return (0);
359*0Sstevel@tonic-gate }
360*0Sstevel@tonic-gate
361*0Sstevel@tonic-gate
362*0Sstevel@tonic-gate /*
363*0Sstevel@tonic-gate * Collect responses from RUSERSVERS_3 broadcast.
364*0Sstevel@tonic-gate */
365*0Sstevel@tonic-gate static int
collectnames_3(void * resultsp,struct netbuf * raddrp,struct netconfig * nconf)366*0Sstevel@tonic-gate collectnames_3(void *resultsp, struct netbuf *raddrp, struct netconfig *nconf)
367*0Sstevel@tonic-gate {
368*0Sstevel@tonic-gate utmp_array *uap;
369*0Sstevel@tonic-gate struct entry *entryp, *lim;
370*0Sstevel@tonic-gate struct nd_hostservlist *hs;
371*0Sstevel@tonic-gate char host[MACHINELEN + 1];
372*0Sstevel@tonic-gate
373*0Sstevel@tonic-gate uap = (utmp_array *)resultsp;
374*0Sstevel@tonic-gate if (uap->utmp_array_len < 1 && !aflag)
375*0Sstevel@tonic-gate return (0);
376*0Sstevel@tonic-gate
377*0Sstevel@tonic-gate if (netdir_getbyaddr(nconf, &hs, raddrp)) {
378*0Sstevel@tonic-gate #ifdef DEBUG
379*0Sstevel@tonic-gate netdir_perror("netdir_getbyaddr");
380*0Sstevel@tonic-gate #endif
381*0Sstevel@tonic-gate /* netdir routine couldn't resolve addr;just print out uaddr */
382*0Sstevel@tonic-gate (void) sprintf(host, "%.*s", MACHINELEN,
383*0Sstevel@tonic-gate taddr2uaddr(nconf, raddrp));
384*0Sstevel@tonic-gate } else {
385*0Sstevel@tonic-gate (void) sprintf(host, "%.*s", MACHINELEN,
386*0Sstevel@tonic-gate hs->h_hostservs->h_host);
387*0Sstevel@tonic-gate netdir_free((char *)hs, ND_HOSTSERVLIST);
388*0Sstevel@tonic-gate }
389*0Sstevel@tonic-gate
390*0Sstevel@tonic-gate /*
391*0Sstevel@tonic-gate * need to realloc more space if we have more than 256 machines
392*0Sstevel@tonic-gate * that respond to broadcast
393*0Sstevel@tonic-gate */
394*0Sstevel@tonic-gate if (curentry >= total_entries) {
395*0Sstevel@tonic-gate struct entry *tmp;
396*0Sstevel@tonic-gate
397*0Sstevel@tonic-gate total_entries += NUMENTRIES;
398*0Sstevel@tonic-gate if ((tmp = realloc(entry, sizeof (struct entry)
399*0Sstevel@tonic-gate * total_entries)) == NULL)
400*0Sstevel@tonic-gate return (1);
401*0Sstevel@tonic-gate entry = tmp;
402*0Sstevel@tonic-gate }
403*0Sstevel@tonic-gate
404*0Sstevel@tonic-gate
405*0Sstevel@tonic-gate /*
406*0Sstevel@tonic-gate * weed out duplicates
407*0Sstevel@tonic-gate */
408*0Sstevel@tonic-gate lim = entry + curentry;
409*0Sstevel@tonic-gate for (entryp = entry; entryp < lim; entryp++) {
410*0Sstevel@tonic-gate if (strcmp(entryp->machine, host) == 0)
411*0Sstevel@tonic-gate return (0);
412*0Sstevel@tonic-gate }
413*0Sstevel@tonic-gate return (print_info_3(uap, host));
414*0Sstevel@tonic-gate }
415*0Sstevel@tonic-gate
416*0Sstevel@tonic-gate static int
print_info_3(utmp_array * uap,const char * name)417*0Sstevel@tonic-gate print_info_3(utmp_array *uap, const char *name)
418*0Sstevel@tonic-gate {
419*0Sstevel@tonic-gate int i, cnt, minidle;
420*0Sstevel@tonic-gate char host[MACHINELEN + 1];
421*0Sstevel@tonic-gate
422*0Sstevel@tonic-gate cnt = uap->utmp_array_len;
423*0Sstevel@tonic-gate
424*0Sstevel@tonic-gate (void) sprintf(host, "%.*s", MACHINELEN, name);
425*0Sstevel@tonic-gate
426*0Sstevel@tonic-gate /*
427*0Sstevel@tonic-gate * if raw, print this entry out immediately
428*0Sstevel@tonic-gate * otherwise store for later sorting
429*0Sstevel@tonic-gate */
430*0Sstevel@tonic-gate if (!sorted) {
431*0Sstevel@tonic-gate if (lflag && (cnt > 0))
432*0Sstevel@tonic-gate for (i = 0; i < cnt; i++)
433*0Sstevel@tonic-gate putline_3(host, &uap->utmp_array_val[i]);
434*0Sstevel@tonic-gate else {
435*0Sstevel@tonic-gate (void) printf("%-*.*s", MACHINELEN, MACHINELEN, host);
436*0Sstevel@tonic-gate for (i = 0; i < cnt; i++)
437*0Sstevel@tonic-gate (void) printf(" %.*s", NMAX,
438*0Sstevel@tonic-gate uap->utmp_array_val[i].ut_user);
439*0Sstevel@tonic-gate (void) printf("\n");
440*0Sstevel@tonic-gate }
441*0Sstevel@tonic-gate /* store just the name */
442*0Sstevel@tonic-gate entry[curentry].machine = malloc(MACHINELEN + 1);
443*0Sstevel@tonic-gate if (entry[curentry].machine == NULL) {
444*0Sstevel@tonic-gate (void) fprintf(stderr, "Ran out of memory - exiting\n");
445*0Sstevel@tonic-gate exit(1);
446*0Sstevel@tonic-gate }
447*0Sstevel@tonic-gate (void) strlcpy(entry[curentry].machine, name, MACHINELEN + 1);
448*0Sstevel@tonic-gate entry[curentry++].cnt = 0;
449*0Sstevel@tonic-gate if (dflag && (++debugcnt >= debug))
450*0Sstevel@tonic-gate return (1);
451*0Sstevel@tonic-gate return (0);
452*0Sstevel@tonic-gate }
453*0Sstevel@tonic-gate
454*0Sstevel@tonic-gate entry[curentry].machine = malloc(MACHINELEN + 1);
455*0Sstevel@tonic-gate if (entry[curentry].machine == NULL) {
456*0Sstevel@tonic-gate (void) fprintf(stderr, "Ran out of memory - exiting\n");
457*0Sstevel@tonic-gate exit(1);
458*0Sstevel@tonic-gate }
459*0Sstevel@tonic-gate (void) strlcpy(entry[curentry].machine, name, MACHINELEN + 1);
460*0Sstevel@tonic-gate entry[curentry].cnt = cnt;
461*0Sstevel@tonic-gate entry[curentry].users.utmp_array_len = cnt;
462*0Sstevel@tonic-gate entry[curentry].users.utmp_array_val = malloc(cnt *
463*0Sstevel@tonic-gate sizeof (rusers_utmp));
464*0Sstevel@tonic-gate minidle = INT_MAX;
465*0Sstevel@tonic-gate for (i = 0; i < cnt; i++) {
466*0Sstevel@tonic-gate entry[curentry].users.utmp_array_val[i].ut_user =
467*0Sstevel@tonic-gate strdup(uap->utmp_array_val[i].ut_user);
468*0Sstevel@tonic-gate entry[curentry].users.utmp_array_val[i].ut_line =
469*0Sstevel@tonic-gate strdup(uap->utmp_array_val[i].ut_line);
470*0Sstevel@tonic-gate entry[curentry].users.utmp_array_val[i].ut_host =
471*0Sstevel@tonic-gate strdup(uap->utmp_array_val[i].ut_host);
472*0Sstevel@tonic-gate entry[curentry].users.utmp_array_val[i].ut_time =
473*0Sstevel@tonic-gate uap->utmp_array_val[i].ut_time;
474*0Sstevel@tonic-gate entry[curentry].users.utmp_array_val[i].ut_idle =
475*0Sstevel@tonic-gate uap->utmp_array_val[i].ut_idle;
476*0Sstevel@tonic-gate minidle = min(minidle, uap->utmp_array_val[i].ut_idle);
477*0Sstevel@tonic-gate }
478*0Sstevel@tonic-gate entry[curentry].idle = minidle;
479*0Sstevel@tonic-gate curentry++;
480*0Sstevel@tonic-gate if (dflag && (++debugcnt >= debug))
481*0Sstevel@tonic-gate return (1);
482*0Sstevel@tonic-gate return (0);
483*0Sstevel@tonic-gate }
484*0Sstevel@tonic-gate
485*0Sstevel@tonic-gate static void
printnames(void)486*0Sstevel@tonic-gate printnames(void)
487*0Sstevel@tonic-gate {
488*0Sstevel@tonic-gate int i, j;
489*0Sstevel@tonic-gate int (*compare)(const void *, const void *);
490*0Sstevel@tonic-gate
491*0Sstevel@tonic-gate /* the name of the machine should already be in the structure */
492*0Sstevel@tonic-gate if (iflag)
493*0Sstevel@tonic-gate compare = (int (*)(const void *, const void *))icompare;
494*0Sstevel@tonic-gate else if (hflag)
495*0Sstevel@tonic-gate compare = (int (*)(const void *, const void *))hcompare;
496*0Sstevel@tonic-gate else
497*0Sstevel@tonic-gate compare = (int (*)(const void *, const void *))ucompare;
498*0Sstevel@tonic-gate qsort(entry, curentry, sizeof (struct entry), compare);
499*0Sstevel@tonic-gate for (i = 0; i < curentry; i++) {
500*0Sstevel@tonic-gate if (!lflag || (entry[i].cnt < 1)) {
501*0Sstevel@tonic-gate (void) printf("%-*.*s", MACHINELEN,
502*0Sstevel@tonic-gate MACHINELEN, entry[i].machine);
503*0Sstevel@tonic-gate for (j = 0; j < entry[i].cnt; j++)
504*0Sstevel@tonic-gate (void) printf(" %.*s", NMAX,
505*0Sstevel@tonic-gate entry[i].users.utmp_array_val[j].ut_user);
506*0Sstevel@tonic-gate (void) printf("\n");
507*0Sstevel@tonic-gate } else {
508*0Sstevel@tonic-gate for (j = 0; j < entry[i].cnt; j++)
509*0Sstevel@tonic-gate putline_3(entry[i].machine,
510*0Sstevel@tonic-gate &entry[i].users.utmp_array_val[j]);
511*0Sstevel@tonic-gate }
512*0Sstevel@tonic-gate }
513*0Sstevel@tonic-gate }
514*0Sstevel@tonic-gate
515*0Sstevel@tonic-gate static int
hcompare(const struct entry * a,const struct entry * b)516*0Sstevel@tonic-gate hcompare(const struct entry *a, const struct entry *b)
517*0Sstevel@tonic-gate {
518*0Sstevel@tonic-gate return (strcmp(a->machine, b->machine));
519*0Sstevel@tonic-gate }
520*0Sstevel@tonic-gate
521*0Sstevel@tonic-gate static int
ucompare(const struct entry * a,const struct entry * b)522*0Sstevel@tonic-gate ucompare(const struct entry *a, const struct entry *b)
523*0Sstevel@tonic-gate {
524*0Sstevel@tonic-gate return (b->cnt - a->cnt);
525*0Sstevel@tonic-gate }
526*0Sstevel@tonic-gate
527*0Sstevel@tonic-gate static int
icompare(const struct entry * a,const struct entry * b)528*0Sstevel@tonic-gate icompare(const struct entry *a, const struct entry *b)
529*0Sstevel@tonic-gate {
530*0Sstevel@tonic-gate return (a->idle - b->idle);
531*0Sstevel@tonic-gate }
532*0Sstevel@tonic-gate
533*0Sstevel@tonic-gate static void
putline_2(char * host,struct utmpidle * uip)534*0Sstevel@tonic-gate putline_2(char *host, struct utmpidle *uip)
535*0Sstevel@tonic-gate {
536*0Sstevel@tonic-gate char *cbuf;
537*0Sstevel@tonic-gate struct ru_utmp *up;
538*0Sstevel@tonic-gate char buf[100];
539*0Sstevel@tonic-gate
540*0Sstevel@tonic-gate up = &uip->ui_utmp;
541*0Sstevel@tonic-gate #define NAMEMAX ((sizeof (up->ut_name) < NMAX) ? NMAX : sizeof (up->ut_name))
542*0Sstevel@tonic-gate #define NAMEMIN ((sizeof (up->ut_name) > NMAX) ? NMAX : sizeof (up->ut_name))
543*0Sstevel@tonic-gate /* Try and align this up nicely */
544*0Sstevel@tonic-gate #define LINEMAX sizeof (up->ut_line)
545*0Sstevel@tonic-gate #define HOSTMAX sizeof (up->ut_host)
546*0Sstevel@tonic-gate /*
547*0Sstevel@tonic-gate * We copy the strings into a buffer because they aren't strictly
548*0Sstevel@tonic-gate * speaking strings but byte arrays (and they may not have a
549*0Sstevel@tonic-gate * terminating NULL.
550*0Sstevel@tonic-gate */
551*0Sstevel@tonic-gate
552*0Sstevel@tonic-gate (void) strncpy(buf, up->ut_name, NAMEMAX);
553*0Sstevel@tonic-gate buf[NAMEMIN] = '\0';
554*0Sstevel@tonic-gate (void) printf("%-*.*s ", NAMEMAX, NAMEMAX, buf);
555*0Sstevel@tonic-gate
556*0Sstevel@tonic-gate (void) strcpy(buf, host);
557*0Sstevel@tonic-gate (void) strcat(buf, ":");
558*0Sstevel@tonic-gate (void) strncat(buf, up->ut_line, LINEMAX);
559*0Sstevel@tonic-gate buf[MACHINELEN+LINEMAX] = '\0';
560*0Sstevel@tonic-gate (void) printf("%-*.*s", MACHINELEN+LINEMAX, MACHINELEN+LINEMAX, buf);
561*0Sstevel@tonic-gate
562*0Sstevel@tonic-gate cbuf = (char *)ctime(&up->ut_time);
563*0Sstevel@tonic-gate (void) printf(" %.12s ", cbuf+4);
564*0Sstevel@tonic-gate if (uip->ui_idle == INT_MAX)
565*0Sstevel@tonic-gate (void) printf(" ??");
566*0Sstevel@tonic-gate else
567*0Sstevel@tonic-gate prttime(uip->ui_idle, "");
568*0Sstevel@tonic-gate if (up->ut_host[0]) {
569*0Sstevel@tonic-gate (void) strncpy(buf, up->ut_host, HOSTMAX);
570*0Sstevel@tonic-gate buf[HOSTMAX] = '\0';
571*0Sstevel@tonic-gate (void) printf(" (%.*s)", HOSTMAX, buf);
572*0Sstevel@tonic-gate }
573*0Sstevel@tonic-gate (void) putchar('\n');
574*0Sstevel@tonic-gate }
575*0Sstevel@tonic-gate
576*0Sstevel@tonic-gate static void
putline_3(char * host,rusers_utmp * rup)577*0Sstevel@tonic-gate putline_3(char *host, rusers_utmp *rup)
578*0Sstevel@tonic-gate {
579*0Sstevel@tonic-gate char *cbuf;
580*0Sstevel@tonic-gate char buf[100];
581*0Sstevel@tonic-gate
582*0Sstevel@tonic-gate (void) printf("%-*.*s ", NMAX, NMAX, rup->ut_user);
583*0Sstevel@tonic-gate (void) strcpy(buf, host);
584*0Sstevel@tonic-gate (void) strcat(buf, ":");
585*0Sstevel@tonic-gate (void) strncat(buf, rup->ut_line, LMAX);
586*0Sstevel@tonic-gate (void) printf("%-*.*s", MACHINELEN+LMAX, MACHINELEN+LMAX, buf);
587*0Sstevel@tonic-gate
588*0Sstevel@tonic-gate cbuf = (char *)ctime((time_t *)&rup->ut_time);
589*0Sstevel@tonic-gate (void) printf(" %.12s ", cbuf+4);
590*0Sstevel@tonic-gate if (rup->ut_idle == INT_MAX)
591*0Sstevel@tonic-gate (void) printf(" ??");
592*0Sstevel@tonic-gate else
593*0Sstevel@tonic-gate prttime(rup->ut_idle, "");
594*0Sstevel@tonic-gate if (rup->ut_host[0])
595*0Sstevel@tonic-gate (void) printf(" (%.*s)", HMAX, rup->ut_host);
596*0Sstevel@tonic-gate (void) putchar('\n');
597*0Sstevel@tonic-gate }
598*0Sstevel@tonic-gate
599*0Sstevel@tonic-gate /*
600*0Sstevel@tonic-gate * prttime prints a time in hours and minutes.
601*0Sstevel@tonic-gate * The character string tail is printed at the end, obvious
602*0Sstevel@tonic-gate * strings to pass are "", " ", or "am".
603*0Sstevel@tonic-gate */
604*0Sstevel@tonic-gate static void
prttime(uint_t tim,char * tail)605*0Sstevel@tonic-gate prttime(uint_t tim, char *tail)
606*0Sstevel@tonic-gate {
607*0Sstevel@tonic-gate int didhrs = 0;
608*0Sstevel@tonic-gate
609*0Sstevel@tonic-gate if (tim >= 60) {
610*0Sstevel@tonic-gate (void) printf("%3d:", tim/60);
611*0Sstevel@tonic-gate didhrs++;
612*0Sstevel@tonic-gate } else {
613*0Sstevel@tonic-gate (void) printf(" ");
614*0Sstevel@tonic-gate }
615*0Sstevel@tonic-gate tim %= 60;
616*0Sstevel@tonic-gate if (tim > 0 || didhrs) {
617*0Sstevel@tonic-gate (void) printf(didhrs && tim < 10 ? "%02d" : "%2d", tim);
618*0Sstevel@tonic-gate } else {
619*0Sstevel@tonic-gate (void) printf(" ");
620*0Sstevel@tonic-gate }
621*0Sstevel@tonic-gate (void) printf("%s", tail);
622*0Sstevel@tonic-gate }
623*0Sstevel@tonic-gate
624*0Sstevel@tonic-gate #ifdef DEBUG
625*0Sstevel@tonic-gate /*
626*0Sstevel@tonic-gate * for debugging
627*0Sstevel@tonic-gate */
628*0Sstevel@tonic-gate int
printit(int i)629*0Sstevel@tonic-gate printit(int i)
630*0Sstevel@tonic-gate {
631*0Sstevel@tonic-gate int j, v;
632*0Sstevel@tonic-gate
633*0Sstevel@tonic-gate (void) printf("%12.12s: ", entry[i].machine);
634*0Sstevel@tonic-gate if (entry[i].cnt) {
635*0Sstevel@tonic-gate putline_3(entry[i].machine, &entry[i].users.utmp_array_val[0]);
636*0Sstevel@tonic-gate for (j = 1; j < entry[i].cnt; j++) {
637*0Sstevel@tonic-gate (void) printf("\t");
638*0Sstevel@tonic-gate putline_3(entry[i].machine,
639*0Sstevel@tonic-gate &entry[i].users.utmp_array_val[j]);
640*0Sstevel@tonic-gate }
641*0Sstevel@tonic-gate } else
642*0Sstevel@tonic-gate (void) printf("\n");
643*0Sstevel@tonic-gate }
644*0Sstevel@tonic-gate #endif
645*0Sstevel@tonic-gate
646*0Sstevel@tonic-gate static void
usage(void)647*0Sstevel@tonic-gate usage(void)
648*0Sstevel@tonic-gate {
649*0Sstevel@tonic-gate (void) fprintf(stderr, "Usage: rusers [-ahilu] [host ...]\n");
650*0Sstevel@tonic-gate free(entry);
651*0Sstevel@tonic-gate exit(1);
652*0Sstevel@tonic-gate }
653