1 | /*
|
---|
2 | * Copyright (c) 1980 Regents of the University of California.
|
---|
3 | * All rights reserved. The Berkeley software License Agreement
|
---|
4 | * specifies the terms and conditions for redistribution.
|
---|
5 | */
|
---|
6 |
|
---|
7 | #ifndef lint
|
---|
8 | static char sccsid[] = "@(#)finger.c 1.1 87/12/21 SMI"; /* from 5.8 3/13/86 */
|
---|
9 | #endif /* not lint */
|
---|
10 |
|
---|
11 | /*
|
---|
12 | * This is a finger program. It prints out useful information about users
|
---|
13 | * by digging it up from various system files.
|
---|
14 | *
|
---|
15 | * There are three output formats, all of which give login name, teletype
|
---|
16 | * line number, and login time. The short output format is reminiscent
|
---|
17 | * of finger on ITS, and gives one line of information per user containing
|
---|
18 | * in addition to the minimum basic requirements (MBR), the full name of
|
---|
19 | * the user, his idle time and location. The
|
---|
20 | * quick style output is UNIX who-like, giving only name, teletype and
|
---|
21 | * login time. Finally, the long style output give the same information
|
---|
22 | * as the short (in more legible format), the home directory and shell
|
---|
23 | * of the user, and, if it exits, a copy of the file .plan in the users
|
---|
24 | * home directory. Finger may be called with or without a list of people
|
---|
25 | * to finger -- if no list is given, all the people currently logged in
|
---|
26 | * are fingered.
|
---|
27 | *
|
---|
28 | * The program is validly called by one of the following:
|
---|
29 | *
|
---|
30 | * finger {short form list of users}
|
---|
31 | * finger -l {long form list of users}
|
---|
32 | * finger -b {briefer long form list of users}
|
---|
33 | * finger -q {quick list of users}
|
---|
34 | * finger -i {quick list of users with idle times}
|
---|
35 | * finger namelist {long format list of specified users}
|
---|
36 | * finger -s namelist {short format list of specified users}
|
---|
37 | * finger -w namelist {narrow short format list of specified users}
|
---|
38 | *
|
---|
39 | * where 'namelist' is a list of users login names.
|
---|
40 | * The other options can all be given after one '-', or each can have its
|
---|
41 | * own '-'. The -f option disables the printing of headers for short and
|
---|
42 | * quick outputs. The -b option briefens long format outputs. The -p
|
---|
43 | * option turns off plans for long format outputs.
|
---|
44 | */
|
---|
45 |
|
---|
46 | #include <sys/types.h>
|
---|
47 | #include <ctype.h>
|
---|
48 | #include <errno.h>
|
---|
49 | #include <fcntl.h>
|
---|
50 | #include <pwd.h>
|
---|
51 | #include <stdio.h>
|
---|
52 | #include <stdlib.h>
|
---|
53 | #include <string.h>
|
---|
54 | #include <time.h>
|
---|
55 | #include <unistd.h>
|
---|
56 | #include <utmp.h>
|
---|
57 | #include <sys/ioctl.h>
|
---|
58 | #include <sys/stat.h>
|
---|
59 | #include <net/gen/in.h>
|
---|
60 | #include <net/gen/inet.h>
|
---|
61 | #include <net/gen/netdb.h>
|
---|
62 | #include <net/gen/socket.h>
|
---|
63 | #include <net/gen/tcp.h>
|
---|
64 | #include <net/gen/tcp_hdr.h>
|
---|
65 | #include <net/gen/tcp_io.h>
|
---|
66 | #include <net/hton.h>
|
---|
67 | #include <net/netlib.h>
|
---|
68 |
|
---|
69 | #define NONOTHING 1 /* don't say "No plan", or "No mail" */
|
---|
70 |
|
---|
71 | #define NONET 0
|
---|
72 |
|
---|
73 | #define ASTERISK '*' /* ignore this in real name */
|
---|
74 | #define COMMA ',' /* separator in pw_gecos field */
|
---|
75 | #define COMMAND '-' /* command line flag char */
|
---|
76 | #define SAMENAME '&' /* repeat login name in real name */
|
---|
77 | #define TALKABLE 0220 /* tty is writable if this mode */
|
---|
78 |
|
---|
79 | struct utmp user;
|
---|
80 | #define NMAX sizeof(user.ut_name)
|
---|
81 | #define LMAX sizeof(user.ut_line)
|
---|
82 | #define HMAX sizeof(user.ut_host)
|
---|
83 |
|
---|
84 | struct person { /* one for each person fingered */
|
---|
85 | char *name; /* name */
|
---|
86 | char tty[LMAX+1]; /* null terminated tty line */
|
---|
87 | char host[HMAX+1]; /* null terminated remote host name */
|
---|
88 | long loginat; /* time of (last) login */
|
---|
89 | long idletime; /* how long idle (if logged in) */
|
---|
90 | char *realname; /* pointer to full name */
|
---|
91 | struct passwd *pwd; /* structure of /etc/passwd stuff */
|
---|
92 | char loggedin; /* person is logged in */
|
---|
93 | char writable; /* tty is writable */
|
---|
94 | char original; /* this is not a duplicate entry */
|
---|
95 | struct person *link; /* link to next person */
|
---|
96 | char *where; /* terminal location */
|
---|
97 | char hostt[HMAX+1]; /* login host */
|
---|
98 | };
|
---|
99 |
|
---|
100 | #include <minix/paths.h>
|
---|
101 |
|
---|
102 | char LASTLOG[] = _PATH_LASTLOG; /* last login info */
|
---|
103 | char USERLOG[] = _PATH_UTMP; /* who is logged in */
|
---|
104 | char PLAN[] = "/.plan"; /* what plan file is */
|
---|
105 | char PROJ[] = "/.project"; /* what project file */
|
---|
106 |
|
---|
107 | int unbrief = 1; /* -b option default */
|
---|
108 | int header = 1; /* -f option default */
|
---|
109 | int hack = 1; /* -h option default */
|
---|
110 | int idle = 0; /* -i option default */
|
---|
111 | int large = 0; /* -l option default */
|
---|
112 | int match = 1; /* -m option default */
|
---|
113 | int plan = 1; /* -p option default */
|
---|
114 | int unquick = 1; /* -q option default */
|
---|
115 | int small = 0; /* -s option default */
|
---|
116 | int wide = 1; /* -w option default */
|
---|
117 |
|
---|
118 | int unshort;
|
---|
119 | int lf; /* LASTLOG file descriptor */
|
---|
120 | struct person *person1; /* list of people */
|
---|
121 | long tloc; /* current time */
|
---|
122 |
|
---|
123 | #if !_MINIX
|
---|
124 | char *strcpy();
|
---|
125 | char *ctime();
|
---|
126 | #endif
|
---|
127 |
|
---|
128 | char *prog_name;
|
---|
129 |
|
---|
130 | int main (int argc, char *argv[]);
|
---|
131 | static void doall(void);
|
---|
132 | static void donames(char **args);
|
---|
133 | static void print(void);
|
---|
134 | static void fwopen(void);
|
---|
135 | static void decode(struct person *pers);
|
---|
136 | static void fwclose(void);
|
---|
137 | static int netfinger (char *name);
|
---|
138 | static int matchcmp (char *gname, char *login, char *given);
|
---|
139 | static void quickprint (struct person *pers);
|
---|
140 | static void shortprint (struct person *pers);
|
---|
141 | static void personprint (struct person *pers);
|
---|
142 | static int AlreadyPrinted(int uid);
|
---|
143 | static int AnyMail (char *name);
|
---|
144 | static struct passwd *pwdcopy(struct passwd *pfrom);
|
---|
145 | static void findidle (struct person *pers);
|
---|
146 | static int ltimeprint (char *dt, long *before, char *after);
|
---|
147 | static void stimeprint (long *dt);
|
---|
148 | static void findwhen (struct person *pers);
|
---|
149 | static int namecmp (char *name1, char *name2);
|
---|
150 |
|
---|
151 | main(argc, argv)
|
---|
152 | int argc;
|
---|
153 | register char **argv;
|
---|
154 | {
|
---|
155 | FILE *fp;
|
---|
156 | register char *s;
|
---|
157 |
|
---|
158 | prog_name= argv[0];
|
---|
159 |
|
---|
160 | /* parse command line for (optional) arguments */
|
---|
161 | while (*++argv && **argv == COMMAND)
|
---|
162 | for (s = *argv + 1; *s; s++)
|
---|
163 | switch (*s) {
|
---|
164 | case 'b':
|
---|
165 | unbrief = 0;
|
---|
166 | break;
|
---|
167 | case 'f':
|
---|
168 | header = 0;
|
---|
169 | break;
|
---|
170 | case 'h':
|
---|
171 | hack = 0;
|
---|
172 | break;
|
---|
173 | case 'i':
|
---|
174 | idle = 1;
|
---|
175 | unquick = 0;
|
---|
176 | break;
|
---|
177 | case 'l':
|
---|
178 | large = 1;
|
---|
179 | break;
|
---|
180 | case 'm':
|
---|
181 | match = 0;
|
---|
182 | break;
|
---|
183 | case 'p':
|
---|
184 | plan = 0;
|
---|
185 | break;
|
---|
186 | case 'q':
|
---|
187 | unquick = 0;
|
---|
188 | break;
|
---|
189 | case 's':
|
---|
190 | small = 1;
|
---|
191 | break;
|
---|
192 | case 'w':
|
---|
193 | wide = 0;
|
---|
194 | break;
|
---|
195 | default:
|
---|
196 | fprintf(stderr, "Usage: finger [-bfhilmpqsw] [login1 [login2 ...] ]\n");
|
---|
197 | exit(1);
|
---|
198 | }
|
---|
199 | if (unquick || idle)
|
---|
200 | time(&tloc);
|
---|
201 | /*
|
---|
202 | * *argv == 0 means no names given
|
---|
203 | */
|
---|
204 | if (*argv == 0)
|
---|
205 | doall();
|
---|
206 | else
|
---|
207 | donames(argv);
|
---|
208 | if (person1)
|
---|
209 | print();
|
---|
210 | exit(0);
|
---|
211 | }
|
---|
212 |
|
---|
213 | static void doall()
|
---|
214 | {
|
---|
215 | register struct person *p;
|
---|
216 | register struct passwd *pw;
|
---|
217 | int uf;
|
---|
218 | char name[NMAX + 1];
|
---|
219 |
|
---|
220 | unshort = large;
|
---|
221 | if ((uf = open(USERLOG, 0)) < 0) {
|
---|
222 | fprintf(stderr, "finger: error opening %s\n", USERLOG);
|
---|
223 | exit(2);
|
---|
224 | }
|
---|
225 | if (unquick) {
|
---|
226 | setpwent();
|
---|
227 | fwopen();
|
---|
228 | }
|
---|
229 | while (read(uf, (char *)&user, sizeof user) == sizeof user) {
|
---|
230 | if (user.ut_name[0] == 0)
|
---|
231 | continue;
|
---|
232 | if (person1 == 0)
|
---|
233 | p = person1 = (struct person *) malloc(sizeof *p);
|
---|
234 | else {
|
---|
235 | p->link = (struct person *) malloc(sizeof *p);
|
---|
236 | p = p->link;
|
---|
237 | }
|
---|
238 | bcopy(user.ut_name, name, NMAX);
|
---|
239 | name[NMAX] = 0;
|
---|
240 | bcopy(user.ut_line, p->tty, LMAX);
|
---|
241 | p->tty[LMAX] = 0;
|
---|
242 | bcopy(user.ut_host, p->host, HMAX);
|
---|
243 | p->host[HMAX] = 0;
|
---|
244 | p->loginat = user.ut_time;
|
---|
245 | p->pwd = 0;
|
---|
246 | p->loggedin = 1;
|
---|
247 | p->where = NULL;
|
---|
248 | if (unquick && (pw = getpwnam(name))) {
|
---|
249 | p->pwd = pwdcopy(pw);
|
---|
250 | decode(p);
|
---|
251 | p->name = p->pwd->pw_name;
|
---|
252 | } else
|
---|
253 | p->name = strcpy(malloc(strlen(name) + 1), name);
|
---|
254 | }
|
---|
255 | if (unquick) {
|
---|
256 | fwclose();
|
---|
257 | endpwent();
|
---|
258 | }
|
---|
259 | close(uf);
|
---|
260 | if (person1 == 0) {
|
---|
261 | printf("No one logged on\n");
|
---|
262 | return;
|
---|
263 | }
|
---|
264 | p->link = 0;
|
---|
265 | }
|
---|
266 |
|
---|
267 | static void donames(argv)
|
---|
268 | char **argv;
|
---|
269 | {
|
---|
270 | register struct person *p;
|
---|
271 | register struct passwd *pw;
|
---|
272 | int uf;
|
---|
273 |
|
---|
274 | /*
|
---|
275 | * get names from command line and check to see if they're
|
---|
276 | * logged in
|
---|
277 | */
|
---|
278 | unshort = !small;
|
---|
279 | for (; *argv != 0; argv++) {
|
---|
280 | if (netfinger(*argv))
|
---|
281 | continue;
|
---|
282 | if (person1 == 0)
|
---|
283 | p = person1 = (struct person *) malloc(sizeof *p);
|
---|
284 | else {
|
---|
285 | p->link = (struct person *) malloc(sizeof *p);
|
---|
286 | p = p->link;
|
---|
287 | }
|
---|
288 | p->name = *argv;
|
---|
289 | p->loggedin = 0;
|
---|
290 | p->original = 1;
|
---|
291 | p->pwd = 0;
|
---|
292 | }
|
---|
293 | if (person1 == 0)
|
---|
294 | return;
|
---|
295 | p->link = 0;
|
---|
296 | /*
|
---|
297 | * if we are doing it, read /etc/passwd for the useful info
|
---|
298 | */
|
---|
299 | if (unquick) {
|
---|
300 | setpwent();
|
---|
301 | if (!match) {
|
---|
302 | for (p = person1; p != 0; p = p->link)
|
---|
303 | if (pw = getpwnam(p->name))
|
---|
304 | p->pwd = pwdcopy(pw);
|
---|
305 | } else while ((pw = getpwent()) != 0) {
|
---|
306 | for (p = person1; p != 0; p = p->link) {
|
---|
307 | if (!p->original)
|
---|
308 | continue;
|
---|
309 | if (strcmp(p->name, pw->pw_name) != 0 &&
|
---|
310 | !matchcmp(pw->pw_gecos, pw->pw_name, p->name))
|
---|
311 | continue;
|
---|
312 | if (p->pwd == 0)
|
---|
313 | p->pwd = pwdcopy(pw);
|
---|
314 | else {
|
---|
315 | struct person *new;
|
---|
316 | /*
|
---|
317 | * handle multiple login names, insert
|
---|
318 | * new "duplicate" entry behind
|
---|
319 | */
|
---|
320 | new = (struct person *)
|
---|
321 | malloc(sizeof *new);
|
---|
322 | new->pwd = pwdcopy(pw);
|
---|
323 | new->name = p->name;
|
---|
324 | new->original = 1;
|
---|
325 | new->loggedin = 0;
|
---|
326 | new->link = p->link;
|
---|
327 | p->original = 0;
|
---|
328 | p->link = new;
|
---|
329 | p = new;
|
---|
330 | }
|
---|
331 | }
|
---|
332 | }
|
---|
333 | endpwent();
|
---|
334 | }
|
---|
335 | /* Now get login information */
|
---|
336 | if ((uf = open(USERLOG, 0)) < 0) {
|
---|
337 | fprintf(stderr, "finger: error opening %s\n", USERLOG);
|
---|
338 | exit(2);
|
---|
339 | }
|
---|
340 | while (read(uf, (char *)&user, sizeof user) == sizeof user) {
|
---|
341 | if (*user.ut_name == 0)
|
---|
342 | continue;
|
---|
343 | for (p = person1; p != 0; p = p->link) {
|
---|
344 | if (p->loggedin == 2)
|
---|
345 | continue;
|
---|
346 | if (strncmp(p->pwd ? p->pwd->pw_name : p->name,
|
---|
347 | user.ut_name, NMAX) != 0)
|
---|
348 | continue;
|
---|
349 | if (p->loggedin == 0) {
|
---|
350 | bcopy(user.ut_line, p->tty, LMAX);
|
---|
351 | p->tty[LMAX] = 0;
|
---|
352 | bcopy(user.ut_host, p->host, HMAX);
|
---|
353 | p->host[HMAX] = 0;
|
---|
354 | p->loginat = user.ut_time;
|
---|
355 | p->loggedin = 1;
|
---|
356 | } else { /* p->loggedin == 1 */
|
---|
357 | struct person *new;
|
---|
358 | new = (struct person *) malloc(sizeof *new);
|
---|
359 | new->name = p->name;
|
---|
360 | bcopy(user.ut_line, new->tty, LMAX);
|
---|
361 | new->tty[LMAX] = 0;
|
---|
362 | bcopy(user.ut_host, new->host, HMAX);
|
---|
363 | new->host[HMAX] = 0;
|
---|
364 | new->loginat = user.ut_time;
|
---|
365 | new->pwd = p->pwd;
|
---|
366 | new->loggedin = 1;
|
---|
367 | new->original = 0;
|
---|
368 | new->link = p->link;
|
---|
369 | p->loggedin = 2;
|
---|
370 | p->link = new;
|
---|
371 | p = new;
|
---|
372 | }
|
---|
373 | }
|
---|
374 | }
|
---|
375 | close(uf);
|
---|
376 | if (unquick) {
|
---|
377 | fwopen();
|
---|
378 | for (p = person1; p != 0; p = p->link)
|
---|
379 | decode(p);
|
---|
380 | fwclose();
|
---|
381 | }
|
---|
382 | }
|
---|
383 |
|
---|
384 | static void print()
|
---|
385 | {
|
---|
386 | register FILE *fp;
|
---|
387 | register struct person *p;
|
---|
388 | register char *s;
|
---|
389 | register c;
|
---|
390 |
|
---|
391 | /*
|
---|
392 | * print out what we got
|
---|
393 | */
|
---|
394 | if (header) {
|
---|
395 | if (unquick) {
|
---|
396 | if (!unshort)
|
---|
397 | if (wide)
|
---|
398 | printf("Login Name TTY Idle When Where\n");
|
---|
399 | else
|
---|
400 | printf("Login TTY Idle When Where\n");
|
---|
401 | } else {
|
---|
402 | printf("Login TTY When");
|
---|
403 | if (idle)
|
---|
404 | printf(" Idle");
|
---|
405 | putchar('\n');
|
---|
406 | }
|
---|
407 | }
|
---|
408 | for (p = person1; p != 0; p = p->link) {
|
---|
409 | if (!unquick) {
|
---|
410 | quickprint(p);
|
---|
411 | continue;
|
---|
412 | }
|
---|
413 | if (!unshort) {
|
---|
414 | shortprint(p);
|
---|
415 | continue;
|
---|
416 | }
|
---|
417 | personprint(p);
|
---|
418 | if (p->pwd != 0 && !AlreadyPrinted(p->pwd->pw_uid)) {
|
---|
419 | AnyMail(p->pwd->pw_name);
|
---|
420 | if (hack) {
|
---|
421 | s = malloc(strlen(p->pwd->pw_dir) +
|
---|
422 | sizeof PROJ);
|
---|
423 | strcpy(s, p->pwd->pw_dir);
|
---|
424 | strcat(s, PROJ);
|
---|
425 | if ((fp = fopen(s, "r")) != 0) {
|
---|
426 | printf("Project: ");
|
---|
427 | while ((c = getc(fp)) != EOF) {
|
---|
428 | if (c == '\n')
|
---|
429 | break;
|
---|
430 | if (isprint(c) || isspace(c))
|
---|
431 | putchar(c);
|
---|
432 | else
|
---|
433 | putchar(c ^ 100);
|
---|
434 | }
|
---|
435 | fclose(fp);
|
---|
436 | putchar('\n');
|
---|
437 | }
|
---|
438 | free(s);
|
---|
439 | }
|
---|
440 | if (plan) {
|
---|
441 | s = malloc(strlen(p->pwd->pw_dir) +
|
---|
442 | sizeof PLAN);
|
---|
443 | strcpy(s, p->pwd->pw_dir);
|
---|
444 | strcat(s, PLAN);
|
---|
445 | if ((fp = fopen(s, "r")) == 0) {
|
---|
446 | if (!NONOTHING) printf("No Plan.\n");
|
---|
447 | } else {
|
---|
448 | printf("Plan:\n");
|
---|
449 | while ((c = getc(fp)) != EOF)
|
---|
450 | if (isprint(c) || isspace(c))
|
---|
451 | putchar(c);
|
---|
452 | else
|
---|
453 | putchar(c ^ 100);
|
---|
454 | fclose(fp);
|
---|
455 | }
|
---|
456 | free(s);
|
---|
457 | }
|
---|
458 | }
|
---|
459 | if (p->link != 0)
|
---|
460 | putchar('\n');
|
---|
461 | }
|
---|
462 | }
|
---|
463 |
|
---|
464 | /*
|
---|
465 | * Duplicate a pwd entry.
|
---|
466 | * Note: Only the useful things (what the program currently uses) are copied.
|
---|
467 | */
|
---|
468 | static struct passwd *
|
---|
469 | pwdcopy(pfrom)
|
---|
470 | register struct passwd *pfrom;
|
---|
471 | {
|
---|
472 | register struct passwd *pto;
|
---|
473 |
|
---|
474 | pto = (struct passwd *) malloc(sizeof *pto);
|
---|
475 | #define savestr(s) strcpy(malloc(strlen(s) + 1), s)
|
---|
476 | pto->pw_name = savestr(pfrom->pw_name);
|
---|
477 | pto->pw_uid = pfrom->pw_uid;
|
---|
478 | pto->pw_gecos = savestr(pfrom->pw_gecos);
|
---|
479 | pto->pw_dir = savestr(pfrom->pw_dir);
|
---|
480 | pto->pw_shell = savestr(pfrom->pw_shell);
|
---|
481 | #undef savestr
|
---|
482 | return pto;
|
---|
483 | }
|
---|
484 |
|
---|
485 | /*
|
---|
486 | * print out information on quick format giving just name, tty, login time
|
---|
487 | * and idle time if idle is set.
|
---|
488 | */
|
---|
489 | static void quickprint(pers)
|
---|
490 | register struct person *pers;
|
---|
491 | {
|
---|
492 | printf("%-*.*s ", NMAX, NMAX, pers->name);
|
---|
493 | if (pers->loggedin) {
|
---|
494 | if (idle) {
|
---|
495 | findidle(pers);
|
---|
496 | printf("%c%-*s %-16.16s", pers->writable ? ' ' : '*',
|
---|
497 | LMAX, pers->tty, ctime(&pers->loginat));
|
---|
498 | ltimeprint(" ", &pers->idletime, "");
|
---|
499 | } else
|
---|
500 | printf(" %-*s %-16.16s", LMAX,
|
---|
501 | pers->tty, ctime(&pers->loginat));
|
---|
502 | putchar('\n');
|
---|
503 | } else
|
---|
504 | printf(" Not Logged In\n");
|
---|
505 | }
|
---|
506 |
|
---|
507 | /*
|
---|
508 | * print out information in short format, giving login name, full name,
|
---|
509 | * tty, idle time, login time, and host.
|
---|
510 | */
|
---|
511 | static void shortprint(pers)
|
---|
512 | register struct person *pers;
|
---|
513 | {
|
---|
514 | char *p;
|
---|
515 | char dialup;
|
---|
516 |
|
---|
517 | if (pers->pwd == 0) {
|
---|
518 | printf("%-15s ???\n", pers->name);
|
---|
519 | return;
|
---|
520 | }
|
---|
521 | printf("%-*s", NMAX, pers->pwd->pw_name);
|
---|
522 | dialup = 0;
|
---|
523 | if (wide) {
|
---|
524 | if (pers->realname)
|
---|
525 | printf(" %-20.20s", pers->realname);
|
---|
526 | else
|
---|
527 | printf(" ??? ");
|
---|
528 | }
|
---|
529 | putchar(' ');
|
---|
530 | if (pers->loggedin && !pers->writable)
|
---|
531 | putchar('*');
|
---|
532 | else
|
---|
533 | putchar(' ');
|
---|
534 | if (*pers->tty) {
|
---|
535 | if (pers->tty[0] == 't' && pers->tty[1] == 't' &&
|
---|
536 | pers->tty[2] == 'y') {
|
---|
537 | if (pers->tty[3] == 'd' && pers->loggedin)
|
---|
538 | dialup = 1;
|
---|
539 | printf("%-2.2s ", pers->tty + 3);
|
---|
540 | } else
|
---|
541 | printf("%-2.2s ", pers->tty);
|
---|
542 | } else
|
---|
543 | printf(" ");
|
---|
544 | p = ctime(&pers->loginat);
|
---|
545 | if (pers->loggedin) {
|
---|
546 | stimeprint(&pers->idletime);
|
---|
547 | printf(" %3.3s %-5.5s ", p, p + 11);
|
---|
548 | } else if (pers->loginat == 0)
|
---|
549 | printf(" < . . . . >");
|
---|
550 | else if (tloc - pers->loginat >= 180L * 24 * 60 * 60)
|
---|
551 | printf(" <%-6.6s, %-4.4s>", p + 4, p + 20);
|
---|
552 | else
|
---|
553 | printf(" <%-12.12s>", p + 4);
|
---|
554 | if (pers->host[0])
|
---|
555 | printf(" %-20.20s", pers->host);
|
---|
556 | putchar('\n');
|
---|
557 | }
|
---|
558 |
|
---|
559 |
|
---|
560 | /*
|
---|
561 | * print out a person in long format giving all possible information.
|
---|
562 | * directory and shell are inhibited if unbrief is clear.
|
---|
563 | */
|
---|
564 | static void
|
---|
565 | personprint(pers)
|
---|
566 | register struct person *pers;
|
---|
567 | {
|
---|
568 | if (pers->pwd == 0) {
|
---|
569 | printf("Login name: %-10s\t\t\tIn real life: ???\n",
|
---|
570 | pers->name);
|
---|
571 | return;
|
---|
572 | }
|
---|
573 | printf("Login name: %-10s", pers->pwd->pw_name);
|
---|
574 | if (pers->loggedin && !pers->writable)
|
---|
575 | printf(" (messages off) ");
|
---|
576 | else
|
---|
577 | printf(" ");
|
---|
578 | if (pers->realname)
|
---|
579 | printf("In real life: %s", pers->realname);
|
---|
580 | if (unbrief) {
|
---|
581 | printf("\nDirectory: %-25s", pers->pwd->pw_dir);
|
---|
582 | if (*pers->pwd->pw_shell)
|
---|
583 | printf("\tShell: %-s", pers->pwd->pw_shell);
|
---|
584 | }
|
---|
585 | if (pers->loggedin) {
|
---|
586 | register char *ep = ctime(&pers->loginat);
|
---|
587 | if (*pers->host) {
|
---|
588 | printf("\nOn since %15.15s on %s from %s",
|
---|
589 | &ep[4], pers->tty, pers->host);
|
---|
590 | ltimeprint("\n", &pers->idletime, " Idle Time");
|
---|
591 | } else {
|
---|
592 | printf("\nOn since %15.15s on %-*s",
|
---|
593 | &ep[4], LMAX, pers->tty);
|
---|
594 | ltimeprint("\t", &pers->idletime, " Idle Time");
|
---|
595 | }
|
---|
596 | } else if (pers->loginat == 0) {
|
---|
597 | if (lf >= 0) printf("\nNever logged in.");
|
---|
598 | } else if (tloc - pers->loginat > 180L * 24 * 60 * 60) {
|
---|
599 | register char *ep = ctime(&pers->loginat);
|
---|
600 | printf("\nLast login %10.10s, %4.4s on %s",
|
---|
601 | ep, ep+20, pers->tty);
|
---|
602 | if (*pers->host)
|
---|
603 | printf(" from %s", pers->host);
|
---|
604 | } else {
|
---|
605 | register char *ep = ctime(&pers->loginat);
|
---|
606 | printf("\nLast login %16.16s on %s", ep, pers->tty);
|
---|
607 | if (*pers->host)
|
---|
608 | printf(" from %s", pers->host);
|
---|
609 | }
|
---|
610 | putchar('\n');
|
---|
611 | }
|
---|
612 |
|
---|
613 |
|
---|
614 | /*
|
---|
615 | * decode the information in the gecos field of /etc/passwd
|
---|
616 | */
|
---|
617 | static void
|
---|
618 | decode(pers)
|
---|
619 | register struct person *pers;
|
---|
620 | {
|
---|
621 | char buffer[256];
|
---|
622 | register char *bp, *gp, *lp;
|
---|
623 | int alldigits;
|
---|
624 | int hasspace;
|
---|
625 | int len;
|
---|
626 |
|
---|
627 | pers->realname = 0;
|
---|
628 | if (pers->pwd == 0)
|
---|
629 | return;
|
---|
630 | gp = pers->pwd->pw_gecos;
|
---|
631 | bp = buffer;
|
---|
632 | if (*gp == ASTERISK)
|
---|
633 | gp++;
|
---|
634 | while (*gp && *gp != COMMA) /* name */
|
---|
635 | if (*gp == SAMENAME) {
|
---|
636 | lp = pers->pwd->pw_name;
|
---|
637 | if (islower(*lp))
|
---|
638 | *bp++ = toupper(*lp++);
|
---|
639 | while (*bp++ = *lp++)
|
---|
640 | ;
|
---|
641 | bp--;
|
---|
642 | gp++;
|
---|
643 | } else
|
---|
644 | *bp++ = *gp++;
|
---|
645 | *bp++ = 0;
|
---|
646 | if ((len = bp - buffer) > 1)
|
---|
647 | pers->realname = strcpy(malloc(len), buffer);
|
---|
648 | if (pers->loggedin)
|
---|
649 | findidle(pers);
|
---|
650 | else
|
---|
651 | findwhen(pers);
|
---|
652 | }
|
---|
653 |
|
---|
654 | /*
|
---|
655 | * find the last log in of a user by checking the LASTLOG file.
|
---|
656 | * the entry is indexed by the uid, so this can only be done if
|
---|
657 | * the uid is known (which it isn't in quick mode)
|
---|
658 | */
|
---|
659 |
|
---|
660 | static void
|
---|
661 | fwopen()
|
---|
662 | {
|
---|
663 | if ((lf = open(LASTLOG, 0)) < 0) {
|
---|
664 | if (errno == ENOENT) return;
|
---|
665 | fprintf(stderr, "finger: %s open error\n", LASTLOG);
|
---|
666 | }
|
---|
667 | }
|
---|
668 |
|
---|
669 | static void
|
---|
670 | findwhen(pers)
|
---|
671 | register struct person *pers;
|
---|
672 | {
|
---|
673 | struct utmp ll;
|
---|
674 | #define ll_line ut_line
|
---|
675 | #define ll_host ut_host
|
---|
676 | #define ll_time ut_time
|
---|
677 |
|
---|
678 | int i;
|
---|
679 |
|
---|
680 | if (lf >= 0) {
|
---|
681 | lseek(lf, (long)pers->pwd->pw_uid * sizeof ll, 0);
|
---|
682 | if ((i = read(lf, (char *)&ll, sizeof ll)) == sizeof ll) {
|
---|
683 | bcopy(ll.ll_line, pers->tty, LMAX);
|
---|
684 | pers->tty[LMAX] = 0;
|
---|
685 | bcopy(ll.ll_host, pers->host, HMAX);
|
---|
686 | pers->host[HMAX] = 0;
|
---|
687 | pers->loginat = ll.ll_time;
|
---|
688 | } else {
|
---|
689 | if (i != 0)
|
---|
690 | fprintf(stderr, "finger: %s read error\n",
|
---|
691 | LASTLOG);
|
---|
692 | pers->tty[0] = 0;
|
---|
693 | pers->host[0] = 0;
|
---|
694 | pers->loginat = 0L;
|
---|
695 | }
|
---|
696 | } else {
|
---|
697 | pers->tty[0] = 0;
|
---|
698 | pers->host[0] = 0;
|
---|
699 | pers->loginat = 0L;
|
---|
700 | }
|
---|
701 | }
|
---|
702 |
|
---|
703 | static void fwclose()
|
---|
704 | {
|
---|
705 | if (lf >= 0)
|
---|
706 | close(lf);
|
---|
707 | }
|
---|
708 |
|
---|
709 | /*
|
---|
710 | * find the idle time of a user by doing a stat on /dev/tty??,
|
---|
711 | * where tty?? has been gotten from USERLOG, supposedly.
|
---|
712 | */
|
---|
713 | static void
|
---|
714 | findidle(pers)
|
---|
715 | register struct person *pers;
|
---|
716 | {
|
---|
717 | struct stat ttystatus;
|
---|
718 | static char buffer[20] = "/dev/";
|
---|
719 | long t;
|
---|
720 | #define TTYLEN 5
|
---|
721 |
|
---|
722 | strcpy(buffer + TTYLEN, pers->tty);
|
---|
723 | buffer[TTYLEN+LMAX] = 0;
|
---|
724 | if (stat(buffer, &ttystatus) < 0) {
|
---|
725 | fprintf(stderr, "finger: Can't stat %s\n", buffer);
|
---|
726 | exit(4);
|
---|
727 | }
|
---|
728 | time(&t);
|
---|
729 | if (t < ttystatus.st_atime)
|
---|
730 | pers->idletime = 0L;
|
---|
731 | else
|
---|
732 | pers->idletime = t - ttystatus.st_atime;
|
---|
733 | pers->writable = (ttystatus.st_mode & TALKABLE) == TALKABLE;
|
---|
734 | }
|
---|
735 |
|
---|
736 | /*
|
---|
737 | * print idle time in short format; this program always prints 4 characters;
|
---|
738 | * if the idle time is zero, it prints 4 blanks.
|
---|
739 | */
|
---|
740 | static void
|
---|
741 | stimeprint(dt)
|
---|
742 | long *dt;
|
---|
743 | {
|
---|
744 | register struct tm *delta;
|
---|
745 |
|
---|
746 | delta = gmtime(dt);
|
---|
747 | if (delta->tm_yday == 0)
|
---|
748 | if (delta->tm_hour == 0)
|
---|
749 | if (delta->tm_min == 0)
|
---|
750 | printf(" ");
|
---|
751 | else
|
---|
752 | printf(" %2d", delta->tm_min);
|
---|
753 | else
|
---|
754 | if (delta->tm_hour >= 10)
|
---|
755 | printf("%3d:", delta->tm_hour);
|
---|
756 | else
|
---|
757 | printf("%1d:%02d",
|
---|
758 | delta->tm_hour, delta->tm_min);
|
---|
759 | else
|
---|
760 | printf("%3dd", delta->tm_yday);
|
---|
761 | }
|
---|
762 |
|
---|
763 | /*
|
---|
764 | * print idle time in long format with care being taken not to pluralize
|
---|
765 | * 1 minutes or 1 hours or 1 days.
|
---|
766 | * print "prefix" first.
|
---|
767 | */
|
---|
768 | static int
|
---|
769 | ltimeprint(before, dt, after)
|
---|
770 | long *dt;
|
---|
771 | char *before, *after;
|
---|
772 | {
|
---|
773 | register struct tm *delta;
|
---|
774 |
|
---|
775 | delta = gmtime(dt);
|
---|
776 | if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0 &&
|
---|
777 | delta->tm_sec <= 10)
|
---|
778 | return (0);
|
---|
779 | printf("%s", before);
|
---|
780 | if (delta->tm_yday >= 10)
|
---|
781 | printf("%d days", delta->tm_yday);
|
---|
782 | else if (delta->tm_yday > 0)
|
---|
783 | printf("%d day%s %d hour%s",
|
---|
784 | delta->tm_yday, delta->tm_yday == 1 ? "" : "s",
|
---|
785 | delta->tm_hour, delta->tm_hour == 1 ? "" : "s");
|
---|
786 | else
|
---|
787 | if (delta->tm_hour >= 10)
|
---|
788 | printf("%d hours", delta->tm_hour);
|
---|
789 | else if (delta->tm_hour > 0)
|
---|
790 | printf("%d hour%s %d minute%s",
|
---|
791 | delta->tm_hour, delta->tm_hour == 1 ? "" : "s",
|
---|
792 | delta->tm_min, delta->tm_min == 1 ? "" : "s");
|
---|
793 | else
|
---|
794 | if (delta->tm_min >= 10)
|
---|
795 | printf("%2d minutes", delta->tm_min);
|
---|
796 | else if (delta->tm_min == 0)
|
---|
797 | printf("%2d seconds", delta->tm_sec);
|
---|
798 | else
|
---|
799 | printf("%d minute%s %d second%s",
|
---|
800 | delta->tm_min,
|
---|
801 | delta->tm_min == 1 ? "" : "s",
|
---|
802 | delta->tm_sec,
|
---|
803 | delta->tm_sec == 1 ? "" : "s");
|
---|
804 | printf("%s", after);
|
---|
805 | }
|
---|
806 |
|
---|
807 | static int
|
---|
808 | matchcmp(gname, login, given)
|
---|
809 | register char *gname;
|
---|
810 | char *login;
|
---|
811 | char *given;
|
---|
812 | {
|
---|
813 | char buffer[100];
|
---|
814 | register char *bp, *lp;
|
---|
815 | register c;
|
---|
816 |
|
---|
817 | if (*gname == ASTERISK)
|
---|
818 | gname++;
|
---|
819 | lp = 0;
|
---|
820 | bp = buffer;
|
---|
821 | for (;;)
|
---|
822 | switch (c = *gname++) {
|
---|
823 | case SAMENAME:
|
---|
824 | for (lp = login; bp < buffer + sizeof buffer
|
---|
825 | && (*bp++ = *lp++);)
|
---|
826 | ;
|
---|
827 | bp--;
|
---|
828 | break;
|
---|
829 | case ' ':
|
---|
830 | case COMMA:
|
---|
831 | case '\0':
|
---|
832 | *bp = 0;
|
---|
833 | if (namecmp(buffer, given))
|
---|
834 | return (1);
|
---|
835 | if (c == COMMA || c == 0)
|
---|
836 | return (0);
|
---|
837 | bp = buffer;
|
---|
838 | break;
|
---|
839 | default:
|
---|
840 | if (bp < buffer + sizeof buffer)
|
---|
841 | *bp++ = c;
|
---|
842 | }
|
---|
843 | /*NOTREACHED*/
|
---|
844 | }
|
---|
845 |
|
---|
846 | static int
|
---|
847 | namecmp(name1, name2)
|
---|
848 | register char *name1, *name2;
|
---|
849 | {
|
---|
850 | register c1, c2;
|
---|
851 |
|
---|
852 | for (;;) {
|
---|
853 | c1 = *name1++;
|
---|
854 | if (islower(c1))
|
---|
855 | c1 = toupper(c1);
|
---|
856 | c2 = *name2++;
|
---|
857 | if (islower(c2))
|
---|
858 | c2 = toupper(c2);
|
---|
859 | if (c1 != c2)
|
---|
860 | break;
|
---|
861 | if (c1 == 0)
|
---|
862 | return (1);
|
---|
863 | }
|
---|
864 | if (!c1) {
|
---|
865 | for (name2--; isdigit(*name2); name2++)
|
---|
866 | ;
|
---|
867 | if (*name2 == 0)
|
---|
868 | return (1);
|
---|
869 | } else if (!c2) {
|
---|
870 | for (name1--; isdigit(*name1); name1++)
|
---|
871 | ;
|
---|
872 | if (*name2 == 0)
|
---|
873 | return (1);
|
---|
874 | }
|
---|
875 | return (0);
|
---|
876 | }
|
---|
877 |
|
---|
878 | #if NONET
|
---|
879 | static int
|
---|
880 | netfinger(name)
|
---|
881 | char *name;
|
---|
882 | {
|
---|
883 | return 0;
|
---|
884 | }
|
---|
885 | #else
|
---|
886 | static int
|
---|
887 | netfinger(name)
|
---|
888 | char *name;
|
---|
889 | {
|
---|
890 | char *host;
|
---|
891 | char fname[100];
|
---|
892 | struct hostent *hp;
|
---|
893 | struct servent *sp;
|
---|
894 | int s, result;
|
---|
895 | #if !_MINIX
|
---|
896 | char *rindex();
|
---|
897 | #endif
|
---|
898 | register FILE *f;
|
---|
899 | register int c;
|
---|
900 | register int lastc;
|
---|
901 | nwio_tcpconf_t tcpconf;
|
---|
902 | nwio_tcpcl_t tcpconnopt;
|
---|
903 | char *tcp_device;
|
---|
904 |
|
---|
905 | if (name == NULL)
|
---|
906 | return (0);
|
---|
907 | host = rindex(name, '@');
|
---|
908 | if (host == NULL)
|
---|
909 | return (0);
|
---|
910 | *host++ = 0;
|
---|
911 | hp = gethostbyname(host);
|
---|
912 | if (hp == NULL) {
|
---|
913 | static struct hostent def;
|
---|
914 | static ipaddr_t defaddr;
|
---|
915 | static char namebuf[128];
|
---|
916 |
|
---|
917 | defaddr = inet_addr(host);
|
---|
918 | if (defaddr == -1) {
|
---|
919 | printf("unknown host: %s\n", host);
|
---|
920 | return (1);
|
---|
921 | }
|
---|
922 | strcpy(namebuf, host);
|
---|
923 | def.h_name = namebuf;
|
---|
924 | def.h_addr = (char *)&defaddr;
|
---|
925 | def.h_length = sizeof (ipaddr_t);
|
---|
926 | def.h_addrtype = AF_INET;
|
---|
927 | def.h_aliases = 0;
|
---|
928 | hp = &def;
|
---|
929 | }
|
---|
930 | printf("[%s] ", hp->h_name);
|
---|
931 | fflush(stdout);
|
---|
932 |
|
---|
933 | tcp_device= getenv("TCP_DEVICE");
|
---|
934 | if (tcp_device == NULL)
|
---|
935 | tcp_device= TCP_DEVICE;
|
---|
936 | s= open (tcp_device, O_RDWR);
|
---|
937 | if (s == -1)
|
---|
938 | {
|
---|
939 | fprintf(stderr, "%s: unable to open %s (%s)\n",
|
---|
940 | prog_name, tcp_device, strerror(errno));
|
---|
941 | exit(1);
|
---|
942 | }
|
---|
943 | tcpconf.nwtc_flags= NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP;
|
---|
944 | tcpconf.nwtc_remaddr= *(ipaddr_t *)hp->h_addr;
|
---|
945 | tcpconf.nwtc_remport= htons(TCPPORT_FINGER);
|
---|
946 |
|
---|
947 | result= ioctl (s, NWIOSTCPCONF, &tcpconf);
|
---|
948 | if (result<0)
|
---|
949 | {
|
---|
950 | fprintf(stderr, "%s\n", strerror(errno));
|
---|
951 | exit(1);
|
---|
952 | }
|
---|
953 |
|
---|
954 | tcpconnopt.nwtcl_flags= 0;
|
---|
955 |
|
---|
956 | do
|
---|
957 | {
|
---|
958 | result= ioctl (s, NWIOTCPCONN, &tcpconnopt);
|
---|
959 | if (result<0 && errno== EAGAIN)
|
---|
960 | {
|
---|
961 | fprintf(stderr, "got EAGAIN error, sleeping 2s\n");
|
---|
962 | sleep(2);
|
---|
963 | }
|
---|
964 | } while (result<0 && errno == EAGAIN);
|
---|
965 | if (result<0)
|
---|
966 | {
|
---|
967 | fprintf(stderr, "%s\n", strerror(errno));
|
---|
968 | exit(1);
|
---|
969 | }
|
---|
970 | printf("\r\n");
|
---|
971 | if (large) write(s, "/W ", 3);
|
---|
972 | write(s, name, strlen(name));
|
---|
973 | write(s, "\r\n", 2);
|
---|
974 | f = fdopen(s, "r");
|
---|
975 | while ((c = getc(f)) != EOF) {
|
---|
976 | /*
|
---|
977 | switch(c) {
|
---|
978 | case 0210:
|
---|
979 | case 0211:
|
---|
980 | case 0212:
|
---|
981 | case 0214:
|
---|
982 | c -= 0200;
|
---|
983 | break;
|
---|
984 | case 0215:
|
---|
985 | c = '\n';
|
---|
986 | break;
|
---|
987 | }
|
---|
988 | */
|
---|
989 | c &= ~0200;
|
---|
990 | if (c == '\r')
|
---|
991 | {
|
---|
992 | c= getc(f) & ~0200;
|
---|
993 | if (c == '\012')
|
---|
994 | {
|
---|
995 | lastc= c;
|
---|
996 | putchar('\n');
|
---|
997 | continue;
|
---|
998 | }
|
---|
999 | else
|
---|
1000 | putchar('\r');
|
---|
1001 | }
|
---|
1002 | lastc = c;
|
---|
1003 | if (isprint(c) || isspace(c))
|
---|
1004 | putchar(c);
|
---|
1005 | else
|
---|
1006 | putchar(c ^ 100);
|
---|
1007 | }
|
---|
1008 | if (lastc != '\n')
|
---|
1009 | putchar('\n');
|
---|
1010 | (void)fclose(f);
|
---|
1011 | return (1);
|
---|
1012 | }
|
---|
1013 | #endif
|
---|
1014 |
|
---|
1015 | /*
|
---|
1016 | * AnyMail - takes a username (string pointer thereto), and
|
---|
1017 | * prints on standard output whether there is any unread mail,
|
---|
1018 | * and if so, how old it is. (JCM@Shasta 15 March 80)
|
---|
1019 | */
|
---|
1020 | #define preamble "/usr/spool/mail/" /* mailboxes are there */
|
---|
1021 | static int
|
---|
1022 | AnyMail(name)
|
---|
1023 | char *name;
|
---|
1024 | {
|
---|
1025 | struct stat buf; /* space for file status buffer */
|
---|
1026 | char *mbxdir = preamble; /* string with path preamble */
|
---|
1027 | char *mbxpath; /* space for entire pathname */
|
---|
1028 |
|
---|
1029 | #if !_MINIX
|
---|
1030 | char *ctime(); /* convert longword time to ascii */
|
---|
1031 | #endif
|
---|
1032 | char *timestr;
|
---|
1033 |
|
---|
1034 | mbxpath = malloc(strlen(name) + strlen(preamble) + 1);
|
---|
1035 |
|
---|
1036 | strcpy(mbxpath, mbxdir); /* copy preamble into path name */
|
---|
1037 | strcat(mbxpath, name); /* concatenate user name to path */
|
---|
1038 |
|
---|
1039 | if (stat(mbxpath, &buf) == -1 || buf.st_size == 0) {
|
---|
1040 | /* Mailbox is empty or nonexistent */
|
---|
1041 | if (!NONOTHING) printf("No unread mail\n");
|
---|
1042 | } else {
|
---|
1043 | if (buf.st_mtime == buf.st_atime) {
|
---|
1044 | /* There is something in the mailbox, but we can't really
|
---|
1045 | * be sure whether it is mail held there by the user
|
---|
1046 | * or a (single) new message that was placed in a newly
|
---|
1047 | * recreated mailbox, so we punt and call it "unread mail."
|
---|
1048 | */
|
---|
1049 | printf("Unread mail since ");
|
---|
1050 | printf(ctime(&buf.st_mtime));
|
---|
1051 | } else {
|
---|
1052 | /* New mail has definitely arrived since the last time
|
---|
1053 | * mail was read. mtime is the time the most recent
|
---|
1054 | * message arrived; atime is either the time the oldest
|
---|
1055 | * unread message arrived, or the last time the mail
|
---|
1056 | * was read.
|
---|
1057 | */
|
---|
1058 | printf("New mail received ");
|
---|
1059 | timestr = ctime(&buf.st_mtime); /* time last modified */
|
---|
1060 | timestr[24] = '\0'; /* suppress newline (ugh) */
|
---|
1061 | printf(timestr);
|
---|
1062 | printf(";\n unread since ");
|
---|
1063 | printf(ctime(&buf.st_atime)); /* time last accessed */
|
---|
1064 | }
|
---|
1065 | }
|
---|
1066 |
|
---|
1067 | free(mbxpath);
|
---|
1068 | }
|
---|
1069 |
|
---|
1070 | /*
|
---|
1071 | * return true iff we've already printed project/plan for this uid;
|
---|
1072 | * if not, enter this uid into table (so this function has a side-effect.)
|
---|
1073 | */
|
---|
1074 | #define PPMAX 200 /* assume no more than 200 logged-in users */
|
---|
1075 | int PlanPrinted[PPMAX+1];
|
---|
1076 | int PPIndex = 0; /* index of next unused table entry */
|
---|
1077 |
|
---|
1078 | static int
|
---|
1079 | AlreadyPrinted(uid)
|
---|
1080 | int uid;
|
---|
1081 | {
|
---|
1082 | int i = 0;
|
---|
1083 |
|
---|
1084 | while (i++ < PPIndex) {
|
---|
1085 | if (PlanPrinted[i] == uid)
|
---|
1086 | return(1);
|
---|
1087 | }
|
---|
1088 | if (i < PPMAX) {
|
---|
1089 | PlanPrinted[i] = uid;
|
---|
1090 | PPIndex++;
|
---|
1091 | }
|
---|
1092 | return(0);
|
---|
1093 | }
|
---|