4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
26 /* All Rights Reserved */
28 * University Copyright- Copyright (c) 1982, 1986, 1988
29 * The Regents of the University of California
32 * University Acknowledgment- Portions of this document are derived from
33 * software developed by the University of California, Berkeley, and its
37 #pragma ident "%Z%%M% %I% %E% SMI"
44 #include <netconfig.h>
48 #include <rpcsvc/rusers.h>
49 #include <sys/resource.h>
56 #define _RPCSVC_CLOSEDOWN 120
58 static void rusers_service();
59 static void closedown();
61 static unsigned min();
63 static int _rpcpmstart
; /* Started by a port monitor ? */
64 static int _rpcfdtype
; /* Whether Stream or Datagram ? */
65 static int _rpcsvcdirty
; /* Still serving ? */
66 static int _rpcsvcrecent
; /* set when we serivce a request; tested */
67 /* and cleared by closedown() routine */
69 #define DIV60(t) ((t+30)/60) /* x/60 rounded */
74 utmp_array utmp_array_res
;
75 int used_array_len
= 0;
76 struct utmpidlearr utmpidlearr
;
78 static void free_ua_entry(rusers_utmp
*uap
);
79 static int findidle(char *name
, int ln
, time_t now
);
80 static void usys5to_ru(struct utmpx
*s5
, struct ru_utmp
*bss
);
83 main(int argc
, char *argv
[])
87 int connmaxrec
= RPC_MAXDATASIZE
;
90 * Set non-blocking mode and maximum record size for
91 * connection oriented RPC transports.
93 if (!rpc_control(RPC_SVC_CONNMAXREC_SET
, &connmaxrec
)) {
94 msgout("unable to set maximum RPC record size");
98 * If stdin looks like a TLI endpoint, we assume
99 * that we were started by a port monitor. If
100 * t_getstate fails with TBADF, this is not a
103 if (t_getstate(0) != -1 || t_errno
!= TBADF
) {
105 struct netconfig
*nconf
= NULL
;
108 extern char *getenv();
111 openlog("rusers", LOG_PID
, LOG_DAEMON
);
112 if ((netid
= getenv("NLSPROVIDER")) == NULL
) {
114 msgout("cannot get transport name");
116 } else if ((nconf
= getnetconfigent(netid
)) == NULL
) {
118 msgout("cannot get transport info");
121 if ((transp
= svc_tli_create(0, nconf
, NULL
, 0, 0)) == NULL
) {
122 msgout("cannot create server handle");
126 freenetconfigent(nconf
);
127 if (!svc_reg(transp
, RUSERSPROG
, RUSERSVERS_3
, rusers_service
,
129 msgout("unable to register (RUSERSPROG, RUSERSVERS_3).");
132 if (!svc_reg(transp
, RUSERSPROG
, RUSERSVERS_IDLE
,
133 rusers_service
, 0)) {
134 msgout("unable to register (RUSERSPROG, RUSERSVERS_IDLE).");
137 (void) signal(SIGALRM
, closedown
);
138 (void) alarm(_RPCSVC_CLOSEDOWN
);
140 msgout("svc_run returned");
147 perror("rpc.rusersd: cannot fork");
152 for (i
= 0; i
< 20; i
++)
155 openlog("rusers", LOG_PID
, LOG_DAEMON
);
157 if (!svc_create(rusers_service
, RUSERSPROG
, RUSERSVERS_3
, "netpath")) {
158 msgout("unable to create (RUSERSPROG, RUSERSVERS_3) for netpath");
161 if (!svc_create(rusers_service
, RUSERSPROG
, RUSERSVERS_IDLE
,
164 "unable to create (RUSERSPROG, RUSERSVERS_IDLE) for netpath");
169 msgout("svc_run returned");
175 * This routine gets the user information.
176 * "all" specifies whether all listings should be counted, or only those of
177 * type "USER_PROCESS".
178 * "version" is either RUSERSVERS_IDLE or RUSERSVERS_3. If anything else,
179 * just a count is returned.
180 * "limit" specifies the maximum number of entries to be processed.
182 * For both versions, the results are placed into an external variable.
183 * For RUSERSVERS_IDLE, this routine mallocs entries in a vector as it
184 * processed each utmpx entry. These malloc'd entries must be freed after the
185 * results are returned.
186 * For RUSERSVERS_3, this routine uses array entries that are malloc'd prior
187 * to this routine being called. "limit" is the number of elements available.
190 getutmpx_3(all
, version
, limit
)
191 int all
; /* give all listings? */
192 int version
; /* version 2 or 3 */
193 int limit
; /* limits users returned, 0 means no limit */
196 struct utmpidle
**q
= utmpidlearr
.uia_arr
;
200 extern char *s_malodup();
202 time(&now
); /* only one call to time() for this rpc call */
203 setutxent(); /* reset the utmpx file */
204 while ((utent
= getutxent()) != NULL
&& (limit
== 0 || cnt
< limit
)) {
205 if (utent
->ut_line
[0] == '\0' || utent
->ut_user
[0] == '\0')
208 * List only user processes.
209 * XXX modified to exclude cmdtool style window entries.
211 if ((all
== REAL_USERS
) && ((utent
->ut_type
!= USER_PROCESS
) ||
215 if (version
== RUSERSVERS_IDLE
) {
217 * need to free this; done after svc_sendreply.
219 *q
= (struct utmpidle
*)
220 malloc(sizeof (struct utmpidle
));
221 (*q
)->ui_idle
= findidle(utent
->ut_line
,
222 sizeof (utent
->ut_line
), now
);
223 if (strncmp(utent
->ut_line
, "console",
224 strlen("console")) == 0) {
225 (*q
)->ui_idle
= min((*q
)->ui_idle
,
228 usys5to_ru(utent
, &((*q
)->ui_utmp
));
230 printf("%-*s %-*s %s; idle %d",
231 sizeof (utent
->ut_line
),
233 sizeof (utent
->ut_name
),
235 ctime(&utent
->ut_xtime
),
239 } else if (version
== RUSERSVERS_3
) {
240 #define uav utmp_array_res.utmp_array_val
243 s_malodup(utent
->ut_host
, utent
->ut_syslen
);
244 uav
[cnt
].ut_user
= s_malodup(utent
->ut_user
,
245 sizeof (utent
->ut_user
));
246 uav
[cnt
].ut_line
= s_malodup(utent
->ut_line
,
247 sizeof (utent
->ut_line
));
248 uav
[cnt
].ut_type
= utent
->ut_type
;
249 uav
[cnt
].ut_time
= utent
->ut_xtime
;
250 uav
[cnt
].ut_idle
= findidle(utent
->ut_line
,
251 sizeof (utent
->ut_line
), now
);
252 if (strncmp(utent
->ut_line
, "console",
253 strlen("console")) == 0) {
255 min(uav
[cnt
].ut_idle
,
259 printf("user: %-10s line: %-10s %s; idle %d (%s)\n",
260 uav
[cnt
].ut_line
, uav
[cnt
].ut_user
,
261 ctime((time_t *)&uav
[cnt
].ut_time
),
262 uav
[cnt
].ut_idle
, uav
[cnt
].ut_host
);
272 * "string" is a character array with maximum size "size". Return a
273 * malloc'd string that's a duplicate of the string.
276 s_malodup(string
, size
)
282 tmp
= (char *)malloc(size
+1);
284 msgout("rpc.rusersd: malloc failed (2)");
287 strncpy(tmp
, string
, size
);
298 * On the console, the user may be running a window system; if so,
299 * their activity will show up in the last-access times of
300 * "/dev/kbd" and "/dev/mouse", so take the minimum of the idle
301 * times on those two devices and "/dev/console" and treat that as
304 return (min((unsigned)findidle("kbd", strlen("kbd"), now
),
305 (unsigned)findidle("mouse", strlen("mouse"), now
)));
309 rusers_service(rqstp
, transp
)
310 register struct svc_req
*rqstp
;
311 register SVCXPRT
*transp
;
315 char *replyerr
= "rpc.rusersd: error replying to request";
317 _rpcsvcrecent
= _rpcsvcdirty
= 1;
318 switch (rqstp
->rq_proc
) {
320 if (svc_sendreply(transp
, xdr_void
, 0) == FALSE
) {
325 cnt
= getutmpx_3(REAL_USERS
, 0, 0);
326 if (!svc_sendreply(transp
, xdr_u_long
, (caddr_t
)&cnt
))
329 case RUSERSPROC_NAMES
:
330 case RUSERSPROC_ALLNAMES
:
331 if (rqstp
->rq_vers
== RUSERSVERS_IDLE
) {
332 utmpidlearr
.uia_arr
= (struct utmpidle
**)
333 malloc(MAXUSERS
*sizeof (struct utmpidle
*));
334 utmpidlearr
.uia_cnt
= getutmpx_3(rqstp
->rq_proc
==
336 RUSERSVERS_IDLE
, MAXUSERS
);
337 if (!svc_sendreply(transp
, xdr_utmpidlearr
,
338 (caddr_t
)&utmpidlearr
))
340 for (i
= 0; i
< utmpidlearr
.uia_cnt
; i
++) {
341 free(utmpidlearr
.uia_arr
[i
]);
343 free(utmpidlearr
.uia_arr
);
344 } else if (rqstp
->rq_vers
== RUSERSVERS_3
) {
345 int entries
, alloc_array_len
;
348 * Always free strings from previous results array
350 for (i
= 0; i
< used_array_len
; i
++) {
351 free_ua_entry(&utmp_array_res
.utmp_array_val
[i
]);
353 entries
= (rqstp
->rq_proc
== RUSERSPROC_ALLNAMES
);
354 cnt
= getutmpx_3(entries
, 0, 0); /* get cnt */
355 if (cnt
> utmp_array_res
.utmp_array_len
) {
356 free(utmp_array_res
.utmp_array_val
);
357 utmp_array_res
.utmp_array_len
= 0;
358 utmp_array_res
.utmp_array_val
= (rusers_utmp
*)
359 malloc(cnt
* sizeof (rusers_utmp
));
360 if (utmp_array_res
.utmp_array_val
== NULL
) {
361 msgout("rpc.rusersd: malloc failed (1)");
364 alloc_array_len
= cnt
;
366 alloc_array_len
= utmp_array_res
.utmp_array_len
;
368 cnt
= getutmpx_3(entries
, RUSERSVERS_3
, cnt
);
369 utmp_array_res
.utmp_array_len
= used_array_len
= cnt
;
370 if (!svc_sendreply(transp
, xdr_utmp_array
,
371 (caddr_t
)&utmp_array_res
))
373 utmp_array_res
.utmp_array_len
= alloc_array_len
;
377 svcerr_noproc(transp
);
385 free_ua_entry(rusers_utmp
*uap
)
399 /* find & return number of minutes current tty has been idle */
401 findidle(char *name
, int ln
, time_t now
)
404 long lastaction
, diff
;
407 strcpy(ttyname
, "/dev/");
408 strncat(ttyname
, name
, ln
);
409 if (stat(ttyname
, &stbuf
) < 0)
411 lastaction
= stbuf
.st_atime
;
412 diff
= now
- lastaction
;
414 if (diff
< 0) diff
= 0;
419 usys5to_ru(struct utmpx
*s5
, struct ru_utmp
*bss
)
424 printf("sizeof (bss->ut_host) == %d\n", sizeof (bss
->ut_host
));
426 strncpy(bss
->ut_name
, s5
->ut_name
, sizeof (bss
->ut_name
));
427 strncpy(bss
->ut_line
, s5
->ut_line
, sizeof (bss
->ut_line
));
428 strncpy(bss
->ut_host
, s5
->ut_host
, sizeof (bss
->ut_host
));
429 bss
->ut_time
= s5
->ut_xtime
;
438 syslog(LOG_ERR
, msg
);
440 (void) fprintf(stderr
, "%s\n", msg
);
442 syslog(LOG_ERR
, msg
);
453 if (_rpcsvcdirty
== 0) {
457 if (t_getinfo(0, &tinfo
) || (tinfo
.servtype
== T_CLTS
))
460 for (i
= 0, openfd
= 0;
461 i
< svc_max_pollfd
&& openfd
< 2;
463 if (svc_pollfd
[i
].fd
>= 0)
471 (void) signal(SIGALRM
, closedown
);
472 (void) alarm(_RPCSVC_CLOSEDOWN
);