Kernel part of bluetooth stack ported by Dmitry Komissaroff. Very much work
[dragonfly.git] / contrib / tcsh / tc.who.c
blobede76023706dda557d0e099945d7184592d94830
1 /* $Header: /src/pub/tcsh/tc.who.c,v 3.35 2002/07/01 21:12:04 christos Exp $ */
2 /*
3 * tc.who.c: Watch logins and logouts...
4 */
5 /*-
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
7 * All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
33 #include "sh.h"
35 RCSID("$Id: tc.who.c,v 3.35 2002/07/01 21:12:04 christos Exp $")
37 #include "tc.h"
39 #ifndef HAVENOUTMP
41 * kfk 26 Jan 1984 - for login watch functions.
43 #include <ctype.h>
45 #ifdef HAVEUTMPX
46 # include <utmpx.h>
47 /* I just redefine a few words here. Changing every occurrence below
48 * seems like too much of work. All UTMP functions have equivalent
49 * UTMPX counterparts, so they can be added all here when needed.
50 * Kimmo Suominen, Oct 14 1991
52 # ifndef _PATH_UTMP
53 # if defined(__UTMPX_FILE) && !defined(UTMPX_FILE)
54 # define _PATH_UTMP __UTMPX_FILE
55 # else
56 # define _PATH_UTMP UTMPX_FILE
57 # endif /* __UTMPX_FILE && !UTMPX_FILE */
58 # endif /* _PATH_UTMP */
59 # define utmp utmpx
60 # ifdef __MVS__
61 # define ut_time ut_tv.tv_sec
62 # define ut_name ut_user
63 # else
64 # define ut_time ut_xtime
65 # endif /* __MVS__ */
66 #else /* !HAVEUTMPX */
67 # ifndef WINNT_NATIVE
68 # include <utmp.h>
69 # endif /* WINNT_NATIVE */
70 #endif /* HAVEUTMPX */
72 #ifndef BROKEN_CC
73 # define UTNAMLEN sizeof(((struct utmp *) 0)->ut_name)
74 # define UTLINLEN sizeof(((struct utmp *) 0)->ut_line)
75 # ifdef UTHOST
76 # ifdef _SEQUENT_
77 # define UTHOSTLEN 100
78 # else
79 # define UTHOSTLEN sizeof(((struct utmp *) 0)->ut_host)
80 # endif
81 # endif /* UTHOST */
82 #else
83 /* give poor cc a little help if it needs it */
84 struct utmp __ut;
86 # define UTNAMLEN sizeof(__ut.ut_name)
87 # define UTLINLEN sizeof(__ut.ut_line)
88 # ifdef UTHOST
89 # ifdef _SEQUENT_
90 # define UTHOSTLEN 100
91 # else
92 # define UTHOSTLEN sizeof(__ut.ut_host)
93 # endif
94 # endif /* UTHOST */
95 #endif /* BROKEN_CC */
97 #ifndef _PATH_UTMP
98 # ifdef UTMP_FILE
99 # define _PATH_UTMP UTMP_FILE
100 # else
101 # define _PATH_UTMP "/etc/utmp"
102 # endif /* UTMP_FILE */
103 #endif /* _PATH_UTMP */
106 struct who {
107 struct who *who_next;
108 struct who *who_prev;
109 char who_name[UTNAMLEN + 1];
110 char who_new[UTNAMLEN + 1];
111 char who_tty[UTLINLEN + 1];
112 #ifdef UTHOST
113 char who_host[UTHOSTLEN + 1];
114 #endif /* UTHOST */
115 time_t who_time;
116 int who_status;
119 static struct who whohead, whotail;
120 static time_t watch_period = 0;
121 static time_t stlast = 0;
122 #ifdef WHODEBUG
123 static void debugwholist __P((struct who *, struct who *));
124 #endif
125 static void print_who __P((struct who *));
128 #define ONLINE 01
129 #define OFFLINE 02
130 #define CHANGED 04
131 #define STMASK 07
132 #define ANNOUNCE 010
135 * Karl Kleinpaste, 26 Jan 1984.
136 * Initialize the dummy tty list for login watch.
137 * This dummy list eliminates boundary conditions
138 * when doing pointer-chase searches.
140 void
141 initwatch()
143 whohead.who_next = &whotail;
144 whotail.who_prev = &whohead;
145 stlast = 1;
146 #ifdef WHODEBUG
147 debugwholist(NULL, NULL);
148 #endif /* WHODEBUG */
151 void
152 resetwatch()
154 watch_period = 0;
155 stlast = 0;
159 * Karl Kleinpaste, 26 Jan 1984.
160 * Watch /etc/utmp for login/logout changes.
162 void
163 watch_login(force)
164 int force;
166 int utmpfd, comp = -1, alldone;
167 int firsttime = stlast == 1;
168 #ifdef BSDSIGS
169 sigmask_t omask;
170 #endif /* BSDSIGS */
171 struct utmp utmp;
172 struct who *wp, *wpnew;
173 struct varent *v;
174 Char **vp = NULL;
175 time_t t, interval = MAILINTVL;
176 struct stat sta;
177 #if defined(UTHOST) && defined(_SEQUENT_)
178 char *host, *ut_find_host();
179 #endif
180 #ifdef WINNT_NATIVE
181 static int ncbs_posted = 0;
182 USE(utmp);
183 USE(utmpfd);
184 USE(sta);
185 USE(wpnew);
186 #endif /* WINNT_NATIVE */
188 /* stop SIGINT, lest our login list get trashed. */
189 #ifdef BSDSIGS
190 omask = sigblock(sigmask(SIGINT));
191 #else
192 (void) sighold(SIGINT);
193 #endif
195 v = adrof(STRwatch);
196 if ((v == NULL || v->vec == NULL) && !force) {
197 #ifdef BSDSIGS
198 (void) sigsetmask(omask);
199 #else
200 (void) sigrelse(SIGINT);
201 #endif
202 return; /* no names to watch */
204 if (!force) {
205 trim(vp = v->vec);
206 if (blklen(vp) % 2) /* odd # args: 1st == # minutes. */
207 interval = (number(*vp)) ? (getn(*vp++) * 60) : MAILINTVL;
209 else
210 interval = 0;
212 (void) time(&t);
213 #ifdef WINNT_NATIVE
215 * Since NCB_ASTATs take time, start em async at least 90 secs
216 * before we are due -amol 6/5/97
218 if (!ncbs_posted) {
219 unsigned long tdiff = t - watch_period;
220 if (!watch_period || ((tdiff > 0) && (tdiff > (interval - 90)))) {
221 start_ncbs(vp);
222 ncbs_posted = 1;
225 #endif /* WINNT_NATIVE */
226 if (t - watch_period < interval) {
227 #ifdef BSDSIGS
228 (void) sigsetmask(omask);
229 #else
230 (void) sigrelse(SIGINT);
231 #endif
232 return; /* not long enough yet... */
234 watch_period = t;
235 #ifdef WINNT_NATIVE
236 ncbs_posted = 0;
237 #else /* !WINNT_NATIVE */
240 * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
241 * Don't open utmp all the time, stat it first...
243 if (stat(_PATH_UTMP, &sta)) {
244 if (!force)
245 xprintf(CGETS(26, 1,
246 "cannot stat %s. Please \"unset watch\".\n"),
247 _PATH_UTMP);
248 # ifdef BSDSIGS
249 (void) sigsetmask(omask);
250 # else
251 (void) sigrelse(SIGINT);
252 # endif
253 return;
255 if (stlast == sta.st_mtime) {
256 # ifdef BSDSIGS
257 (void) sigsetmask(omask);
258 # else
259 (void) sigrelse(SIGINT);
260 # endif
261 return;
263 stlast = sta.st_mtime;
264 if ((utmpfd = open(_PATH_UTMP, O_RDONLY)) < 0) {
265 if (!force)
266 xprintf(CGETS(26, 2,
267 "%s cannot be opened. Please \"unset watch\".\n"),
268 _PATH_UTMP);
269 # ifdef BSDSIGS
270 (void) sigsetmask(omask);
271 # else
272 (void) sigrelse(SIGINT);
273 # endif
274 return;
278 * xterm clears the entire utmp entry - mark everyone on the status list
279 * OFFLINE or we won't notice X "logouts"
281 for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) {
282 wp->who_status = OFFLINE;
283 wp->who_time = 0;
287 * Read in the utmp file, sort the entries, and update existing entries or
288 * add new entries to the status list.
290 while (read(utmpfd, (char *) &utmp, sizeof utmp) == sizeof utmp) {
292 # ifdef DEAD_PROCESS
293 # ifndef IRIS4D
294 if (utmp.ut_type != USER_PROCESS)
295 continue;
296 # else
297 /* Why is that? Cause the utmp file is always corrupted??? */
298 if (utmp.ut_type != USER_PROCESS && utmp.ut_type != DEAD_PROCESS)
299 continue;
300 # endif /* IRIS4D */
301 # endif /* DEAD_PROCESS */
303 if (utmp.ut_name[0] == '\0' && utmp.ut_line[0] == '\0')
304 continue; /* completely void entry */
305 # ifdef DEAD_PROCESS
306 if (utmp.ut_type == DEAD_PROCESS && utmp.ut_line[0] == '\0')
307 continue;
308 # endif /* DEAD_PROCESS */
309 wp = whohead.who_next;
310 while (wp->who_next && (comp = strncmp(wp->who_tty, utmp.ut_line, UTLINLEN)) < 0)
311 wp = wp->who_next;/* find that tty! */
313 if (wp->who_next && comp == 0) { /* found the tty... */
314 # ifdef DEAD_PROCESS
315 if (utmp.ut_type == DEAD_PROCESS) {
316 wp->who_time = utmp.ut_time;
317 wp->who_status = OFFLINE;
319 else
320 # endif /* DEAD_PROCESS */
321 if (utmp.ut_name[0] == '\0') {
322 wp->who_time = utmp.ut_time;
323 wp->who_status = OFFLINE;
325 else if (strncmp(utmp.ut_name, wp->who_name, UTNAMLEN) == 0) {
326 /* someone is logged in */
327 wp->who_time = utmp.ut_time;
328 wp->who_status = 0; /* same guy */
330 else {
331 (void) strncpy(wp->who_new, utmp.ut_name, UTNAMLEN);
332 # ifdef UTHOST
333 # ifdef _SEQUENT_
334 host = ut_find_host(wp->who_tty);
335 if (host)
336 (void) strncpy(wp->who_host, host, UTHOSTLEN);
337 else
338 wp->who_host[0] = 0;
339 # else
340 (void) strncpy(wp->who_host, utmp.ut_host, UTHOSTLEN);
341 # endif
342 # endif /* UTHOST */
343 wp->who_time = utmp.ut_time;
344 if (wp->who_name[0] == '\0')
345 wp->who_status = ONLINE;
346 else
347 wp->who_status = CHANGED;
350 else { /* new tty in utmp */
351 wpnew = (struct who *) xcalloc(1, sizeof *wpnew);
352 (void) strncpy(wpnew->who_tty, utmp.ut_line, UTLINLEN);
353 # ifdef UTHOST
354 # ifdef _SEQUENT_
355 host = ut_find_host(wpnew->who_tty);
356 if (host)
357 (void) strncpy(wpnew->who_host, host, UTHOSTLEN);
358 else
359 wpnew->who_host[0] = 0;
360 # else
361 (void) strncpy(wpnew->who_host, utmp.ut_host, UTHOSTLEN);
362 # endif
363 # endif /* UTHOST */
364 wpnew->who_time = utmp.ut_time;
365 # ifdef DEAD_PROCESS
366 if (utmp.ut_type == DEAD_PROCESS)
367 wpnew->who_status = OFFLINE;
368 else
369 # endif /* DEAD_PROCESS */
370 if (utmp.ut_name[0] == '\0')
371 wpnew->who_status = OFFLINE;
372 else {
373 (void) strncpy(wpnew->who_new, utmp.ut_name, UTNAMLEN);
374 wpnew->who_status = ONLINE;
376 # ifdef WHODEBUG
377 debugwholist(wpnew, wp);
378 # endif /* WHODEBUG */
380 wpnew->who_next = wp; /* link in a new 'who' */
381 wpnew->who_prev = wp->who_prev;
382 wpnew->who_prev->who_next = wpnew;
383 wp->who_prev = wpnew; /* linked in now */
386 (void) close(utmpfd);
387 # if defined(UTHOST) && defined(_SEQUENT_)
388 endutent();
389 # endif
390 #endif /* !WINNT_NATIVE */
392 if (force || vp == NULL)
393 return;
396 * The state of all logins is now known, so we can search the user's list
397 * of watchables to print the interesting ones.
399 for (alldone = 0; !alldone && *vp != NULL && **vp != '\0' &&
400 *(vp + 1) != NULL && **(vp + 1) != '\0';
401 vp += 2) { /* args used in pairs... */
403 if (eq(*vp, STRany) && eq(*(vp + 1), STRany))
404 alldone = 1;
406 for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) {
407 if (wp->who_status & ANNOUNCE ||
408 (!eq(STRany, vp[0]) &&
409 !Gmatch(str2short(wp->who_name), vp[0]) &&
410 !Gmatch(str2short(wp->who_new), vp[0])) ||
411 (!Gmatch(str2short(wp->who_tty), vp[1]) &&
412 !eq(STRany, vp[1])))
413 continue; /* entry doesn't qualify */
414 /* already printed or not right one to print */
417 if (wp->who_time == 0)/* utmp entry was cleared */
418 wp->who_time = watch_period;
420 if ((wp->who_status & OFFLINE) &&
421 (wp->who_name[0] != '\0')) {
422 if (!firsttime)
423 print_who(wp);
424 wp->who_name[0] = '\0';
425 wp->who_status |= ANNOUNCE;
426 continue;
428 if (wp->who_status & ONLINE) {
429 if (!firsttime)
430 print_who(wp);
431 (void) strcpy(wp->who_name, wp->who_new);
432 wp->who_status |= ANNOUNCE;
433 continue;
435 if (wp->who_status & CHANGED) {
436 if (!firsttime)
437 print_who(wp);
438 (void) strcpy(wp->who_name, wp->who_new);
439 wp->who_status |= ANNOUNCE;
440 continue;
444 #ifdef BSDSIGS
445 (void) sigsetmask(omask);
446 #else
447 (void) sigrelse(SIGINT);
448 #endif
451 #ifdef WHODEBUG
452 static void
453 debugwholist(new, wp)
454 register struct who *new, *wp;
456 register struct who *a;
458 a = whohead.who_next;
459 while (a->who_next != NULL) {
460 xprintf("%s/%s -> ", a->who_name, a->who_tty);
461 a = a->who_next;
463 xprintf("TAIL\n");
464 if (a != &whotail) {
465 xprintf(CGETS(26, 3, "BUG! last element is not whotail!\n"));
466 abort();
468 a = whotail.who_prev;
469 xprintf(CGETS(26, 4, "backward: "));
470 while (a->who_prev != NULL) {
471 xprintf("%s/%s -> ", a->who_name, a->who_tty);
472 a = a->who_prev;
474 xprintf("HEAD\n");
475 if (a != &whohead) {
476 xprintf(CGETS(26, 5, "BUG! first element is not whohead!\n"));
477 abort();
479 if (new)
480 xprintf(CGETS(26, 6, "new: %s/%s\n"), new->who_name, new->who_tty);
481 if (wp)
482 xprintf("wp: %s/%s\n", wp->who_name, wp->who_tty);
484 #endif /* WHODEBUG */
487 static void
488 print_who(wp)
489 struct who *wp;
491 #ifdef UTHOST
492 Char *cp = str2short(CGETS(26, 7, "%n has %a %l from %m."));
493 #else
494 Char *cp = str2short(CGETS(26, 8, "%n has %a %l."));
495 #endif /* UTHOST */
496 struct varent *vp = adrof(STRwho);
497 Char buf[BUFSIZE];
499 if (vp && vp->vec && vp->vec[0])
500 cp = vp->vec[0];
502 tprintf(FMT_WHO, buf, cp, BUFSIZE, NULL, wp->who_time, (ptr_t) wp);
503 for (cp = buf; *cp;)
504 xputchar(*cp++);
505 xputchar('\n');
506 } /* end print_who */
509 const char *
510 who_info(ptr, c, wbuf, wbufsiz)
511 ptr_t ptr;
512 int c;
513 char *wbuf;
514 size_t wbufsiz;
516 struct who *wp = (struct who *) ptr;
517 #ifdef UTHOST
518 char *wb = wbuf;
519 int flg;
520 char *pb;
521 #endif /* UTHOST */
523 switch (c) {
524 case 'n': /* user name */
525 switch (wp->who_status & STMASK) {
526 case ONLINE:
527 case CHANGED:
528 return wp->who_new;
529 case OFFLINE:
530 return wp->who_name;
531 default:
532 break;
534 break;
536 case 'a':
537 switch (wp->who_status & STMASK) {
538 case ONLINE:
539 return CGETS(26, 9, "logged on");
540 case OFFLINE:
541 return CGETS(26, 10, "logged off");
542 case CHANGED:
543 xsnprintf(wbuf, wbufsiz, CGETS(26, 11, "replaced %s on"),
544 wp->who_name);
545 return wbuf;
546 default:
547 break;
549 break;
551 #ifdef UTHOST
552 case 'm':
553 if (wp->who_host[0] == '\0')
554 return CGETS(26, 12, "local");
555 else {
556 /* the ':' stuff is for <host>:<display>.<screen> */
557 for (pb = wp->who_host, flg = Isdigit(*pb) ? '\0' : '.';
558 *pb != '\0' &&
559 (*pb != flg || ((pb = strchr(pb, ':')) != 0));
560 pb++) {
561 if (*pb == ':')
562 flg = '\0';
563 *wb++ = Isupper(*pb) ? Tolower(*pb) : *pb;
565 *wb = '\0';
566 return wbuf;
569 case 'M':
570 if (wp->who_host[0] == '\0')
571 return CGETS(26, 12, "local");
572 else {
573 for (pb = wp->who_host; *pb != '\0'; pb++)
574 *wb++ = Isupper(*pb) ? Tolower(*pb) : *pb;
575 *wb = '\0';
576 return wbuf;
578 #endif /* UTHOST */
580 case 'l':
581 return wp->who_tty;
583 default:
584 wbuf[0] = '%';
585 wbuf[1] = (char) c;
586 wbuf[2] = '\0';
587 return wbuf;
589 return NULL;
592 void
593 /*ARGSUSED*/
594 dolog(v, c)
595 Char **v;
596 struct command *c;
598 struct who *wp;
599 struct varent *vp;
601 USE(v);
602 USE(c);
603 vp = adrof(STRwatch); /* lint insists vp isn't used unless we */
604 if (vp == NULL) /* unless we assign it outside the if */
605 stderror(ERR_NOWATCH);
606 resetwatch();
607 wp = whohead.who_next;
608 while (wp->who_next != NULL) {
609 wp->who_name[0] = '\0';
610 wp = wp->who_next;
614 # ifdef UTHOST
615 size_t
616 utmphostsize()
618 return UTHOSTLEN;
621 char *
622 utmphost()
624 char *tty = short2str(varval(STRtty));
625 struct who *wp;
626 char *host = NULL;
628 watch_login(1);
630 for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) {
631 if (strcmp(tty, wp->who_tty) == 0)
632 host = wp->who_host;
633 wp->who_name[0] = '\0';
635 resetwatch();
636 return host;
638 # endif /* UTHOST */
640 #ifdef WINNT_NATIVE
641 void add_to_who_list(name, mach_nm)
642 char *name;
643 char *mach_nm;
646 struct who *wp, *wpnew;
647 int comp = -1;
649 wp = whohead.who_next;
650 while (wp->who_next && (comp = strncmp(wp->who_tty,mach_nm,UTLINLEN)) < 0)
651 wp = wp->who_next;/* find that tty! */
653 if (wp->who_next && comp == 0) { /* found the tty... */
655 if (*name == '\0') {
656 wp->who_time = 0;
657 wp->who_status = OFFLINE;
659 else if (strncmp(name, wp->who_name, UTNAMLEN) == 0) {
660 /* someone is logged in */
661 wp->who_time = 0;
662 wp->who_status = 0; /* same guy */
664 else {
665 (void) strncpy(wp->who_new, name, UTNAMLEN);
666 wp->who_time = 0;
667 if (wp->who_name[0] == '\0')
668 wp->who_status = ONLINE;
669 else
670 wp->who_status = CHANGED;
673 else {
674 wpnew = (struct who *) xcalloc(1, sizeof *wpnew);
675 (void) strncpy(wpnew->who_tty, mach_nm, UTLINLEN);
676 wpnew->who_time = 0;
677 if (*name == '\0')
678 wpnew->who_status = OFFLINE;
679 else {
680 (void) strncpy(wpnew->who_new, name, UTNAMLEN);
681 wpnew->who_status = ONLINE;
683 #ifdef WHODEBUG
684 debugwholist(wpnew, wp);
685 #endif /* WHODEBUG */
687 wpnew->who_next = wp; /* link in a new 'who' */
688 wpnew->who_prev = wp->who_prev;
689 wpnew->who_prev->who_next = wpnew;
690 wp->who_prev = wpnew; /* linked in now */
693 #endif /* WINNT_NATIVE */
694 #endif /* HAVENOUTMP */