chris@umcp-cs.UUCP (Chris Torek) (06/09/85)
Here is a very simple set of remote file access routines which I'm using for a very specific purpose (remote access to TeX fonts from Suns) but which can be expanded easily to support more system calls. The whole thing was written and debugged in under 8 hours (and it probably shows) so it's not real production quality, but I figure someone out there will probably find it useful. Note that this is not a true remote file system in any real sense. It just happens to do what I want it to do... Unfortunately, I use some code that is really Berkeley's, so you'll have to do more work than just unbundling this script. You also need to copy /usr/src/lib/libc/vax/sys/SYS.h and make the changes given in the diff listing, and you need to copy the following .c files from the same directory, renaming them to start with a leading underscore and a .s suffix instead of .c: access.c close.c dup.c dup2.c fstat.c lseek.c open.c read.c write.c I have (by hand) made up a shell script which will hopefully do this for you, but it's untested.... You can run setup.sh or do it yourself; it's up to you. In either case, you need to add a ``simple-rfs'' entry in /etc/services. (``Pick a port number, any port number.'') I use: simple-rfs 1200/tcp # simple remote file system stuff On Suns, the same procedure suffices (but you need source, or careful hand disassembly and recoding---which is what I used---to make the system calls work). The ``cat'' program (/usr/src/bin/cat.c) makes a reasonable test for the rfs library. The rest of this (up to the signature at the end) is the srfs source. : Run this shell script with "sh" not "csh" PATH=:/bin:/usr/bin:/usr/ucb export PATH all=FALSE if [ $1x = -ax ]; then all=TRUE fi /bin/echo 'Extracting Makefile' sed 's/^X//' <<'//go.sysin dd *' >Makefile OBJS= access.o close.o dup.o dup2.o\ fstat.o lseek.o open.o read.o write.o\ raccess.o rclose.o\ rfstat.o rlseek.o ropen.o rread.o rwrite.o\ rconnect.o rio.o\ _access.o _close.o _dup.o _dup2.o\ _fstat.o _lseek.o _open.o _read.o _write.o CFLAGS= -O -R X.s.o: trap 'rm /tmp/cas$$$$' 0 1 2 3 15; /lib/cpp -E < $< > /tmp/cas$$$$; ${AS} -o $@ /tmp/cas$$$$ -ld -x -r $*.o mv a.out $*.o X.c.o: $(CC) $(CFLAGS) -c $< -ld -x -r $@ mv a.out $@ all: rfsd librfs.a librfs.a: $(OBJS) -mkdir libc cd libc; ar x /lib/libc.a rm -f librfs.a ar cr librfs.a libc/*.o ar r librfs.a $(OBJS) ranlib librfs.a rm -rf libc rfsd: rfsd.c r.h $(CC) $(CFLAGS) -o rfsd rfsd.c $(OBJS): r.h install: rfsd librfs.a install -s rfsd /etc/rfsd install librfs.a /usr/local/lib/librfs.a ranlib /usr/local/lib/librfs.a clean: rm -f *.o a.out core //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 Makefile /bin/echo -n ' '; /bin/ls -ld Makefile fi /bin/echo 'Extracting SYS.h.diff' sed 's/^X//' <<'//go.sysin dd *' >SYS.h.diff *** /usr/src/lib/libc/vax/sys/SYS.h Thu Jun 30 19:11:37 1983 --- SYS.h Sat Jun 8 23:36:00 1985 *************** *** 5,7 #ifdef PROF ! #define ENTRY(x) .globl _/**/x; .align 2; _/**/x: .word 0; \ .data; 1:; .long 0; .text; moval 1b,r0; jsb mcount --- 5,7 ----- #ifdef PROF ! #define ENTRY(x) .globl __/**/x; .align 2; __/**/x: .word 0; \ .data; 1:; .long 0; .text; moval 1b,r0; jsb mcount *************** *** 8,10 #else ! #define ENTRY(x) .globl _/**/x; .align 2; _/**/x: .word 0 #endif PROF --- 8,10 ----- #else ! #define ENTRY(x) .globl __/**/x; .align 2; __/**/x: .word 0 #endif PROF //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 664 SYS.h.diff /bin/echo -n ' '; /bin/ls -ld SYS.h.diff fi /bin/echo 'Extracting access.c' sed 's/^X//' <<'//go.sysin dd *' >access.c #ifndef lint static char rcsid[] = "$Header$"; #endif #include "r.h" #include <errno.h> extern int errno; X/* * access system call */ int open (name, a) char *name; int a; { int e; if (_access (name, a) == 0) /* normal file */ return 0; if (errno == ENOENT && *name == '/') { e = errno; if (_raccess (name, a) == 0) /* rfs file */ return 0; errno = e; /* return original error number */ } return (-1); } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 access.c /bin/echo -n ' '; /bin/ls -ld access.c fi /bin/echo 'Extracting close.c' sed 's/^X//' <<'//go.sysin dd *' >close.c #ifndef lint static char rcsid[] = "$Header$"; #endif #include "r.h" X/* * close system call */ int close (fd) int fd; { int rv; if (_isremote (fd)) { rv = _rclose (fd); if (rv == 0) _clrremote (fd); } else rv = _close (fd); return rv; } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 close.c /bin/echo -n ' '; /bin/ls -ld close.c fi /bin/echo 'Extracting dup.c' sed 's/^X//' <<'//go.sysin dd *' >dup.c #ifndef lint static char rcsid[] = "$Header$"; #endif #include "r.h" X/* * dup system call */ int dup (fd) int fd; { int rv; if ((rv = _dup (fd)) == 0) if (_isremote (fd)) _setremote (rv); return rv; } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 dup.c /bin/echo -n ' '; /bin/ls -ld dup.c fi /bin/echo 'Extracting dup2.c' sed 's/^X//' <<'//go.sysin dd *' >dup2.c #ifndef lint static char rcsid[] = "$Header$"; #endif #include "r.h" X/* * dup2 system call */ int dup2 (f1, f2) int f1, f2; { int rv, wasremote; wasremote = _isremote (f2); rv = _dup2 (f1, f2); if (rv == 0) { if (_isremote (f1)) _setremote (f2); else if (wasremote) _clrremote (f2); } return rv; } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 dup2.c /bin/echo -n ' '; /bin/ls -ld dup2.c fi /bin/echo 'Extracting fstat.c' sed 's/^X//' <<'//go.sysin dd *' >fstat.c #ifndef lint static char rcsid[] = "$Header$"; #endif #include <sys/types.h> #include <sys/stat.h> #include "r.h" X/* * fstat system call */ int fstat (fd, statp) int fd; struct stat *statp; { int rv; if (_isremote (fd)) rv = _rfstat (fd, statp); else rv = _fstat (fd, statp); return rv; } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 fstat.c /bin/echo -n ' '; /bin/ls -ld fstat.c fi /bin/echo 'Extracting lseek.c' sed 's/^X//' <<'//go.sysin dd *' >lseek.c #ifndef lint static char rcsid[] = "$Header$"; #endif #include "r.h" X/* * lseek system call */ long lseek (fd, off, t) int fd; long off; int t; { int rv; if (_isremote (fd)) rv = _rlseek (fd, off, t); else rv = _lseek (fd, off, t); return rv; } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 lseek.c /bin/echo -n ' '; /bin/ls -ld lseek.c fi /bin/echo 'Extracting open.c' sed 's/^X//' <<'//go.sysin dd *' >open.c #ifndef lint static char rcsid[] = "$Header$"; #endif #include "r.h" #include <errno.h> extern int errno; X/* * open system call */ int open (name, a, c) char *name; int a, c; { register int rv; int e; if ((rv = _open (name, a, c)) >= 0)/* normal open */ return rv; if (errno == ENOENT && *name == '/') { e = errno; if ((rv = _ropen (name, a, c)) >= 0) {/* rfs open */ _setremote (rv); return rv; } errno = e; /* return original error number */ } return rv; } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 open.c /bin/echo -n ' '; /bin/ls -ld open.c fi /bin/echo 'Extracting r.h' sed 's/^X//' <<'//go.sysin dd *' >r.h X/* * simplerfs - simple remote file system stuff * * File descriptors are *not* passed across exec()s, etc. This * is NOT a real remote file system! */ X/* * RFS requests are made as a ``stream'' using the following magic * codes. Codes <= R_NOTOPEN are legal before a file is open. */ #define R_OPEN 1 #define R_ACCESS 2 #define R_CLOSE 3 #define R_READ 4 #define R_WRITE 5 #define R_SEEK 6 #define R_FSTAT 7 #define R_NOTOPEN 2 X/* * Arguments are either integers or character (byte) strings. * Integers are sent in ``network long'' order (BigEndian). * Strings are sent as counted byte thingamabobs; the count * is yet another ``network long''. * * To perform a request, one sends the R_ command, followed by * its arguments, then reads the return status (or in the case * of "read", the status followed by the bytes read). E.g.: * * putchar(R_OPEN); putnetlong(strlen("foo")); putstr("foo"); * putnetlong(0); putnetlong(0); rv = getnetlong(); * * might open file "foo" for reading. * * The server switches uid's to ``guest'', thus can only access * publicly-accessible files. */ X/* * We need to keep track of which files are local, and which are * remote. One way to do this is to simply use larger file descriptor * numbers than usual. This may cause problems with program that * assume magic fd's (like 0, 1, 2), so I've elected to use flags * instead. (N.B.: I've assumed at most 32 valid fd's, 0-31, and * 32 bit longs.) */ long _remotebits; #define _isremote(fd) (_remotebits & (1L << (fd))) #define _setremote(fd) (_remotebits |= (1L << (fd))) #define _clrremote(fd) (_remotebits &= ~(1L << (fd))) X/* * _rresp() returns a response value from the server */ long _rresp (); X/* * _rconnect() connects to the server, given a pathname, and returns * the modified pathname to be handed to the server. It takes a * second argument (an int *) and fills that in with the server fd. * If the connection fails for some reason, _rconnect() returns NULL. */ char *_rconnect(); X/* * the ``stat'' format varies too much to use directly; we make up * one that has all "long"s. (And we drop the spares.) */ struct rfsstat { long st_dev; long st_ino; long st_mode; long st_nlink; long st_uid; long st_gid; long st_rdev; long st_size; long st_atime; long st_mtime; long st_ctime; long st_blksize; long st_blocks; }; //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 r.h /bin/echo -n ' '; /bin/ls -ld r.h fi /bin/echo 'Extracting raccess.c' sed 's/^X//' <<'//go.sysin dd *' >raccess.c #ifndef lint static char rcsid[] = "$Header$"; #endif #include "r.h" X/* * remote access * * We pull off the leading part of the pathname and use that as * a machine name (/mimsy/foo/bar => mimsy, file /foo/bar) * * access.c has guaranteed that we get a name starting with /. */ int _raccess (name, a) register char *name; int a; { int s, rv; if ((name = _rconnect (name, &s)) != 0) { /* Send an open request, and get the return status (0=>success) */ if (_wrequest (s, R_ACCESS) == 0 && _wstring (s, name, strlen (name) + 1L) == 0 && _wlong (s, (long) a) == 0) rv = _rresp (s); else rv = -1; (void) close (s); } return rv; } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 raccess.c /bin/echo -n ' '; /bin/ls -ld raccess.c fi /bin/echo 'Extracting rclose.c' sed 's/^X//' <<'//go.sysin dd *' >rclose.c #ifndef lint static char rcsid[] = "$Header$"; #endif #include "r.h" #include <stdio.h> X/* * remote close */ int _rclose (fd) int fd; { (void) _wrequest (fd, R_CLOSE); (void) _close (fd); return (0); } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 rclose.c /bin/echo -n ' '; /bin/ls -ld rclose.c fi /bin/echo 'Extracting rconnect.c' sed 's/^X//' <<'//go.sysin dd *' >rconnect.c #ifndef lint static char rcsid[] = "$Header$"; #endif #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> X/* * remote connect * * We pull off the leading part of the pathname and use that as * a machine name (/mimsy/foo/bar => mimsy, file /foo/bar), connect to * it, fill in the supplied afd pointer, and return the tail of the * name (to be given to the other side). If something goes wrong, we * return 0. */ char * _rconnect (name, afd) char *name; int *afd; { static int beenhere; /* true => been thru here before */ static int cando; /* true => have a server addr */ static struct sockaddr_in saddr;/* rfsd addr */ if (!beenhere) { register struct servent *sp; beenhere++; if ((sp = getservbyname ("simple-rfs", 0)) != 0) { saddr.sin_family = AF_INET;/* presumably! */ saddr.sin_port = sp->s_port;/* foreign port # */ cando++; } } if (cando) { register char *p = name; register char *cp; register int l; register int c; register struct hostent *hp; int s; long t; char hostname[40]; /* Figure out the host name / address */ while (*p == '/') p++; cp = hostname; l = 0; while (*p && (c = *p++) != '/') if (++l < sizeof hostname) *cp++ = c; *cp = 0; if ((hp = gethostbyname (hostname)) == 0) return 0; bcopy (hp -> h_addr, &saddr.sin_addr, sizeof saddr.sin_addr); /* Get a tcp socket and connect to the RFS daemon */ if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0) return 0; if (connect (s, &saddr, sizeof saddr) >= 0) { *afd = s; /* Success! */ return p; } (void) close (s); } return 0; } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 rconnect.c /bin/echo -n ' '; /bin/ls -ld rconnect.c fi /bin/echo 'Extracting read.c' sed 's/^X//' <<'//go.sysin dd *' >read.c #ifndef lint static char rcsid[] = "$Header$"; #endif #include "r.h" X/* * read system call */ int read (fd, buf, n) int fd; char *buf; int n; { int rv; if (_isremote (fd)) rv = _rread (fd, buf, n); else rv = _read (fd, buf, n); return rv; } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 read.c /bin/echo -n ' '; /bin/ls -ld read.c fi /bin/echo 'Extracting rfsd.c' sed 's/^X//' <<'//go.sysin dd *' >rfsd.c X/* * rfsd - simple RFS daemon * * N.B.: The other side sees a file system rooted at whatever the * current directory is when the daemon is started. Thus, * the default startup should be (cd /; /etc/rfsd &) or similar. */ X/* #define TRACE */ char GUEST[] = "guest"; char GUESTGRP[] = "junk"; #include <stdio.h> #include <signal.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <sys/resource.h> #include <sys/stat.h> #include <sys/wait.h> #include <netinet/in.h> #include <netdb.h> #include <errno.h> #include <pwd.h> #include <grp.h> #include "r.h" char *ProgName; extern int errno; X/* * error (from -lum library) * * Useful for printing error messages. Will print the program name * and (optionally) the system error associated with the values in * <errno.h>. * * Note that the type (and even the existence!) of ``arg'' is undefined. */ error (quit, e, fmt, arg) int quit; register int e; char *fmt; { extern char *sys_errlist[]; extern int sys_nerr; register char *p = ProgName; if (p == NULL) p = "tomb of the unknown program"; fprintf (stderr, "%s: ", p); _doprnt (fmt, &arg, stderr); /* magic */ if (e > 0) { p = e < sys_nerr ? sys_errlist[e] : "unknown error"; fprintf (stderr, ": %s", p); } putc ('\n', stderr); fflush (stderr); if (quit) exit (quit); } X/* * globals */ int servfd; /* fd to service */ X/* **DANGER***************** * fuzzing long vs. int! * **DANGER***************** */ char *string; int stringlen; struct passwd *getpwnam (); struct group *getgrnam (); reap () { union wait w; int pid; while ((pid = wait3 (&w, WNOHANG, (struct rusage *) 0)) > 0); } X/* * Try hard to fork. */ ffoorrkk () { register int p, n = 0; while ((p = fork ()) < 0) { if (errno == EAGAIN && ++n < 10) { sleep (1); continue; } return (-1); } return p; } X/* * Get a long */ long getlong () { long l; if (read (servfd, &l, sizeof l) != sizeof l) error (1, errno, "getlong read"); return ntohl (l); } X/* * Get a string, return the length. */ long getstring () { long l; register int len; char *malloc (); if (read (servfd, &l, sizeof l) != sizeof l) error (1, errno, "getstring length read"); l = ntohl (l); len = l; if (len > stringlen) { if (string) free (string); if ((string = malloc (len)) == 0) error (1, errno, "can't allocate %d bytes for string", len); stringlen = len; } if (read (servfd, string, len) != len) error (1, errno, "getstring string read"); return l; } putlong (l) long l; { long l1 = htonl (l); if (write (servfd, &l1, sizeof l1) != sizeof l1) error (1, errno, "putlong write"); } putstat (s) register struct stat *s; { struct rfsstat rst; rst.st_dev = htonl ((long) s -> st_dev); rst.st_ino = htonl ((long) s -> st_ino); rst.st_mode = htonl ((long) s -> st_mode); rst.st_nlink = htonl ((long) s -> st_nlink); rst.st_uid = htonl ((long) s -> st_uid); rst.st_gid = htonl ((long) s -> st_gid); rst.st_rdev = htonl ((long) s -> st_rdev); rst.st_size = htonl (s -> st_size); rst.st_atime = htonl (s -> st_atime); rst.st_mtime = htonl (s -> st_mtime); rst.st_ctime = htonl (s -> st_ctime); rst.st_blksize = htonl (s -> st_blksize); rst.st_blocks = htonl (s -> st_blocks); if (write (servfd, &rst, sizeof rst) != sizeof rst) error (1, errno, "fstat write"); } X/* * Service the connection. We had better get a code <= R_NOTOPEN first. * If it's R_OPEN, then we hang around, and we better not get any more * codes <= R_NOTOPEN. We should get an R_CLOSE last. */ serve () { char ch; int isopen = 0; int a, c, localfd; long l; struct stat st; long lseek (); for (;;) { if (read (servfd, &ch, 1) != 1) error (1, errno, "read"); #ifdef TRACE error (0, 0, "req. #%d", ch); #endif if (ch > R_NOTOPEN) { if (!isopen) error (1, 0, "request #%d (>R_NOTOPEN), no file open", ch); } else if (isopen) error (1, 0, "request #%d (<=R_NOTOPEN), file open", ch); switch (ch) { case R_OPEN: /* open (str, int, int) */ #ifdef TRACE error (0, 0, "open"); #endif (void) getstring (); a = getlong (); c = getlong (); #ifdef TRACE error (0, 0, "open(\"%s\",%d,%d)", string, a, c); #endif localfd = open (string, a, c); if (localfd < 0) { putlong (-1L); (void) close (servfd); exit (0); } putlong (0L); isopen++; break; case R_ACCESS: /* access (str, int) */ (void) getstring (); a = getlong (); c = access (string, a); #ifdef TRACE error (0, 0, "access(\"%s\",%d) => %d", string, a, c); #endif putlong ((long) c); (void) close (servfd); exit (0); #ifdef R_STAT case R_STAT: /* stat (str) */ (void) getstring (); c = stat (string, &st); #ifdef TRACE error (0, 0, "stat(\"%s\") => %d", string, c); #endif putlong ((long) c); if (c == 0) sendstats (&st); (void) close (servfd); exit (0); #endif R_STAT case R_CLOSE: /* close () */ #ifdef TRACE error (0, 0, "close(%d)", localfd); #endif (void) close (localfd); exit (0); case R_READ: /* read (int) */ #ifdef TRACE error (0, 0, "read"); #endif l = getlong (); #ifdef TRACE error (0, 0, "read(%d,%ld)", localfd, l); #endif if (l > stringlen) { if (string) free (string); string = malloc ((int) l); if (string == 0) error (1, errno, "R_READ malloc %d failed", (int) l); stringlen = l; } c = read (localfd, string, (int) l); #ifdef TRACE error (0, 0, "read returned %d\n", c); #endif putlong ((long) c); { register char *p = string; register int n; while (c > 0) { if ((n = write (servfd, p, c)) < 0) error (1, errno, "write"); c -= n; p += n; } } break; case R_WRITE: /* write (str) */ #ifdef TRACE error (0, 0, "write"); #endif l = getstring (); #ifdef TRACE error (0, 0, "write(%d,,%ld)", localfd, l); #endif putlong ((long) write (localfd, string, (int) l)); break; case R_SEEK: /* lseek (int, int) */ #ifdef TRACE error (0, 0, "seek"); #endif l = getlong (); c = (int) getlong (); #ifdef TRACE error (0, 0, "lseek(%d,%ld,%d)", localfd, l, c); #endif putlong (lseek (localfd, l, c)); break; case R_FSTAT: /* fstat */ #ifdef TRACE error (0, 0, "fstat(%d,)", localfd); #endif (void) fstat (localfd, &st); putstat (&st); break; default: error (1, 0, "unknown rfs req. #%d", ch); } } } X/*ARGSUSED*/ main (argc, argv) int argc; char **argv; { int s, slen, pid, fd, guestuid; struct sockaddr_in saddr; struct servent *sp; struct passwd *pw; struct group *gr; ProgName = *argv; if ((pw = getpwnam (GUEST)) == 0) error (1, 0, "can't find user \"%s\"", GUEST); guestuid = pw -> pw_uid; if ((gr = getgrnam (GUESTGRP)) == 0) error (1, 0, "can't find group \"%s\"", GUESTGRP); (void) setgid (gr -> gr_gid); (void) setuid (guestuid); /* Find out who we are supposed to live as */ if ((sp = getservbyname ("simple-rfs", 0)) == 0) error (1, errno, "can't find simple-rfs service info"); saddr.sin_family = AF_INET; saddr.sin_port = sp -> s_port; /* Make the network connection */ if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0) error (1, errno, "socket"); if (bind (s, &saddr, sizeof saddr) < 0) error (1, errno, "bind"); if (listen (s, 4) < 0) error (1, errno, "listen"); signal (SIGCHLD, reap); slen = sizeof saddr; for (;;) { if ((fd = accept (s, &saddr, &slen)) < 0) { if (errno == EINTR) continue; break; } if ((pid = ffoorrkk ()) < 0) { long l = -1; /* first thing should be an R_OPEN; we will answer it with "error" */ (void) write (fd, l, sizeof l); (void) close (fd); continue; } if (pid == 0) { close (s); servfd = fd; serve (); } close (fd); } error (1, errno, "accept"); } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 rfsd.c /bin/echo -n ' '; /bin/ls -ld rfsd.c fi /bin/echo 'Extracting rfstat.c' sed 's/^X//' <<'//go.sysin dd *' >rfstat.c #ifndef lint static char rcsid[] = "$Header$"; #endif #include <sys/types.h> #include <sys/stat.h> #include <netinet/in.h> #include "r.h" X/* * remote fstat */ int _rfstat (fd, s) int fd; register struct stat *s; { struct rfsstat rst; if (_wrequest (fd, R_FSTAT)) return (-1); if (_read (fd, &rst, sizeof rst) != sizeof rst) return (-1); s -> st_dev = ntohl (rst.st_dev); s -> st_ino = (u_long) ntohl (rst.st_ino); s -> st_mode = (u_short) ntohl (rst.st_mode); s -> st_nlink = ntohl (rst.st_nlink); s -> st_uid = ntohl (rst.st_uid); s -> st_gid = ntohl (rst.st_gid); s -> st_rdev = ntohl (rst.st_rdev); s -> st_size = ntohl (rst.st_size); s -> st_atime = ntohl (rst.st_atime); s -> st_mtime = ntohl (rst.st_mtime); s -> st_ctime = ntohl (rst.st_ctime); s -> st_blksize = ntohl (rst.st_blksize); s -> st_blocks = ntohl (rst.st_blocks); return 0; } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 rfstat.c /bin/echo -n ' '; /bin/ls -ld rfstat.c fi /bin/echo 'Extracting rio.c' sed 's/^X//' <<'//go.sysin dd *' >rio.c #ifndef lint static char rcsid[] = "$Header$"; #endif X/* * RFS I/O */ #include <sys/types.h> #include <netinet/in.h> X/* * _wrequest sends a (byte) request over the given fd. */ _wrequest (fd, req) int fd, req; { char c = req; if (_write (fd, &c, 1) != 1) return (-1); return 0; } X/* * _wstring sends a counted string */ _wstring (fd, s, len) int fd; char *s; long len; { long l; l = htonl (len); if (_write (fd, &l, sizeof l) != sizeof l) return (-1); if (_write (fd, s, len) != len) return (-1); return 0; } X/* * _wlong sends a long */ _wlong (fd, l) int fd; long l; { long l1 = ntohl (l); if (_write (fd, &l1, sizeof l1) != sizeof l1) return (-1); return 0; } X/* * _rresp reads a long and returns it */ long _rresp (fd) int fd; { long l; if (_read (fd, &l, sizeof l) != sizeof l) return (-1); /* generic error stuff */ l = ntohl (l); return l; } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 rio.c /bin/echo -n ' '; /bin/ls -ld rio.c fi /bin/echo 'Extracting rlseek.c' sed 's/^X//' <<'//go.sysin dd *' >rlseek.c #ifndef lint static char rcsid[] = "$Header$"; #endif #include "r.h" X/* * remote lseek */ int _rlseek (fd, off, t) int fd; long off; int t; { if (_wrequest (fd, R_SEEK) || _wlong (fd, off) || _wlong (fd, (long) t)) return (-1); return _rresp (fd); } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 rlseek.c /bin/echo -n ' '; /bin/ls -ld rlseek.c fi /bin/echo 'Extracting ropen.c' sed 's/^X//' <<'//go.sysin dd *' >ropen.c #ifndef lint static char rcsid[] = "$Header$"; #endif #include "r.h" X/* * remote open * * We pull off the leading part of the pathname and use that as * a machine name (/mimsy/foo/bar => mimsy, file /foo/bar) * * open.c has guaranteed that we get a name starting with /. */ int _ropen (name, a, c) register char *name; int a, c; { int s; if ((name = _rconnect (name, &s)) != 0) { /* Send an open request, and get the return status (0=>success) */ if (_wrequest (s, R_OPEN) == 0 && _wstring (s, name, strlen (name) + 1L) == 0 && _wlong (s, (long) a) == 0 && _wlong (s, (long) c) == 0 && _rresp (s) == 0) return s; /* Success! */ (void) close (s); /* something went wrong */ } return (-1); } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 ropen.c /bin/echo -n ' '; /bin/ls -ld ropen.c fi /bin/echo 'Extracting rread.c' sed 's/^X//' <<'//go.sysin dd *' >rread.c #ifndef lint static char rcsid[] = "$Header$"; #endif #include "r.h" X/* * remote read * * This guy is a bit different from all the rest, since we have more * than just a ``long'' for return info. We work this way: get the * return value, then read that many bytes into the caller's buffer. */ int _rread (fd, buf, n) int fd; register char *buf; int n; { register int left; register int nn; int t; if (_wrequest (fd, R_READ) || _wlong (fd, (long) n)) return (-1); t = left = _rresp (fd); while (left > 0) { if ((nn = _read (fd, buf, left)) <= 0) return (-1); buf += nn; left -= nn; } return t; } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 rread.c /bin/echo -n ' '; /bin/ls -ld rread.c fi /bin/echo 'Extracting rwrite.c' sed 's/^X//' <<'//go.sysin dd *' >rwrite.c #ifndef lint static char rcsid[] = "$Header$"; #endif #include "r.h" X/* * remote write */ int _rwrite (fd, buf, n) int fd; char *buf; int n; { if (_wrequest (fd, R_WRITE) || _wstring (fd, buf, (long) n)) return (-1); return _rresp (fd); } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 rwrite.c /bin/echo -n ' '; /bin/ls -ld rwrite.c fi /bin/echo 'Extracting write.c' sed 's/^X//' <<'//go.sysin dd *' >write.c #ifndef lint static char rcsid[] = "$Header$"; #endif #include "r.h" X/* * write system call */ int write (fd, buf, n) int fd; char *buf; int n; { int rv; if (_isremote (fd)) rv = _rwrite (fd, buf, n); else rv = _write (fd, buf, n); return rv; } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 write.c /bin/echo -n ' '; /bin/ls -ld write.c fi /bin/echo 'Extracting setup.sh' sed 's/^X//' <<'//go.sysin dd *' >setup.sh #! /bin/sh # # setup.sh - set up the RFS directory by copying and editing the # various BSD sources needed src=/usr/src/lib/libc/vax/sys routines=access close dup dup2 fstat lseek open read write cp $src/SYS.h SYS.h ed - SYS.h << 'eof' g/ENTRY/s/_/__/g w q eof for i in $routines; do cp $src/$i.c _$i.s done echo done. //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 755 setup.sh /bin/echo -n ' '; /bin/ls -ld setup.sh fi -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@maryland