source: trunk/minix/commands/ps/ps.c@ 12

Last change on this file since 12 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 18.4 KB
Line 
1/* ps - print status Author: Peter Valkenburg */
2
3/* Ps.c, Peter Valkenburg (valke@psy.vu.nl), january 1990.
4 *
5 * This is a V7 ps(1) look-alike for MINIX >= 1.5.0.
6 * It does not support the 'k' option (i.e. cannot read memory from core file).
7 * If you want to compile this for non-IBM PC architectures, the header files
8 * require that you have your CHIP, MACHINE etc. defined.
9 * Full syntax:
10 * ps [-][aeflx]
11 * Option `a' gives all processes, `l' for detailed info, `x' includes even
12 * processes without a terminal.
13 * The `f' and `e' options were added by Kees Bot for the convenience of
14 * Solaris users accustomed to these options. The `e' option is equivalent to
15 * `a' and `f' is equivalent to -l. These do not appear in the usage message.
16 *
17 * VERY IMPORTANT NOTE:
18 * To compile ps, the kernel/, fs/ and pm/ source directories must be in
19 * ../../ relative to the directory where ps is compiled (normally the
20 * tools source directory).
21 *
22 * If you want your ps to be useable by anyone, you can arrange the
23 * following access permissions (note the protected memory files and set
24 * *group* id on ps):
25 * -rwxr-sr-x 1 bin kmem 11916 Jul 4 15:31 /bin/ps
26 * crw-r----- 1 bin kmem 1, 1 Jan 1 1970 /dev/mem
27 * crw-r----- 1 bin kmem 1, 2 Jan 1 1970 /dev/kmem
28 */
29
30/* Some technical comments on this implementation:
31 *
32 * Most fields are similar to V7 ps(1), except for CPU, NICE, PRI which are
33 * absent, RECV which replaces WCHAN, and PGRP that is an extra.
34 * The info is obtained from the following fields of proc, mproc and fproc:
35 * F - kernel status field, p_rts_flags
36 * S - kernel status field, p_rts_flags; mm status field, mp_flags (R if p_rts_flags
37 * is 0; Z if mp_flags == ZOMBIE; T if mp_flags == STOPPED; else W).
38 * UID - mm eff uid field, mp_effuid
39 * PID - mm pid field, mp_pid
40 * PPID - mm parent process index field, mp_parent (used as index in proc).
41 * PGRP - mm process group field, mp_procgrp
42 * SZ - kernel text size + physical stack address - physical data address
43 * + stack size
44 * p_memmap[T].mem_len + p_memmap[S].mem_phys - p_memmap[D].mem_phys
45 * + p_memmap[S].mem_len
46 * RECV - kernel process index field for message receiving, p_getfrom
47 * If sleeping, mm's mp_flags, or fs's fp_task are used for more info.
48 * TTY - fs controlling tty device field, fp_tty.
49 * TIME - kernel user + system times fields, user_time + sys_time
50 * CMD - system process index (converted to mnemonic name by using the p_name
51 * field), or user process argument list (obtained by reading the stack
52 * frame; the resulting address is used to get the argument vector from
53 * user space and converted into a concatenated argument list).
54 */
55
56#include <minix/config.h>
57#include <minix/endpoint.h>
58#include <limits.h>
59#include <timers.h>
60#include <sys/types.h>
61
62#include <minix/const.h>
63#include <minix/type.h>
64#include <minix/ipc.h>
65#include <string.h>
66#include <stdlib.h>
67#include <unistd.h>
68
69#include <minix/com.h>
70#include <fcntl.h>
71#include <a.out.h>
72#include <dirent.h>
73#include <sys/stat.h>
74#include <sys/ioctl.h>
75#include <signal.h>
76#include <stdio.h>
77#include <ttyent.h>
78
79#include "../../kernel/const.h"
80#include "../../kernel/type.h"
81#include "../../kernel/proc.h"
82
83#include "../../servers/pm/mproc.h"
84#include "../../servers/fs/fproc.h"
85#include "../../servers/fs/const.h"
86
87
88/*----- ps's local stuff below this line ------*/
89
90
91#define mindev(dev) (((dev)>>MINOR) & 0377) /* yield minor device */
92#define majdev(dev) (((dev)>>MAJOR) & 0377) /* yield major device */
93
94#define TTY_MAJ 4 /* major device of console */
95
96/* Structure for tty name info. */
97typedef struct {
98 char tty_name[NAME_MAX + 1]; /* file name in /dev */
99 dev_t tty_dev; /* major/minor pair */
100} ttyinfo_t;
101
102ttyinfo_t *ttyinfo; /* ttyinfo holds actual tty info */
103size_t n_ttyinfo; /* Number of tty info slots */
104
105/* Macro to convert memory offsets to rounded kilo-units */
106#define off_to_k(off) ((unsigned) (((off) + 512) / 1024))
107
108
109/* Number of tasks and processes and addresses of the main process tables. */
110int nr_tasks, nr_procs;
111vir_bytes proc_addr, mproc_addr, fproc_addr;
112extern int errno;
113
114/* Process tables of the kernel, MM, and FS. */
115struct proc *ps_proc;
116struct mproc *ps_mproc;
117struct fproc *ps_fproc;
118
119/* Where is INIT? */
120int init_proc_nr;
121#define low_user init_proc_nr
122
123#define KMEM_PATH "/dev/kmem" /* opened for kernel proc table */
124#define MEM_PATH "/dev/mem" /* opened for pm/fs + user processes */
125
126int kmemfd, memfd; /* file descriptors of [k]mem */
127
128/* Short and long listing formats:
129 *
130 * PID TTY TIME CMD
131 * ppppp tttmmm:ss cccccccccc...
132 *
133 * F S UID PID PPID PGRP SZ RECV TTY TIME CMD
134 * fff s uuu ppppp ppppp ppppp ssss rrrrrrrrrr tttmmm:ss cccccccc...
135 */
136#define S_HEADER " PID TTY TIME CMD\n"
137#define S_FORMAT "%5s %3s %s %s\n"
138#define L_HEADER " F S UID PID PPID PGRP SZ RECV TTY TIME CMD\n"
139#define L_FORMAT "%3o %c %3d %5s %5d %5d %6d %12s %3s %s %s\n"
140
141
142struct pstat { /* structure filled by pstat() */
143 dev_t ps_dev; /* major/minor of controlling tty */
144 uid_t ps_ruid; /* real uid */
145 uid_t ps_euid; /* effective uid */
146 pid_t ps_pid; /* process id */
147 pid_t ps_ppid; /* parent process id */
148 int ps_pgrp; /* process group id */
149 int ps_flags; /* kernel flags */
150 int ps_mflags; /* mm flags */
151 int ps_ftask; /* (possibly pseudo) fs suspend task */
152 char ps_state; /* process state */
153 vir_bytes ps_tsize; /* text size (in bytes) */
154 vir_bytes ps_dsize; /* data size (in bytes) */
155 vir_bytes ps_ssize; /* stack size (in bytes) */
156 phys_bytes ps_vtext; /* virtual text offset */
157 phys_bytes ps_vdata; /* virtual data offset */
158 phys_bytes ps_vstack; /* virtual stack offset */
159 phys_bytes ps_text; /* physical text offset */
160 phys_bytes ps_data; /* physical data offset */
161 phys_bytes ps_stack; /* physical stack offset */
162 int ps_recv; /* process number to receive from */
163 time_t ps_utime; /* accumulated user time */
164 time_t ps_stime; /* accumulated system time */
165 char *ps_args; /* concatenated argument string */
166 vir_bytes ps_procargs; /* initial stack frame from MM */
167};
168
169/* Ps_state field values in pstat struct above */
170#define Z_STATE 'Z' /* Zombie */
171#define W_STATE 'W' /* Waiting */
172#define S_STATE 'S' /* Sleeping */
173#define R_STATE 'R' /* Runnable */
174#define T_STATE 'T' /* stopped (Trace) */
175
176_PROTOTYPE(char *tname, (Dev_t dev_nr ));
177_PROTOTYPE(char *taskname, (int p_nr ));
178_PROTOTYPE(char *prrecv, (struct pstat *bufp ));
179_PROTOTYPE(void disaster, (int sig ));
180_PROTOTYPE(int main, (int argc, char *argv []));
181_PROTOTYPE(char *get_args, (struct pstat *bufp ));
182_PROTOTYPE(int pstat, (int p_nr, struct pstat *bufp ));
183_PROTOTYPE(int addrread, (int fd, phys_clicks base, vir_bytes addr,
184 char *buf, int nbytes ));
185_PROTOTYPE(void usage, (char *pname ));
186_PROTOTYPE(void err, (char *s ));
187_PROTOTYPE(int gettynames, (void));
188
189
190/*
191 * Tname returns mnemonic string for dev_nr. This is "?" for maj/min pairs that
192 * are not found. It uses the ttyinfo array (prepared by gettynames).
193 * Tname assumes that the first three letters of the tty's name can be omitted
194 * and returns the rest (except for the console, which yields "co").
195 */
196char *tname(dev_nr)
197Dev_t dev_nr;
198{
199 int i;
200
201 if (majdev(dev_nr) == TTY_MAJ && mindev(dev_nr) == 0) return "co";
202
203 for (i = 0; i < n_ttyinfo && ttyinfo[i].tty_name[0] != '\0'; i++)
204 if (ttyinfo[i].tty_dev == dev_nr)
205 return ttyinfo[i].tty_name + 3;
206
207 return "?";
208}
209
210/* Return canonical task name of task p_nr; overwritten on each call (yucch) */
211char *taskname(p_nr)
212int p_nr;
213{
214 return ps_proc[_ENDPOINT_P(p_nr) + nr_tasks].p_name;
215}
216
217/* Prrecv prints the RECV field for process with pstat buffer pointer bufp.
218 * This is either "ANY", "taskname", or "(blockreason) taskname".
219 */
220char *prrecv(bufp)
221struct pstat *bufp;
222{
223 char *blkstr, *task; /* reason for blocking and task */
224 static char recvstr[20];
225
226 if (bufp->ps_recv == ANY) return "ANY";
227
228 task = taskname(bufp->ps_recv);
229 if (bufp->ps_state != S_STATE) return task;
230
231 blkstr = "?";
232 if (bufp->ps_recv == PM_PROC_NR) {
233 if (bufp->ps_mflags & PAUSED)
234 blkstr = "pause";
235 else if (bufp->ps_mflags & WAITING)
236 blkstr = "wait";
237 else if (bufp->ps_mflags & SIGSUSPENDED)
238 blkstr = "ssusp";
239 } else if (bufp->ps_recv == FS_PROC_NR) {
240 if (-bufp->ps_ftask == XPIPE)
241 blkstr = "pipe";
242 else if (-bufp->ps_ftask == XPOPEN)
243 blkstr = "popen";
244 else if (-bufp->ps_ftask == XLOCK)
245 blkstr = "flock";
246 else if(-bufp->ps_ftask == XSELECT)
247 blkstr = "select";
248 else if(-bufp->ps_ftask >= 0)
249 blkstr = taskname(-bufp->ps_ftask);
250 else
251 blkstr = "??";
252 }
253 (void) sprintf(recvstr, "(%s) %s", blkstr, task);
254 return recvstr;
255}
256
257/* If disaster is called some of the system parameters imported into ps are
258 * probably wrong. This tends to result in memory faults.
259 */
260void disaster(sig)
261int sig;
262{
263 fprintf(stderr, "Ooops, got signal %d\n", sig);
264 fprintf(stderr, "Was ps recompiled since the last kernel change?\n");
265 exit(3);
266}
267
268/* Main interprets arguments, gets system addresses, opens [k]mem, reads in
269 * process tables from kernel/pm/fs and calls pstat() for relevant entries.
270 */
271int main(argc, argv)
272int argc;
273char *argv[];
274{
275 int i;
276 struct pstat buf;
277 int db_fd;
278 int uid = getuid(); /* real uid of caller */
279 char *opt;
280 int opt_all = FALSE; /* -a */
281 int opt_long = FALSE; /* -l */
282 int opt_notty = FALSE; /* -x */
283 char *ke_path; /* paths of kernel, */
284 char *mm_path; /* mm, */
285 char *fs_path; /* and fs used in ps -U */
286 char pid[2 + sizeof(pid_t) * 3];
287 unsigned long ustime;
288 char cpu[sizeof(clock_t) * 3 + 1 + 2];
289 struct kinfo kinfo;
290 int s;
291
292 (void) signal(SIGSEGV, disaster); /* catch a common crash */
293
294 /* Parse arguments; a '-' need not be present (V7/BSD compatability) */
295 for (i = 1; i < argc; i++) {
296 opt = argv[i];
297 if (opt[0] == '-') opt++;
298 while (*opt != 0) switch (*opt++) {
299 case 'a': opt_all = TRUE; break;
300 case 'e': opt_all = opt_notty = TRUE; break;
301 case 'f':
302 case 'l': opt_long = TRUE; break;
303 case 'x': opt_notty = TRUE; break;
304 default: usage(argv[0]);
305 }
306 }
307
308 /* Open memory devices and get PS info from the kernel */
309 if ((kmemfd = open(KMEM_PATH, O_RDONLY)) == -1) err(KMEM_PATH);
310 if ((memfd = open(MEM_PATH, O_RDONLY)) == -1) err(MEM_PATH);
311 if (gettynames() == -1) err("Can't get tty names");
312
313 getsysinfo(PM_PROC_NR, SI_PROC_ADDR, &mproc_addr);
314 getsysinfo(FS_PROC_NR, SI_PROC_ADDR, &fproc_addr);
315 getsysinfo(PM_PROC_NR, SI_KINFO, &kinfo);
316 proc_addr = kinfo.proc_addr;
317 nr_tasks = kinfo.nr_tasks;
318 nr_procs = kinfo.nr_procs;
319
320 /* Allocate memory for process tables */
321 ps_proc = (struct proc *) malloc((nr_tasks + nr_procs) * sizeof(ps_proc[0]));
322 ps_mproc = (struct mproc *) malloc(nr_procs * sizeof(ps_mproc[0]));
323 ps_fproc = (struct fproc *) malloc(nr_procs * sizeof(ps_fproc[0]));
324 if (ps_proc == NULL || ps_mproc == NULL || ps_fproc == NULL)
325 err("Out of memory");
326
327 /* Get kernel process table */
328 if (addrread(kmemfd, (phys_clicks) 0,
329 proc_addr, (char *) ps_proc,
330 (nr_tasks + nr_procs) * sizeof(ps_proc[0]))
331 != (nr_tasks + nr_procs) * sizeof(ps_proc[0]))
332 err("Can't get kernel proc table from /dev/kmem");
333
334 /* Get mm/fs process tables */
335 if (addrread(memfd, ps_proc[nr_tasks + PM_PROC_NR].p_memmap[D].mem_phys,
336 mproc_addr, (char *) ps_mproc,
337 nr_procs * sizeof(ps_mproc[0]))
338 != nr_procs * sizeof(ps_mproc[0]))
339 err("Can't get mm proc table from /dev/mem");
340 if (addrread(memfd, ps_proc[nr_tasks + FS_PROC_NR].p_memmap[D].mem_phys,
341 fproc_addr, (char *) ps_fproc,
342 nr_procs * sizeof(ps_fproc[0]))
343 != nr_procs * sizeof(ps_fproc[0]))
344 err("Can't get fs proc table from /dev/mem");
345
346 /* We need to know where INIT hangs out. */
347 for (i = FS_PROC_NR; i < nr_procs; i++) {
348 if (strcmp(ps_proc[nr_tasks + i].p_name, "init") == 0) break;
349 }
350 init_proc_nr = i;
351
352 /* Now loop through process table and handle each entry */
353 printf("%s", opt_long ? L_HEADER : S_HEADER);
354 for (i = -nr_tasks; i < nr_procs; i++) {
355 if (pstat(i, &buf) != -1 &&
356 (opt_all || buf.ps_euid == uid || buf.ps_ruid == uid) &&
357 (opt_notty || majdev(buf.ps_dev) == TTY_MAJ)) {
358 if (buf.ps_pid == 0 && i != PM_PROC_NR) {
359 sprintf(pid, "(%d)", i);
360 } else {
361 sprintf(pid, "%d", buf.ps_pid);
362 }
363
364 ustime = (buf.ps_utime + buf.ps_stime) / HZ;
365 if (ustime < 60 * 60) {
366 sprintf(cpu, "%2lu:%02lu", ustime / 60, ustime % 60);
367 } else
368 if (ustime < 100L * 60 * 60) {
369 ustime /= 60;
370 sprintf(cpu, "%2luh%02lu", ustime / 60, ustime % 60);
371 } else {
372 sprintf(cpu, "%4luh", ustime / 3600);
373 }
374
375 if (opt_long) printf(L_FORMAT,
376 buf.ps_flags, buf.ps_state,
377 buf.ps_euid, pid, buf.ps_ppid,
378 buf.ps_pgrp,
379 off_to_k((buf.ps_tsize
380 + buf.ps_stack - buf.ps_data
381 + buf.ps_ssize)),
382 (buf.ps_flags & RECEIVING ?
383 prrecv(&buf) :
384 ""),
385 tname((Dev_t) buf.ps_dev),
386 cpu,
387 i <= init_proc_nr || buf.ps_args == NULL
388 ? taskname(i) : buf.ps_args);
389 else
390 printf(S_FORMAT,
391 pid, tname((Dev_t) buf.ps_dev),
392 cpu,
393 i <= init_proc_nr || buf.ps_args == NULL
394 ? taskname(i) : buf.ps_args);
395 }
396 }
397 return(0);
398}
399
400char *get_args(bufp)
401struct pstat *bufp;
402{
403 int nargv;
404 int cnt; /* # of bytes read from stack frame */
405 int neos; /* # of '\0's seen in argv string space */
406 phys_bytes iframe;
407 long l;
408 char *cp, *args;
409 static union stack {
410 vir_bytes stk_i;
411 char *stk_cp;
412 char stk_c;
413 } stk[ARG_MAX / sizeof(char *)];
414 union stack *sp;
415
416 /* Phys address of the original stack frame. */
417 iframe = bufp->ps_procargs - bufp->ps_vstack + bufp->ps_stack;
418
419 /* Calculate the number of bytes to read from user stack */
420 l = (phys_bytes) bufp->ps_ssize - (iframe - bufp->ps_stack);
421 if (l > ARG_MAX) l = ARG_MAX;
422 cnt = l;
423
424 /* Get cnt bytes from user initial stack to local stack buffer */
425 if (lseek(memfd, (off_t) iframe, 0) < 0)
426 return NULL;
427
428 if ( read(memfd, (char *)stk, cnt) != cnt )
429 return NULL;
430
431 sp = stk;
432 nargv = (int) sp[0].stk_i; /* number of argv arguments */
433
434 /* See if argv[0] is with the bytes we read in */
435 l = (long) sp[1].stk_cp - (long) bufp->ps_procargs;
436
437 if ( ( l < 0 ) || ( l > cnt ) )
438 return NULL;
439
440 /* l is the offset of the argv[0] argument */
441 /* change for concatenation the '\0' to space, for nargv elements */
442
443 args = &((char *) stk)[(int)l];
444 neos = 0;
445 for (cp = args; cp < &((char *) stk)[cnt]; cp++)
446 if (*cp == '\0')
447 if (++neos >= nargv)
448 break;
449 else
450 *cp = ' ';
451 if (cp == args) return NULL;
452 *cp = '\0';
453
454 return args;
455
456}
457
458/* Pstat collects info on process number p_nr and returns it in buf.
459 * It is assumed that tasks do not have entries in fproc/mproc.
460 */
461int pstat(p_nr, bufp)
462int p_nr;
463struct pstat *bufp;
464{
465 int p_ki = p_nr + nr_tasks; /* kernel proc index */
466
467 if (p_nr < -nr_tasks || p_nr >= nr_procs) return -1;
468
469 if ((ps_proc[p_ki].p_rts_flags == SLOT_FREE)
470 && !(ps_mproc[p_nr].mp_flags & IN_USE))
471 return -1;
472
473 bufp->ps_flags = ps_proc[p_ki].p_rts_flags;
474
475 if (p_nr >= low_user) {
476 bufp->ps_dev = ps_fproc[p_nr].fp_tty;
477 bufp->ps_ftask = ps_fproc[p_nr].fp_task;
478 } else {
479 bufp->ps_dev = 0;
480 bufp->ps_ftask = 0;
481 }
482
483 if (p_nr >= 0) {
484 bufp->ps_ruid = ps_mproc[p_nr].mp_realuid;
485 bufp->ps_euid = ps_mproc[p_nr].mp_effuid;
486 bufp->ps_pid = ps_mproc[p_nr].mp_pid;
487 bufp->ps_ppid = ps_mproc[ps_mproc[p_nr].mp_parent].mp_pid;
488 bufp->ps_pgrp = ps_mproc[p_nr].mp_procgrp;
489 bufp->ps_mflags = ps_mproc[p_nr].mp_flags;
490 } else {
491 bufp->ps_pid = 0;
492 bufp->ps_ppid = 0;
493 bufp->ps_ruid = bufp->ps_euid = 0;
494 bufp->ps_pgrp = 0;
495 bufp->ps_mflags = 0;
496 }
497
498 /* State is interpretation of combined kernel/mm flags for non-tasks */
499 if (p_nr >= low_user) { /* non-tasks */
500 if (ps_mproc[p_nr].mp_flags & ZOMBIE)
501 bufp->ps_state = Z_STATE; /* zombie */
502 else if (ps_mproc[p_nr].mp_flags & STOPPED)
503 bufp->ps_state = T_STATE; /* stopped (traced) */
504 else if (ps_proc[p_ki].p_rts_flags == 0)
505 bufp->ps_state = R_STATE; /* in run-queue */
506 else if (ps_mproc[p_nr].mp_flags & (WAITING | PAUSED | SIGSUSPENDED) ||
507 ps_fproc[p_nr].fp_suspended == SUSPENDED)
508 bufp->ps_state = S_STATE; /* sleeping */
509 else
510 bufp->ps_state = W_STATE; /* a short wait */
511 } else { /* tasks are simple */
512 if (ps_proc[p_ki].p_rts_flags == 0)
513 bufp->ps_state = R_STATE; /* in run-queue */
514 else
515 bufp->ps_state = W_STATE; /* other i.e. waiting */
516 }
517
518 bufp->ps_tsize = (size_t) ps_proc[p_ki].p_memmap[T].mem_len << CLICK_SHIFT;
519 bufp->ps_dsize = (size_t) ps_proc[p_ki].p_memmap[D].mem_len << CLICK_SHIFT;
520 bufp->ps_ssize = (size_t) ps_proc[p_ki].p_memmap[S].mem_len << CLICK_SHIFT;
521 bufp->ps_vtext = (off_t) ps_proc[p_ki].p_memmap[T].mem_vir << CLICK_SHIFT;
522 bufp->ps_vdata = (off_t) ps_proc[p_ki].p_memmap[D].mem_vir << CLICK_SHIFT;
523 bufp->ps_vstack = (off_t) ps_proc[p_ki].p_memmap[S].mem_vir << CLICK_SHIFT;
524 bufp->ps_text = (off_t) ps_proc[p_ki].p_memmap[T].mem_phys << CLICK_SHIFT;
525 bufp->ps_data = (off_t) ps_proc[p_ki].p_memmap[D].mem_phys << CLICK_SHIFT;
526 bufp->ps_stack = (off_t) ps_proc[p_ki].p_memmap[S].mem_phys << CLICK_SHIFT;
527
528 bufp->ps_recv = _ENDPOINT_P(ps_proc[p_ki].p_getfrom_e);
529
530 bufp->ps_utime = ps_proc[p_ki].p_user_time;
531 bufp->ps_stime = ps_proc[p_ki].p_sys_time;
532
533 bufp->ps_procargs = ps_mproc[p_nr].mp_procargs;
534
535 if (bufp->ps_state == Z_STATE)
536 bufp->ps_args = "<defunct>";
537 else if (p_nr > init_proc_nr)
538 bufp->ps_args = get_args(bufp);
539
540 return 0;
541}
542
543/* Addrread reads nbytes from offset addr to click base of fd into buf. */
544int addrread(fd, base, addr, buf, nbytes)
545int fd;
546phys_clicks base;
547vir_bytes addr;
548char *buf;
549int nbytes;
550{
551 if (lseek(fd, ((off_t) base << CLICK_SHIFT) + addr, 0) < 0)
552 return -1;
553
554 return read(fd, buf, nbytes);
555}
556
557void usage(pname)
558char *pname;
559{
560 fprintf(stderr, "Usage: %s [-][aeflx]\n", pname);
561 exit(1);
562}
563
564void err(s)
565char *s;
566{
567 extern int errno;
568
569 if (errno == 0)
570 fprintf(stderr, "ps: %s\n", s);
571 else
572 fprintf(stderr, "ps: %s: %s\n", s, strerror(errno));
573
574 exit(2);
575}
576
577/* Fill ttyinfo by fstatting character specials in /dev. */
578int gettynames()
579{
580 static char dev_path[] = "/dev/";
581 struct stat statbuf;
582 static char path[sizeof(dev_path) + NAME_MAX];
583 int index;
584 struct ttyent *ttyp;
585
586 index = 0;
587 while ((ttyp = getttyent()) != NULL) {
588 strcpy(path, dev_path);
589 strcat(path, ttyp->ty_name);
590 if (stat(path, &statbuf) == -1 || !S_ISCHR(statbuf.st_mode))
591 continue;
592 if (index >= n_ttyinfo) {
593 n_ttyinfo= (index+16) * 2;
594 ttyinfo = realloc(ttyinfo, n_ttyinfo * sizeof(ttyinfo[0]));
595 if (ttyinfo == NULL) err("Out of memory");
596 }
597 ttyinfo[index].tty_dev = statbuf.st_rdev;
598 strcpy(ttyinfo[index].tty_name, ttyp->ty_name);
599 index++;
600 }
601 endttyent();
602 while (index < n_ttyinfo) ttyinfo[index++].tty_dev= 0;
603
604 return 0;
605}
Note: See TracBrowser for help on using the repository browser.