Simple "remote file system" stuff for 4.2BSD
Chris Torek
chris at umcp-cs.UUCP
Sun Jun 9 14:39:51 AEST 1985
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 at umcp-cs ARPA: chris at maryland
More information about the Comp.sources.unix
mailing list