home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / mint104s.zoo / mint.src / shmfs.c < prev    next >
C/C++ Source or Header  |  1993-03-08  |  15KB  |  705 lines

  1. /*
  2. Copyright 1992 Eric R. Smith.
  3. All rights reserved.
  4.  */
  5.  
  6. /* Shared memory file system */
  7.  
  8. #include "mint.h"
  9.  
  10.  
  11. static long    ARGS_ON_STACK shm_root    P_((int drv, fcookie *fc));
  12. static long    ARGS_ON_STACK shm_creat    P_((fcookie *dir, const char *name, unsigned mode,
  13.                     int attrib, fcookie *fc));
  14. static long    ARGS_ON_STACK shm_lookup    P_((fcookie *dir, const char *name, fcookie *fc));
  15. static long    ARGS_ON_STACK shm_getxattr    P_((fcookie *fc, XATTR *xattr));
  16. static long    ARGS_ON_STACK shm_chattr    P_((fcookie *fc, int attrib));
  17. static long    ARGS_ON_STACK shm_chown    P_((fcookie *fc, int uid, int gid));
  18. static long    ARGS_ON_STACK shm_chmode    P_((fcookie *fc, unsigned mode));
  19. static long    ARGS_ON_STACK shm_rmdir    P_((fcookie *dir, const char *name));
  20. static long    ARGS_ON_STACK shm_remove    P_((fcookie *dir, const char *name));
  21. static long    ARGS_ON_STACK shm_getname    P_((fcookie *root, fcookie *dir,
  22.                             char *pathname, int size));
  23. static long    ARGS_ON_STACK shm_rename    P_((fcookie *olddir, char *oldname,
  24.                     fcookie *newdir, const char *newname));
  25. static long    ARGS_ON_STACK shm_opendir    P_((DIR *dirh, int flags));
  26. static long    ARGS_ON_STACK shm_readdir    P_((DIR *dirh, char *nm, int nmlen, fcookie *));
  27. static long    ARGS_ON_STACK shm_rewinddir    P_((DIR *dirh));
  28. static long    ARGS_ON_STACK shm_closedir    P_((DIR *dirh));
  29. static long    ARGS_ON_STACK shm_pathconf    P_((fcookie *dir, int which));
  30. static long    ARGS_ON_STACK shm_dfree    P_((fcookie *dir, long *buf));
  31. static DEVDRV *    ARGS_ON_STACK shm_getdev    P_((fcookie *fc, long *devsp));
  32.  
  33. static long    ARGS_ON_STACK shm_open    P_((FILEPTR *f));
  34. static long    ARGS_ON_STACK shm_write    P_((FILEPTR *f, const char *buf, long bytes));
  35. static long    ARGS_ON_STACK shm_read    P_((FILEPTR *f, char *buf, long bytes));
  36. static long    ARGS_ON_STACK shm_lseek    P_((FILEPTR *f, long where, int whence));
  37. static long    ARGS_ON_STACK shm_ioctl    P_((FILEPTR *f, int mode, void *buf));
  38. static long    ARGS_ON_STACK shm_datime    P_((FILEPTR *f, short *time, int rwflag));
  39. static long    ARGS_ON_STACK shm_close    P_((FILEPTR *f, int pid));
  40.  
  41. /* dummy routines from biosfs.c */
  42. extern long    ARGS_ON_STACK null_select    P_((FILEPTR *f, long p, int mode));
  43. extern void    ARGS_ON_STACK null_unselect    P_((FILEPTR *f, long p, int mode));
  44.  
  45. static short shmtime, shmdate;
  46.  
  47. #define SHMNAME_MAX 15
  48.  
  49. typedef struct shmfile {
  50.     struct shmfile *next;
  51.     char filename[SHMNAME_MAX+1];
  52.     int uid, gid;
  53.     short time, date;
  54.     unsigned mode;
  55.     int inuse;
  56.     MEMREGION *reg;
  57. } SHMFILE;
  58.  
  59. SHMFILE *shmroot = 0;
  60.  
  61. DEVDRV shm_device = {
  62.     shm_open, shm_write, shm_read, shm_lseek, shm_ioctl, shm_datime,
  63.     shm_close, null_select, null_unselect
  64. };
  65.  
  66. FILESYS shm_filesys = {
  67.     (FILESYS *)0,
  68.     FS_LONGPATH,
  69.     shm_root,
  70.     shm_lookup, shm_creat, shm_getdev, shm_getxattr,
  71.     shm_chattr, shm_chown, shm_chmode,
  72.     nomkdir, shm_rmdir, shm_remove, shm_getname, shm_rename,
  73.     shm_opendir, shm_readdir, shm_rewinddir, shm_closedir,
  74.     shm_pathconf, shm_dfree,
  75.     nowritelabel, noreadlabel, nosymlink, noreadlink, nohardlink,
  76.     nofscntl, nodskchng
  77. };
  78.  
  79. long ARGS_ON_STACK 
  80. shm_root(drv, fc)
  81.     int drv;
  82.     fcookie *fc;
  83. {
  84.     if ((unsigned)drv == SHMDRV) {
  85.         fc->fs = &shm_filesys;
  86.         fc->dev = drv;
  87.         fc->index = 0L;
  88.         return 0;
  89.     }
  90.     fc->fs = 0;
  91.     return EINTRN;
  92. }
  93.  
  94. static long ARGS_ON_STACK 
  95. shm_lookup(dir, name, fc)
  96.     fcookie *dir;
  97.     const char *name;
  98.     fcookie *fc;
  99. {
  100.     SHMFILE *s;
  101.  
  102.     if (dir->index != 0) {
  103.         DEBUG(("shm_lookup: bad directory"));
  104.         return EPTHNF;
  105.     }
  106.  
  107. /* special case: an empty name in a directory means that directory */
  108. /* so does "." */
  109.     if (!*name || (name[0] == '.' && name[1] == 0)) {
  110.         *fc = *dir;
  111.         return 0;
  112.     }
  113.  
  114. /* another special case: ".." could be a mount point */
  115.     if (!strcmp(name, "..")) {
  116.         *fc = *dir;
  117.         return EMOUNT;
  118.     }
  119.  
  120.     for (s = shmroot; s; s = s->next) {
  121.         if (!stricmp(s->filename,name))
  122.             break;
  123.     }
  124.  
  125.     if (!s) {
  126.         DEBUG(("shm_lookup: name not found"));
  127.         return EFILNF;
  128.     } else {
  129.         fc->index = (long)s;
  130.         fc->fs = &shm_filesys;
  131.         fc->dev = SHMDRV;
  132.     }
  133.     return 0;
  134. }
  135.  
  136. static long ARGS_ON_STACK 
  137. shm_getxattr(fc, xattr)
  138.     fcookie *fc;
  139.     XATTR *xattr;
  140. {
  141.     SHMFILE *s;
  142.  
  143.     xattr->blksize = 1;
  144.     if (fc->index == 0) {
  145.         /* the root directory */
  146.         xattr->index = 0;
  147.         xattr->dev = SHMDRV;
  148.         xattr->nlink = 1;
  149.         xattr->uid = xattr->gid = 0;
  150.         xattr->size = xattr->nblocks = 0;
  151.         xattr->mtime = xattr->atime = xattr->ctime = shmtime;
  152.         xattr->mdate = xattr->adate = xattr->cdate = shmdate;
  153.         xattr->mode = S_IFDIR | DEFAULT_DIRMODE;
  154.         xattr->attr = FA_DIR;
  155.         return 0;
  156.     }
  157.  
  158.     s = (SHMFILE *)fc->index;
  159.     xattr->index = (long) s;
  160.     xattr->dev = SHMDRV;
  161.     xattr->uid = s->uid; xattr->gid = s->gid;
  162.     if (s->reg) {
  163.         xattr->size = xattr->nblocks = s->reg->len;
  164.         xattr->nlink = s->reg->links + 1;
  165.      } else {
  166.         xattr->size = xattr->nblocks = 0;
  167.         xattr->nlink = 1;
  168.     }
  169.     xattr->mtime = xattr->ctime = xattr->atime = s->time;
  170.     xattr->mdate = xattr->cdate = xattr->adate = s->date;
  171.     xattr->mode = s->mode;
  172.     xattr->attr = (s->mode & (S_IWUSR|S_IWGRP|S_IWOTH)) ? 0 : 
  173.             FA_RDONLY;
  174.     return 0;
  175. }
  176.  
  177. static long ARGS_ON_STACK 
  178. shm_chattr(fc, attrib)
  179.     fcookie *fc;
  180.     int attrib;
  181. {
  182.     SHMFILE *s;
  183.  
  184.     s = (SHMFILE *)fc->index;
  185.     if (!s) return EACCDN;
  186.  
  187.     if (attrib & FA_RDONLY) {
  188.         s->mode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
  189.     } else if ( !(s->mode & (S_IWUSR|S_IWGRP|S_IWOTH)) ) {
  190.         s->mode |= (S_IWUSR|S_IWGRP|S_IWOTH);
  191.     }
  192.     return 0;
  193. }
  194.  
  195. static long ARGS_ON_STACK 
  196. shm_chown(fc, uid, gid)
  197.     fcookie *fc;
  198.     int uid, gid;
  199. {
  200.     SHMFILE *s;
  201.  
  202.     s = (SHMFILE *)fc->index;
  203.     if (!s)
  204.         return EACCDN;
  205.     s->uid = uid;
  206.     s->gid = gid;
  207.     return 0;
  208. }
  209.  
  210. static long ARGS_ON_STACK 
  211. shm_chmode(fc, mode)
  212.     fcookie *fc;
  213.     unsigned mode;
  214. {
  215.     SHMFILE *s;
  216.  
  217.     s = (SHMFILE *)fc->index;
  218.     if (!s)
  219.         return EINVFN;
  220.     s->mode = mode;
  221.     return 0;
  222. }
  223.  
  224. static long ARGS_ON_STACK 
  225. shm_rmdir(dir, name)
  226.     fcookie *dir;
  227.     const char *name;
  228. {
  229.     UNUSED(dir); UNUSED(name);
  230.  
  231.     return EPTHNF;
  232. }
  233.  
  234. static long ARGS_ON_STACK 
  235. shm_remove(dir, name)
  236.     fcookie *dir;
  237.     const char *name;
  238. {
  239.     SHMFILE *s, **old;
  240.  
  241.     if (dir->index != 0)
  242.         return EPTHNF;
  243.  
  244.     old = &shmroot;
  245.     for (s = shmroot; s; s = s->next) {
  246.         if (!stricmp(s->filename, name))
  247.             break;
  248.         old = &s->next;
  249.     }
  250.     if (!s)
  251.         return EFILNF;
  252.     if (s->inuse)
  253.         return EACCDN;
  254.     *old = s->next;
  255.  
  256.     s->reg->links--;
  257.     if (s->reg->links <= 0) {
  258.         free_region(s->reg);
  259.     }
  260.     kfree(s);
  261.     shmtime = timestamp;
  262.     shmdate = datestamp;
  263.     return 0;
  264. }
  265.  
  266. static long ARGS_ON_STACK 
  267. shm_getname(root, dir, pathname, size)
  268.     fcookie *root, *dir; char *pathname;
  269.     int size;
  270. {
  271.     UNUSED(root); UNUSED(dir);
  272.  
  273. /* BUG: 'size' should be used in a more meaningful way */
  274.     if (size <= 0) return ERANGE;
  275.     *pathname = 0;
  276.     return 0;
  277. }
  278.  
  279. static long ARGS_ON_STACK 
  280. shm_rename(olddir, oldname, newdir, newname)
  281.     fcookie *olddir;
  282.     char *oldname;
  283.     fcookie *newdir;
  284.     const char *newname;
  285. {
  286.     SHMFILE *s;
  287.  
  288.     if (olddir->index != 0 || newdir->index != 0)
  289.         return EPTHNF;
  290.  
  291. /* verify that "newname" doesn't exist */
  292.     for (s = shmroot; s; s = s->next)
  293.         if (!stricmp(s->filename, newname))
  294.             return EACCDN;
  295.  
  296.     for (s = shmroot; s; s = s->next)
  297.         if (!stricmp(s->filename, oldname))
  298.             break;
  299.     if (!s)
  300.         return EFILNF;
  301.  
  302.     strncpy(s->filename, newname, SHMNAME_MAX);
  303.     shmtime = timestamp;
  304.     shmdate = datestamp;
  305.     return 0;
  306. }
  307.  
  308. static long ARGS_ON_STACK 
  309. shm_opendir(dirh, flags)
  310.     DIR *dirh;
  311.     int flags;
  312. {
  313.     UNUSED(flags);
  314.  
  315.     dirh->index = 0;
  316.     return 0;
  317. }
  318.  
  319. static long ARGS_ON_STACK 
  320. shm_readdir(dirh, name, namelen, fc)
  321.     DIR *dirh;
  322.     char *name;
  323.     int namelen;
  324.     fcookie *fc;
  325. {
  326.     int i;
  327.     int giveindex = (dirh->flags == 0);
  328.     SHMFILE *s;
  329.  
  330.     s = shmroot;
  331.     i = dirh->index++;
  332.     while (i > 0 && s != 0) {
  333.         s = s->next;
  334.         --i;
  335.     }
  336.     if (!s)
  337.         return ENMFIL;
  338.  
  339.     fc->index = (long)s;
  340.     fc->fs = &shm_filesys;
  341.     fc->dev = SHMDRV;
  342.  
  343.     if (giveindex) {
  344.         namelen -= (int)sizeof(long);
  345.         if (namelen <= 0) return ERANGE;
  346.         *((long *)name) = (long)s;
  347.         name += sizeof(long);
  348.     }
  349.     if (namelen < strlen(s->filename))
  350.         return ENAMETOOLONG;
  351.     strcpy(name, s->filename);
  352.     return 0;
  353. }
  354.  
  355. static long ARGS_ON_STACK 
  356. shm_rewinddir(dirh)
  357.     DIR *dirh;
  358. {
  359.     dirh->index = 0;
  360.     return 0;
  361. }
  362.  
  363. static long ARGS_ON_STACK 
  364. shm_closedir(dirh)
  365.     DIR *dirh;
  366. {
  367.     UNUSED(dirh);
  368.     return 0;
  369. }
  370.  
  371. static long ARGS_ON_STACK 
  372. shm_pathconf(dir, which)
  373.     fcookie *dir;
  374.     int which;
  375. {
  376.     UNUSED(dir);
  377.  
  378.     switch(which) {
  379.     case -1:
  380.         return DP_MAXREQ;
  381.     case DP_IOPEN:
  382.         return UNLIMITED;    /* no internal limit on open files */
  383.     case DP_MAXLINKS:
  384.         return 1;        /* we don't have hard links */
  385.     case DP_PATHMAX:
  386.         return PATH_MAX;    /* max. path length */
  387.     case DP_NAMEMAX:
  388.         return SHMNAME_MAX;    /* max. length of individual name */
  389.     case DP_ATOMIC:
  390.         return UNLIMITED;    /* all writes are atomic */
  391.     case DP_TRUNC:
  392.         return DP_AUTOTRUNC;    /* file names are truncated */
  393.     case DP_CASE:
  394.         return DP_CASEINSENS;    /* case preserved, but ignored */
  395.     default:
  396.         return EINVFN;
  397.     }
  398. }
  399.  
  400. static long ARGS_ON_STACK 
  401. shm_dfree(dir, buf)
  402.     fcookie *dir;
  403.     long *buf;
  404. {
  405.     long size;
  406. /* "sector" size is the size of the smallest amount of memory that can be
  407.    allocated. see mem.h for the definition of ROUND
  408.  */
  409.     long secsiz = ROUND(1);
  410.  
  411.     UNUSED(dir);
  412.  
  413.     size = tot_rsize(core, 0) + tot_rsize(alt, 0);
  414.     *buf++ = size/secsiz;            /* number of free clusters */
  415.     size = tot_rsize(core, 1) + tot_rsize(alt, 1);
  416.     *buf++ = size/secsiz;            /* total number of clusters */
  417.     *buf++ = secsiz;            /* sector size (bytes) */
  418.     *buf = 1;                /* cluster size (in sectors) */
  419.     return 0;
  420. }
  421.  
  422. static DEVDRV * ARGS_ON_STACK 
  423. shm_getdev(fc, devsp)
  424.     fcookie *fc;
  425.     long *devsp;
  426. {
  427.     SHMFILE *s;
  428.  
  429.     s = (SHMFILE *)fc->index;
  430.  
  431.     *devsp = (long)s;
  432.     return &shm_device;
  433. }
  434.  
  435. /*
  436.  * create a shared memory region
  437.  */
  438.  
  439. static long ARGS_ON_STACK 
  440. shm_creat(dir, name, mode, attrib, fc)
  441.     fcookie *dir;
  442.     const char *name;
  443.     unsigned mode;
  444.     int attrib;
  445.     fcookie *fc;
  446. {
  447.     SHMFILE *s;
  448.  
  449.     UNUSED(attrib);
  450. /*
  451.  * see if the name already exists
  452.  */
  453.     for (s = shmroot; s; s = s->next) {
  454.         if (!stricmp(s->filename, name)) {
  455.             DEBUG(("shm_creat: file exists"));
  456.             return EACCDN;
  457.         }
  458.     }
  459.  
  460.     s = (SHMFILE *)kmalloc(SIZEOF(SHMFILE));
  461.     if (!s)
  462.         return ENSMEM;
  463.  
  464.     s->inuse = 0;
  465.     strncpy(s->filename, name, SHMNAME_MAX);
  466.     s->filename[SHMNAME_MAX] = 0;
  467.     s->uid = curproc->ruid;
  468.     s->gid = curproc->rgid;
  469.     s->mode = mode;
  470.     s->next = shmroot;
  471.     s->reg = 0;
  472.     s->time = shmtime = timestamp;
  473.     s->date = shmdate = datestamp;
  474.     shmroot = s;
  475.  
  476.     fc->fs = &shm_filesys;
  477.     fc->index = (long)s;
  478.     fc->dev = dir->dev;
  479.  
  480.     return 0;
  481. }
  482.  
  483. /*
  484.  * Shared memory device driver
  485.  */
  486.  
  487. /*
  488.  * BUG: file locking and the O_SHMODE restrictions are not implemented
  489.  * for shared memory
  490.  */
  491.  
  492. static long ARGS_ON_STACK 
  493. shm_open(f)
  494.     FILEPTR *f;
  495. {
  496.     SHMFILE *s;
  497.  
  498.     s = (SHMFILE *)f->devinfo;
  499.     s->inuse++;
  500.     return 0;
  501. }
  502.  
  503. static long ARGS_ON_STACK 
  504. shm_write(f, buf, nbytes)
  505.     FILEPTR *f; const char *buf; long nbytes;
  506. {
  507.     SHMFILE *s;
  508.     char *where;
  509.     long bytes_written = 0;
  510.  
  511.     s = (SHMFILE *)f->devinfo;
  512.     if (!s->reg)
  513.         return 0;
  514.  
  515.     if (nbytes + f->pos > s->reg->len)
  516.         nbytes = s->reg->len - f->pos;
  517.  
  518.     where = (char *)s->reg->loc + f->pos;
  519.  
  520. /* BUG: memory read/writes should check for valid addresses */
  521.  
  522. TRACE(("shm_write: %ld bytes to %lx", nbytes, where));
  523.  
  524.     while (nbytes-- > 0) {
  525.         *where++ = *buf++;
  526.         bytes_written++;
  527.     }
  528.     f->pos += bytes_written;
  529.     s->time = timestamp;
  530.     s->date = datestamp;
  531.     return bytes_written;
  532. }
  533.  
  534. static long ARGS_ON_STACK 
  535. shm_read(f, buf, nbytes)
  536.     FILEPTR *f; char *buf; long nbytes;
  537. {
  538.     SHMFILE *s;
  539.     char *where;
  540.     long bytes_read = 0;
  541.  
  542.     s = (SHMFILE *)f->devinfo;
  543.     if (!(s->reg))
  544.         return 0;
  545.  
  546.     if (nbytes + f->pos > s->reg->len)
  547.         nbytes = s->reg->len - f->pos;
  548.  
  549.     where = (char *)s->reg->loc + f->pos;
  550.  
  551. TRACE(("shm_read: %ld bytes from %lx", nbytes, where));
  552.  
  553.     while (nbytes-- > 0) {
  554.         *buf++ = *where++;
  555.         bytes_read++;
  556.     }
  557.     f->pos += bytes_read;
  558.     return bytes_read;
  559. }
  560.  
  561. /*
  562.  * shm_ioctl: currently, the only IOCTL's available are:
  563.  * SHMSETBLK:  set the address of the shared memory file. This
  564.  *             call may only be made once per region, and then only
  565.  *           if the region is open for writing.
  566.  * SHMGETBLK:  get the address of the shared memory region. This
  567.  *             call fails (returns 0) if SHMSETBLK has not been
  568.  *             called yet for this shared memory file.
  569.  */
  570.  
  571. static long ARGS_ON_STACK 
  572. shm_ioctl(f, mode, buf)
  573.     FILEPTR *f; int mode; void *buf;
  574. {
  575.     SHMFILE *s;
  576.     MEMREGION *m;
  577.     int i;
  578.     long r;
  579.  
  580.     s = (SHMFILE *)f->devinfo;
  581.     switch(mode) {
  582.     case SHMSETBLK:
  583.         if (s->reg) {
  584.             DEBUG(("Fcntl: SHMSETBLK already performed for %s",
  585.                 s->filename));
  586.             return ERANGE;
  587.         }
  588.         if ((f->flags & O_RWMODE) == O_RDONLY) {
  589.             DEBUG(("Fcntl: SHMSETBLK: %s was opened read-only",
  590.                 s->filename));
  591.             return EACCDN;
  592.         }
  593.     /* find the memory region to be attached */
  594.         m = 0;
  595.         for (i = curproc->num_reg - 1; i >= 0; i--) {
  596.             if (curproc->addr[i] == (virtaddr)buf) {
  597.                 m = curproc->mem[i];
  598.                 break;
  599.             }
  600.         }
  601.         if (!m || !buf) {
  602.             DEBUG(("Fcntl: SHMSETBLK: bad address %lx", buf));
  603.             return EIMBA;
  604.         }
  605.         m->links++;
  606.         s->reg = m;
  607.         return 0;
  608.     case SHMGETBLK:
  609.         if ((m = s->reg) == 0) {
  610.             DEBUG(("Fcntl: no address for SHMGETBLK"));
  611.             return 0;
  612.         }
  613.     /* check for memory limits */
  614.         if (curproc->maxmem) {
  615.             if (m->len > curproc->maxmem - memused(curproc)) {
  616.                 DEBUG(("Fcntl: SHMGETBLK would violate memory limits"));
  617.                 return 0;
  618.             }
  619.         }
  620.         return (long)attach_region(curproc, m);
  621.     case FIONREAD:
  622.     case FIONWRITE:
  623.         if (s->reg == 0) {
  624.             r = 0;
  625.         } else {
  626.             r = s->reg->len - f->pos;
  627.             if (r < 0) r = 0;
  628.         }
  629.         *((long *)buf) = r;
  630.         return 0;
  631.     default:
  632.         DEBUG(("shmfs: bad Fcntl command"));
  633.     }
  634.     return EINVFN;
  635. }
  636.  
  637. static long ARGS_ON_STACK 
  638. shm_lseek(f, where, whence)
  639.     FILEPTR *f; long where; int whence;
  640. {
  641.     long newpos, maxpos;
  642.     SHMFILE *s;
  643.  
  644.     s = (SHMFILE *)f->devinfo;
  645.  
  646.     if (s->reg)
  647.         maxpos = s->reg->len;
  648.     else
  649.         maxpos = 0;
  650.  
  651.     switch(whence) {
  652.     case 0:
  653.         newpos = where;
  654.         break;
  655.     case 1:
  656.         newpos = f->pos + where;
  657.         break;
  658.     case 2:
  659.         newpos = maxpos - where;
  660.         break;
  661.     default:
  662.         return EINVFN;
  663.     }
  664.  
  665.     if (newpos < 0 || newpos > maxpos)
  666.         return ERANGE;
  667.  
  668.     f->pos = newpos;
  669.     return newpos;
  670. }
  671.  
  672. static long ARGS_ON_STACK 
  673. shm_datime(f, timeptr, rwflag)
  674.     FILEPTR *f;
  675.     short *timeptr;
  676.     int rwflag;
  677. {
  678.     SHMFILE *s;
  679.  
  680.     s = (SHMFILE *)f->devinfo;
  681.     if (rwflag) {
  682.         s->time = *timeptr++;
  683.         s->date = *timeptr;
  684.     } else {
  685.         *timeptr++ = s->time;
  686.         *timeptr = s->date;
  687.     }
  688.     return 0;
  689. }
  690.  
  691. static long ARGS_ON_STACK 
  692. shm_close(f, pid)
  693.     FILEPTR *f;
  694.     int pid;
  695. {
  696.     SHMFILE *s;
  697.  
  698.     UNUSED(pid);
  699.     if (f->links <= 0) {
  700.         s = (SHMFILE *)f->devinfo;
  701.         s->inuse--;
  702.     }
  703.     return 0;
  704. }
  705.