]>
git.saurik.com Git - apple/shell_cmds.git/blob - w/w.c
e94fc0f9d240590a4e50b10b4f831cc534a0f52c
1 /* $NetBSD: w.c,v 1.30 1998/07/06 07:50:20 mrg Exp $ */
4 * Copyright (c) 1980, 1991, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include <sys/cdefs.h>
38 __COPYRIGHT("@(#) Copyright (c) 1980, 1991, 1993, 1994\n\
39 The Regents of the University of California. All rights reserved.\n");
44 static char sccsid
[] = "@(#)w.c 8.6 (Berkeley) 6/30/94";
46 __RCSID("$NetBSD: w.c,v 1.30 1998/07/06 07:50:20 mrg Exp $");
51 * w - print system status (who and what)
53 * This program is similar to the systat command on Tenex/Tops 10/20
56 #include <sys/param.h>
59 #include <sys/sysctl.h>
62 #include <sys/ioctl.h>
63 #include <sys/socket.h>
65 #include <machine/cpu.h>
66 #include <netinet/in.h>
67 #include <arpa/inet.h>
89 struct timeval boottime
;
93 time_t now
; /* the current time of day */
94 time_t uptime
; /* time of last reboot & elapsed time since */
95 int ttywidth
; /* width of tty */
96 int argwidth
; /* width of tty */
97 int header
= 1; /* true if -h flag: don't print heading */
98 int nflag
; /* true if -n flag: don't convert addrs */
99 int sortidle
; /* sort bu idle time */
100 char *sel_user
; /* login of particular user selected */
101 char domain
[MAXHOSTNAMELEN
+ 1];
104 * One of these per active utmp entry.
109 dev_t tdev
; /* dev_t of terminal */
110 time_t idle
; /* idle time of terminal in seconds */
111 struct kinfo_proc
*kp
; /* `most interesting' proc */
112 } *ep
, *ehead
= NULL
, **nextp
= &ehead
;
114 static void pr_args
__P((struct kinfo_proc
*));
115 static void pr_header
__P((time_t *, int));
117 *ttystat
__P((char *));
118 static void usage
__P((int));
119 int main
__P((int, char **));
126 extern char *__progname
;
127 struct kinfo_proc
*kp
;
132 int ch
, i
, nentries
, nusers
, wcmd
;
133 gid_t egid
= getegid();
134 char *memf
, *nlistf
, *p
, *x
;
135 char buf
[MAXHOSTNAMELEN
], errbuf
[_POSIX2_LINE_MAX
];
137 (void)setegid(getgid());
139 /* Are we w(1) or uptime(1)? */
151 memf
= nlistf
= NULL
;
152 while ((ch
= getopt(argc
, argv
, p
)) != -1)
170 case 'f': case 'l': case 's': case 'u': case 'w':
171 warnx("[-flsuw] no longer supported");
181 * Discard setgid privileges. If not the running kernel, we toss
182 * them away totally so that bad guys can't print interesting stuff
183 * from kernel memory, otherwise switch back to kmem for the
184 * duration of the kvm_openfiles() call.
186 if (nlistf
!= NULL
|| memf
!= NULL
)
187 (void)setgid(getgid());
191 if ((kd
= kvm_openfiles(nlistf
, memf
, NULL
, O_RDONLY
, errbuf
)) == NULL
)
192 errx(1, "%s", errbuf
);
194 /* get rid of it now anyway */
195 if (nlistf
== NULL
&& memf
== NULL
)
196 (void)setgid(getgid());
199 if ((ut
= fopen(_PATH_UTMP
, "r")) == NULL
)
200 err(1, "%s", _PATH_UTMP
);
205 for (nusers
= 0; fread(&utmp
, sizeof(utmp
), 1, ut
);) {
206 if (utmp
.ut_name
[0] == '\0')
209 if (wcmd
== 0 || (sel_user
&&
210 strncmp(utmp
.ut_name
, sel_user
, UT_NAMESIZE
) != 0))
212 if ((ep
= calloc(1, sizeof(struct entry
))) == NULL
)
216 memmove(&(ep
->utmp
), &utmp
, sizeof(struct utmp
));
217 if (!(stp
= ttystat(ep
->utmp
.ut_line
)))
219 ep
->tdev
= stp
->st_rdev
;
222 * If this is the console device, attempt to ascertain
223 * the true console device dev_t.
229 mib
[0] = CTL_MACHDEP
;
230 mib
[1] = CPU_CONSDEV
;
231 size
= sizeof(dev_t
);
232 (void) sysctl(mib
, 2, &ep
->tdev
, &size
, NULL
, 0);
235 if ((ep
->idle
= now
- stp
->st_atime
) < 0)
240 if (header
|| wcmd
== 0) {
241 pr_header(&now
, nusers
);
246 #define HEADER "USER TTY FROM LOGIN@ IDLE WHAT\n"
247 #define WUSED (sizeof (HEADER) - sizeof ("WHAT\n"))
248 (void)printf(HEADER
);
250 if ((kp
= kvm_getprocs(kd
, KERN_PROC_ALL
, 0, &nentries
)) == NULL
)
251 errx(1, "%s", kvm_geterr(kd
));
252 for (i
= 0; i
< nentries
; i
++, kp
++) {
254 struct proc
*p
= (struct proc
*)&kp
->kp_proc
;
256 struct proc
*p
= &kp
->kp_proc
;
260 if (p
->p_stat
== SIDL
|| p
->p_stat
== SZOMB
)
263 for (ep
= ehead
; ep
!= NULL
; ep
= ep
->next
) {
264 if (ep
->tdev
== e
->e_tdev
&& e
->e_pgid
== e
->e_tpgid
) {
266 * Proc is in foreground of this terminal
269 if (proc_compare((struct proc
*)&ep
->kp
->kp_proc
, p
))
271 if (proc_compare(&ep
->kp
->kp_proc
, p
))
278 if ((ioctl(STDOUT_FILENO
, TIOCGWINSZ
, &ws
) == -1 &&
279 ioctl(STDERR_FILENO
, TIOCGWINSZ
, &ws
) == -1 &&
280 ioctl(STDIN_FILENO
, TIOCGWINSZ
, &ws
) == -1) || ws
.ws_col
== 0)
283 ttywidth
= ws
.ws_col
- 1;
284 argwidth
= ttywidth
- WUSED
;
287 /* sort by idle time */
288 if (sortidle
&& ehead
!= NULL
) {
289 struct entry
*from
= ehead
, *save
;
292 while (from
!= NULL
) {
294 (*nextp
) && from
->idle
>= (*nextp
)->idle
;
295 nextp
= &(*nextp
)->next
)
307 rv
= gethostname(domain
, sizeof(domain
));
308 domain
[sizeof(domain
) - 1] = '\0';
309 if (rv
< 0 || (p
= strchr(domain
, '.')) == 0)
312 memmove(domain
, p
, strlen(p
) + 1);
315 for (ep
= ehead
; ep
!= NULL
; ep
= ep
->next
) {
316 p
= *ep
->utmp
.ut_host
? ep
->utmp
.ut_host
: "-";
317 for (x
= p
; x
< p
+ UT_HOSTSIZE
; x
++)
318 if (*x
== '\0' || *x
== ':')
320 if (x
== p
+ UT_HOSTSIZE
|| *x
!= ':')
325 if (!nflag
&& inet_aton(p
, &l
) &&
326 (hp
= gethostbyaddr((char *)&l
, sizeof(l
), AF_INET
))) {
327 if (domain
[0] != '\0') {
329 p
+= strlen(hp
->h_name
);
331 if (p
> hp
->h_name
&& strcmp(p
, domain
) == 0)
337 (void)snprintf(buf
, sizeof(buf
), "%s:%.*s", p
,
338 (int)(ep
->utmp
.ut_host
+ UT_HOSTSIZE
- x
), x
);
341 (void)printf("%-*.*s %-2.2s %-*.*s ",
342 UT_NAMESIZE
, UT_NAMESIZE
, ep
->utmp
.ut_name
,
343 strncmp(ep
->utmp
.ut_line
, "tty", 3) ?
344 ep
->utmp
.ut_line
: ep
->utmp
.ut_line
+ 3,
345 UT_HOSTSIZE
, UT_HOSTSIZE
, *p
? p
: "-");
346 pr_attime(&ep
->utmp
.ut_time
, &now
);
356 struct kinfo_proc
*kp
;
364 argv
= kvm_getargv(kd
, kp
, argwidth
);
368 fmt_puts(*argv
, &left
);
370 fmt_putc(' ', &left
);
378 pr_header(nowp
, nusers
)
384 int days
, hrs
, i
, mins
;
392 * SCCS forces the string manipulation below, as it replaces
393 * %, M, and % in a character string with the file name.
395 (void)strftime(buf
, sizeof(buf
),
396 __CONCAT("%l:%","M%p"), localtime(nowp
));
397 buf
[sizeof(buf
) - 1] = '\0';
398 (void)printf("%s ", buf
);
401 * Print how long system has been up.
402 * (Found by looking getting "boottime" from the kernel)
405 mib
[1] = KERN_BOOTTIME
;
406 size
= sizeof(boottime
);
407 if (sysctl(mib
, 2, &boottime
, &size
, NULL
, 0) != -1 &&
408 boottime
.tv_sec
!= 0) {
409 uptime
= now
- boottime
.tv_sec
;
411 if (uptime
> SECSPERMIN
) {
412 days
= uptime
/ SECSPERDAY
;
413 uptime
%= SECSPERDAY
;
414 hrs
= uptime
/ SECSPERHOUR
;
415 uptime
%= SECSPERHOUR
;
416 mins
= uptime
/ SECSPERMIN
;
419 (void)printf(" %d day%s,", days
,
420 days
> 1 ? "s" : "");
421 if (hrs
> 0 && mins
> 0)
422 (void)printf(" %2d:%02d,", hrs
, mins
);
425 (void)printf(" %d hr%s,",
426 hrs
, hrs
> 1 ? "s" : "");
428 (void)printf(" %d min%s,",
429 mins
, mins
> 1 ? "s" : "");
434 /* Print number of users logged in to system */
435 (void)printf(" %d user%s", nusers
, nusers
!= 1 ? "s" : "");
438 * Print 1, 5, and 15 minute load averages.
440 if (getloadavg(avenrun
, sizeof(avenrun
) / sizeof(avenrun
[0])) == -1)
441 (void)printf(", no load average information available\n");
443 (void)printf(", load averages:");
444 for (i
= 0; i
< (sizeof(avenrun
) / sizeof(avenrun
[0])); i
++) {
447 (void)printf(" %.2f", avenrun
[i
]);
457 static struct stat sb
;
458 char ttybuf
[MAXPATHLEN
];
460 (void)snprintf(ttybuf
, sizeof(ttybuf
), "%s/%s", _PATH_DEV
, line
);
461 if (stat(ttybuf
, &sb
))
471 (void)fprintf(stderr
,
472 "usage: w: [-hin] [-M core] [-N system] [user]\n");
474 (void)fprintf(stderr
, "uptime\n");