/contrib/tcsh/tc.who.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 717 lines · 583 code · 56 blank · 78 comment · 161 complexity · e7708c8b8336d5a7fedafd3ba744adbb MD5 · raw file

  1. /* $Header: /p/tcsh/cvsroot/tcsh/tc.who.c,v 3.57 2012/01/17 20:53:38 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.
  8. *
  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.
  20. *
  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.
  32. */
  33. #include "sh.h"
  34. RCSID("$tcsh: tc.who.c,v 3.57 2012/01/17 20:53:38 christos Exp $")
  35. #include "tc.h"
  36. #ifndef HAVENOUTMP
  37. /*
  38. * kfk 26 Jan 1984 - for login watch functions.
  39. */
  40. #include <ctype.h>
  41. #ifdef HAVE_UTMPX_H
  42. # include <utmpx.h>
  43. # define UTNAMLEN sizeof(((struct utmpx *) 0)->ut_name)
  44. # define UTLINLEN sizeof(((struct utmpx *) 0)->ut_line)
  45. # ifdef HAVE_STRUCT_UTMPX_UT_HOST
  46. # define UTHOSTLEN sizeof(((struct utmpx *) 0)->ut_host)
  47. # endif
  48. /* I just redefine a few words here. Changing every occurrence below
  49. * seems like too much of work. All UTMP functions have equivalent
  50. * UTMPX counterparts, so they can be added all here when needed.
  51. * Kimmo Suominen, Oct 14 1991
  52. */
  53. # if defined(__UTMPX_FILE) && !defined(UTMPX_FILE)
  54. # define TCSH_PATH_UTMP __UTMPX_FILE
  55. # elif defined(_PATH_UTMPX)
  56. # define TCSH_PATH_UTMP _PATH_UTMPX
  57. # elif defined(UTMPX_FILE)
  58. # define TCSH_PATH_UTMP UTMPX_FILE
  59. # elif __FreeBSD_version >= 900000
  60. # /* Why isn't this defined somewhere? */
  61. # define TCSH_PATH_UTMP "/var/run/utx.active"
  62. # elif defined(__hpux)
  63. # define TCSH_PATH_UTMP "/etc/utmpx"
  64. # endif
  65. # if defined(TCSH_PATH_UTMP) || !defined(HAVE_UTMP_H)
  66. # define utmp utmpx
  67. # define TCSH_USE_UTMPX
  68. # if defined(HAVE_GETUTENT) || defined(HAVE_GETUTXENT)
  69. # define getutent getutxent
  70. # define setutent setutxent
  71. # define endutent endutxent
  72. # endif /* HAVE_GETUTENT || HAVE_GETUTXENT */
  73. # if defined(HAVE_STRUCT_UTMPX_UT_TV)
  74. # define ut_time ut_tv.tv_sec
  75. # elif defined(HAVE_STRUCT_UTMPX_UT_XTIME)
  76. # define ut_time ut_xtime
  77. # endif
  78. # if defined(HAVE_STRUCT_UTMPX_UT_USER)
  79. # define ut_name ut_user
  80. # endif
  81. # endif /* TCSH_PATH_UTMP || !HAVE_UTMP_H */
  82. #endif /* HAVE_UTMPX_H */
  83. #if !defined(TCSH_USE_UTMPX) && defined(HAVE_UTMP_H)
  84. # include <utmp.h>
  85. # if defined(HAVE_STRUCT_UTMP_UT_TV)
  86. # define ut_time ut_tv.tv_sec
  87. # elif defined(HAVE_STRUCT_UTMP_UT_XTIME)
  88. # define ut_time ut_xtime
  89. # endif
  90. # if defined(HAVE_STRUCT_UTMP_UT_USER)
  91. # define ut_name ut_user
  92. # endif
  93. # ifndef BROKEN_CC
  94. # define UTNAMLEN sizeof(((struct utmp *) 0)->ut_name)
  95. # define UTLINLEN sizeof(((struct utmp *) 0)->ut_line)
  96. # ifdef HAVE_STRUCT_UTMP_UT_HOST
  97. # ifdef _SEQUENT_
  98. # define UTHOSTLEN 100
  99. # else
  100. # define UTHOSTLEN sizeof(((struct utmp *) 0)->ut_host)
  101. # endif
  102. # endif /* HAVE_STRUCT_UTMP_UT_HOST */
  103. # else
  104. /* give poor cc a little help if it needs it */
  105. struct utmp __ut;
  106. # define UTNAMLEN sizeof(__ut.ut_name)
  107. # define UTLINLEN sizeof(__ut.ut_line)
  108. # ifdef HAVE_STRUCT_UTMP_UT_HOST
  109. # ifdef _SEQUENT_
  110. # define UTHOSTLEN 100
  111. # else
  112. # define UTHOSTLEN sizeof(__ut.ut_host)
  113. # endif
  114. # endif /* HAVE_STRUCT_UTMP_UT_HOST */
  115. # endif /* BROKEN_CC */
  116. # ifndef TCSH_PATH_UTMP
  117. # ifdef UTMP_FILE
  118. # define TCSH_PATH_UTMP UTMP_FILE
  119. # elif defined(_PATH_UTMP)
  120. # define TCSH_PATH_UTMP _PATH_UTMP
  121. # else
  122. # define TCSH_PATH_UTMP "/etc/utmp"
  123. # endif /* UTMP_FILE */
  124. # endif /* TCSH_PATH_UTMP */
  125. #endif /* !TCSH_USE_UTMPX && HAVE_UTMP_H */
  126. #ifndef UTNAMLEN
  127. #define UTNAMLEN 64
  128. #endif
  129. #ifndef UTLINLEN
  130. #define UTLINLEN 64
  131. #endif
  132. struct who {
  133. struct who *who_next;
  134. struct who *who_prev;
  135. char who_name[UTNAMLEN + 1];
  136. char who_new[UTNAMLEN + 1];
  137. char who_tty[UTLINLEN + 1];
  138. #ifdef UTHOSTLEN
  139. char who_host[UTHOSTLEN + 1];
  140. #endif /* UTHOSTLEN */
  141. time_t who_time;
  142. int who_status;
  143. };
  144. static struct who whohead, whotail;
  145. static time_t watch_period = 0;
  146. static time_t stlast = 0;
  147. #ifdef WHODEBUG
  148. static void debugwholist (struct who *, struct who *);
  149. #endif
  150. static void print_who (struct who *);
  151. #define ONLINE 01
  152. #define OFFLINE 02
  153. #define CHANGED 04
  154. #define STMASK 07
  155. #define ANNOUNCE 010
  156. #define CLEARED 020
  157. /*
  158. * Karl Kleinpaste, 26 Jan 1984.
  159. * Initialize the dummy tty list for login watch.
  160. * This dummy list eliminates boundary conditions
  161. * when doing pointer-chase searches.
  162. */
  163. void
  164. initwatch(void)
  165. {
  166. whohead.who_next = &whotail;
  167. whotail.who_prev = &whohead;
  168. stlast = 1;
  169. #ifdef WHODEBUG
  170. debugwholist(NULL, NULL);
  171. #endif /* WHODEBUG */
  172. }
  173. void
  174. resetwatch(void)
  175. {
  176. watch_period = 0;
  177. stlast = 0;
  178. }
  179. /*
  180. * Karl Kleinpaste, 26 Jan 1984.
  181. * Watch /etc/utmp for login/logout changes.
  182. */
  183. void
  184. watch_login(int force)
  185. {
  186. int comp = -1, alldone;
  187. int firsttime = stlast == 1;
  188. #if defined(HAVE_GETUTENT) || defined(HAVE_GETUTXENT)
  189. struct utmp *uptr;
  190. #else
  191. int utmpfd;
  192. #endif
  193. struct utmp utmp;
  194. struct who *wp, *wpnew;
  195. struct varent *v;
  196. Char **vp = NULL;
  197. time_t t, interval = MAILINTVL;
  198. struct stat sta;
  199. #if defined(HAVE_STRUCT_UTMP_UT_HOST) && defined(_SEQUENT_)
  200. char *host, *ut_find_host();
  201. #endif
  202. #ifdef WINNT_NATIVE
  203. static int ncbs_posted = 0;
  204. USE(utmp);
  205. USE(utmpfd);
  206. USE(sta);
  207. USE(wpnew);
  208. #endif /* WINNT_NATIVE */
  209. /* stop SIGINT, lest our login list get trashed. */
  210. pintr_disabled++;
  211. cleanup_push(&pintr_disabled, disabled_cleanup);
  212. v = adrof(STRwatch);
  213. if ((v == NULL || v->vec == NULL) && !force) {
  214. cleanup_until(&pintr_disabled);
  215. return; /* no names to watch */
  216. }
  217. if (!force) {
  218. trim(vp = v->vec);
  219. if (blklen(vp) % 2) /* odd # args: 1st == # minutes. */
  220. interval = (number(*vp)) ? (getn(*vp++) * 60) : MAILINTVL;
  221. }
  222. else
  223. interval = 0;
  224. (void) time(&t);
  225. #ifdef WINNT_NATIVE
  226. /*
  227. * Since NCB_ASTATs take time, start em async at least 90 secs
  228. * before we are due -amol 6/5/97
  229. */
  230. if (!ncbs_posted) {
  231. time_t tdiff = t - watch_period;
  232. if (!watch_period || ((tdiff > 0) && (tdiff > (interval - 90)))) {
  233. start_ncbs(vp);
  234. ncbs_posted = 1;
  235. }
  236. }
  237. #endif /* WINNT_NATIVE */
  238. if (t - watch_period < interval) {
  239. cleanup_until(&pintr_disabled);
  240. return; /* not long enough yet... */
  241. }
  242. watch_period = t;
  243. #ifdef WINNT_NATIVE
  244. ncbs_posted = 0;
  245. #else /* !WINNT_NATIVE */
  246. /*
  247. * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
  248. * Don't open utmp all the time, stat it first...
  249. */
  250. if (stat(TCSH_PATH_UTMP, &sta)) {
  251. if (!force)
  252. xprintf(CGETS(26, 1,
  253. "cannot stat %s. Please \"unset watch\".\n"),
  254. TCSH_PATH_UTMP);
  255. cleanup_until(&pintr_disabled);
  256. return;
  257. }
  258. if (stlast == sta.st_mtime) {
  259. cleanup_until(&pintr_disabled);
  260. return;
  261. }
  262. stlast = sta.st_mtime;
  263. #if defined(HAVE_GETUTENT) || defined(HAVE_GETUTXENT)
  264. setutent();
  265. #else
  266. if ((utmpfd = xopen(TCSH_PATH_UTMP, O_RDONLY|O_LARGEFILE)) < 0) {
  267. if (!force)
  268. xprintf(CGETS(26, 2,
  269. "%s cannot be opened. Please \"unset watch\".\n"),
  270. TCSH_PATH_UTMP);
  271. cleanup_until(&pintr_disabled);
  272. return;
  273. }
  274. cleanup_push(&utmpfd, open_cleanup);
  275. #endif
  276. /*
  277. * xterm clears the entire utmp entry - mark everyone on the status list
  278. * OFFLINE or we won't notice X "logouts"
  279. */
  280. for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next)
  281. wp->who_status = OFFLINE | CLEARED;
  282. /*
  283. * Read in the utmp file, sort the entries, and update existing entries or
  284. * add new entries to the status list.
  285. */
  286. #if defined(HAVE_GETUTENT) || defined(HAVE_GETUTXENT)
  287. while ((uptr = getutent()) != NULL) {
  288. memcpy(&utmp, uptr, sizeof (utmp));
  289. #else
  290. while (xread(utmpfd, &utmp, sizeof utmp) == sizeof utmp) {
  291. #endif
  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 */
  302. if (utmp.ut_name[0] == '\0' && utmp.ut_line[0] == '\0')
  303. continue; /* completely void entry */
  304. # ifdef DEAD_PROCESS
  305. if (utmp.ut_type == DEAD_PROCESS && utmp.ut_line[0] == '\0')
  306. continue;
  307. # endif /* DEAD_PROCESS */
  308. wp = whohead.who_next;
  309. while (wp->who_next && (comp = strncmp(wp->who_tty, utmp.ut_line, UTLINLEN)) < 0)
  310. wp = wp->who_next;/* find that tty! */
  311. if (wp->who_next && comp == 0) { /* found the tty... */
  312. if (utmp.ut_time < wp->who_time)
  313. continue;
  314. # ifdef DEAD_PROCESS
  315. if (utmp.ut_type == DEAD_PROCESS) {
  316. wp->who_time = utmp.ut_time;
  317. wp->who_status = OFFLINE;
  318. }
  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;
  324. }
  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 = ONLINE | ANNOUNCE; /* same guy */
  329. }
  330. else {
  331. (void) strncpy(wp->who_new, utmp.ut_name, UTNAMLEN);
  332. # ifdef UTHOSTLEN
  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 /* UTHOSTLEN */
  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;
  348. }
  349. }
  350. else { /* new tty in utmp */
  351. wpnew = xcalloc(1, sizeof *wpnew);
  352. (void) strncpy(wpnew->who_tty, utmp.ut_line, UTLINLEN);
  353. # ifdef UTHOSTLEN
  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 /* UTHOSTLEN */
  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;
  375. }
  376. # ifdef WHODEBUG
  377. debugwholist(wpnew, wp);
  378. # endif /* WHODEBUG */
  379. wpnew->who_next = wp; /* link in a new 'who' */
  380. wpnew->who_prev = wp->who_prev;
  381. wpnew->who_prev->who_next = wpnew;
  382. wp->who_prev = wpnew; /* linked in now */
  383. }
  384. }
  385. #if defined(HAVE_GETUTENT) || defined(HAVE_GETUTXENT)
  386. endutent();
  387. #else
  388. cleanup_until(&utmpfd);
  389. #endif
  390. #endif /* !WINNT_NATIVE */
  391. if (force || vp == NULL) {
  392. cleanup_until(&pintr_disabled);
  393. return;
  394. }
  395. /*
  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.
  398. */
  399. for (alldone = 0; !alldone && *vp != NULL && **vp != '\0' &&
  400. *(vp + 1) != NULL && **(vp + 1) != '\0';
  401. vp += 2) { /* args used in pairs... */
  402. if (eq(*vp, STRany) && eq(*(vp + 1), STRany))
  403. alldone = 1;
  404. for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) {
  405. if (wp->who_status & ANNOUNCE ||
  406. (!eq(STRany, vp[0]) &&
  407. !Gmatch(str2short(wp->who_name), vp[0]) &&
  408. !Gmatch(str2short(wp->who_new), vp[0])) ||
  409. (!Gmatch(str2short(wp->who_tty), vp[1]) &&
  410. !eq(STRany, vp[1])))
  411. continue; /* entry doesn't qualify */
  412. /* already printed or not right one to print */
  413. if (wp->who_status & CLEARED) {/* utmp entry was cleared */
  414. wp->who_time = watch_period;
  415. wp->who_status &= ~CLEARED;
  416. }
  417. if ((wp->who_status & OFFLINE) &&
  418. (wp->who_name[0] != '\0')) {
  419. if (!firsttime)
  420. print_who(wp);
  421. wp->who_name[0] = '\0';
  422. wp->who_status |= ANNOUNCE;
  423. continue;
  424. }
  425. if (wp->who_status & ONLINE) {
  426. if (!firsttime)
  427. print_who(wp);
  428. (void) strcpy(wp->who_name, wp->who_new);
  429. wp->who_status |= ANNOUNCE;
  430. continue;
  431. }
  432. if (wp->who_status & CHANGED) {
  433. if (!firsttime)
  434. print_who(wp);
  435. (void) strcpy(wp->who_name, wp->who_new);
  436. wp->who_status |= ANNOUNCE;
  437. continue;
  438. }
  439. }
  440. }
  441. cleanup_until(&pintr_disabled);
  442. }
  443. #ifdef WHODEBUG
  444. static void
  445. debugwholist(struct who *new, struct who *wp)
  446. {
  447. struct who *a;
  448. a = whohead.who_next;
  449. while (a->who_next != NULL) {
  450. xprintf("%s/%s -> ", a->who_name, a->who_tty);
  451. a = a->who_next;
  452. }
  453. xprintf("TAIL\n");
  454. if (a != &whotail) {
  455. xprintf(CGETS(26, 3, "BUG! last element is not whotail!\n"));
  456. abort();
  457. }
  458. a = whotail.who_prev;
  459. xprintf(CGETS(26, 4, "backward: "));
  460. while (a->who_prev != NULL) {
  461. xprintf("%s/%s -> ", a->who_name, a->who_tty);
  462. a = a->who_prev;
  463. }
  464. xprintf("HEAD\n");
  465. if (a != &whohead) {
  466. xprintf(CGETS(26, 5, "BUG! first element is not whohead!\n"));
  467. abort();
  468. }
  469. if (new)
  470. xprintf(CGETS(26, 6, "new: %s/%s\n"), new->who_name, new->who_tty);
  471. if (wp)
  472. xprintf("wp: %s/%s\n", wp->who_name, wp->who_tty);
  473. }
  474. #endif /* WHODEBUG */
  475. static void
  476. print_who(struct who *wp)
  477. {
  478. #ifdef UTHOSTLEN
  479. Char *cp = str2short(CGETS(26, 7, "%n has %a %l from %m."));
  480. #else
  481. Char *cp = str2short(CGETS(26, 8, "%n has %a %l."));
  482. #endif /* UTHOSTLEN */
  483. struct varent *vp = adrof(STRwho);
  484. Char *str;
  485. if (vp && vp->vec && vp->vec[0])
  486. cp = vp->vec[0];
  487. str = tprintf(FMT_WHO, cp, NULL, wp->who_time, wp);
  488. cleanup_push(str, xfree);
  489. for (cp = str; *cp;)
  490. xputwchar(*cp++);
  491. cleanup_until(str);
  492. xputchar('\n');
  493. } /* end print_who */
  494. char *
  495. who_info(ptr_t ptr, int c)
  496. {
  497. struct who *wp = ptr;
  498. char *wbuf;
  499. #ifdef UTHOSTLEN
  500. char *wb;
  501. int flg;
  502. char *pb;
  503. #endif /* UTHOSTLEN */
  504. switch (c) {
  505. case 'n': /* user name */
  506. switch (wp->who_status & STMASK) {
  507. case ONLINE:
  508. case CHANGED:
  509. return strsave(wp->who_new);
  510. case OFFLINE:
  511. return strsave(wp->who_name);
  512. default:
  513. break;
  514. }
  515. break;
  516. case 'a':
  517. switch (wp->who_status & STMASK) {
  518. case ONLINE:
  519. return strsave(CGETS(26, 9, "logged on"));
  520. case OFFLINE:
  521. return strsave(CGETS(26, 10, "logged off"));
  522. case CHANGED:
  523. return xasprintf(CGETS(26, 11, "replaced %s on"), wp->who_name);
  524. default:
  525. break;
  526. }
  527. break;
  528. #ifdef UTHOSTLEN
  529. case 'm':
  530. if (wp->who_host[0] == '\0')
  531. return strsave(CGETS(26, 12, "local"));
  532. else {
  533. pb = wp->who_host;
  534. wbuf = xmalloc(strlen(pb) + 1);
  535. wb = wbuf;
  536. /* the ':' stuff is for <host>:<display>.<screen> */
  537. for (flg = isdigit((unsigned char)*pb) ? '\0' : '.';
  538. *pb != '\0' && (*pb != flg || ((pb = strchr(pb, ':')) != 0));
  539. pb++) {
  540. if (*pb == ':')
  541. flg = '\0';
  542. *wb++ = isupper((unsigned char)*pb) ?
  543. tolower((unsigned char)*pb) : *pb;
  544. }
  545. *wb = '\0';
  546. return wbuf;
  547. }
  548. case 'M':
  549. if (wp->who_host[0] == '\0')
  550. return strsave(CGETS(26, 12, "local"));
  551. else {
  552. pb = wp->who_host;
  553. wbuf = xmalloc(strlen(pb) + 1);
  554. wb = wbuf;
  555. for (; *pb != '\0'; pb++)
  556. *wb++ = isupper((unsigned char)*pb) ?
  557. tolower((unsigned char)*pb) : *pb;
  558. *wb = '\0';
  559. return wbuf;
  560. }
  561. #endif /* UTHOSTLEN */
  562. case 'l':
  563. return strsave(wp->who_tty);
  564. default:
  565. wbuf = xmalloc(3);
  566. wbuf[0] = '%';
  567. wbuf[1] = (char) c;
  568. wbuf[2] = '\0';
  569. return wbuf;
  570. }
  571. return NULL;
  572. }
  573. void
  574. /*ARGSUSED*/
  575. dolog(Char **v, struct command *c)
  576. {
  577. struct who *wp;
  578. struct varent *vp;
  579. USE(v);
  580. USE(c);
  581. vp = adrof(STRwatch); /* lint insists vp isn't used unless we */
  582. if (vp == NULL) /* unless we assign it outside the if */
  583. stderror(ERR_NOWATCH);
  584. resetwatch();
  585. wp = whohead.who_next;
  586. while (wp->who_next != NULL) {
  587. wp->who_name[0] = '\0';
  588. wp = wp->who_next;
  589. }
  590. }
  591. # ifdef UTHOSTLEN
  592. size_t
  593. utmphostsize(void)
  594. {
  595. return UTHOSTLEN;
  596. }
  597. char *
  598. utmphost(void)
  599. {
  600. char *tty = short2str(varval(STRtty));
  601. struct who *wp;
  602. char *host = NULL;
  603. watch_login(1);
  604. for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) {
  605. if (strcmp(tty, wp->who_tty) == 0)
  606. host = wp->who_host;
  607. wp->who_name[0] = '\0';
  608. }
  609. resetwatch();
  610. return host;
  611. }
  612. # endif /* UTHOSTLEN */
  613. #ifdef WINNT_NATIVE
  614. void
  615. add_to_who_list(char *name, char *mach_nm)
  616. {
  617. struct who *wp, *wpnew;
  618. int comp = -1;
  619. wp = whohead.who_next;
  620. while (wp->who_next && (comp = strncmp(wp->who_tty,mach_nm,UTLINLEN)) < 0)
  621. wp = wp->who_next;/* find that tty! */
  622. if (wp->who_next && comp == 0) { /* found the tty... */
  623. if (*name == '\0') {
  624. wp->who_time = 0;
  625. wp->who_status = OFFLINE;
  626. }
  627. else if (strncmp(name, wp->who_name, UTNAMLEN) == 0) {
  628. /* someone is logged in */
  629. wp->who_time = 0;
  630. wp->who_status = 0; /* same guy */
  631. }
  632. else {
  633. (void) strncpy(wp->who_new, name, UTNAMLEN);
  634. wp->who_time = 0;
  635. if (wp->who_name[0] == '\0')
  636. wp->who_status = ONLINE;
  637. else
  638. wp->who_status = CHANGED;
  639. }
  640. }
  641. else {
  642. wpnew = xcalloc(1, sizeof *wpnew);
  643. (void) strncpy(wpnew->who_tty, mach_nm, UTLINLEN);
  644. wpnew->who_time = 0;
  645. if (*name == '\0')
  646. wpnew->who_status = OFFLINE;
  647. else {
  648. (void) strncpy(wpnew->who_new, name, UTNAMLEN);
  649. wpnew->who_status = ONLINE;
  650. }
  651. #ifdef WHODEBUG
  652. debugwholist(wpnew, wp);
  653. #endif /* WHODEBUG */
  654. wpnew->who_next = wp; /* link in a new 'who' */
  655. wpnew->who_prev = wp->who_prev;
  656. wpnew->who_prev->who_next = wpnew;
  657. wp->who_prev = wpnew; /* linked in now */
  658. }
  659. }
  660. #endif /* WINNT_NATIVE */
  661. #endif /* HAVENOUTMP */