home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume15 / unfsd / part01 next >
Encoding:
Internet Message Format  |  1988-05-24  |  45.3 KB

  1. Path: bbn.com!bbn!husc6!mailrus!ames!lll-lcc!pyramid!munnari!bogus-address
  2. From: shand@cad.jmrc.eecs.unsw.oz (Mark Shand)
  3. Newsgroups: comp.sources.unix
  4. Subject: v15i001:  unfsd - user-level NFS server, Part01/02
  5. Keywords: nfs sunrpc
  6. Message-ID: <2143@munnari.oz>
  7. Date: 25 May 88 01:06:16 GMT
  8. Sender: kre@munnari.oz
  9. Lines: 1836
  10. Approved: kre@munnari.oz.au
  11.  
  12. Submitted by: shand@cad.jmrc.eecs.unsw.oz (Mark Shand)
  13. Posting-number: Volume 15, Issue 1
  14. Archive-name: unfsd/Part01
  15.  
  16.     [ Within the stated limitations, this seems to be a useful
  17.       tool.  It compiled and ran fine on my (slightly pre) 4.3bsd vax.
  18.  
  19.       Nb: you need the Sun RPC version 3.9 from Volume 13 or
  20.       comp.sources.unix in order to use this submission.    ..kre ]
  21.  
  22.  
  23. UNFSD - USER-LEVEL NFS SERVER
  24. =============================
  25.  
  26. This package implements a simple user level NFS server based on the
  27. sunrpc3.9 package that was posted to the net a few months ago.  The
  28. current version only provides read access from the clients.  It has
  29. been tested between a VAX11/780 running 4.3BSD (the server) and several
  30. diskful SUN3/60 running SunOS 3.4 (the clients) and on a diskless
  31. SUN3/50 running SunOS 3.2 remounting its own root at a lower level of
  32. its file hierarchy.
  33.  
  34. #--------------------------------CUT HERE-------------------------------------
  35. #! /bin/sh
  36. #
  37. # This is a shell archive.  Save this into a file, edit it
  38. # and delete all lines above this comment.  Then give this
  39. # file to sh by executing the command "sh file".  The files
  40. # will be extracted into the current directory owned by
  41. # you with default permissions.
  42. #
  43. # The files contained herein are:
  44. #
  45. # -rw-rw-r--  1 shand        2392 May 17 01:59 Makefile
  46. # -rw-rw-r--  1 shand        6087 May 18 21:30 README
  47. # -rw-r--r--  1 shand       18021 May 17 02:24 fh.c
  48. # -rw-rw-r--  1 shand         727 May 17 02:24 fh.h
  49. # -rw-rw-r--  1 shand        9203 May 17 02:25 init.c
  50. # -rw-rw-r--  1 shand        4310 May 16 02:24 mount.x
  51. #
  52. echo 'x - Makefile'
  53. if test -f Makefile; then echo 'shar: not overwriting Makefile'; else
  54. sed 's/^X//' << '________This_Is_The_END________' > Makefile
  55. X# For standard 4.3BSD systems with sunrpc3.9 installed
  56. X#LIB=-lrpclib
  57. X# For SunOS and other systems with rpc in the c library
  58. XLIB=
  59. X
  60. X# Client authorization file
  61. XEXPORTSFILE=/etc/unfsd_exports
  62. X
  63. X# Try -DDEBUG for a copious debug log to be written to /tmp/unfsd.log
  64. XCFLAGS= -O -DREAD_ONLY -DEXPORTSFILE='"${EXPORTSFILE}"'
  65. XLDFLAGS= -O
  66. X
  67. XRPCGEN=    rpcgen
  68. XCC=    cc
  69. X#------------------------------End of configuration section.
  70. X
  71. XNFSOBJS= nfs_prot_svc.o nfs_prot_xdr.o unfsd.o init.o \
  72. X    fh.o ugid_map.o ugid_xdr.o ugid_clnt.o
  73. X
  74. Xall: unfsd unfsmntd
  75. X
  76. Xinstall: unfsd unfsmntd
  77. X    cp unfsd ${INSDIR}/unfsd
  78. X    cp unfsmntd ${INSDIR}/unfsmntd
  79. X
  80. Xunfsd:    ${NFSOBJS}
  81. X    ${CC} $(LDFLAGS) -o unfsd ${NFSOBJS} ${LIB}
  82. X
  83. Xunfsmntd: mount_svc.o mount_xdr.o unfsmntd.o fh.o
  84. X    ${CC} $(LDFLAGS) -o unfsmntd mount_svc.o mount_xdr.o unfsmntd.o fh.o ${LIB}
  85. X
  86. Xugidd:    ugid_svc.o ugid_xdr.o ugidd.o
  87. X    ${CC} $(LDFLAGS) -o ugidd ugid_svc.o ugid_xdr.o ugidd.o ${LIB}
  88. Xmprobe: mprobe.o mount_xdr.o nfs_prot_xdr.o
  89. X    ${CC} ${LDFLAGS} -o mprobe mprobe.o mount_xdr.o nfs_prot_xdr.o \
  90. X        rpc/rpc/librpclib.a
  91. X
  92. Xnfs_prot.h: nfs_prot.x
  93. X    ${RPCGEN} -h -o $@ $?
  94. X
  95. Xnfs_prot_svc.c: nfs_prot.x
  96. X    ${RPCGEN} -s udp $? | \
  97. X    sed \
  98. X        -e 's/main()/main(argc,argv) int argc; char **argv;/' \
  99. X        -e 's/RPC_ANYSOCK/makesock(NFS_PORT, NFS_MAXDATA)/' \
  100. X        -e 's/svc_run();/unfsd_init(argc,argv); svc_run();/' \
  101. X        > $@
  102. X
  103. Xnfs_prot_xdr.c: nfs_prot.x
  104. X    ${RPCGEN} -c -o $@ $?
  105. X
  106. Xmount.h: mount.x
  107. X    ${RPCGEN} -h -o $@ $?
  108. X
  109. Xmount_svc.c: mount.x
  110. X    ${RPCGEN} -s udp $? | \
  111. X    sed \
  112. X        -e 's/main()/main(argc,argv) int argc; char **argv;/' \
  113. X        -e 's/svc_run();/unfsmntd_init(argc,argv); svc_run();/' \
  114. X        > $@
  115. X
  116. Xmount_xdr.c: mount.x
  117. X    ${RPCGEN} -c -o $@ $?
  118. X
  119. Xugid.h:    ugid.x
  120. X    ${RPCGEN} -h -o $@ $?
  121. X
  122. Xugid_svc.c: ugid.x 
  123. X    ${RPCGEN} -s udp $? | \
  124. X    sed \
  125. X        -e 's/main()/main(argc,argv) int argc; char **argv;/' \
  126. X        -e 's/RPC_ANYSOCK/run_mode_from_args(argc,argv)/' \
  127. X        > $@
  128. X
  129. Xugid_xdr.c: ugid.x
  130. X    ${RPCGEN} -c -o $@ $?
  131. X
  132. Xugid_clnt.c: ugid.x
  133. X    ${RPCGEN} -l -o $@ $?
  134. Xclean:
  135. X    rm -rf *.o nfs_prot_svc.c nfs_prot_xdr.c nfs_prot.h \
  136. X        mount_svc.c mount_xdr.c mount.h \
  137. X        ugid_svc.c ugid_xdr.c ugid_clnt.c ugid.h \
  138. X        unfsd unfsmntd ugidd mprobe
  139. X
  140. X# include dependencies
  141. Xnfs_prot_svc.o nfs_prot_xdr.o unfsd.o fh.o init.o: nfs_prot.h
  142. X
  143. Xmount_svc.o mount_xdr.o unfsmntd.o: mount.h
  144. X
  145. Xugid_map.o ugid_svc.o ugid_xdr.o ugidd.o unfsd.o init.o: ugid.h
  146. X
  147. Xmprobe.o: mount.h
  148. X
  149. Xfh.o unfsd.o: fh.h
  150. X
  151. Xunfsd.o ugid_map.o init.o: unfsd.h
  152. ________This_Is_The_END________
  153. if test `wc -l < Makefile` -ne 97; then
  154.     echo 'shar: Makefile was damaged during transit (should have been 97 bytes)'
  155. fi
  156. fi        ; : end of overwriting check
  157. echo 'x - README'
  158. if test -f README; then echo 'shar: not overwriting README'; else
  159. sed 's/^X//' << '________This_Is_The_END________' > README
  160. XUNFSD - USER-LEVEL NFS SERVER
  161. X=============================
  162. X
  163. XThis package implements a simple user level NFS server based on the
  164. Xsunrpc3.9 package that was posted to the net a few months ago.  The
  165. Xcurrent version only provides read access from the clients.  It has
  166. Xbeen tested between a VAX11/780 running 4.3BSD (the server) and several
  167. Xdiskful SUN3/60 running SunOS 3.4 (the clients) and on a diskless
  168. XSUN3/50 running SunOS 3.2 remounting its own root at a lower level of
  169. Xits file hierarchy.
  170. X
  171. XThe server is implemented by two programs unfsd and unfsmntd.
  172. XUnfsmntd handles the mount protocol, and unfsd handles all subsequent
  173. Xoperations.
  174. X
  175. XCurrently NFS is defined to use internet port 2049.  As a consequence
  176. Xthere can only be one implementation of NFS active on a given machine.
  177. XThus a machine cannot make it filesystem available through this server
  178. Xwhile concurrently running some alternate server implementation.
  179. X
  180. XNormally the server would be run by the super-user.  I had hoped to be
  181. Xable to run the server as a normal user, and indeed the server contains
  182. Xcode to cope with paths containing directories that can be accessed but
  183. Xnot searched, however the sunrpc portmapper listens on port 111 so some
  184. Xsuperuser cooperation is required to at least gain support for sunrpc
  185. Xon sites running standard 4.3 BSD.
  186. X
  187. XUnlike SUN's NFS-servers, the file hierarchy exported by unfsd treats
  188. Xmount points within an exports filesystem transparently; thus the
  189. Xclient sees the same file hierarchy as is seen from the server.
  190. X
  191. XCOPYRIGHT
  192. X=========
  193. X
  194. XThese programs may be freely distributed provided they retain my
  195. Xcopyright notices.  They are provided as is, with no warranty
  196. Xexpressed or implied.
  197. X
  198. XINSTALLATION
  199. X============
  200. X
  201. X1. If you have installed Van Jacobson's TCP/IP code be sure you have
  202. X   installed the fix I posted to comp.bugs.4bsd (reproduced below).
  203. X   Otherwise UDP packets larger than the maximum IP fragment size of
  204. X   your net will mysteriously fail.
  205. X
  206. X2. Edit the first few lines of the Makefile to reflect local conditions.
  207. X
  208. X3. If your client and server machines have different uid/username
  209. X   mappings you may wish to run ugidd on the client (see below).
  210. X   Otherwise the server assumes  one-to-one correspondence between
  211. X   uids and gids on the server.
  212. X
  213. X4. "make" and "make install".
  214. X
  215. X5. Create a /etc/unfsd_exports file to authorize clients of your server,
  216. X   and set desired options (Note: options may also be set with the
  217. X   command that starts the server see unfsd(8) and installation step 7).
  218. X
  219. X6. Run "unfsmntd" and "unfsd" and try to mount server file systems from
  220. X   your authorized clients.
  221. X
  222. X7. Arrange for the server to be started at boot-time.  EG in /etc/rc.local
  223. X   add:
  224. X    if [ -f /etc/unfsmntd ]; then
  225. X        /etc/unfsmntd
  226. X    fi
  227. X    if [ -f /etc/unfsd ]; then
  228. X        /etc/unfsd
  229. X    fi
  230. X
  231. X8. Edit client fstabs to mount from the new server at boot-time.
  232. X
  233. XUGIDD
  234. X=====
  235. X
  236. XIf you have the same set of user group names on your client and server
  237. Xmachines but differing uids and gids you may wish to run the ugidd on
  238. Xthe clients and enable to server to map between local and remote ids
  239. Xusing this pprogram.  Ugidd is a simple rpc-based service that supplies
  240. Xtranslations between names and uid/gids on the client.  To guard against
  241. Xtrojan horses the ugidd authenicates itself by signalling the unfsd on
  242. Xa reserved internet port.
  243. X
  244. XTo install ugidd on a client:
  245. X
  246. X1. "make ugidd" and copy ugidd to standard place like /usr/etc/rpc.ugidd
  247. X
  248. X2. Either run it from /etc/rc.local with the command
  249. X    /usr/etc/rpc.ugidd -d
  250. X   or if using a version of inetd that supports sunrpc, invoke it
  251. X   from inetd with the line
  252. X    rpc     udp     /usr/etc/rpc.ugidd      545580417 1
  253. X   in /etc/servers (SunOS 3.x) or /etc/inetd.conf (4.3 BSD).
  254. X   (See ugidd(8)).
  255. X
  256. X3. Set the "map_daemon" option for this client in the servers
  257. X   /etc/unfsd_exports file.  (See unfsd_exports(5)).
  258. X
  259. XNote: When ugidd fails to respond to a server, or the specified
  260. Xname (or uid/gid) has no corresponding uid/gid (or name), the
  261. Xserver assumes a mapping to the unprivelegded user "nobody" (uid: -2).
  262. X
  263. XTCP/IP FIX
  264. X==========
  265. X
  266. XHere follows a fix to the Van Jacobson TCP/IP upgrade.
  267. X
  268. XSubject: bug in new tcp/ip code
  269. X
  270. X[ posted to comp.bugs.4bsd Thu Apr 21 16:36:04 1988 ]
  271. X
  272. XThere is a bug in the upgrade of 4.3BSD networking code that was
  273. Xrecently posted to comp.bugs.4bsd.ucb-fixes.  When an IP packet is
  274. Xtoo large for an interface and must therefore be fragmented, some of
  275. Xthe fields of the IP header in the first packet are not converted to
  276. Xnetwork byte-order.
  277. X
  278. XThe fix is as follows:
  279. X
  280. X*** /sys/netinet/ip_output.c.orig    Tue Apr 12 15:52:46 1988
  281. X--- /sys/netinet/ip_output.c    Thu Apr 21 13:16:16 1988
  282. X***************
  283. X*** 232,239 ****
  284. X       * and updating header, then send each fragment (in order).
  285. X       */
  286. X      m_adj(m0, hlen + firstlen - ip->ip_len);
  287. X!     ip->ip_len = hlen + firstlen;
  288. X!     ip->ip_off |= IP_MF;
  289. X      ip->ip_sum = 0;
  290. X      ip->ip_sum = in_cksum(m0, hlen);
  291. X  sendorfree:
  292. X--- 232,239 ----
  293. X       * and updating header, then send each fragment (in order).
  294. X       */
  295. X      m_adj(m0, hlen + firstlen - ip->ip_len);
  296. X!     ip->ip_len = htons((u_short)(hlen + firstlen));
  297. X!     ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
  298. X      ip->ip_sum = 0;
  299. X      ip->ip_sum = in_cksum(m0, hlen);
  300. X  sendorfree:
  301. X
  302. XSECURITY ISSUES
  303. X===============
  304. X
  305. XWhen I first started looking at standard SunOS 3.x NFS I was pretty well
  306. Xappalled by the lack of security.  I later found that Security could be
  307. Ximproved considerably it was just that the defaults were (in my opinion)
  308. Xwrong.  By default, unfsd insists that NFS requests originate from a
  309. Xsecure port from a known internet address.
  310. X
  311. XUnfsd presumes that the kernel of the client deals correctly with access
  312. Xpermission checks.  In my experience this seems to be true of SunOS 3.x
  313. Xkernels for read accesses across NFS, but not for write accesses.  It is
  314. Xfor this reason that write accesses remain unimplemented in the current
  315. Xversion of the server.
  316. X
  317. X----------
  318. X
  319. XMark Shand
  320. XJoint Microelectronics Research Centre
  321. XSchool of Electrical Engineering
  322. XUniversity of NSW
  323. XPO Box 1
  324. XKensington
  325. XNSW 2033
  326. XAUSTRALIA
  327. X
  328. X+61 2 697 4898
  329. X
  330. Xshand@cad.jmrc.eecs.unsw.oz
  331. ________This_Is_The_END________
  332. if test `wc -l < README` -ne 171; then
  333.     echo 'shar: README was damaged during transit (should have been 171 bytes)'
  334. fi
  335. fi        ; : end of overwriting check
  336. echo 'x - fh.c'
  337. if test -f fh.c; then echo 'shar: not overwriting fh.c'; else
  338. sed 's/^X//' << '________This_Is_The_END________' > fh.c
  339. X/* UNFSD - copyright Mark A Shand, May 1988.
  340. X * This software maybe be used for any purpose provided
  341. X * the above copyright notice is retained.  It is supplied
  342. X * as is, with no warranty expressed or implied.
  343. X */
  344. X
  345. X/*
  346. X *    FILE HANDLE PACKAGE FOR USER-LEVEL NFS SERVER
  347. X *
  348. X *    Interfaces:
  349. X *        pseudo_inode
  350. X *        mostly used internally, but also called from unfsd.c
  351. X *        when reporting directory contents.
  352. X *        fh_pr
  353. X *        debugging primitive; converts file handle into a printable
  354. X *        text string
  355. X *        fh_create
  356. X *        establishes initial file handle; called from mount daemon
  357. X *        fh_path
  358. X *        returns unix path corresponding to fh
  359. X *        fh_fd
  360. X *        returns open file descriptor for given file handle;
  361. X *        provides caching of open files
  362. X *        fd_idle
  363. X *        provides mututal exclusion of normal file descriptor cache
  364. X *        use, and alarm-driven cache flushing
  365. X *        fh_compose
  366. X *        construct new file handle from existing file handle and
  367. X *        directory entry
  368. X *        fh_psi
  369. X *        returns pseudo_inode corresponding to file handle
  370. X */
  371. X
  372. X#include <sys/param.h>
  373. X#include <sys/types.h>
  374. X#include <sys/file.h>
  375. X#include <sys/time.h>
  376. X#include <sys/stat.h>
  377. X#include <rpc/rpc.h>
  378. X#include <sys/dir.h>
  379. X#include <strings.h>
  380. X#include <errno.h>
  381. X#include <syslog.h>
  382. X
  383. X/* mask SUNOS/BSD4.3 syslog incompatibilities */
  384. X#ifndef LOG_DAEMON
  385. X#define    LOG_DAEMON    0
  386. X#endif /* LOG_DAEMON */
  387. X
  388. X#ifdef DEBUG
  389. X#include <stdio.h>
  390. XFILE *debuglog;
  391. X#endif DEBUG
  392. X
  393. X#include "nfs_prot.h"
  394. X
  395. X#include "fh.h"
  396. X
  397. X#define    FHC_XONLY_PATH    01
  398. X#define    FHC_BUSY    02    /* NOT USED */
  399. X
  400. X#define    CACHE_SIZE_LIMIT    500
  401. X#define    LOWAT_CACHE_SIZE    3*CACHE_SIZE_LIMIT
  402. X#define    HIWAT_CACHE_SIZE    4*CACHE_SIZE_LIMIT
  403. X#define HASH_TAB_SIZE        (5*CACHE_SIZE_LIMIT | 03)
  404. X
  405. X/*
  406. X * Paths constructed in this system always consist of real directories
  407. X * (excepting the last element) i.e. they do not contain symbolic links.
  408. X * This is guaranteed by the way NFS constructs the paths.
  409. X * As a consequence we may assume that
  410. X *    /x/y/z/.. == /x/y
  411. X * and    /x/y/z/. == /x/y/z
  412. X * provided that z != . && z != ..
  413. X * These relations are exploited in fh_compose.
  414. X *
  415. X * Further assumptions:
  416. X *    All cached pathnames consist of a leading /
  417. X *    followed by zero or more / separated names
  418. X *    s.t.
  419. X *        name != .
  420. X *        name != ..
  421. X *        index(name, '/') == 0
  422. X */
  423. X
  424. Xtypedef struct fhcache
  425. X{
  426. X    struct fhcache    *next;
  427. X    struct fhcache    *prev;
  428. X    struct fhcache    *hash_next;
  429. X    svc_fh    h;
  430. X    int    fd;
  431. X    int    omode;
  432. X    char    *path;
  433. X    time_t    last_used;
  434. X    int    flags;
  435. X}
  436. X    fhcache;
  437. X
  438. Xstatic int path_psi();
  439. Xstatic fhcache fh_head, fh_tail, *last_flushable;
  440. Xstatic fhcache *fh_hashed[HASH_TAB_SIZE];
  441. Xstatic int fh_list_size;
  442. Xstatic time_t    curtime;
  443. Xextern int errno;
  444. X
  445. Xstatic void
  446. Xfh_move_to_front(fhc)
  447. Xfhcache    *fhc;
  448. X{
  449. X    /* Remove from current posn */
  450. X    fhc->prev->next = fhc->next;
  451. X    fhc->next->prev = fhc->prev;
  452. X    /* Insert at head */
  453. X    fhc->prev = &fh_head;
  454. X    fhc->next = fh_head.next;
  455. X    fhc->prev->next = fhc;
  456. X    fhc->next->prev = fhc;
  457. X}
  458. X
  459. Xstatic void
  460. Xfh_inserthead(fhc)
  461. Xfhcache    *fhc;
  462. X{
  463. X    fhcache    **hash_slot;
  464. X
  465. X    /* Insert at head */
  466. X    fhc->prev = &fh_head;
  467. X    fhc->next = fh_head.next;
  468. X    fhc->prev->next = fhc;
  469. X    fhc->next->prev = fhc;
  470. X    fh_list_size++;
  471. X
  472. X    /* Insert into hash tab */
  473. X    hash_slot = &(fh_hashed[fhc->h.psi % HASH_TAB_SIZE]);
  474. X    fhc->hash_next = *hash_slot;
  475. X    *hash_slot = fhc;
  476. X}
  477. X
  478. Xstatic fhcache *
  479. Xfh_lookup(psi)
  480. Xu_long    psi;
  481. X{
  482. X    fhcache    *fhc;
  483. X    fhc = fh_hashed[psi % HASH_TAB_SIZE];
  484. X    while (fhc != NULL && fhc->h.psi != psi)
  485. X        fhc = fhc->hash_next;
  486. X    return fhc;
  487. X}
  488. X
  489. Xstatic void
  490. Xfh_delete(fhc)
  491. Xfhcache *fhc;
  492. X{
  493. X    fhcache    **hash_slot;
  494. X
  495. X    /* Remove from current posn */
  496. X    fhc->prev->next = fhc->next;
  497. X    fhc->next->prev = fhc->prev;
  498. X    fh_list_size--;
  499. X
  500. X    /* Remove from hash tab */
  501. X    hash_slot = &(fh_hashed[fhc->h.psi % HASH_TAB_SIZE]);
  502. X    while (*hash_slot != NULL && *hash_slot != fhc)
  503. X        hash_slot = &((*hash_slot)->hash_next);
  504. X    if (*hash_slot == NULL)
  505. X        syslog(LOG_DAEMON|LOG_WARNING,
  506. X            "internal inconsistency -- fhc(%x) not in hash table", fhc);
  507. X    else
  508. X        *hash_slot = fhc->hash_next;
  509. X
  510. X    /* Free storage */
  511. X    if (fhc->path != NULL)
  512. X    {
  513. X#ifdef DEBUG
  514. X        if (debuglog != NULL)
  515. X            fprintf(debuglog, "flushing: %s\n",
  516. X                fhc->path);
  517. X#endif DEBUG
  518. X        free(fhc->path);
  519. X    }
  520. X    free(fhc);
  521. X}
  522. X
  523. X/*
  524. X * INODES and DEVICES.  NFS assumes that each file within an NFS mounted
  525. X * file-system has a unique inode number.  Thus to mount an entire file
  526. X * hierarchy, as this server sets out to do, requires mapping from inode/devs
  527. X * to pseudo-inode.  Furthermore mount points must be detected and so that
  528. X *    pseudo-inode("name") == pseudo-inode(direntry("name/../name"))
  529. X * One option is to force the directory entry inode to correspond to the
  530. X * result of the stat call, but this involves stat'ing every directory entry
  531. X * during a readdir.  Instead we force the stat call to corresopnd to the
  532. X * directory entry inode (see inner_getattr).  Of course this technique
  533. X * requires that the parent directory is readable.  If it is not the normal
  534. X * stat call result is used.  There is no chance of conflict because the
  535. X * directory can never be read.
  536. X *
  537. X * In theory unique pseudo-inodes cannot be guaranteed, since inode/dev
  538. X * contains 48 bits of information which must be crammed into an inode
  539. X * number constrained to 32 bits.  Fortunately inodes numbers tend to be
  540. X * small (often < 64k, almost always < 512k)
  541. X */
  542. X
  543. Xint
  544. Xpseudo_inode(inode,dev)
  545. Xu_long    inode;
  546. Xu_short    dev;
  547. X{
  548. X    register dmajor,dminor;
  549. X
  550. X    /* Assuming major and minor numbers are small integers,
  551. X     * gravitate bits of dmajor & dminor device number to
  552. X     * high-order bits of word, to avoid clash with real inode num.
  553. X     */
  554. X    /* reverse (byte-wise) */
  555. X    dmajor = ((dev & 0xf0f) << 4) | ((dev & 0xf0f0) >> 4);
  556. X    dmajor = ((dmajor & 0x3333) << 2) | ((dmajor & 0xcccc) >> 2);
  557. X    dmajor = ((dmajor & 0x5555) << 1) | ((dmajor & 0xaaaa) >> 1);
  558. X    /* spread low-16 -> 32 with 0's in even posn */
  559. X    dmajor = ((dmajor & 0xff00) << 8) | (dmajor & 0xff);
  560. X    dmajor = ((dmajor & 0xf000f0) << 4) | (dmajor & 0xf000f);
  561. X    dmajor = ((dmajor & 0xc0c0c0c) << 2) | (dmajor & 0x3030303);
  562. X    dmajor = ((dmajor & 0x22222222) << 1) | (dmajor & 0x11111111);
  563. X    dminor = (dmajor & 0x5555) << 15;
  564. X    dmajor = dmajor & 0x55550000;
  565. X
  566. X    return (dmajor | dminor) ^ inode;
  567. X}
  568. X
  569. X#define hash_psi(psi) (((psi)^((psi)>>8)^((psi)>>16)^((psi)>>24)) & 0xff)
  570. X
  571. Xint
  572. Xmallocfailed()
  573. X{
  574. X    syslog(LOG_DAEMON|LOG_WARNING, "malloc failed -- exiting");
  575. X    exit(1);
  576. X}
  577. X
  578. X/* flush_cache() is invoked periodically from SIGALRM, and on
  579. X * demand from fh_find.  A simple form of mutual exclusion
  580. X * protects this routine from multiple concurrent executions.
  581. X * Since the preemption that occurs when a signal is received
  582. X * is one-sided, we do need an atomic test and set.  If the 
  583. X * signal arrives between the test and the set, the first
  584. X * invocation safely stalls until the signal-caused invocation
  585. X * completes.
  586. X */
  587. Xtypedef enum { idle, active } mutex;
  588. X
  589. Xstatic mutex ex_state = idle;
  590. X
  591. X/* The following affect execute-only directories */
  592. X#define FLUSH_INTERVAL    (60*60*12)    /* Twice a day */
  593. X#define BUSY_RETRY_INTERVAL    (60*10)    /* Ten minutes */
  594. X#define DISCARD_INTERVAL (FLUSH_INTERVAL*2) /* Two days */
  595. X
  596. Xstatic int
  597. Xflush_cache()
  598. X{
  599. X    fhcache    *h;
  600. X
  601. X#ifdef DEBUG
  602. X    if (debuglog != NULL)
  603. X    {
  604. X        long    thing;
  605. X        time(&thing);
  606. X        fprintf(debuglog, "flushing cache at %s: state = %s\n",
  607. X            ctime(&thing),
  608. X            (ex_state == idle) ? "idle" : "active");
  609. X    }
  610. X#endif DEBUG
  611. X    if (ex_state == idle)
  612. X    {
  613. X        int    cache_size = 0;
  614. X
  615. X        ex_state = active;
  616. X        time(&curtime);
  617. X        /* Single execution thread */
  618. X        /* discard old open files */
  619. X        fh_fd(NULL);
  620. X
  621. X        /* works in empty case because: fh_tail.next = &fh_tail */
  622. X        h = fh_head.next->next;
  623. X        while (h != &fh_tail)
  624. X        {
  625. X            if (cache_size > LOWAT_CACHE_SIZE
  626. X                || (cache_size > CACHE_SIZE_LIMIT
  627. X                && (h->flags & FHC_XONLY_PATH) == 0)
  628. X                || curtime > h->last_used + DISCARD_INTERVAL)
  629. X            {
  630. X                h = h->next;
  631. X                fh_delete(h->prev);
  632. X            }
  633. X            else
  634. X            {
  635. X                cache_size++;
  636. X                h = h->next;
  637. X            }
  638. X        }
  639. X        if (fh_list_size != cache_size)
  640. X            syslog(LOG_DAEMON|LOG_WARNING,
  641. X                "internal inconsistency (fh_list_size=%d) != (cache_size=%d)",
  642. X                fh_list_size, cache_size);
  643. X        fh_list_size = cache_size;
  644. X        ex_state = idle;
  645. X        signal(SIGALRM, flush_cache);
  646. X        alarm(FLUSH_INTERVAL);
  647. X    }
  648. X    else
  649. X    {
  650. X        signal(SIGALRM, flush_cache);
  651. X        alarm(BUSY_RETRY_INTERVAL);
  652. X    }
  653. X}
  654. X
  655. Xvoid
  656. Xfh_init()
  657. X{
  658. X    fh_head.next = fh_tail.next = &fh_tail;
  659. X    fh_head.prev = fh_tail.prev = &fh_head;
  660. X    last_flushable = &fh_tail;
  661. X    fh_tail.flags = FHC_XONLY_PATH;
  662. X    signal(SIGALRM, flush_cache);
  663. X    alarm(FLUSH_INTERVAL);
  664. X}
  665. X
  666. Xstatic char *fh_buildpath();
  667. X
  668. Xstatic fhcache *
  669. Xfh_find(h, create)
  670. Xsvc_fh    *h;
  671. Xint    create;
  672. X{
  673. X    fhcache    *fhc;
  674. X
  675. X    ex_state = active;
  676. X    time(&curtime);
  677. X    while ((fhc = fh_lookup(h->psi)) != NULL)
  678. X    {
  679. X        /* but what if hash_paths are not the same? */
  680. X        /* Something is stale */
  681. X        if (bcmp(h->hash_path, fhc->h.hash_path, HP_LEN) != 0)
  682. X        {
  683. X            if (!create)
  684. X                return NULL;
  685. X            fh_delete(fhc);
  686. X            break;
  687. X        }
  688. X        if (fhc != fh_head.next)
  689. X            fh_move_to_front(fhc);
  690. X        fhc->last_used = curtime;
  691. X        ex_state = idle;
  692. X        return fhc;
  693. X    }
  694. X    if (fh_list_size > CACHE_SIZE_LIMIT)
  695. X    {
  696. X        /* don't flush current head */
  697. X        while (last_flushable != fh_head.next)
  698. X        {
  699. X            if ((last_flushable->flags & FHC_XONLY_PATH) == 0)
  700. X            {
  701. X                fhc = last_flushable;
  702. X                last_flushable = last_flushable->prev;
  703. X                fh_delete(fhc);
  704. X                break;
  705. X            }
  706. X            last_flushable = last_flushable->prev;
  707. X        }
  708. X        last_flushable = last_flushable->next;
  709. X    }
  710. X    if (create)
  711. X    {
  712. X        if ((fhc = (fhcache *) malloc(sizeof *fhc)) == NULL)
  713. X            mallocfailed();
  714. X        fhc->path = NULL;
  715. X        fhc->last_used = curtime;
  716. X        fhc->h = *h;
  717. X        fh_inserthead(fhc);
  718. X    }
  719. X    else
  720. X    {
  721. X        /* attempt to contruct from hash_path */
  722. X        char    *path;
  723. X
  724. X        if ((path = fh_buildpath(h)) == NULL)
  725. X            return NULL;
  726. X        if ((fhc = (fhcache *) malloc(sizeof *fhc)) == NULL)
  727. X            mallocfailed();
  728. X        fhc->path = path;
  729. X        fhc->fd = -1;
  730. X        fhc->flags = 0;
  731. X        fhc->last_used = curtime;
  732. X        fhc->h = *h;
  733. X        fh_inserthead(fhc);
  734. X    }
  735. X    ex_state = idle;
  736. X    if (fh_list_size > HIWAT_CACHE_SIZE)
  737. X        flush_cache();
  738. X    return fhc;
  739. X}
  740. X
  741. Xstatic char *
  742. Xfh_buildpath(h)
  743. Xsvc_fh    *h;
  744. X{
  745. X    int    i;
  746. X    int    psi;
  747. X    char    *path;
  748. X    struct    stat    sbuf;
  749. X    char    pathbuf[MAXPATHLEN+MAXNAMLEN+1];
  750. X    long    cookie_stack[HP_LEN+1];
  751. X    char    *slash_stack[HP_LEN];
  752. X
  753. X    if (stat("/", &sbuf) < 0)
  754. X        return NULL;
  755. X    psi = pseudo_inode(sbuf.st_ino, sbuf.st_dev);
  756. X    if (h->hash_path[0] == 0)
  757. X    {
  758. X        if (psi != h->psi)
  759. X            return NULL;
  760. X        if ((path = malloc(2)) == NULL)
  761. X            mallocfailed();
  762. X        strcpy(path, "/");
  763. X        return path;
  764. X    }
  765. X    /* else */
  766. X    if (hash_psi(psi) != h->hash_path[1])
  767. X        return NULL;
  768. X    strcpy(pathbuf, "/");
  769. X    cookie_stack[2] = 0;
  770. X    for (i = 2; i <= h->hash_path[0]+1; i++)
  771. X    {
  772. X        DIR        *dir;
  773. X        struct direct    *dp;
  774. X
  775. X        backtrack:
  776. X        if (stat(pathbuf, &sbuf) >= 0
  777. X            && (dir = opendir(pathbuf)) != NULL)
  778. X        {
  779. X            if (cookie_stack[i] != 0)
  780. X                seekdir(dir, cookie_stack[i]);
  781. X            while (dp = readdir(dir))
  782. X            {
  783. X                if (strcmp(dp->d_name, ".") != 0
  784. X                 && strcmp(dp->d_name, "..") != 0)
  785. X                {
  786. X                    psi = pseudo_inode(dp->d_ino, sbuf.st_dev);
  787. X                    if (i == h->hash_path[0]+1)
  788. X                    {
  789. X                        if (psi == h->psi)
  790. X                        {
  791. X                            /*GOT IT*/
  792. X                            strcat(pathbuf, dp->d_name);
  793. X                            if ((path = malloc(strlen(pathbuf)+1)) == NULL)
  794. X                                mallocfailed();
  795. X                            strcpy(path, pathbuf);
  796. X                            closedir(dir);
  797. X                            return path;
  798. X                        }
  799. X                    }
  800. X                    else
  801. X                    {
  802. X                        if (hash_psi(psi) == h->hash_path[i])
  803. X                        {
  804. X                            /*PERHAPS WE'VE GOT IT */
  805. X                            cookie_stack[i] = telldir(dir);
  806. X                            cookie_stack[i+1] = 0;
  807. X                            slash_stack[i] = pathbuf + strlen(pathbuf);
  808. X                            strcpy(slash_stack[i], dp->d_name);
  809. X                            strcat(pathbuf, "/");
  810. X
  811. X                            closedir(dir);
  812. X                            goto deeper;
  813. X                        }
  814. X                    }
  815. X                }
  816. X            }
  817. X            /* dp == NULL */
  818. X            closedir(dir);
  819. X        }
  820. X        else if (i <= h->hash_path[0]
  821. X            && access(pathbuf, R_OK) != 0
  822. X            && access(pathbuf, X_OK) == 0)
  823. X        {
  824. X            /* Execute-only directory?  Maybe its in the cache. */
  825. X            /* Note: cache is frozen for duration of fh_buildpath */
  826. X            svc_fh    xh;
  827. X            fhcache    *fhc;
  828. X
  829. X            xh = *h;
  830. X            xh.hash_path[0] = i-1;
  831. X            if (cookie_stack[i] == 0)
  832. X                fhc = fh_head.next;
  833. X            else
  834. X                fhc = ((fhcache *)(cookie_stack[i]))->next;
  835. X            while (fhc != &fh_tail)
  836. X                if (bcmp(xh.hash_path, fhc->h.hash_path, i) == 0
  837. X                    && xh.hash_path[i] == hash_psi(fhc->h.psi))
  838. X                    break;
  839. X                else
  840. X                    fhc = fhc->next;
  841. X            if (fhc != NULL)
  842. X            {
  843. X                strcpy(pathbuf, fhc->path);
  844. X                cookie_stack[i] = (long) fhc;
  845. X                cookie_stack[i+1] = 0;
  846. X                slash_stack[i] = rindex(pathbuf,'/')+1;
  847. X                strcat(pathbuf, "/");
  848. X                goto deeper;
  849. X            }
  850. X        }
  851. X        /* shallower */
  852. X        i--;
  853. X        if (i < 2)
  854. X            return NULL; /* SEARCH EXHAUSTED */
  855. X        /* Prune path */
  856. X        *(slash_stack[i]) = '\0';
  857. X        goto backtrack;
  858. X        deeper: ;
  859. X    }
  860. X    return NULL; /* Actually not reached */
  861. X}
  862. X
  863. Xchar *
  864. Xfh_pr(fh)
  865. Xnfs_fh    *fh;
  866. X{
  867. X    char    *p;
  868. X    nfsstat    status;
  869. X
  870. X    p = fh_path(fh, &status);
  871. X    if (status != NFS_OK)
  872. X        return "///STALE///";
  873. X    else
  874. X        return p;
  875. X}
  876. X
  877. Xint
  878. Xfh_create(fh, path)
  879. Xnfs_fh    *fh;
  880. Xchar    *path;
  881. X{
  882. X    svc_fh    *key = (svc_fh *) fh;
  883. X    fhcache    *h;
  884. X    int psi;
  885. X    nfsstat    status;
  886. X    char    *s;
  887. X
  888. X    bzero((char *) fh, sizeof fh);
  889. X    key->hash_path[0] = 0;
  890. X    status = NFS_OK;
  891. X    if ((psi = path_psi("/", &status, NULL)) == 0)
  892. X        return (int) status;
  893. X    s = path;
  894. X    while ((s = index(s+1, '/')) != NULL)
  895. X    {
  896. X        if (++(key->hash_path[0]) >= HP_LEN)
  897. X            return (int) NFSERR_NAMETOOLONG;
  898. X        key->hash_path[key->hash_path[0]] = hash_psi(psi);
  899. X        *s = '\0';
  900. X        if ((psi = path_psi(path, &status, NULL)) == 0)
  901. X            return (int) status;
  902. X        *s = '/';
  903. X    }
  904. X    if (*(rindex(path, '/')+1) != '\0')
  905. X    {
  906. X        if (++(key->hash_path[0]) >= HP_LEN)
  907. X            return (int) NFSERR_NAMETOOLONG;
  908. X        key->hash_path[key->hash_path[0]] = hash_psi(psi);
  909. X        if ((psi = path_psi(path, &status, NULL)) == 0)
  910. X            return (int) status;
  911. X    }
  912. X    key->psi = psi;
  913. X    h = fh_find(key, 1);
  914. X    /* assert(h != NULL); */
  915. X    if (h->path == NULL)
  916. X    {
  917. X        h->fd = -1;
  918. X        if ((h->path = malloc(strlen(path)+1)) == NULL)
  919. X            mallocfailed();
  920. X        strcpy(h->path, path);
  921. X        h->flags = 0;
  922. X    }
  923. X    return (int) status;
  924. X}
  925. X
  926. Xchar *
  927. Xfh_path(fh, status)
  928. Xnfs_fh    *fh;
  929. Xnfsstat    *status;
  930. X{
  931. X    fhcache    *h;
  932. X
  933. X    if ((h = fh_find((svc_fh *) fh, 0)) == NULL)
  934. X    {
  935. X        *status = NFSERR_STALE;
  936. X        return NULL;
  937. X    }
  938. X    *status = NFS_OK;
  939. X    return h->path;
  940. X}
  941. X
  942. Xstatic mutex io_state = idle;
  943. X
  944. Xint
  945. Xfh_fd(fh, status, omode)
  946. Xnfs_fh    *fh;
  947. Xnfsstat    *status;
  948. Xint    omode;
  949. X{
  950. X    /* Currently we cache 1 open file descriptor.
  951. X     * in the future we could allocate an array of size
  952. X     * getdtablesize() which would contain psi's to provide
  953. X     * an mapping from descriptor to psi's.
  954. X     * Then we could maintain many concurrently open files.
  955. X     */
  956. X    fhcache        *h;
  957. X    static int    fd = -1;
  958. X    static int    psi = 0;
  959. X
  960. X    if (fh == NULL && io_state == idle)
  961. X    {
  962. X        /* special case -- request to flush fd cache */
  963. X        if (fd >= 0)
  964. X            close(fd);
  965. X        fd = -1;
  966. X        return -1;
  967. X    }
  968. X
  969. X    if ((h = fh_find((svc_fh *) fh, 0)) == NULL)
  970. X    {
  971. X        *status = NFSERR_STALE;
  972. X        return -1;
  973. X    }
  974. X    io_state = active;
  975. X    if (fd >= 0)
  976. X    {
  977. X        if (psi == h->h.psi && h->omode == omode)
  978. X            return fd;
  979. X        close(fd);
  980. X    }
  981. X    errno = 0;
  982. X    h->fd = fd = open(h->path, omode);
  983. X    h->omode = omode;
  984. X    psi = h->h.psi;
  985. X    *status = (nfsstat) errno;
  986. X    return fd;
  987. X}
  988. X
  989. Xint
  990. Xfd_idle(fd)
  991. Xint    fd;
  992. X{
  993. X    io_state = idle;
  994. X}
  995. X
  996. Xnfsstat
  997. Xfh_compose(dopa, new_fh, sbpp)
  998. Xdiropargs    *dopa;
  999. Xnfs_fh    *new_fh;
  1000. Xstruct stat **sbpp;
  1001. X{
  1002. X    svc_fh    *key;
  1003. X    fhcache    *dirh, *h;
  1004. X    char    *sindx;
  1005. X    int    is_dd;
  1006. X    nfsstat    ret;
  1007. X    struct stat    sbuf;
  1008. X    char    pathbuf[MAXPATHLEN+MAXNAMLEN+1];
  1009. X
  1010. X    if ((dirh = fh_find((svc_fh *) &(dopa->dir), 0)) == NULL)
  1011. X        return NFSERR_STALE;
  1012. X
  1013. X    *new_fh = dopa->dir;
  1014. X    /* Construct path */
  1015. X
  1016. X    if (strcmp(dopa->name, ".") == 0)
  1017. X    {
  1018. X        *sbpp = NULL;
  1019. X        return NFS_OK;
  1020. X    }
  1021. X    if (strcmp(dopa->name, "..") == 0)
  1022. X    {
  1023. X        is_dd = 1;
  1024. X        sindx = rindex(dirh->path, '/');
  1025. X        if (sindx == dirh->path)
  1026. X            strcpy(pathbuf, "/");
  1027. X        else
  1028. X        {
  1029. X            int    len = sindx - dirh->path;
  1030. X            strncpy(pathbuf, dirh->path, len);
  1031. X            pathbuf[len] = '\0';
  1032. X        }
  1033. X    }
  1034. X    else
  1035. X    {
  1036. X        int    len = strlen(dirh->path);
  1037. X
  1038. X        is_dd = 0;
  1039. X        if (dirh->path[len-1] == '/')
  1040. X            len--;
  1041. X        strncpy(pathbuf, dirh->path, len);
  1042. X        pathbuf[len] = '/';
  1043. X        strcpy(pathbuf + (len+1), dopa->name);
  1044. X    }
  1045. X
  1046. X    key = (svc_fh *) new_fh;
  1047. X    if ((key->psi = path_psi(pathbuf, &ret, *sbpp)) == 0)
  1048. X        return ret;
  1049. X
  1050. X    if (is_dd)
  1051. X        key->hash_path[key->hash_path[0]--] = 0;
  1052. X    else
  1053. X    {
  1054. X        if (++(key->hash_path[0]) >= HP_LEN)
  1055. X            return NFSERR_NAMETOOLONG;
  1056. X        key->hash_path[key->hash_path[0]] = hash_psi(dirh->h.psi);
  1057. X    }
  1058. X    h = fh_find(key, 1);
  1059. X    /* assert(h != NULL); */
  1060. X    if (h->path == 0)
  1061. X    {
  1062. X        h->fd = -1;
  1063. X        if ((h->path = malloc(strlen(pathbuf)+1)) == NULL)
  1064. X            mallocfailed();
  1065. X        strcpy(h->path, pathbuf);
  1066. X        h->flags = 0;
  1067. X        if (!is_dd
  1068. X            && access(dirh->path, R_OK) != 0
  1069. X            && access(dirh->path, X_OK) == 0)
  1070. X            h->flags |= FHC_XONLY_PATH;
  1071. X    }
  1072. X    return NFS_OK;
  1073. X}
  1074. X
  1075. Xint
  1076. Xfh_psi(fh)
  1077. Xnfs_fh    *fh;
  1078. X{
  1079. X    svc_fh    *h = (svc_fh *) fh;
  1080. X    return h->psi;
  1081. X}
  1082. X
  1083. Xstatic int
  1084. Xpath_psi(path, status, sbp)
  1085. X    char    *path;
  1086. X    nfsstat    *status;
  1087. X    struct stat *sbp;
  1088. X{
  1089. X    struct stat sbuf;
  1090. X
  1091. X    if (sbp == NULL)
  1092. X        sbp = &sbuf;
  1093. X    if (lstat(path, sbp) < 0)
  1094. X        *status = (nfsstat) errno;
  1095. X        
  1096. X    if ((sbp->st_mode & S_IFMT) == S_IFDIR && strcmp(path, "/") != 0)
  1097. X    {
  1098. X        /* Special case for directories--test for mount point */
  1099. X        struct    stat    ddbuf;
  1100. X        char    *sindx;
  1101. X        char    *name;
  1102. X        char    squirrel;
  1103. X
  1104. X        /* find start of last component of path */
  1105. X        if ((sindx = rindex(path, '/')) == path)
  1106. X        {
  1107. X            sindx++;
  1108. X            name = sindx;
  1109. X        }
  1110. X        else
  1111. X            name = sindx + 1;
  1112. X        /* remove last element of path */
  1113. X        squirrel = *sindx;
  1114. X        *sindx = '\0';
  1115. X        if (lstat(path, &ddbuf) < 0)
  1116. X        {
  1117. X            *sindx = squirrel;
  1118. X            *status = (nfsstat) errno;
  1119. X            return 0;
  1120. X        }
  1121. X        /* sindx now points to directory entry name */
  1122. X        if (ddbuf.st_dev != sbp->st_dev)
  1123. X        {
  1124. X            /* directory is a mount point */
  1125. X            DIR    *dirp;
  1126. X            struct direct *dp;
  1127. X
  1128. X            errno = 0;
  1129. X            if ((dirp = opendir(path)) == NULL)
  1130. X            {
  1131. X                *sindx = squirrel; /* restore path */
  1132. X                if (errno == EACCES)
  1133. X                    goto unreadable;
  1134. X                if (errno != 0)
  1135. X                    *status = (nfsstat) errno;
  1136. X                else
  1137. X                    *status = NFSERR_NOENT;
  1138. X            }
  1139. X            else
  1140. X            {
  1141. X                *sindx = squirrel; /* restore path */
  1142. X                *status = NFS_OK;
  1143. X                do
  1144. X                {
  1145. X                    if ((dp = readdir(dirp)) == NULL)
  1146. X                    {
  1147. X                        *status = NFSERR_NOENT;
  1148. X                        closedir(dirp);
  1149. X                        return 0;
  1150. X                    }
  1151. X                } while(strcmp(name, dp->d_name) != 0);
  1152. X                sbp->st_dev = ddbuf.st_dev;
  1153. X                sbp->st_ino = dp->d_ino;
  1154. X                closedir(dirp);
  1155. X            }
  1156. X        }
  1157. X        else
  1158. X            *sindx = squirrel; /* restore path */ 
  1159. X        unreadable:
  1160. X        ;
  1161. X    }
  1162. X    return pseudo_inode(sbp->st_ino, sbp->st_dev);
  1163. X}
  1164. ________This_Is_The_END________
  1165. if test `wc -l < fh.c` -ne 825; then
  1166.     echo 'shar: fh.c was damaged during transit (should have been 825 bytes)'
  1167. fi
  1168. fi        ; : end of overwriting check
  1169. echo 'x - fh.h'
  1170. if test -f fh.h; then echo 'shar: not overwriting fh.h'; else
  1171. sed 's/^X//' << '________This_Is_The_END________' > fh.h
  1172. X/* UNFSD - copyright Mark A Shand, May 1988.
  1173. X * This software maybe be used for any purpose provided
  1174. X * the above copyright notice is retained.  It is supplied
  1175. X * as is, with no warranty expressed or implied.
  1176. X */
  1177. X
  1178. X/* compatibility between mount and nfs_prot */
  1179. X#ifndef NFS_FHSIZE
  1180. X#define NFS_FHSIZE    FHSIZE
  1181. X#endif
  1182. X
  1183. X#define    HP_LEN    (NFS_FHSIZE - sizeof(u_long))
  1184. X
  1185. Xtypedef struct
  1186. X{
  1187. X    u_long    psi;
  1188. X    u_char    hash_path[HP_LEN];
  1189. X    /* Hashed search path to this file.
  1190. X     * path is: hash_path[1] ... hash_path[hash_path[0]]
  1191. X     *
  1192. X     * hash_path[hash_path[0]+1] ... hash_path[HP_LEN-1] == 0
  1193. X     */
  1194. X}
  1195. X    svc_fh;
  1196. X
  1197. Xextern void fh_init();
  1198. Xextern int fh_fd();
  1199. Xextern char *fh_path();
  1200. Xextern nfsstat fh_compose();
  1201. Xextern char *fh_pr();
  1202. Xextern int fh_psi();
  1203. ________This_Is_The_END________
  1204. if test `wc -l < fh.h` -ne 31; then
  1205.     echo 'shar: fh.h was damaged during transit (should have been 31 bytes)'
  1206. fi
  1207. fi        ; : end of overwriting check
  1208. echo 'x - init.c'
  1209. if test -f init.c; then echo 'shar: not overwriting init.c'; else
  1210. sed 's/^X//' << '________This_Is_The_END________' > init.c
  1211. X/* UNFSD - copyright Mark A Shand, May 1988.
  1212. X * This software maybe be used for any purpose provided
  1213. X * the above copyright notice is retained.  It is supplied
  1214. X * as is, with no warranty expressed or implied.
  1215. X */
  1216. X
  1217. X/*
  1218. X**    Udp socket establishment routine
  1219. X*/
  1220. X
  1221. X
  1222. X#ifndef    lint
  1223. Xstatic char    sccsid[]    = "@(#)makesock.c    1.0    88/03/12";
  1224. X#endif    lint
  1225. X
  1226. X#include "unfsd.h"
  1227. Xextern char    *malloc();
  1228. Xextern char    *realloc();
  1229. X
  1230. X#define DEFAULT_EXPORTSFILE    EXPORTSFILE
  1231. X
  1232. X#ifndef SYSERROR
  1233. X#define SYSERROR    (-1)
  1234. X#endif
  1235. X
  1236. Xint
  1237. Xmakesock(port,socksz)
  1238. Xint    port;
  1239. Xint    socksz;
  1240. X{
  1241. X    struct sockaddr_in    my_sock;
  1242. X    int            s;
  1243. X    extern int        errno;
  1244. X    extern char        *sys_errlist;
  1245. X
  1246. X    bzero((char *)&my_sock, sizeof(my_sock));
  1247. X    my_sock.sin_addr.s_addr = INADDR_ANY;
  1248. X    my_sock.sin_family = AF_INET;
  1249. X    my_sock.sin_port = htons(port);
  1250. X
  1251. X    if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
  1252. X    {
  1253. X        syslog(LOG_DAEMON|LOG_ERR, "could not make a socket: %s",
  1254. X            sys_errlist[errno]);
  1255. X        return SYSERROR;
  1256. X    }
  1257. X#ifdef SO_SNDBUF
  1258. X    {
  1259. X        int    sblen, rblen;
  1260. X
  1261. X        sblen = rblen = socksz + 1024;
  1262. X        /* 1024 for rpc & transport overheads */
  1263. X        if (
  1264. X        setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sblen, sizeof sblen) < 0
  1265. X        ||
  1266. X        setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rblen, sizeof sblen) < 0
  1267. X        )
  1268. X        syslog(LOG_DAEMON|LOG_ERR, "setsockopt failed",
  1269. X            sys_errlist[errno]);
  1270. X    }
  1271. X#endif
  1272. X
  1273. X    if (bind(s, &my_sock, sizeof(my_sock)) == -1)
  1274. X    {
  1275. X        syslog(LOG_DAEMON|LOG_ERR, "could not bind name to socket",
  1276. X            sys_errlist[errno]);
  1277. X        return SYSERROR;
  1278. X    }
  1279. X
  1280. X    return s;
  1281. X}
  1282. X
  1283. Xftype ft_map[16];
  1284. Xint svc_euid;
  1285. Xint svc_egid;
  1286. Xint cur_gid;
  1287. Xint svc_ngids;
  1288. Xint svc_gids[NGROUPS+2];
  1289. X
  1290. Xstatic clnt_param    *clients = NULL;
  1291. Xstatic clnt_param    *default_client = NULL;
  1292. X
  1293. X#define    LINE_SIZE    1024
  1294. X
  1295. Xstatic char *
  1296. Xparse_opts(s, terminator, o, client_name)
  1297. Xchar    *s;
  1298. Xchar    terminator;
  1299. Xoptions    *o;
  1300. Xchar    *client_name;
  1301. X{
  1302. X    /* parse option string pointed to by s and set o accordingly */
  1303. X    char    kwdbuf[LINE_SIZE];
  1304. X    char    *k;
  1305. X
  1306. X    /* skip white */
  1307. X    while (isspace(*s))
  1308. X        s++;
  1309. X    while (*s != terminator)
  1310. X    {
  1311. X        k = kwdbuf;
  1312. X        while (isalnum(*s) || *s == '_')
  1313. X            *k++ = *s++;
  1314. X        *k = '\0';
  1315. X        /* process keyword */
  1316. X        if (strcmp(kwdbuf, "secure") == 0)
  1317. X            o->secure_port = 1;
  1318. X        else if (strcmp(kwdbuf, "insecure") == 0)
  1319. X            o->secure_port = 0;
  1320. X        else if (strcmp(kwdbuf, "root_squash") == 0)
  1321. X            o->root_squash = 1;
  1322. X        else if (strcmp(kwdbuf, "no_root_squash") == 0)
  1323. X            o->root_squash = 0;
  1324. X        else if (strcmp(kwdbuf, "ro") == 0)
  1325. X            o->read_only = 1;
  1326. X        else if (strcmp(kwdbuf, "rw") == 0)
  1327. X            o->read_only = 0;
  1328. X        else if (strcmp(kwdbuf, "link_relative") == 0)
  1329. X            o->link_relative = 1;
  1330. X        else if (strcmp(kwdbuf, "link_absolute") == 0)
  1331. X            o->link_relative = 0;
  1332. X        else if (strcmp(kwdbuf, "map_daemon") == 0)
  1333. X            o->uidmap = map_daemon;
  1334. X        else if (strcmp(kwdbuf, "map_identity") == 0)
  1335. X            o->uidmap = identity;
  1336. X        else
  1337. X            syslog(LOG_DAEMON|LOG_ERR, "Unknown keyword \"%s\"", kwdbuf);
  1338. X        while (isspace(*s))
  1339. X            s++;
  1340. X        if (*s == ',')
  1341. X            s++;
  1342. X        else if (!isalnum(*s) && *s != '_' && *s != '\0')
  1343. X        {
  1344. X            if (client_name == NULL)
  1345. X                syslog(LOG_DAEMON|LOG_ERR,
  1346. X                    "comma expected in option list for default client (found %c)", *s);
  1347. X            else
  1348. X                syslog(LOG_DAEMON|LOG_ERR,
  1349. X                    "comma expected in option list for client %s (found %c)",
  1350. X                    client_name, *s);
  1351. X        }
  1352. X        while (isspace(*s))
  1353. X            s++;
  1354. X        if (*s == '\0' && *s != terminator)
  1355. X        {
  1356. X            syslog(LOG_DAEMON|LOG_ERR,
  1357. X                "missing terminator \"%c\" on option list",
  1358. X                terminator);
  1359. X            return s;
  1360. X        }
  1361. X    }
  1362. X    while (isspace(*s))
  1363. X        s++;
  1364. X    return s;
  1365. X}
  1366. X
  1367. Xstatic int
  1368. Xfilt_getc(f)
  1369. XFILE    *f;
  1370. X{
  1371. X    int    c;
  1372. X
  1373. X    c = getc(f);
  1374. X    if (c == '\\')
  1375. X    {
  1376. X        c = getc(f);
  1377. X        if (c == '\n')
  1378. X            c = ' ';
  1379. X        else if (c != EOF)
  1380. X            ungetc(c, f);
  1381. X        c = '\\';
  1382. X    }
  1383. X    else if (c == '#')
  1384. X    {
  1385. X        int lastc = c;
  1386. X        while ((c = getc(f)) != '\n' && c != EOF)
  1387. X            lastc = c;
  1388. X        if (c == '\n' && lastc == '\\')
  1389. X            c = getc(f);
  1390. X    }
  1391. X    return c;
  1392. X}
  1393. X
  1394. X#define CHUNK_SIZE    512
  1395. X
  1396. Xstatic int
  1397. Xgetline(lbuf, f)
  1398. Xchar    **lbuf;
  1399. XFILE    *f;
  1400. X{
  1401. X    register    c;
  1402. X    register char    *p;
  1403. X    char    *buf;
  1404. X    int    sz = CHUNK_SIZE;
  1405. X
  1406. X    if ((buf = malloc(CHUNK_SIZE)) == NULL)
  1407. X        mallocfailed();
  1408. X    p = buf;
  1409. X    while ((c = filt_getc(f)) != '\n' && c != EOF)
  1410. X    {
  1411. X        if (p - buf == sz-2)
  1412. X        {
  1413. X            if ((buf = realloc(buf, sz*2)) == NULL)
  1414. X                mallocfailed();
  1415. X            p = buf + sz-2;
  1416. X            sz *= 2;
  1417. X        }
  1418. X        *p++ = c;
  1419. X    }
  1420. X    if (c == EOF && p == buf)
  1421. X    {
  1422. X        free(buf);
  1423. X        *lbuf = NULL;
  1424. X        return 0;
  1425. X    }
  1426. X    *p++ = '\0';
  1427. X    *lbuf = buf;
  1428. X    return 1;
  1429. X}
  1430. X
  1431. Xunfsd_init(argc, argv)
  1432. Xint    argc;
  1433. Xchar    **argv;
  1434. X{
  1435. X    int    i, n;
  1436. X    FILE    *f;
  1437. X    char    *lbuf;
  1438. X    char    *p, *q, *r;
  1439. X    char    *exportsfile = DEFAULT_EXPORTSFILE;
  1440. X    struct hostent    *hent;
  1441. X    clnt_param *tmp;
  1442. X    char    *mount_point;
  1443. X
  1444. X    /* options */
  1445. X    int    promiscuous = 0;
  1446. X    char    *o_string = NULL;
  1447. X    options    def_opts;
  1448. X
  1449. X#ifndef DEBUG
  1450. X    {
  1451. X        int fd;
  1452. X
  1453. X        if (fork())
  1454. X            exit(0);
  1455. X        close(0);
  1456. X        close(1);
  1457. X        close(2);
  1458. X        if ((fd = open("/dev/tty", 2)) >= 0)
  1459. X        {
  1460. X            ioctl(fd, TIOCNOTTY, (char *)0);
  1461. X            (void) close(fd);
  1462. X        }
  1463. X    }
  1464. X#endif DEBUG
  1465. X    /* setup defaults */
  1466. X    def_opts.uidmap = identity;
  1467. X    def_opts.root_squash = 0;
  1468. X    def_opts.secure_port = 1;
  1469. X    def_opts.read_only = 1;
  1470. X    def_opts.link_relative = 1;
  1471. X
  1472. X    openlog("unfsd", LOG_PID|LOG_TIME);
  1473. X
  1474. X    argc--; argv++;
  1475. X    while (argc > 0)
  1476. X    {
  1477. X        if ((*argv)[0] == '-')
  1478. X        {
  1479. X            switch ((*argv)[1])
  1480. X            {
  1481. X                case 'o':
  1482. X                    if ((*argv)[2] == '\0' && argc > 1)
  1483. X                    {
  1484. X                        argc--; argv++;
  1485. X                        o_string = *argv;
  1486. X                    }
  1487. X                    else
  1488. X                        o_string = *argv + 2;
  1489. X                    break;
  1490. X                case 'p':
  1491. X                    promiscuous = 1;
  1492. X                    break;
  1493. X                case 'f':
  1494. X                    if ((*argv)[2] == '\0' && argc > 1)
  1495. X                    {
  1496. X                        argc--; argv++;
  1497. X                        exportsfile = *argv;
  1498. X                    }
  1499. X                    else
  1500. X                        exportsfile = *argv + 2;
  1501. X                    break;
  1502. X                default:
  1503. X                    syslog(LOG_DAEMON|LOG_ERR, "Unknown option");
  1504. X            }
  1505. X        }
  1506. X        else
  1507. X            syslog(LOG_DAEMON|LOG_ERR, "Bad argument -- %s", *argv);
  1508. X        argc--; argv++;
  1509. X    }
  1510. X
  1511. X    fh_init();
  1512. X
  1513. X    ft_map[0] = NFNON;
  1514. X    for (i = 1; i < 16; i++)
  1515. X        ft_map[i] = NFBAD;
  1516. X#ifdef S_IFIFO
  1517. X    ft_map[ft_extr(S_IFIFO)] = NFFIFO;
  1518. X#endif
  1519. X    ft_map[ft_extr(S_IFCHR)] = NFCHR;
  1520. X    ft_map[ft_extr(S_IFDIR)] = NFDIR;
  1521. X    ft_map[ft_extr(S_IFBLK)] = NFBLK;
  1522. X    ft_map[ft_extr(S_IFREG)] = NFREG;
  1523. X    ft_map[ft_extr(S_IFLNK)] = NFLNK;
  1524. X    ft_map[ft_extr(S_IFSOCK)] = NFSOCK;
  1525. X
  1526. X    umask(0);
  1527. X
  1528. X    svc_euid = geteuid();
  1529. X    svc_ngids = getgroups(NGROUPS, svc_gids);
  1530. X    /* Does this always include gid and egid? I don't know. Play it safe */
  1531. X    if (svc_ngids < 0)
  1532. X        svc_ngids = 0;
  1533. X    n = getgid();
  1534. X    for (i = 0; i < svc_ngids; i++)
  1535. X        if (svc_gids[i] == n)
  1536. X            break;
  1537. X    if (i == svc_ngids)
  1538. X        svc_gids[svc_ngids++] = n;
  1539. X    n = svc_egid = getegid();
  1540. X    for (i = 0; i < svc_ngids; i++)
  1541. X        if (svc_gids[i] == n)
  1542. X            break;
  1543. X    if (i == svc_ngids)
  1544. X        svc_gids[svc_ngids++] = n;
  1545. X    cur_gid = svc_gids[0];
  1546. X    if (o_string != NULL)
  1547. X        parse_opts(o_string, '\0', &def_opts, NULL);
  1548. X
  1549. X    if (exportsfile != NULL)
  1550. X    {
  1551. X        if ((f = fopen(exportsfile, "r")) == NULL)
  1552. X        {
  1553. X            syslog(LOG_DAEMON|LOG_WARNING, "Could not open %s: %m", exportsfile);
  1554. X            exit(1);
  1555. X        }
  1556. X        /* process exports file */
  1557. X        while (getline(&lbuf, f))
  1558. X        {
  1559. X            p = lbuf;
  1560. X            while (isspace(*p))
  1561. X                p++;
  1562. X            q = p;
  1563. X            /* file-system name */
  1564. X            while (*q != '\0' && !isspace(*q))
  1565. X                q++;
  1566. X            if ((mount_point = malloc(q-p+1)) == NULL)
  1567. X                mallocfailed();
  1568. X            for (r = mount_point; p < q;)
  1569. X                *r++ = *p++;
  1570. X            *r = '\0';
  1571. X            p = q;
  1572. X            while (isspace(*p))
  1573. X                p++;
  1574. X            while (*p != '\0')
  1575. X            {
  1576. X                q = p;
  1577. X                /* host name */
  1578. X                while (*q != '\0' && !isspace(*q) && *q != '(')
  1579. X                    q++;
  1580. X                if ((tmp = (clnt_param *) malloc(sizeof *tmp)) == NULL
  1581. X                 || (tmp->clnt_name = malloc(q-p+1)) == NULL)
  1582. X                    mallocfailed();
  1583. X                for (r = tmp->clnt_name; p < q;)
  1584. X                    *r++ = *p++;
  1585. X                *r = '\0';
  1586. X                tmp->mount_point = mount_point;
  1587. X                if ((hent = gethostbyname(tmp->clnt_name)) == NULL)
  1588. X                {
  1589. X                    syslog(LOG_DAEMON|LOG_WARNING, "Unknown host %s in %s",
  1590. X                        tmp->clnt_name, exportsfile);
  1591. X                    free(tmp->clnt_name); free(tmp);
  1592. X                    continue;
  1593. X                }
  1594. X                tmp->clnt_addr = *((struct in_addr *)hent->h_addr);
  1595. X                tmp->next = clients;
  1596. X                clients = tmp;
  1597. X                tmp->o = def_opts;
  1598. X                while (isspace(*p))
  1599. X                    p++;
  1600. X                if (*p == '(')
  1601. X                    p = parse_opts(p+1, ')', &(tmp->o), tmp->clnt_name);
  1602. X            }
  1603. X            free(lbuf);
  1604. X        }
  1605. X        fclose(f);
  1606. X    }
  1607. X    if (promiscuous)
  1608. X    {
  1609. X        if ((tmp = (clnt_param *) malloc(sizeof *tmp)) == NULL)
  1610. X            mallocfailed();
  1611. X        tmp->clnt_name = NULL;
  1612. X        tmp->mount_point = NULL;
  1613. X        default_client = tmp;
  1614. X        tmp->o = def_opts;
  1615. X    }
  1616. X}
  1617. X
  1618. Xint
  1619. X_in_gid_set(gid)
  1620. Xint    gid;
  1621. X{
  1622. X    int i;
  1623. X
  1624. X    for (i = 0; i < svc_ngids; i++)
  1625. X        if (svc_gids[i] == gid)
  1626. X        {
  1627. X            cur_gid = gid;
  1628. X            return 1;
  1629. X        }
  1630. X    return 0;
  1631. X}
  1632. X
  1633. Xclnt_param *
  1634. Xknownclient(rqstp)
  1635. X    struct svc_req *rqstp;
  1636. X{
  1637. X    clnt_param    **cpp, *cp;
  1638. X
  1639. X    /* find host parameter struct */
  1640. X    for (cpp = &clients; *cpp != NULL; cpp = &((*cpp)->next))
  1641. X    {
  1642. X        if ((*cpp)->clnt_addr.s_addr == svc_getcaller(rqstp->rq_xprt)->sin_addr.s_addr)
  1643. X        {
  1644. X            cp = *cpp;
  1645. X            if (cp != clients)
  1646. X            {
  1647. X                /* Move to front */
  1648. X                *cpp = cp->next;
  1649. X                cp->next = clients;
  1650. X                clients = cp;
  1651. X            }
  1652. X            goto found_it;
  1653. X        }
  1654. X    }
  1655. X    if (default_client != NULL)
  1656. X        cp = default_client;
  1657. X    else
  1658. X    {
  1659. X        syslog(LOG_DAEMON|LOG_CRIT, "Access attempt by unknown client %08X",
  1660. X            ntohl(svc_getcaller(rqstp->rq_xprt)->sin_addr));
  1661. X        return NULL;
  1662. X    }
  1663. X    found_it:
  1664. X    /* check request originated on a privileged port */
  1665. X    if (ntohs(svc_getcaller(rqstp->rq_xprt)->sin_port) >= IPPORT_RESERVED && cp->o.secure_port)
  1666. X    {
  1667. X        syslog(LOG_DAEMON|LOG_CRIT, "NFS request from %08X originated on insecure port",
  1668. X            ntohl(svc_getcaller(rqstp->rq_xprt)->sin_addr));
  1669. X        return NULL;
  1670. X    }
  1671. X    return cp;
  1672. X}
  1673. ________This_Is_The_END________
  1674. if test `wc -l < init.c` -ne 462; then
  1675.     echo 'shar: init.c was damaged during transit (should have been 462 bytes)'
  1676. fi
  1677. fi        ; : end of overwriting check
  1678. echo 'x - mount.x'
  1679. if test -f mount.x; then echo 'shar: not overwriting mount.x'; else
  1680. sed 's/^X//' << '________This_Is_The_END________' > mount.x
  1681. X/* @(#)mount.x    1.2 87/11/12 3.9 RPCSRC */
  1682. X/* @(#)mount.x 1.2 87/09/18 Copyr 1987 Sun Micro */
  1683. X
  1684. X/*
  1685. X * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
  1686. X * unrestricted use provided that this legend is included on all tape
  1687. X * media and as a part of the software program in whole or part.  Users
  1688. X * may copy or modify Sun RPC without charge, but are not authorized
  1689. X * to license or distribute it to anyone else except as part of a product or
  1690. X * program developed by the user.
  1691. X * 
  1692. X * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
  1693. X * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  1694. X * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
  1695. X * 
  1696. X * Sun RPC is provided with no support and without any obligation on the
  1697. X * part of Sun Microsystems, Inc. to assist in its use, correction,
  1698. X * modification or enhancement.
  1699. X * 
  1700. X * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
  1701. X * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
  1702. X * OR ANY PART THEREOF.
  1703. X * 
  1704. X * In no event will Sun Microsystems, Inc. be liable for any lost revenue
  1705. X * or profits or other special, indirect and consequential damages, even if
  1706. X * Sun has been advised of the possibility of such damages.
  1707. X * 
  1708. X * Sun Microsystems, Inc.
  1709. X * 2550 Garcia Avenue
  1710. X * Mountain View, California  94043
  1711. X */
  1712. X
  1713. X/*
  1714. X * Protocol description for the mount program
  1715. X */
  1716. X
  1717. X
  1718. Xconst MNTPATHLEN = 1024;    /* maximum bytes in a pathname argument */
  1719. Xconst MNTNAMLEN = 255;        /* maximum bytes in a name argument */
  1720. Xconst FHSIZE = 32;        /* size in bytes of a file handle */
  1721. X
  1722. X/*
  1723. X * The fhandle is the file handle that the server passes to the client.
  1724. X * All file operations are done using the file handles to refer to a file
  1725. X * or a directory. The file handle can contain whatever information the
  1726. X * server needs to distinguish an individual file.
  1727. X */
  1728. Xstruct fhandle {
  1729. X    opaque data[FHSIZE];    
  1730. X};
  1731. X
  1732. X/*
  1733. X * If a status of zero is returned, the call completed successfully, and 
  1734. X * a file handle for the directory follows. A non-zero status indicates
  1735. X * some sort of error. The status corresponds with UNIX error numbers.
  1736. X */
  1737. Xunion fhstatus switch (unsigned fhs_status) {
  1738. Xcase 0:
  1739. X    struct fhandle fhs_fhandle;
  1740. Xdefault:
  1741. X    void;
  1742. X};
  1743. X
  1744. X/*
  1745. X * The type dirpath is the pathname of a directory
  1746. X */
  1747. Xtypedef string dirpath<MNTPATHLEN>;
  1748. X
  1749. X/*
  1750. X * The type name is used for arbitrary names (hostnames, groupnames)
  1751. X */
  1752. Xtypedef string name<MNTNAMLEN>;
  1753. X
  1754. X/*
  1755. X * A list of who has what mounted
  1756. X */
  1757. Xstruct mountlist {
  1758. X    name ml_hostname;
  1759. X    dirpath ml_directory;
  1760. X    mountlist *ml_next;
  1761. X};
  1762. X
  1763. X/*
  1764. X * A list of netgroups
  1765. X */
  1766. Xtypedef struct groupnode *groups;
  1767. Xstruct groupnode {
  1768. X    name gr_name;
  1769. X    groups *gr_next;
  1770. X};
  1771. X
  1772. X/*
  1773. X * A list of what is exported and to whom
  1774. X */
  1775. Xstruct exports {
  1776. X    dirpath ex_dir;
  1777. X    groups ex_groups;
  1778. X    exports *ex_next;
  1779. X};
  1780. X
  1781. Xprogram MOUNTPROG {
  1782. X    /*
  1783. X     * Version one of the mount protocol communicates with version two
  1784. X     * of the NFS protocol. The only connecting point is the fhandle 
  1785. X     * structure, which is the same for both protocols.
  1786. X     */
  1787. X    version MOUNTVERS {
  1788. X        /*
  1789. X         * Does no work. It is made available in all RPC services
  1790. X         * to allow server reponse testing and timing
  1791. X         */
  1792. X        void
  1793. X        MOUNTPROC_NULL(void) = 0;
  1794. X
  1795. X        /*    
  1796. X         * If fhs_status is 0, then fhs_fhandle contains the
  1797. X          * file handle for the directory. This file handle may
  1798. X         * be used in the NFS protocol. This procedure also adds
  1799. X         * a new entry to the mount list for this client mounting
  1800. X         * the directory.
  1801. X         * Unix authentication required.
  1802. X         */
  1803. X        fhstatus 
  1804. X        MOUNTPROC_MNT(dirpath) = 1;
  1805. X
  1806. X        /*
  1807. X         * Returns the list of remotely mounted filesystems. The 
  1808. X         * mountlist contains one entry for each hostname and 
  1809. X         * directory pair.
  1810. X         */
  1811. X        mountlist
  1812. X        MOUNTPROC_DUMP(void) = 2;
  1813. X
  1814. X        /*
  1815. X         * Removes the mount list entry for the directory
  1816. X         * Unix authentication required.
  1817. X         */
  1818. X        void
  1819. X        MOUNTPROC_UMNT(dirpath) = 3;
  1820. X
  1821. X        /*
  1822. X         * Removes all of the mount list entries for this client
  1823. X         * Unix authentication required.
  1824. X         */
  1825. X        void
  1826. X        MOUNTPROC_UMNTALL(void) = 4;
  1827. X
  1828. X        /*
  1829. X         * Returns a list of all the exported filesystems, and which
  1830. X         * machines are allowed to import it.
  1831. X         */
  1832. X        exports
  1833. X        MOUNTPROC_EXPORT(void)  = 5;
  1834. X    
  1835. X        /*
  1836. X         * Identical to MOUNTPROC_EXPORT above
  1837. X         */
  1838. X        exports
  1839. X        MOUNTPROC_EXPORTALL(void) = 6;
  1840. X    } = 1;
  1841. X} = 100005;
  1842. ________This_Is_The_END________
  1843. if test `wc -l < mount.x` -ne 161; then
  1844.     echo 'shar: mount.x was damaged during transit (should have been 161 bytes)'
  1845. fi
  1846. fi        ; : end of overwriting check
  1847. exit 0
  1848.