/* Copyright 1991,1992 Eric R. Smith. All rights reserved. */ /* PROC pseudo-filesystem routines */ /* basically just to allow 'ls -l X:' to give a list of active processes * some things to note: * process names are given as name.XXX, where 'XXX' is the pid of the * process * process attributes depend on the run queue as follows: * RUNNING: 0x00 (normal) * READY: 0x01 (read-only) * WAIT: 0x20 (archive bit) * IOBOUND: 0x21 (archive bit+read-only) * ZOMBIE: 0x22 (archive+hidden) * TSR: 0x02 (hidden) * STOP: 0x24 (archive bit+system) * the general principle is: inactive processes have the archive bit (0x20) * set, terminated processes have the hidden bit (0x02) set, stopped processes * have the system bit (0x04) set, and the read-only bit is used to * otherwise distinguish states (which is unfortunate, since it would be * nice if this bit corresponded with file permissions). */ #include "mint.h" static long proc_root P_((int drv, fcookie *fc)); static long proc_lookup P_((fcookie *dir, const char *name, fcookie *fc)); static long proc_getxattr P_((fcookie *fc, XATTR *xattr)); static long proc_chattr P_((fcookie *fc, int attrib)); static long proc_chown P_((fcookie *fc, int uid, int gid)); static long proc_chmode P_((fcookie *fc, unsigned mode)); static long proc_rmdir P_((fcookie *dir, const char *name)); static long proc_remove P_((fcookie *dir, const char *name)); static long proc_getname P_((fcookie *root, fcookie *dir, char *pathname)); static long proc_rename P_((fcookie *olddir, char *oldname, fcookie *newdir, const char *newname)); static long proc_opendir P_((DIR *dirh, int flags)); static long proc_readdir P_((DIR *dirh, char *nm, int nmlen, fcookie *)); static long proc_rewinddir P_((DIR *dirh)); static long proc_closedir P_((DIR *dirh)); static long proc_pathconf P_((fcookie *dir, int which)); static long proc_dfree P_((fcookie *dir, long *buf)); static DEVDRV * proc_getdev P_((fcookie *fc, long *devsp)); static long proc_open P_((FILEPTR *f)); static long proc_write P_((FILEPTR *f, const char *buf, long bytes)); static long proc_read P_((FILEPTR *f, char *buf, long bytes)); static long proc_lseek P_((FILEPTR *f, long where, int whence)); static long proc_ioctl P_((FILEPTR *f, int mode, void *buf)); static long proc_datime P_((FILEPTR *f, short *time, int rwflag)); static long proc_close P_((FILEPTR *f, int pid)); /* dummy routines from biosfs.c */ extern long null_select P_((FILEPTR *f, long p, int mode)); extern void null_unselect P_((FILEPTR *f, long p, int mode)); static PROC * name2proc P_((const char *name)); DEVDRV proc_device = { proc_open, proc_write, proc_read, proc_lseek, proc_ioctl, proc_datime, proc_close, null_select, null_unselect }; FILESYS proc_filesys = { (FILESYS *)0, 0, proc_root, proc_lookup, nocreat, proc_getdev, proc_getxattr, proc_chattr, proc_chown, proc_chmode, nomkdir, proc_rmdir, proc_remove, proc_getname, proc_rename, proc_opendir, proc_readdir, proc_rewinddir, proc_closedir, proc_pathconf, proc_dfree, nowritelabel, noreadlabel, nosymlink, noreadlink, nohardlink, nofscntl, nodskchng }; long proc_root(drv, fc) int drv; fcookie *fc; { if (drv == PROCDRV) { fc->fs = &proc_filesys; fc->dev = drv; fc->index = 0L; return 0; } fc->fs = 0; return EINTRN; } static PROC * name2proc(name) const char *name; { const char *pstr; char c; int i; pstr = name; while ( (c = *name++) != 0) { if (c == '.') pstr = name; } if (!isdigit(*pstr) && *pstr != '-') return 0; i = atoi(pstr); if (i == -1) return curproc; else if (i == -2) i = curproc->ppid; return pid2proc(i); } static long proc_lookup(dir, name, fc) fcookie *dir; const char *name; fcookie *fc; { PROC *p; if (dir->index != 0) { DEBUG("proc_lookup: bad directory"); return EPTHNF; } /* special case: an empty name in a directory means that directory */ /* so does "." */ if (!*name || (name[0] == '.' && name[1] == 0)) { *fc = *dir; return 0; } /* another special case: ".." could be a mount point */ if (!strcmp(name, "..")) { *fc = *dir; return EMOUNT; } if (!(p = name2proc(name))) { DEBUG("proc_lookup: name not found"); return EFILNF; } else { fc->index = (long)p; fc->fs = &proc_filesys; fc->dev = PROC_BASE_DEV | p->pid; } return 0; } static int p_attr[NUM_QUEUES] = { /* attributes corresponding to queues */ 0, /* "RUNNING" */ 0x01, /* "READY" */ 0x20, /* "WAITING" */ 0x21, /* "IOBOUND" */ 0x22, /* "ZOMBIE" */ 0x02, /* "TSR" */ 0x24, /* "STOPPED" */ 0x21 /* "SELECT" (same as IOBOUND) */ }; static long proc_getxattr(fc, xattr) fcookie *fc; XATTR *xattr; { PROC *p; extern int proctime, procdate; /* see dosmem.c */ xattr->blksize = 1; if (fc->index == 0) { /* the root directory */ xattr->index = 0; xattr->dev = PROCDRV; xattr->nlink = 1; xattr->uid = xattr->gid = 0; xattr->size = xattr->nblocks = 0; xattr->mtime = xattr->atime = xattr->ctime = proctime; xattr->mdate = xattr->adate = xattr->cdate = procdate; xattr->mode = S_IFDIR | DEFAULT_DIRMODE; xattr->attr = FA_DIR; return 0; } p = (PROC *)fc->index; xattr->index = p->pid; xattr->dev = PROC_BASE_DEV | p->pid; xattr->nlink = 1; xattr->uid = p->ruid; xattr->gid = p->rgid; xattr->size = xattr->nblocks = memused(p); xattr->mtime = xattr->ctime = xattr->atime = p->starttime; xattr->mdate = xattr->cdate = xattr->adate = p->startdate; xattr->mode = S_IMEM | S_IRUSR | S_IWUSR; xattr->attr = p_attr[p->wait_q]; return 0; } static long proc_chattr(fc, attrib) fcookie *fc; int attrib; { return EACCDN; } static long proc_chown(fc, uid, gid) fcookie *fc; int uid, gid; { return EINVFN; } static long proc_chmode(fc, mode) fcookie *fc; unsigned mode; { return EINVFN; } static long proc_rmdir(dir, name) fcookie *dir; const char *name; { return EPTHNF; } static long proc_remove(dir, name) fcookie *dir; const char *name; { PROC *p; if (dir->index != 0) return EPTHNF; p = name2proc(name); if (!p) return EFILNF; post_sig(p, SIGTERM); check_sigs(); /* it might have been us */ return 0; } static long proc_getname(root, dir, pathname) fcookie *root, *dir; char *pathname; { PROC *p; if (dir->index == 0) *pathname = 0; else { p = (PROC *)dir->index; ksprintf(pathname, "%s.03d", p->name, p->pid); } return 0; } static long proc_rename(olddir, oldname, newdir, newname) fcookie *olddir; char *oldname; fcookie *newdir; const char *newname; { PROC *p; int i; if (olddir->index != 0 || newdir->index != 0) return EPTHNF; if (!(p = name2proc(oldname))) return EFILNF; oldname = p->name; for (i = 0; i < PNAMSIZ; i++) { if (*newname == 0 || *newname == '.') { *oldname = 0; break; } *oldname++ = *newname++; } return 0; } static long proc_opendir(dirh, flags) DIR *dirh; int flags; { dirh->index = 0; return 0; } static long proc_readdir(dirh, name, namelen, fc) DIR *dirh; char *name; int namelen; fcookie *fc; { int i; int giveindex = (dirh->flags == 0); PROC *p; do { i = dirh->index++; /* BUG: we shouldn't have the magic number "1000" for maximum proc pid */ if (i >= 1000) { p = 0; break; } p = pid2proc(i); } while (!p); if (!p) return ENMFIL; fc->index = (long)p; fc->fs = &proc_filesys; fc->dev = PROC_BASE_DEV | p->pid; if (giveindex) { namelen -= sizeof(long); if (namelen <= 0) return ERANGE; *((long *)name) = (long)p->pid; name += sizeof(long); } if (namelen < strlen(p->name) + 5) return ENAMETOOLONG; ksprintf(name, "%s.%03d", p->name, p->pid); return 0; } static long proc_rewinddir(dirh) DIR *dirh; { dirh->index = 0; return 0; } static long proc_closedir(dirh) DIR *dirh; { return 0; } static long proc_pathconf(dir, which) fcookie *dir; int which; { switch(which) { case -1: return DP_MAXREQ; case DP_IOPEN: return UNLIMITED; /* no internal limit on open files */ case DP_MAXLINKS: return 1; /* we don't have hard links */ case DP_PATHMAX: return PATH_MAX; /* max. path length */ case DP_NAMEMAX: return PNAMSIZ; /* max. length of individual name */ case DP_ATOMIC: return UNLIMITED; /* all writes are atomic */ case DP_TRUNC: return DP_DOSTRUNC; /* file names are truncated to 8.3 */ case DP_CASE: return DP_CASEINSENS; /* case preserved, but ignored */ default: return EINVFN; } } static long proc_dfree(dir, buf) fcookie *dir; long *buf; { long size; /* "sector" size is the size of the smallest amount of memory that can be allocated. see mem.h for the definition of ROUND */ long secsiz = ROUND(1); size = tot_rsize(core, 0) + tot_rsize(alt, 0); *buf++ = size/secsiz; /* number of free clusters */ size = tot_rsize(core, 1) + tot_rsize(alt, 1); *buf++ = size/secsiz; /* total number of clusters */ *buf++ = secsiz; /* sector size (bytes) */ *buf++ = 1; /* cluster size (in sectors) */ return 0; } static DEVDRV * proc_getdev(fc, devsp) fcookie *fc; long *devsp; { PROC *p; p = (PROC *)fc->index; *devsp = (long)p; return &proc_device; } /* * PROC device driver */ /* * BUG: file locking and the O_SHMODE restrictions are not implemented * for processes */ static long proc_open(f) FILEPTR *f; { return 0; } static long proc_write(f, buf, nbytes) FILEPTR *f; const char *buf; long nbytes; { PROC *p; char *where; long bytes_written = 0; p = (PROC *)f->devinfo; where = (char *)f->pos; /* BUG: process read/writes should check for valid addresses */ TRACE("proc_write: %ld bytes to %lx", nbytes, where); while (nbytes-- > 0) { *where++ = *buf++; bytes_written++; } f->pos += bytes_written; return bytes_written; } static long proc_read(f, buf, nbytes) FILEPTR *f; char *buf; long nbytes; { PROC *p; char *where; long bytes_read = 0; p = (PROC *)f->devinfo; where = (char *)f->pos; TRACE("proc_read: %ld bytes from %lx", nbytes, where); while (nbytes-- > 0) { *buf++ = *where++; bytes_read++; } f->pos += bytes_read; return bytes_read; } /* * proc_ioctl: currently, the only IOCTL's available are: * PPROCADDR: get address of PROC structure's "interesting" bits * PCTXTSIZE: get the size of the CONTEXT structure * PBASEADDR: get address of process basepage * PSETFLAGS: set the memory allocation flags (e.g. to malloc from fastram) * PGETFLAGS: get the memory allocation flags */ static long proc_ioctl(f, mode, buf) FILEPTR *f; int mode; void *buf; { PROC *p; p = (PROC *)f->devinfo; switch(mode) { case PPROCADDR: *((long *)buf) = (long)&p->magic; return 0; case PBASEADDR: *((long *)buf) = (long)p->base; return 0; case PCTXTSIZE: *((long *)buf) = sizeof(CONTEXT); return 0; case PSETFLAGS: /* note: only the low 16 bits are actually used */ p->memflags = *((long *)buf); return 0; case PGETFLAGS: *((long *)buf) = p->memflags; return 0; case FIONREAD: case FIONWRITE: *((long *)buf) = 1L; /* we're always ready for i/o */ return 0; default: DEBUG("procfs: bad Fcntl command"); } return EINVFN; } static long proc_lseek(f, where, whence) FILEPTR *f; long where; int whence; { switch(whence) { case 0: f->pos = where; break; case 1: f->pos += where; break; case 2: f->pos = -where; break; default: return EINVFN; } return f->pos; } static long proc_datime(f, timeptr, rwflag) FILEPTR *f; short *timeptr; int rwflag; { PROC *p; p = (PROC *)f->devinfo; if (rwflag) { return EACCDN; } else { *timeptr++ = p->starttime; *timeptr++ = p->startdate; } return 0; } static long proc_close(f, pid) FILEPTR *f; int pid; { return 0; }