toddb@tekcrl.UUCP (Todd Brunhoff) (03/11/86)
#!/bin/sh # # RFS, a kernel-resident remote file system. Shar 4 of 7 # # # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # remote/serverdata.c # remote/serverdir.c # remote/serverio.c # remote/serversyscall.c # remote/shells/makemake # remote/shells/mkdist # remote/shells/mkdist.shar # remote/shells/rfs_clean # remote/shells/rfs_kerninstall # remote/shells/rfs_kernpatch # remote/shells/rfs_setup # remote/shells/rfs_userpatch # remote/usr.include.PYR2.5/syscall.h.diff # remote/usr.include.VAX4.2/syscall.h.diff # remote/usr.src.lib.libc/Makefile # remote/usr.src.lib.libc/gen/pyr.errlst.c.diff # remote/usr.src.lib.libc/gen/vax.errlst.c.diff # # remote/serverdata.c # if [ -f remote/serverdata.c ]; then echo -n 'Hit <return> to overwrite remote/serverdata.c or ^C to quit' read ans rm -f remote/serverdata.c fi sed -e 's/^.//' << \SHAREOF > remote/serverdata.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: serverdata.c,v $ X * Revision 2.0 85/12/07 18:22:20 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: serverdata.c,v 2.0 85/12/07 18:22:20 toddb Rel $"; X#include "server.h" X#include <nlist.h> X#include <signal.h> X#include <netdb.h> X#include <sys/stat.h> X X/* X * system calls. X */ Xlong access(), chdir(), chmod(), chown(), close(), dup(), execve(), X fchmod(), fchown(), fcntl(), flock(), fork(), fstat(), fsync(), X ftruncate(), ioctl(), link(), lseek(), lstat(), mkdir(), X mknod(), open(), read(), readlink(), rename(), rmdir(), X stat(), symlink(), truncate(), unlink(), utimes(), X write(), X/* X * ...and our own routines to set up for the system calls. X */ X noop(), s_access(), s_dup(), s_execinfo(), s_execread(), s_exit(), X s_fcntl(), s_fd1(), s_fd1_plus(), s_fork(), s_ioctl(), s_lseek(), X s_open(), s_path1(), s_path1_plus(), s_path2(), s_read(), X s_readlink(), s_stat(), s_utimes(), s_write(); X Xsyscallmap smap[] = { X s_fork, noop, NEED_ZIP, /* RSYS_fork */ X s_read, read, NEED_ZIP, /* RSYS_read */ X s_write, write, NEED_ZIP, /* RSYS_write */ X s_open, open, NEED_CWD X |NEED_MYSERVER X |NEED_PERM X |NEED_FD, /* RSYS_open */ X s_fd1, close, NEED_ZIP, /* RSYS_close */ X noop, noop, NEED_CWD X |NEED_PERM X |NEED_FD, /* RSYS_creat */ X s_path2, link, NEED_CWD X |NEED_MYSERVER X |NEED_2PATH X |NEED_2REMOTE X |NEED_PERM, /* RSYS_link */ X s_path1, unlink, NEED_CWD|NEED_PERM, /* RSYS_unlink */ X s_path1, chdir, NEED_MYSERVER X |NEED_CWD X |NEED_PERM X |NEED_MYSERVER, /* RSYS_chdir */ X s_path1_plus, mknod, NEED_CWD|NEED_PERM, /* RSYS_mknod */ X s_path1_plus, chmod, NEED_CWD|NEED_PERM, /* RSYS_chmod */ X s_path1_plus, chown, NEED_CWD|NEED_PERM, /* RSYS_chown */ X s_stat, stat, NEED_CWD|NEED_PERM, /* RSYS_stat */ X s_lseek, lseek, NEED_ZIP, /* RSYS_lseek */ X s_access, access, NEED_CWD|NEED_PERM, /* RSYS_access */ X s_stat, lstat, NEED_CWD|NEED_PERM, /* RSYS_lstat */ X s_dup, dup, NEED_FD, /* RSYS_dup */ X s_ioctl, ioctl, NEED_ZIP, /* RSYS_ioctl */ X s_path2, symlink, NEED_CWD X |NEED_2PATH X |NEED_PERM, /* RSYS_symlink */ X s_readlink, readlink, NEED_CWD|NEED_PERM, /* RSYS_readlink */ X s_stat, fstat, NEED_ZIP, /* RSYS_fstat */ X s_dup, dup, NEED_FD, /* RSYS_dup2 */ X s_fd1_plus, fcntl, NEED_ZIP, /* RSYS_fcntl */ X s_fd1, fsync, NEED_ZIP, /* RSYS_fsync */ X noop, noop, NEED_ZIP, /* RSYS_readv */ X noop, noop, NEED_ZIP, /* RSYS_writev */ X s_fd1_plus, fchown, NEED_PERM, /* RSYS_fchown */ X s_fd1_plus, fchmod, NEED_PERM, /* RSYS_fchmod */ X s_path2, rename, NEED_MYSERVER X |NEED_2REMOTE X |NEED_CWD X |NEED_2PATH X |NEED_PERM, /* RSYS_rename */ X s_path1_plus, truncate, NEED_CWD|NEED_PERM, /* RSYS_truncate */ X s_fd1_plus, ftruncate,NEED_ZIP, /* RSYS_ftruncate */ X s_fd1_plus, flock, NEED_ZIP, /* RSYS_flock */ X s_path1_plus, mkdir, NEED_CWD|NEED_PERM, /* RSYS_mkdir */ X s_path1, rmdir, NEED_CWD|NEED_PERM, /* RSYS_rmdir */ X s_utimes, utimes, NEED_CWD|NEED_PERM, /* RSYS_utimes */ X s_exit, noop, NEED_ZIP, /* RSYS_exit */ X s_fork, noop, NEED_ZIP, /* RSYS_Vfork */ X s_execinfo, noop, NEED_MYSERVER X |NEED_CWD X |NEED_PERM, /* RSYS_execinfo */ X s_execread, noop, NEED_PERM, /* RSYS_execread */ X noop, noop, NEED_ZIP, /* RSYS_execve */ X noop, noop, NEED_ZIP, /* RSYS_nosys */ X s_lseek, lseek, NEED_ZIP, /* RSYS_qlseek */ X}; X Xchar *syscallnames[] = { X "fork", X "read", X "write", X "open", X "close", X "creat", X "link", X "unlink", X "chdir", X "mknod", X "chmod", X "chown", X "stat", X "lseek", X "access", X "lstat", X "dup", X "ioctl", X "symlink", X "readlink", X "fstat", X "dup2", X "fcntl", X "fsync", X "readv", X "writev", X "fchown", X "fchmod", X "rename", X "truncate", X "ftruncate", X "flock", X "mkdir", X "rmdir", X "utimes", X "exit", X "vfork", X "execinfo", X "execread", X "execve", X "nosys", X "quick lseek" X}; X Xchar hostname[ HOSTNAMELEN ];/* our host name */ Xchar mntpt[ MAXPATHLEN ]; /* mount point for client */ Xchar *program; /* name of this program */ Xchar *last_argaddr; /* last address that we can scribble on */ Xchar *service = REMOTE_FS_SERVER; /* name of alternate internet service */ Xchar *stdlogfile = "/usr/tmp/rfs_log"; /* log file for server */ Xchar *logfile; Xlong serviceport; /* port number for service */ Xlong remote_debug; /* level of debug output */ Xshort current_uid; /* whatever uid we are, right now */ Xshort current_pid; /* whatever pid we are, right now */ Xshort current_ppid; /* our parent server */ Xshort current_umask; /* whatever umask we have, right now */ Xshort current_server; /* server that has control right now */ Xshort gateway_server; /* pid of our gateway */ Xshort last_sentry; /* previous sentry server (if non-zero) */ Xlong fds_in_use; /* number of total file descriptors open */ Xlong to_gateway; /* file descriptor for messages to gateway */ Xlong so_listen; /* socket for listening for connections */ Xlong from_servers; /* file descriptor for messages from servers */ Xlong blocking_servers; /* number of servers waiting for I/O */ Xhosts *hostlist; /* all the hosts we know of */ Xhosts *host; /* the current host that we talk to */ Xhosts *thishost; /* host pointer for this machine */ Xusers *userlist; /* all the users on this host we know of */ Xusers *default_user; /* default user to map unknown clients to */ Xprocess *wildcard; /* wildcard process for easy requests */ Xboolean i_am_gateway = TRUE; /* whether we are the gateway server */ Xboolean i_have_control = TRUE; /* whether the gateway server has control of */ X /* the command socket */ Xboolean i_am_asleep; /* whether we are sleeping or not */ Xboolean gateway_needs_control; /* True if gateway wants control back */ Xboolean watch_for_lock; /* True if we need to watch for lock on fd 2 */ Xboolean route_to_gateway; /* True if we should route to gateway */ Xboolean in_root_directory = TRUE;/* whether we are at root directory or not */ Xstruct stat filetypes[ NOFILE ]; /* file types for open files */ X Xchar byteorder[4] = { BYTEORDER }; Xlong catch(), X nameserver(), X wakeup_call(), X alarmsig(); X Xstruct sigvec sig_continue = { X wakeup_call, X 1<<(SIGIO -1), X 0 X}; X Xstruct sigvec sig_ignore = { X (int (*)())SIG_IGN, X 1<<(SIGHUP -1), X 0 X}; X Xstruct sigvec sig_alarm = { X alarmsig, X 1<<(SIGALRM -1), X 0 X}; X Xstruct sigvec sig_name = { X nameserver, X 1<<(SIGURG -1), X 0 X}; X Xstruct sigvec sig_vec = { X catch, X (1<<(SIGINT -1)) X |(1<<(SIGQUIT-1)) X |(1<<(SIGBUS-1)) X |(1<<(SIGILL-1)) X |(1<<(SIGSEGV-1)) X |(1<<(SIGPIPE-1)) X |(1<<(SIGSYS-1)) X |(1<<(SIGTERM-1)) X |(1<<(SIGTTIN-1)) X |(1<<(SIGTTOU-1)) X |(1<<(SIGXCPU-1)) X |(1<<(SIGXFSZ-1)) X |(1<<(SIGVTALRM-1)), X 0 X}; X X#ifdef RFSDEBUG X Xlong newdebug(); X Xstruct sigvec sig_debug = { X newdebug, X (1<<(SIGTRAP -1)), X 0 X}; X#endif RFSDEBUG X Xstruct stat root; /* stat info for root directory */ SHAREOF chmod 444 remote/serverdata.c # # remote/serverdir.c # if [ -f remote/serverdir.c ]; then echo -n 'Hit <return> to overwrite remote/serverdir.c or ^C to quit' read ans rm -f remote/serverdir.c fi sed -e 's/^.//' << \SHAREOF > remote/serverdir.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: serverdir.c,v $ X * Revision 2.0 85/12/07 18:22:28 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: serverdir.c,v 2.0 85/12/07 18:22:28 toddb Rel $"; X#include "server.h" X#include <sys/dir.h> X#include <sys/stat.h> X#include <errno.h> X Xextern hosts *host; Xextern long errno; Xextern char byteorder[]; Xextern struct stat filetypes[]; X X/* X * Check to see type open file type... we may have to massage input X * it if the user wants to read this file descriptor and it is a directory. X */ Xcheckfiletype(fd) X register int fd; X{ X struct stat statb, *statp = &statb; X X if (fd < 0) X return; X fstat(fd, statp); X filetypes[ fd ] = statb; X} X X/* X * If byte-ordering is different between this machine and our client, X * the directories must be massaged into the right byte order. X */ Xfixdir(fd, buf, size) X register long size, X fd; X register char *buf; X{ X register struct direct *dirp; X register char *next, *last; X register u_char *clientorder = host->h_byteorder; X short fixshort(); X X if (size < 0) X return(errno); X if (fd >= NOFILE || (filetypes[fd].st_mode & S_IFDIR) == 0) X return(0); X X /* X * we don't know this client's byteorder... can't do it right X */ X if (!host->h_mounted) X return(EIO); X dirp = (struct direct *)buf; X last = buf; X debug7("nuxi directory entry buf=0%x, size=%d, end @%x\n", X buf, size, buf+size); X while(last < buf + size && dirp->d_reclen) X { X dirp = (struct direct *)last; X next = last + dirp->d_reclen; X X debug7("dir @0x%x (next+%d @0x%x): %x %x %x %s -->", X last, dirp->d_reclen, next, X dirp->d_ino, X (unsigned)dirp->d_reclen, X (unsigned)dirp->d_namlen, X dirp->d_name); X dirp->d_ino = fixlong(clientorder, &dirp->d_ino); X dirp->d_reclen = fixshort(clientorder, &dirp->d_reclen); X dirp->d_namlen = fixshort(clientorder, &dirp->d_namlen); X debug7(" %x %x %x %s\n", X dirp->d_ino, X (unsigned)dirp->d_reclen, X (unsigned)dirp->d_namlen, X dirp->d_name); X last = next; X } X return(0); X} X Xfixlong(clto, from) X register char *clto, /* clients byte order */ X *from; /* data to be fixed */ X{ X register char *srvo, /* server's byte order */ X *to; X long result; X X to = (char *)&result; X srvo = byteorder; X to[ clto[0] ] = from[ srvo[0] ]; X to[ clto[1] ] = from[ srvo[1] ]; X to[ clto[2] ] = from[ srvo[2] ]; X to[ clto[3] ] = from[ srvo[3] ]; X return(result); X} X Xshort fixshort(clto, from) X register char *clto, /* clients byte order */ X *from; /* data to be fixed */ X{ X register char *srvo, /* server's byte order */ X *to; X short result; X X to = (char *)&result; X srvo = byteorder; X to[ clto[0]&0x1 ] = from[ srvo[0]&0x1 ]; X to[ clto[1]&0x1 ] = from[ srvo[1]&0x1 ]; X return(result); X} SHAREOF chmod 444 remote/serverdir.c # # remote/serverio.c # if [ -f remote/serverio.c ]; then echo -n 'Hit <return> to overwrite remote/serverio.c or ^C to quit' read ans rm -f remote/serverio.c fi sed -e 's/^.//' << \SHAREOF > remote/serverio.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: serverio.c,v $ X * Revision 2.1 86/01/27 11:30:05 toddb X * Changed the h_addr component of the hosts structure to be h_iaddr so X * as not to conflict with the 4.3 define if h_addr in netdb.h. X * X * Revision 2.0 85/12/07 18:22:33 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: serverio.c,v 2.1 86/01/27 11:30:05 toddb Exp $"; X#include <errno.h> X#include <stdio.h> X#include "server.h" X#include <sys/uio.h> X#include <sys/file.h> X#include <netdb.h> X#include <signal.h> X X/* X * This routine prepares to recieve a connection from another process. X * To be any good it must be followed by a call to tcpaccept(). X */ Xextern long errno; Xextern short current_pid; Xextern char *sys_errlist[], X *service, X *logfile, X *stdlogfile, X *getbuf(); Xextern boolean i_am_gateway; Xextern hosts *host; Xextern long serviceport, X errno; Xextern short last_sentry; X Xint read(), X write(); X X/* X * Get ready to accept connections. X */ Xtcppassive() X{ X int f; X struct sockaddr_in sin; X struct servent *servp; X X if ((servp = getservbyname(service, "tcp")) == NULL) X log_fatal("%s: unknown service\n", service); X serviceport = servp->s_port; X X sin.sin_port = serviceport; X sin.sin_addr.s_addr = INADDR_ANY; X sin.sin_family = AF_INET; X X f = socket(AF_INET, SOCK_STREAM, 0); X setsockopt(f, SOL_SOCKET, SO_KEEPALIVE, 0, 0); X setsockopt(f, SOL_SOCKET, SO_REUSEADDR, 0, 0); X X while (bind(f, (caddr_t)&sin, sizeof (sin)) < 0) { X if (last_sentry && errno == EADDRINUSE) X { X log("shutting down old sentry (pid %d)\n", X last_sentry); X if (! sendsig(last_sentry, SIGTERM)) X last_sentry = 0; X sleep(2); /* give it time to die */ X continue; X } X log("cannot bind %s\n", service); X return(-1); X } X X listen(f, 5); X return(f); X} X X/* X * Here we passively accept a connection from another process. X * We return a pointer to the hosts structure. If there is no X * corresponding host for a given connection, we make up a new one X * and return that. X */ Xhosts *tcpaccept(f) X int f; X{ X hosts *h = NULL; X struct sockaddr_in sin; X int g, X i, X len = sizeof (struct sockaddr_in); X X for (i = 0, g = -1; g < 0 && i < 10; i++) { X g = accept(f, &sin, &len); X if (g < 0) X { X log("accept failed\n"); X continue; X } X X /* X * Ok, we have recieved a connection. Find out what we X * know about this fella, and save the command file descriptor X * and the port number. X */ X h = findhostaddr(&sin.sin_addr); X h->h_cmdfd = g; X h->h_portnum = htons((u_short)sin.sin_port); X } X X return(h); X} X X/* X * Call another host's server. We assume that he is using the same service X * as we. X */ Xtcpconnect(h) X register hosts *h; X{ X struct sockaddr_in sin; X register long s; X X bzero((char *)&sin, sizeof (sin)); X bcopy(&h->h_iaddr, (char *)&sin.sin_addr, sizeof(struct in_addr)); X sin.sin_family = AF_INET; X sin.sin_port = serviceport; X s = socket(AF_INET, SOCK_STREAM, 0); X if (s < 0) X { X log("can't get socket to remote server\n"); X return(-1); X } X X /* X * time out on connection rather quickly. X */ X alarm(5); X if (connect(s, (char *)&sin, sizeof (sin)) < 0) { X alarm(0); X log("can't connect to server\n"); X close(s); X return(-1); X } X alarm(0); X return(s); X} X Xalarmsig() X{ X log("timeout\n"); X errno = EINTR; X} X Xlog(x1, x2, x3, x4, x5, x6, x7, x8, x9) X{ X char buf[ BUFSIZ ]; X register char *p = buf; X static boolean printpid = TRUE; X X *p = '\0'; X if (printpid) X { X sprintf(p, "(%d)", current_pid); X p += strlen(p); X if (errno) X { X sprintf(p, "%s: ", sys_errlist[ errno ]); X p += strlen(p); X errno = 0; X } X } X sprintf(p, x1, x2, x3, x4, x5, x6, x7, x8, x9); X p += strlen(p); X if (*(p-1) == '\n') X printpid = TRUE; X else X printpid = FALSE; X write(2, buf, p-buf); X} X Xlog_fatal(x1, x2, x3, x4, x5, x6, x7, x8, x9) X{ X static boolean entered = FALSE; X X if (! entered) X { X entered = TRUE; X log ("fileserver: FATAL ERROR: "); X log (x1, x2, x3, x4, x5, x6, x7, x8, x9); X cleanup(); X } X exit (1); X} X X/* X * Set up the log file for the current process. If there is no current X * host defined, then we are the sentry server and simply use the X * standard logfile: this should be done once only. If 'host' is defined, X * then set up a logfile for this particular connection. X * X * The sentry server always puts his signature at the top of the file X * (pid number). So as a side effect, the global variable last_sentry X * is set to this signature (if there exists one). X */ Xsetlogfile() X{ X char buf[ BUFSIZ ]; X register char *pbuf = buf; X register long newstderr; X boolean sentry = FALSE; X FILE *fd; X X if (logfile) X free (logfile); X if (host == NULL) X { X sentry = TRUE; X strcpy(pbuf, stdlogfile); X } X else X sprintf(pbuf, "%s.%s.%d", X stdlogfile, host->h_names[0], current_pid); X logfile = malloc(strlen(pbuf)+1); X strcpy(logfile, pbuf); X X /* X * Get the previous signature. X */ X if (sentry) X { X if ((fd = fopen(logfile, "r")) != NULL) X { X *pbuf = '\0'; X fgets(pbuf, BUFSIZ, fd); X last_sentry = atoi(pbuf+1); X fclose(fd); X } X } X X newstderr = open(logfile, O_RDWR|O_APPEND|O_CREAT|O_TRUNC, 0444); X if (newstderr < 0) X log_fatal("cannot reopen stderr\n"); X dup2(newstderr, 2); X close(newstderr); X log("startup.\n"); /* put down our signature. */ X} X Xcleanup() X{ X register process *proc; X X if (i_am_gateway && host) X for (proc=host->h_proclist; proc; proc=proc->p_next) X if (proc->p_handler != current_pid) X sendsig(proc->p_handler, SIGKILL); X mourne(); X} X Xsndmsg(fd, msg, msglen, data, len) X register struct message *msg; X register char *data; X register int fd, msglen, len; X{ X register int num; X struct iovec iov[2]; X X X showmsg(msg, TRUE); X /* X * set up for the write and if there is any data to send, try to send X * a bunch of it. X */ X if (len > 0 && data) X { X iov[0].iov_base = (char *)msg; X iov[0].iov_len = msglen; X iov[1].iov_base = data; X iov[1].iov_len = len; X if ((num = writev(fd, iov, 2)) == len + msglen) X { X debug8("wrote data and msg (%d)!!\n", len + msglen); X return(TRUE); X } X debug8("wrote %d of %d msg + data\n", num, len+msglen); X if (num < 0) X return(FALSE); X if (_rmtio(write, fd, data+num, len-num) <= 0) X return(FALSE); X } X else if (_rmtio(write, fd, msg, msglen) <= 0) X return(FALSE); X return(TRUE); X} X X/* X * Read the next message. Its format is null-separated hex-ascii strings. X * In order, they are: X * total_length length of this request X * header_length length of the message request (minus length of data) X * pid Process id on requesting machine X * uid user id of process on requesting machine X * syscall our internal syscall number X * args... between 0 and ? X * X * Followed by actual data (if any). We grab the first two fields, and X * use them for making sure we read all that is necessary. The remainder X * are returned in a array of character pointers. It there is any data X * in this request, then it is pointed to by the last character pointer. X * X * The way that we read messages is as follows: X * X * last message length = 0 X * while no more messages X * do X * if last message length > 0 X * gobbleup last message length bytes X * peek at next message X * if this message is for another process X * then X * wake up the other process X * last message length = 0 X * go to sleep X * continue X * endif X * if data in this message X * then X * read the message X * last message length = 0 X * else X * last message length = length of this message X * endif X * service request X * done X */ X Xstruct message *getmsg(fd) X register long fd; X{ X register long cnt, X lastcnt = 0, X len; X register struct message *msg; X X msg = (struct message *)getbuf(BIGBUF); X /* X * Check to see if there is a message still in the queue, that has X * been processed, but not yet read. X */ X gobble_last_msg(fd, msg); X for (;;) X { X debug8("peek at fd %d... ", fd); X cnt = recv(fd, (char *)msg, BIGBUF, MSG_PEEK); X if (cnt < R_MINRMSG) X { X if (cnt < 0 && errno == EINTR) X continue; X debug8("eof, cnt=%d\n", cnt); X return(NULL); X } X debug8("got %d from peek\n", cnt); X X /* X * Now find out how long the request is (excluding data) X * and make sure that we have at least that amount. X */ X#ifdef magnolia X len = msg->m_hdlen; X#else /* magnolias don't need to do this garbage (MC68000) */ X msg->m_totlen = ntohl(msg->m_totlen); X len = msg->m_hdlen = ntohs(msg->m_hdlen); X msg->m_pid = ntohs(msg->m_pid); X msg->m_uid = ntohs(msg->m_uid); X msg->m_syscall = ntohs(msg->m_syscall); X msg->m_args[0] = ntohl(msg->m_args[0]); X msg->m_args[1] = ntohl(msg->m_args[1]); X msg->m_args[2] = ntohl(msg->m_args[2]); X msg->m_args[3] = ntohl(msg->m_args[3]); X#endif X if (len > cnt) X { X if (cnt == lastcnt) X { X log("most but not all of message is in\n"); X dumpmsg(msg, cnt); X return(NULL); X } X else X debug8("didn't get all of message headder\n"); X lastcnt = cnt; X sleep(5); X } X else if (len < R_MINRMSG) X { X log("bad soft msg len=%d, got %d\n", len, cnt); X dumpmsg(msg, cnt); X if (i_am_gateway) X log_fatal(""); X say_something(S_CORRUPTED, 0); X sendsig(current_pid, SIGSTOP); X } X else X break; X } X showmsg(msg, FALSE); X return(msg); X} X X/* X * Here we format the response to be sent to the client. Note that X * the client can never tolerate a message shorter than X * R_MINRMSG + sizeof(long). The declaration of x0-xf is for the X * sake of stupid Pyramid argument conventions. X */ Xsendreturn(proc, fd, data, cnt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,xa,xb,xc,xd,xe,xf) X process *proc; X register long cnt; X register char *data; X long fd; X{ X char buf[ BUFSIZ ]; X struct message msgbuf; X register struct message *msg = &msgbuf; X register *argp = &x0, msglen, i; X X msg->m_errno = htons(proc->p_errno); X msg->m_pid = htons(proc->p_pid); X msg->m_uid = htons(proc->p_uid); X if (proc->p_errno > 0) /* -1 is valid errno: says its a local file */ X { X msglen = R_MINRMSG + sizeof(long); X msg->m_totlen = htonl(msglen); X proc->p_returnval = -1; X } X else X { X msglen = R_MINRMSG + (cnt+1)*sizeof(long); X if (data) X msg->m_totlen = htonl(msglen + proc->p_returnval); X else X msg->m_totlen = htonl(msglen); X#ifdef pyr /* Pyramid */ X msg->m_args[ R_RETVAL+1 ] = htonl(x0); X msg->m_args[ R_RETVAL+2 ] = htonl(x1); X msg->m_args[ R_RETVAL+3 ] = htonl(x2); X msg->m_args[ R_RETVAL+4 ] = htonl(x3); X msg->m_args[ R_RETVAL+5 ] = htonl(x4); X msg->m_args[ R_RETVAL+6 ] = htonl(x5); X msg->m_args[ R_RETVAL+7 ] = htonl(x6); X msg->m_args[ R_RETVAL+8 ] = htonl(x7); X msg->m_args[ R_RETVAL+9 ] = htonl(x8); X msg->m_args[ R_RETVAL+10 ] = htonl(x9); X msg->m_args[ R_RETVAL+11 ] = htonl(xa); X msg->m_args[ R_RETVAL+12 ] = htonl(xb); X msg->m_args[ R_RETVAL+13 ] = htonl(xc); X msg->m_args[ R_RETVAL+14 ] = htonl(xd); X msg->m_args[ R_RETVAL+15 ] = htonl(xe); X msg->m_args[ R_RETVAL+16 ] = htonl(xf); X#else pyr X for (i=0; i<cnt; i++) X msg->m_args[ R_RETVAL+1+i ] = htonl(argp[ i ]); X#endif X } X msg->m_args[ R_RETVAL ] = htonl(proc->p_returnval); X msg->m_hdlen = htons(msglen); X sndmsg(fd, msg, msglen, data, proc->p_returnval); X errno = 0; X} X X_shutdown(fd) X int fd; X{ X log("shutdown fd %d\n", fd); X close(fd); X} X Xchar *getbuf(size) X{ X static char *buf, *calloc(), *realloc(); X static int cursize; X static int highwater; X X if (size > highwater) X { X if (buf == NULL) X buf = calloc(cursize = size, sizeof(char)); X else X { X buf = realloc(buf, highwater = size); X debug8("resize buffer to %d\n", size); X } X highwater = size; X if (buf == NULL) X log_fatal("cannot allocate buffer space\n"); X } X return(buf); X} X Xchar *get_data_buf(size) X{ X static char *buf, *malloc(), *realloc(); X static int cursize; X static int highwater; X X if (size > highwater) X { X if (buf == NULL) X buf = malloc(cursize = size); X else X { X buf = realloc(buf, highwater = size); X debug8("resize data buffer to %d\n", size); X } X highwater = size; X if (buf == NULL) X log_fatal("cannot allocate data buffer space\n"); X } X return(buf); X} X Xgobble_last_msg(fd, msg) X register long fd; X register struct message *msg; X{ X if (msg->m_totlen) X { X debug8("gobble up last %d byte message... ", msg->m_totlen); X _rmtio(read, fd, msg, msg->m_totlen); X msg->m_totlen = 0; X } X} X X_rmtio(iofunc, fd, buf, len) X register func iofunc; X register int fd, len; X register char *buf; X{ X register int cnt, need = len; X X debug8("io %d bytes, fd=%d...", len, fd); X while(need) X { X if ((cnt = (*iofunc)(fd, buf+len-need, need)) <= 0) X { X _shutdown(fd); X return(cnt); X } X need -= cnt; X } X debug8("did %d.\n", len - need); X return(len); X} X X_rmtiov(iofunc, fd, iovec, len) X register func iofunc; X register int fd, len; X register struct iovec *iovec; X{ X X debug8("io %d vectors, fd=%d...", len, fd); X if ((len = (*iofunc)(fd, iovec, len)) <= 0) X _shutdown(fd); X debug8("did %d.\n", len); X return(len); X} X X/* X * Show the message in characters and hex. X */ Xdumpmsg(msg, len) X char *msg; X long len; X{ X char string[ 100 ], *pstring = string, X words[ 100 ], *pwords = words, X dwords[ 100 ], *pdwords = dwords, X longs[ 100 ], *plongs = longs, X *p; X long cnt = 0; X X for(p = msg; cnt<len; cnt++, p++) X { X /* character */ X if (*p >= ' ') X sprintf(pstring, "%c ", *p > '~' ? '?' : *p); X else X sprintf(pstring, "^%c ", *p | 0x40); X pstring += 3; X if ((cnt & 0x1) == 0) X { X sprintf(pwords, "%-4.4x ", X *((unsigned short *)p)); X sprintf(pdwords, "%-5.5d ", X *((unsigned short *)p)); X pwords += 6; X pdwords += 6; X } X if ((cnt & 0x3) == 0) X { X sprintf(plongs, "%-8.8x ", *((long *)p)); X plongs += 12; X } X if (pstring >= string+72) X { X log("%s\n", pstring = string); X log("%s\n", pwords = words); X log("%s\n", pdwords = dwords); X log("%s\n\n", plongs = longs); X } X } X log("%s\n", string); X log("%s\n", words); X log("%s\n", dwords); X log("%s\n", longs); X} X X#ifdef RFSDEBUG X Xshowmsg(msg, fromserver) X register struct message *msg; X long fromserver; X{ X register long end, len, pid, uid, totlen; X X if ((remote_debug & 0x100) == 0) X return; X if (fromserver) X len = ntohs(msg->m_hdlen), X totlen = ntohl(msg->m_totlen), X pid = ntohs(msg->m_pid), X uid = ntohs(msg->m_uid); X else X len = msg->m_hdlen, X totlen = msg->m_totlen, X pid = msg->m_pid, X uid = msg->m_uid; X log("%s server: len=%d,tot=%d,pid=%d,uid=%d", X fromserver ? "from" : "to", len, totlen, pid, uid); X X /* round up into long words */ X len = (len - R_MINRMSG + 3) >> 2; X if (fromserver) X { X log(",errno=%d,retval=%d", X htons(msg->m_errno), htonl(msg->m_args[ R_RETVAL ])); X end = R_RETVAL+1; X } X else X { X log(",syscall=%d", msg->m_syscall); X end = 0; X } X for (; end<len; end++) X log(",0x%x", ntohl(msg->m_args[ end ])); X log("\n"); X} X X/* X * Set new debug levels. X */ Xnewdebug() X{ X register long fd, cnt; X char *dbfile = "/usr/tmp/rfs_debug", X buf[ BUFSIZ ]; X register char *p = buf; X X fd = open(dbfile, O_RDONLY); X if (fd < 0) { X log("can't open %s\n", dbfile); X goto out; X } X X cnt = read(fd, buf, BUFSIZ); X close(fd); X if (cnt <= 0) { X log("can't read %s\n", dbfile); X goto out; X } X X while ((*p >= 'a' && *p <= 'f') X || (*p >= 'A' && *p <= 'F') X || (*p >= '0' && *p <= '9')) X p++; X *p = '\0'; X remote_debug = atox(buf); Xout: X log("debug=%x\n", remote_debug); X} X#endif RFSDEBUG SHAREOF chmod 444 remote/serverio.c # # remote/serversyscall.c # if [ -f remote/serversyscall.c ]; then echo -n 'Hit <return> to overwrite remote/serversyscall.c or ^C to quit' read ans rm -f remote/serversyscall.c fi sed -e 's/^.//' << \SHAREOF > remote/serversyscall.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: serversyscall.c,v $ X * Revision 2.1 86/01/27 10:47:30 toddb X * s_execinfo() was returning the wrong error if the access permission X * was wrong: ENOEXEC. It now returns EACCESS. Thanks to Joe Othemer@vax135. X * X * Revision 2.0 85/12/07 18:22:44 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: serversyscall.c,v 2.1 86/01/27 10:47:30 toddb Exp $"; X#include "server.h" X#include <sys/stat.h> X#include <sys/dir.h> X#include <sys/file.h> X#include <sys/user.h> X#include <errno.h> X Xextern char *syscallnames[]; Xextern short current_pid; Xextern short gateway_server; Xextern boolean i_am_gateway; Xextern boolean in_root_directory; Xextern syscallmap smap[]; Xextern struct stat filetypes[]; Xextern hosts *host; Xextern long errno; X Xs_fork(msg, proc) X register struct message *msg; X register process *proc; X{ X register process *newproc; X register long newpid = msg->m_args[ 0 ], X i, fd; X register short syscall = msg->m_syscall; X boolean needtofork = FALSE; X X if (newproc = findprocess(newpid, msg->m_uid)) X debug1("%d = %sfork(%d), redundant\n", X newpid, syscall == RSYS_vfork ? "v" : "", X msg->m_args[ 1 ]); X else X { X debug1("%d = %sfork(%d)\n", X newpid, syscall == RSYS_vfork ? "v" : "", X proc->p_pid); X newproc = add_new_process(msg->m_uid, newpid); X for (i=0; i<NOFILE; i++) X if ((fd = proc->p_fds[ i ]) >= 0) X newproc->p_fds[ i ] = fd, needtofork = TRUE; X X if (needtofork) X become_server(msg); X else if (! i_am_gateway) X say_something(S_NEWPROCESS, newpid); X } X /* X * No return message is sent! X */ X} X Xs_read(msg, proc) X register struct message *msg; X register process *proc; X{ X register long clientfd = msg->m_args[0], X fd, X size = msg->m_args[1]; X register char *buf = get_data_buf(size); X X fd = MAPFD(clientfd, proc); X proc->p_returnval = read(fd, buf, size); X proc->p_errno = fixdir(fd, buf, proc->p_returnval); X debug1("%d = read(%d->%d, 0x%x, %d);\n", X proc->p_returnval, clientfd, fd, buf, size); X sendreturn(proc, host->h_cmdfd, buf, 0); X} X Xs_write(msg, proc) X register struct message *msg; X register process *proc; X{ X register long clientfd = msg->m_args[0], X fd, X size = msg->m_args[1], X totlen = msg->m_totlen; X register char *buf; X X if (totlen > BIGBUF) X msg = (struct message *)getbuf(totlen); X buf = (char *)&msg->m_args[R_DATA]; X gobble_last_msg(host->h_cmdfd, msg); X fd = MAPFD(clientfd, proc); X proc->p_returnval = write(fd, buf, size); X proc->p_errno = errno; X debug1("%d = write(%d->%d, 0x%x, %d);\n", X proc->p_returnval, clientfd, fd, buf, size); X sendreturn(proc, host->h_cmdfd, NULL, 0); X} X X/* X * Open a file. Also interface for creat(). Note that we pass back X * the current file offset. X */ Xs_open(msg, proc) X struct message *msg; X register process *proc; X{ X#define mask args[ 3 ] X#define clientfd args[ 2 ] X#define mode args[ 1 ] X#define flags args[ 0 ] X X register long ourfd, X *args = msg->m_args; X register char *path = path1addr(msg); X X change_to_umask(mask); X ourfd = open(path, flags, mode); X proc->p_errno = errno; X proc->p_returnval = allocate_fd(ourfd, proc, clientfd); X debug1("%d = open(\"%s\", 0%o, %d)\n", X proc->p_returnval, path, flags, mode); X sendreturn(proc, host->h_cmdfd, NULL, 1, lseek(ourfd, 0, L_INCR)); X X#undef mask X#undef clientfd X#undef mode X#undef flags X} X Xs_fd1(msg, proc) X register struct message *msg; X register process *proc; X{ X register long clientfd = msg->m_args[0], X fd, X syscall = msg->m_syscall; X X fd = MAPFD(clientfd, proc); X /* X * No return sent for close or fsync! X */ X if (syscall == RSYS_close || syscall == RSYS_fsync) X proc->p_returnval = deallocate_fd(proc, msg->m_args[0]); X else X { X proc->p_returnval = (*smap[ syscall ].s_syscall)(fd); X proc->p_errno = errno; X if (syscall != RSYS_fsync) X sendreturn(proc, host->h_cmdfd, NULL, 0); X } X debug1("%d = %s(%d->%d)\n", X proc->p_returnval, syscallnames[ syscall ], clientfd, fd); X} X Xs_fd1_plus(msg, proc) X register struct message *msg; X register process *proc; X{ X#define arg1 msg->m_args[1] X#define arg2 msg->m_args[2] X register long clientfd = msg->m_args[0], X fd; X X fd = MAPFD(clientfd, proc); X proc->p_returnval = (*smap[ msg->m_syscall ].s_syscall)(fd, arg1, arg2); X proc->p_errno = errno; X debug1("%d = %s(%d->%d, %d(0%o), %d(0%o))\n", X proc->p_returnval, syscallnames[ msg->m_syscall ], X clientfd, fd, arg1, arg1, arg2, arg2); X sendreturn(proc, host->h_cmdfd, NULL, 0); X#undef arg1 X#undef arg2 X} X X/* X * link, symlink and rename X */ Xs_path2(msg, proc) X register struct message *msg; X register process *proc; X{ X#define mask msg->m_args[0] X register char *path1, *path2; X register short syscall = msg->m_syscall; X X change_to_umask(mask); X path2 = twopath2addr(msg); X path1 = twopath1addr(msg); X proc->p_returnval = (*smap[ syscall ].s_syscall)(path1, path2); X proc->p_errno = errno; X debug1("%d = %s(\"%s\", \"%s\")\n", syscallnames[ syscall ], X proc->p_returnval, path1, path2); X sendreturn(proc, host->h_cmdfd, NULL, 0); X#undef mask X} X Xs_path1(msg, proc) X register struct message *msg; X register process *proc; X{ X register char *path; X register short syscall = msg->m_syscall; X register long mask = msg->m_args[0]; X struct stat statb; X extern struct stat root; X register struct stat *statp = &statb; X X change_to_umask(mask); X path = path1addr(msg); X proc->p_returnval = (*smap[ syscall ].s_syscall)(path); X proc->p_errno = errno; X debug1("%d = %s(\"%s\")\n", X proc->p_returnval, syscallnames[ syscall ], path); X if (syscall == RSYS_chdir) X if (proc->p_returnval == -1) X debug1("can't chdir to %s\n", path); X else X { X if (stat(".", statp) == 0 && isroot(statp)) X in_root_directory = TRUE; X else X in_root_directory = FALSE; X debug10("Now I'm %sin root\n", X !in_root_directory ? "not " : ""); X } X sendreturn(proc, host->h_cmdfd, NULL, 0); X} X Xs_access(msg, proc) X register struct message *msg; X register process *proc; X{ X register char *path; X register long perm = msg->m_args[0]; X X path = path1addr(msg); X X /* X * The kernel access is strange: it first sets the effective uid X * and gid to be the real uid/gid and THEN it does the access. X * Well, our real uid is always 0 (so we can change our effective X * uid at will), so the effect is different than a normal user X * would expect. i.e. access always succeeds no matter what X * the arguments. This is clearly not what we want, so we apply X * an awful kludge here; change our real uid to be the user we X * are pretending to be, and then call access. X */ X change_to_uid(0); X setreuid(proc->p_ruser->r_user->u_local_uid, 0); X proc->p_returnval = access(path, perm); X proc->p_errno = errno; X debug1("%d = access(\"%s\", 0%o\n", proc->p_returnval, path, perm); X setreuid(0, 0); X sendreturn(proc, host->h_cmdfd, NULL, 0); X} X Xs_path1_plus(msg, proc) X register struct message *msg; X register process *proc; X{ X register char *path; X register long syscall = msg->m_syscall, X arg1 = msg->m_args[0], X arg2 = msg->m_args[1], X mask = msg->m_args[2]; X X path = path1addr(msg); X change_to_umask(mask); X X proc->p_returnval = (*smap[ syscall ].s_syscall)(path, arg1, arg2); X proc->p_errno = errno; X debug1("%d = %s(\"%s\", %d(0%o), %d(%o))\n", X proc->p_returnval, X syscallnames[ syscall ], path, arg1, arg1, arg2, arg2); X sendreturn(proc, host->h_cmdfd, NULL, 0); X} X Xs_stat(msg, proc) X register struct message *msg; X register process *proc; X{ X union a { X char *path; X long fd; X } arg; X register short syscall = msg->m_syscall; X register long clientfd = msg->m_args[0]; X struct stat statbuf; X register struct stat *statp = &statbuf; X X if (syscall == RSYS_fstat) X arg.fd = MAPFD(clientfd, proc); X else X arg.path = path1addr(msg); X proc->p_returnval = (*smap[ syscall ].s_syscall)(arg.path, statp); X proc->p_errno = errno; X#ifdef RFSDEBUG X if (syscall == RSYS_fstat) X debug1("%d = fstat(%d->%d, 0x%x)\n", X proc->p_returnval, clientfd, arg.fd, &statbuf); X else X debug1("%d = %s(\"%s\", 0x%x)\n", proc->p_returnval, X syscallnames[ syscall ], arg.path, &statbuf); X#endif RFSDEBUG X if (proc->p_returnval == -1) X sendreturn(proc, host->h_cmdfd, NULL, 0); X else X sendreturn(proc, host->h_cmdfd, NULL, 14, X statp->st_dev, X statp->st_ino, X statp->st_mode, X statp->st_nlink, X statp->st_uid, X statp->st_gid, X statp->st_rdev, X statp->st_size, X statp->st_atime, X statp->st_mtime, X statp->st_ctime, X statp->st_blksize, X statp->st_blocks, X isroot(statp)); X} X Xs_lseek(msg, proc) X register struct message *msg; X register process *proc; X{ X register long clientfd = msg->m_args[0], fd; X X fd = MAPFD(clientfd, proc); X proc->p_returnval = lseek(fd, msg->m_args[1], msg->m_args[2]); X proc->p_errno = errno; X debug1("%d = lseek(%d->%d, %d, %d)\n", proc->p_returnval, X clientfd, fd, msg->m_args[1], msg->m_args[2]); X if (msg->m_syscall == RSYS_lseek) X sendreturn(proc, host->h_cmdfd, NULL, 0); X} X Xs_dup(msg, proc) X register struct message *msg; X register process *proc; X{ X register long clientfd = msg->m_args[0], fd, X newclientfd = msg->m_args[1], X ourfd, X newfd; X X fd = MAPFD(clientfd, proc); X if (msg->m_syscall == RSYS_dup2) X { X newfd = MAPFD(newclientfd, proc); X if (newfd >= 0) X { X proc->p_returnval = deallocate_fd(proc, newclientfd, 0); X debug1("%d = (dup2)close(%d->%d)... ", X proc->p_returnval, newclientfd, newfd); X } X } X if (fd >= 0) X { X ourfd = dup(fd); X proc->p_returnval = allocate_fd(ourfd, proc, newclientfd); X proc->p_errno = errno; X } X else if (msg->m_syscall == RSYS_dup2 && newfd >= 0) X proc->p_returnval = newclientfd; X else X { X proc->p_returnval = -1; X proc->p_errno = EINVAL; X } X debug1("%d = dup(%d->%d)\n", proc->p_returnval, clientfd, fd); X sendreturn(proc, host->h_cmdfd, NULL, 0); X} X Xs_ioctl(msg, proc) X struct message *msg; X process *proc; X{ X long fd = msg->m_args[0]; X} X Xs_readlink(msg, proc) X register struct message *msg; X register process *proc; X{ X register long size = msg->m_args[0]; X register char *buf = get_data_buf(size), X *path = path1addr(msg); X X proc->p_returnval = readlink(path, buf, size); X proc->p_errno = errno; X debug1("%d = readlink(\"%s\", 0x%x, %d);\n", X proc->p_returnval, path, buf, size); X sendreturn(proc, host->h_cmdfd, buf, 0); X} X X/* X * Send exec information the remote host. X */ Xs_execinfo(msg, proc) X register struct message *msg; X register process *proc; X{ X register long hdrsize = msg->m_args[ 0 ], X red, X err = 0, X msglen = R_MINRMSG + sizeof(long)*R_EXECDATA; X register char *path = path1addr(msg), X *p; X struct stat st; X struct message msgbuf; X X errno = 0; X if (hdrsize > (R_MAXARGS - R_EXECDATA)*sizeof(long)) X { X log("exec: hdrsize = %d!!\n", hdrsize); X err = EINVAL; X goto done; X } X /* X * Start building the outgoing message... get header, X * check permissions and open file. X */ X msg = &msgbuf; X if ((proc->p_execfd = open(path, O_RDONLY)) == -1) X goto done; X fstat(proc->p_execfd, &st); X if ((st.st_mode & S_IFMT) != S_IFREG X || ! myaccess(&st, proc->p_ruser->r_user, X_OK)) X { X err = EACCES; X debug12("%s mode=0%o %sreg file, %sexecutable\n", X path, st.st_mode, X (st.st_mode & S_IFMT) != S_IFREG ? "not " : "", X myaccess(&st, proc->p_ruser->r_user, X_OK) ? X "" : "not "); X goto done; X } X msg->m_args[ R_EXECREADONLY ] = X (myaccess(&st, proc->p_ruser->r_user, W_OK) == FALSE); X msg->m_args[R_EXECDATA] = 0; /* for zero-length files */ X red = read(proc->p_execfd, msg->m_args + R_EXECDATA, hdrsize); X if (red <= 0) X { X debug12("read on exec fd %d=%d\n", proc->p_execfd, red); X err = EINVAL; X goto done; X } X msglen += red; X X X /* X * Check setuid/setgid info X */ X if (st.st_mode & S_ISUID) X msg->m_args[ R_EXECUID ] = htonl(st.st_uid); X else X msg->m_args[ R_EXECUID ] = htonl(-1); X if (st.st_mode & S_ISGID) X msg->m_args[ R_EXECGID ] = htonl(st.st_gid); X else X msg->m_args[ R_EXECGID ] = htonl(-1); X Xdone: X proc->p_execstarted = FALSE; X msg->m_hdlen = htons(msglen); X msg->m_totlen = htonl(msglen); X if (errno) X err = errno; X if (err) X { X debug12("execinfo: err=%d\n", err); X close(proc->p_execfd); X proc->p_execfd = -1; X } X debug1("%d = execve(\"%s\");\n", proc->p_returnval, path); X if (msg->m_errno = htons(err)) X msg->m_args[ R_RETVAL ] = htonl(-1); X else X msg->m_args[ R_RETVAL ] = htonl(st.st_size); X msg->m_pid = htons(proc->p_pid); X msg->m_uid = htons(proc->p_uid); X sndmsg(host->h_cmdfd, msg, msglen, 0, 0); X} X X/* X * Send exec text and data to remote host. X */ Xs_execread(msg, proc) X struct message *msg; X process *proc; X{ X register long fd = proc->p_execfd, X hdrsize = msg->m_args[0], X size = msg->m_args[1], X red; X register char *buf = get_data_buf(size); X X if (!proc->p_execstarted) X { X if (lseek(fd, hdrsize, 0) != hdrsize) X { X log("can't seek to %d on fd %d for exec\n", X hdrsize, fd); X proc->p_errno = EINVAL; X } X proc->p_execstarted = TRUE; X } X if (size) X { X proc->p_returnval = read(fd, buf, size); X proc->p_errno = errno; X debug1("%d = execread(%d)\n", proc->p_returnval, size); X } X else /* all done; send no return */ X { X proc->p_returnval = close(proc->p_execfd); X proc->p_execfd = -1; X debug1("%d = execread(%d)\n", proc->p_returnval, size); X return; X } X X sendreturn(proc, host->h_cmdfd, buf, 0); X} X Xs_utimes(msg, proc) X struct message *msg; X process *proc; X{ X char *path; X struct timeval tv[2]; X X path = path1addr(msg); X tv[0].tv_sec = msg->m_args[0]; X tv[0].tv_usec = msg->m_args[1]; X tv[1].tv_sec = msg->m_args[2]; X tv[1].tv_usec = msg->m_args[3]; X X X proc->p_returnval = utimes(path, tv); X proc->p_errno = errno; X debug1("%d = utimes(\"%s\", 0x%x\n", proc->p_returnval, path, tv); X sendreturn(proc, host->h_cmdfd, NULL, 0); X} X X/* X * Let a process exit. X */ Xs_exit(msg, proc) X struct message *msg; X process *proc; X{ X long otherprocs = 0; X process *p2; X X /* X * No return message sent! X */ X debug1("exit()\n"); X deletelist(&host->h_proclist, proc); X freeproc(proc); X if (! i_am_gateway) X { X for (proc=host->h_proclist; proc; proc=proc->p_next) X if (proc->p_handler == current_pid) X otherprocs++; X if (otherprocs == 0) X { X gobble_last_msg(host->h_cmdfd, msg); X say_something(S_ALLDONE, 0); X mourne(); X exit(0); X } X else X say_something(S_PROCEXIT, msg->m_pid); X } X} X Xnoop(msg, proc) X struct message *msg; X process *proc; X{ X extern long errno; X X log("*** FUNCTION IGNORED ***\n", proc->p_pid); X proc->p_returnval = -1; X proc->p_errno = EINVAL; X sendreturn(proc, host->h_cmdfd, NULL, 0); X} SHAREOF chmod 444 remote/serversyscall.c # # remote/shells/makemake # if [ -f remote/shells/makemake ]; then echo -n 'Hit <return> to overwrite remote/shells/makemake or ^C to quit' read ans rm -f remote/shells/makemake fi sed -e 's/^.//' << \SHAREOF > remote/shells/makemake X#!/bin/sh XMAKEFILE=Makefile X Xcase "$1" in X"") X echo "Usage: $0 <machinetype>" X exit 1 X ;; XM68) X MAKEFILE=M68 X ;; Xesac X Xif [ ! -f make.base.$1 ] Xthen X echo No machine type $1 supported. X exit 1 Xfi X Xcat make.base.$1 make.base > $MAKEFILE SHAREOF chmod 755 remote/shells/makemake # # remote/shells/mkdist # if [ -f remote/shells/mkdist ]; then echo -n 'Hit <return> to overwrite remote/shells/mkdist or ^C to quit' read ans rm -f remote/shells/mkdist fi sed -e 's/^.//' << \SHAREOF > remote/shells/mkdist X#!/bin/sh X XFILES=' X remote/README X remote/*.[ch] X remote/doc X remote/make.* X remote/shells X remote/usr.*' X XFILES=`echo $FILES` Xcd .. Xtar cvhf - $FILES > remote/remotefs.tar SHAREOF chmod 755 remote/shells/mkdist # # remote/shells/mkdist.shar # if [ -f remote/shells/mkdist.shar ]; then echo -n 'Hit <return> to overwrite remote/shells/mkdist.shar or ^C to quit' read ans rm -f remote/shells/mkdist.shar fi sed -e 's/^.//' << \SHAREOF > remote/shells/mkdist.shar X#!/bin/sh X XFILES=' X remote/README X remote/*.[ch] X remote/doc X remote/make.* X remote/shells X remote/usr.*' X Xset -x Xcd .. Xshar $FILES Xmv shar.? remote X X# X# put in the count X# XCOUNT=`ls remote/shar.? | grep -c .` Xcnt=1 Xwhile [ $cnt -le $COUNT ] Xdo X Xed remote/shar.$cnt << EOF X1a X# X# RFS, a kernel-resident remote file system. Shar $cnt of $COUNT X# X. Xw Xq XEOF X cnt=`expr $cnt + 1` Xdone X X# X# add in the intro X# Xed remote/shar.1 << \EOF X1i XThese seven shar files contain the software and documentation for Xinstallation, maintenance and adjustment of RFS, a public domain, Xkernel-resident distributed file system, written at Tektronix Computer XResearch Laboratories* by me for partial fulfillment of the master's Xdegree program at the University of Denver. It was designed to provide Xcomplete transparency with respect to file access and protections for Xall programs whether they use local or remote files and directories. XIt has been installed on VAX BSD 4.2 and 4.3 UNIX, Pyramid 4.2/5.0 XUNIX, version 2.5, and on a Tektronix internal proprietary workstation, Xcalled Magnolia. The instructions are designed in a way that keeps all Xchanges separate from your standard sources, in hope that it will Xencourage sites to try the installation. X X Todd Brunhoff X toddb%crl@tektronix.csnet X decvax!tektronix!crl!toddb X X* RFS should not be confused with another completely different (but X excellent) implementation from Tektronix available on the 6000 series X workstation, called DFS, and done by a separate product group. The X work on RFS was designed and written strictly by the author of this X paper at about the same time as DFS, and draws none of its X implementation details from DFS. RFS is public domain, while DFS is X proprietary. X X. Xw Xq XEOF SHAREOF chmod 755 remote/shells/mkdist.shar # # remote/shells/rfs_clean # if [ -f remote/shells/rfs_clean ]; then echo -n 'Hit <return> to overwrite remote/shells/rfs_clean or ^C to quit' read ans rm -f remote/shells/rfs_clean fi sed -e 's/^.//' << \SHAREOF > remote/shells/rfs_clean X#!/bin/sh X Xcd /usr/tmp Xfor file in rfs_log.*.* Xdo X pid=`expr "$file" : '.*\.\(.*\)'` X result=`kill -19 $pid 2>&1` X case "$result" in X *"No such process") (set -x; rm -f $file);; X esac Xdone SHAREOF chmod 755 remote/shells/rfs_clean # # remote/shells/rfs_kerninstall # if [ -f remote/shells/rfs_kerninstall ]; then echo -n 'Hit <return> to overwrite remote/shells/rfs_kerninstall or ^C to quit' read ans rm -f remote/shells/rfs_kerninstall fi sed -e 's/^.//' << \SHAREOF > remote/shells/rfs_kerninstall X#!/bin/sh X X# X# Install script for added RFS kernel sources. X# X NL=' X' X SRC=$1 X DEST=$2 X VER=$3 X USAGE="${NL}Usage: $0 src-dir dest-dir VAX4.3|VAX4.2|PYR2.5" XRemove_start= X Remove_end= X Delete= X X# X# Figure out what software we are running... X# Xcase "$VER" in XVAX4.3) Remove_start='^#else[ ]BSD4_3' X Remove_end='^#endif[ ]BSD4_3' X Delete='^#ifdef[ ]BSD4_3' X ;; XVAX4.2) Remove_start='^#ifdef[ ]BSD4_3' X Remove_end='^#else[ ]BSD4_3' X Delete='^#endif[ ]BSD4_3' X ;; XPYR2.5) Remove_start='^#ifdef[ ]BSD4_3' X Remove_end='^#else[ ]BSD4_3' X Delete='^#endif[ ]BSD4_3' X ;; X*) echo "$0: Unknown type = $VER" \ X "$USAGE" X exit 1 X ;; Xesac Xif [ "$SRC" = "" -o ! -d "$SRC" \ X -o "$DEST" = "" -o ! -d "$DEST" ] Xthen X echo "Either \"$SRC\" or \"$DEST\" is not a directory!" \ X "$USAGE" X exit 1 Xfi X Xfor file in `ls $SRC` Xdo X echo -n "${NL}$file " X sed -e "/$Remove_start/,/$Remove_end/d" \ X -e "/$Delete/d" \ X < $SRC/$file > $DEST/$file Xdone Xchmod 0755 $DEST/remote_mkdata Xecho SHAREOF chmod 755 remote/shells/rfs_kerninstall # # remote/shells/rfs_kernpatch # if [ -f remote/shells/rfs_kernpatch ]; then echo -n 'Hit <return> to overwrite remote/shells/rfs_kernpatch or ^C to quit' read ans rm -f remote/shells/rfs_kernpatch fi sed -e 's/^.//' << \SHAREOF > remote/shells/rfs_kernpatch X#!/bin/sh X# X# Kernel level setup for compiling RFS. X# XCHANGELIST=' h/errno.h X h/param.h X h/user.h X sys/init_sysent.c X sys/kern_exec.c X sys/kern_exit.c X sys/ufs_syscalls.c' XCHANGE_42=' sys/sys_inode.c X sys/ufs_nami.c X sys/uipc_socket.c X machine/trap.c X conf/files' XCHANGE_43=' sys/ufs_namei.c X machine/trap.c X conf/files' XCHANGE_PYR=' sys/kern_trap.c' X PATCHES=$1 X SRC=$2 X DEST=$3 X VER=$4 X USAGE="Usage: $0 patch-dir src-dir dest-dir VAX4.3|VAX4.2|PYR2.5" X NL=' X' X Xif [ ! -d "$PATCHES" -o ! -d "$SRC" -o ! -d "$DEST" ] Xthen X echo "One of \"$PATCHES\", \"$SRC\" or \"$DEST\" is not a directory" \ X "$NL$USAGE" X exit 1 Xfi X Xcase "$VER" in XVAX4.3) CHANGELIST="$CHANGELIST $CHANGE_43" X if [ -f $SRC/conf/Makefile.vax ] X then X CHANGELIST="$CHANGELIST conf/Makefile.vax" X else X CHANGELIST="$CHANGELIST conf/makefile.vax" X fi X ;; XVAX4.2) CHANGELIST="$CHANGELIST $CHANGE_42 conf/makefile.vax" ;; XPYR2.5) CHANGELIST="$CHANGELIST $CHANGE_PYR conf/makefromsource" ;; X*) echo "Invalid version = \"$VER\"$NL$USAGE" X exit 1 X ;; Xesac X X# X# copy the target files for the patches. X# Xcase "$DEST" in X X$SRC) ;; # no need to copy X X*) echo "Copy in files that must be changed..." X (cd $DEST; rm -f $CHANGELIST) X for file in $CHANGELIST X do X (set -x; cp $SRC/$file $DEST/$file) X done X ;; Xesac X(cd $DEST; chmod 0644 $CHANGELIST) X X# X# do the patches X# Xfor file in $CHANGELIST Xdo X while : X do X echo -n "${NL}${NL}Hit <return> to patch" \ X "$file or 'n' to skip: " X read prompt X case "$prompt" in X "") (set -x; patch $DEST/$file $PATCHES/$file.diff) X ;; X n) ;; X *) echo "Enter <return> or the letter 'n' only!" X continue X ;; X esac X break X done Xdone SHAREOF chmod 755 remote/shells/rfs_kernpatch # # remote/shells/rfs_setup # if [ -f remote/shells/rfs_setup ]; then echo -n 'Hit <return> to overwrite remote/shells/rfs_setup or ^C to quit' read ans rm -f remote/shells/rfs_setup fi sed -e 's/^.//' << \SHAREOF > remote/shells/rfs_setup X#!/bin/sh X# X# Setup for compiling RFS. X# XPWD=`pwd` XKERNELDIRS=' conf X h X net X netimp X netinet X remote X sys' XKDIRS_42=' vax X vaxif X vaxmba X vaxuba X netpup' XKDIRS_43=' vax X vaxif X vaxmba X vaxuba X bbnnet X netns' XKDIRS_PYR=' ether X io X kernel X kernel_m X ml X netpup X vls' XINCLUDEFILE=syscall.h X NL=' X' XEXECDIR=`expr $0 : '\(.*\)\/.*'` X X# X# Figure out what software they are running... X# Xwhile : Xdo X echo -n "Are you running" \ X "${NL} 1. VAX 4.3 BSD" \ X "${NL} 2. VAX 4.2 BSD" \ X "${NL} 3. Pyramid 2.5 (4.2/5.0)" \ X "${NL}enter 1, 2 or 3: " X read ans X case "$ans" in X 1) VER=VAX4.3 X MACH=vax X KERNELDIRS="$KERNELDIRS $KDIRS_43" X ;; X 2) VER=VAX4.2 X MACH=vax X KERNELDIRS="$KERNELDIRS $KDIRS_42" X ;; X 3) VER=PYR2.5 X MACH=pyr X KERNELDIRS="$KERNELDIRS $KDIRS_PYR" X ;; X *) echo "only 1, 2 and 3 are supported..." X continue X ;; X esac X break; Xdone X X# X# Find out the sys directory X# XSYSDIR= Xwhile : Xdo X echo -n "${NL}${NL}What is the top-level path of your kernel source" \ X "${NL}directory (normally it is /usr/sys)? " X read ans X if [ "$ans" = "" -o ! -d "$ans" ] X then X echo "...but \"$ans\" is not a directory!" X continue X fi X X # X # Ensure that the path begins with / X # X case "$ans" in X /*) ;; X *) echo "\"$ans\" must begin with '/'" X continue X ;; X esac X X SYSDIR=$ans X break Xdone X X# X# ask if the changes are to be permanent X# Xwhile : Xdo X echo -n "${NL}${NL}Do you want these changes" \ X "$NL 1. installed in $SYSDIR and in /usr/include" \ X "$NL 2. installed in this directory (reccomended 1st pass)" \ X "${NL}enter 1 or 2: " X read ans X case "$ans" in X 1) DEST=$SYSDIR X INCLUDEDIR=/usr/include X ;; X 2) DEST=$PWD/sys X INCLUDEDIR=usr.include X ;; X *) echo "only 1 or 2 allowed." X continue X ;; X esac X break Xdone X X Xumask 022 Xcase "$DEST" in X X"$SYSDIR") # don't need to make local directories, 'cept one. X mkdir $SYSDIR/remote X ;; X X*) # X # make directories X # X echo "${NL}${NL}Make kernel source directories in `pwd` ..." X ERR= X mkdir sys X for dir in $KERNELDIRS X do X mkdir sys/$dir X X case "$dir" in X remote) continue;; # don't check its existence... X esac X X if [ ! -d $SYSDIR/$dir ] X then X echo "Kernel sources not in $SYSDIR/$dir ???" X ERR=true X fi X done X case "$ERR" in X "") ;; X *) exit 1;; X esac X X case "$VER" in X VAX4.2|VAX4.3) (cd sys; ln -s vax machine);; X esac X X # X # make the symbolic links X # X for dir in $KERNELDIRS X do X case "$dir" in X remote) continue;; X esac X X echo "Make symbolic links from $DEST/$dir/*" \ X "${NL}to $SYSDIR/$dir/*..." X (cd $DEST/$dir; ln -s $SYSDIR/$dir/* .) X done X ;; Xesac X X# X# move the remote kernel stuff into place... X# Xecho "${NL}${NL}Copy $PWD/remote/usr.sys.remote/* files" \ X "${NL}to $DEST/remote (and remove" \ X "${NL}#ifdef BSD4_3 at the same time)..." X$EXECDIR/rfs_kerninstall $PWD/remote/usr.sys.remote $DEST/remote $VER X X# X# Now run patch on each files to install X# the changes necessary. X# Xcat <<EOF X X XI will now install all the kernel changes for you in X$DEST with the 'patch' utility, so you must have that Xprogram to continue. You will be given an opportunity to either suspend Xthis program or kill it before each file is patched so that you may Xmake adjustments as you think of them. You may also skip the patches Xif you know that they are already installed (Better be sure, though). X XFor the C-source files with the exception of two bug fixes, all changes Xwill be installed between the control statements: X X#ifdef REMOTEFS X#endif REMOTEFS X XEOF X X$EXECDIR/rfs_kernpatch remote/usr.sys.$VER $SYSDIR $DEST $VER X$EXECDIR/rfs_userpatch remote/usr.include.$VER $INCLUDEDIR $DEST X Xcat <<EOF X X XRfs software is set up and ready for compilation. See the installation Xmanual. X XEOF SHAREOF chmod 755 remote/shells/rfs_setup # # remote/shells/rfs_userpatch # if [ -f remote/shells/rfs_userpatch ]; then echo -n 'Hit <return> to overwrite remote/shells/rfs_userpatch or ^C to quit' read ans rm -f remote/shells/rfs_userpatch fi sed -e 's/^.//' << \SHAREOF > remote/shells/rfs_userpatch X#!/bin/sh X# X# User-level software setup for compiling RFS. X# Xumask 02 X PATCHES=$1 XINCLUDEDIR=$2 X SYS=$3 X NL=' X' X Xecho "$NL" X Xif [ ! -d $PATCHES -o ! -d $SYS ] Xthen X echo "Either \"$PATCHES\" or \"$SYS\" is not a directory" X exit 1 Xfi X X# X# Make the proper include directories if they don't already exist. X# link in remotefs.h and param.h X# Xif [ ! -d $INCLUDEDIR ] Xthen X mkdir $INCLUDEDIR Xfi Xif [ ! -d $INCLUDEDIR/remote ] Xthen X mkdir $INCLUDEDIR/remote Xfi Xif [ ! -d $INCLUDEDIR/sys ] Xthen X mkdir $INCLUDEDIR/sys Xfi X Xrm -f $INCLUDEDIR/remote/remotefs.h $INCLUDEDIR/sys/param.h X Xln -s $SYS/remote/remotefs.h $INCLUDEDIR/remote/remotefs.h Xln -s $SYS/h/param.h $INCLUDEDIR/sys/param.h X X# X# Finally make the change to syscall.h. If the changes go in usr.include, X# then assume that we must copy it there first. Otherwise, we make the X# changes in place. X# Xcase "$INCLUDEDIR" in X X/usr/include) ;; X X*) rm -f $INCLUDEDIR/syscall.h X cat /usr/include/syscall.h > $INCLUDEDIR/syscall.h X ;; Xesac X Xwhile : Xdo X echo -n "${NL}${NL}Hit <return> to patch" \ X "$INCLUDEDIR/syscall.h or 'n' to skip: " X read prompt X case "$prompt" in X "") (set -x; patch $INCLUDEDIR/syscall.h $PATCHES/syscall.h.diff) X ;; X n) ;; X *) echo "Enter <return> or the letter 'n' only!" X continue X ;; X esac X break Xdone SHAREOF chmod 755 remote/shells/rfs_userpatch # # remote/usr.include.PYR2.5/syscall.h.diff # if [ -f remote/usr.include.PYR2.5/syscall.h.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.include.PYR2.5/syscall.h.diff or ^C to quit' read ans rm -f remote/usr.include.PYR2.5/syscall.h.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.include.PYR2.5/syscall.h.diff XIf the changes to sys/init_sysent.c succeeded, then this should be fine. XIf not, you should check that the system call numbers added coincide with Xthose in sys/init_sysent.c. X*************** X*** 154,159 X /* 152 thru 165 reserved */ X #define SYS_setprocesshost 166 X #define SYS_getprocesshost 167 X X /* X * BTL system call header table. X X--- 154,162 ----- X /* 152 thru 165 reserved */ X #define SYS_setprocesshost 166 X #define SYS_getprocesshost 167 X+ #define SYS_remoteon 168 X+ #define SYS_remoteoff 169 X+ #define SYS_remotename 170 X X /* X * BTL system call header table. SHAREOF chmod 664 remote/usr.include.PYR2.5/syscall.h.diff # # remote/usr.include.VAX4.2/syscall.h.diff # if [ -f remote/usr.include.VAX4.2/syscall.h.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.include.VAX4.2/syscall.h.diff or ^C to quit' read ans rm -f remote/usr.include.VAX4.2/syscall.h.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.include.VAX4.2/syscall.h.diff XIf the changes to sys/init_sysent.c succeeded, then this should be fine. XIf not, you should check that the system call numbers added coincide with Xthose in sys/init_sysent.c. X*************** X*** 150,152 X #define SYS_setquota 148 X #define SYS_quota 149 X #define SYS_getsockname 150 X X--- 150,155 ----- X #define SYS_setquota 148 X #define SYS_quota 149 X #define SYS_getsockname 150 X+ #define SYS_remoteon 151 X+ #define SYS_remoteoff 152 X+ #define SYS_remotename 153 SHAREOF chmod 664 remote/usr.include.VAX4.2/syscall.h.diff # # remote/usr.src.lib.libc/Makefile # if [ -f remote/usr.src.lib.libc/Makefile ]; then echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/Makefile or ^C to quit' read ans rm -f remote/usr.src.lib.libc/Makefile fi sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/Makefile X# X# This makefile is present only to build a temporary libc... until X# you decide that the files compiled here should be installed in the X# source directory. This makefile should not be installed anywhere. X# XOBJS= remotename.o remoteon.o remoteoff.o errlst.o XSRC=/usr/src XLIBSRC=${SRC}/lib/libc XUSR_INCLUDE=../../usr.include XLIBDIR=/lib X Xnothing: X echo "Nothing made!" X echo "You must type 'make vax' or 'make pyr'" X Xvax: /tmp X make INCLUDE="-I${LIBSRC}/vax/sys -I${USR_INCLUDE}" \ X MACHTYPE=vax \ X SUFFIX=c \ X LIBDIR=${LIBDIR} \ X SRC=${SRC} \ X install X Xpyr: /tmp X make INCLUDE="-I${USR_INCLUDE}" \ X MACHTYPE=pyr \ X SUFFIX=s \ X LIBDIR=${LIBDIR} \ X SRC=${SRC} \ X install X Xnewlibc.a: ${OBJS} libc.a X cp libc.a newlibc.a X ar cru newlibc.a ${OBJS} X Xinstall: newlibc.a libc.a X -cp ${LIBDIR}/libc.a ${LIBDIR}/libc.a.bak X cp newlibc.a ${LIBDIR}/libc.a X ranlib ${LIBDIR}/libc.a X Xlibc.a: /lib/libc.a X cp /lib/libc.a . X Xerrlst.o: errlst.c Xremotename.o remoteon.o remoteoff.o: Xremotename.o: ${MACHTYPE}/sys/remotename.${SUFFIX} X /lib/cpp ${INCLUDE} -E $? | ${AS} -o $@ X -ld -x -r $@ X mv a.out $@ Xremoteon.o: ${MACHTYPE}/sys/remoteon.${SUFFIX} X /lib/cpp ${INCLUDE} -E $? | ${AS} -o $@ X -ld -x -r $@ X mv a.out $@ Xremoteoff.o: ${MACHTYPE}/sys/remoteoff.${SUFFIX} X /lib/cpp ${INCLUDE} -E $? | ${AS} -o $@ X -ld -x -r $@ X mv a.out $@ X Xerrlst.c: ${LIBSRC}/gen/errlst.c X cp ${LIBSRC}/gen/errlst.c nerrlst.c X patch nerrlst.c gen/${MACHTYPE}.errlst.c.diff X mv nerrlst.c errlst.c SHAREOF chmod 664 remote/usr.src.lib.libc/Makefile # # remote/usr.src.lib.libc/gen/pyr.errlst.c.diff # if [ -f remote/usr.src.lib.libc/gen/pyr.errlst.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/gen/pyr.errlst.c.diff or ^C to quit' read ans rm -f remote/usr.src.lib.libc/gen/pyr.errlst.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/gen/pyr.errlst.c.diff XThese changes being installed should be just fine if you were able to make Xthe earlier changes to h/errno.h. Otherwise, you must install these changes Xby hand. X*************** X*** 82,88 X "Too many processes", /* 67 - EPROCLIM */ X "Too many users", /* 68 - EUSERS */ X "Disc quota exceeded", /* 69 - EDQUOT */ X! "","","","","","","","","","", /* 70-79 - spare */ X "","","","","","","","","","", /* 80-89 - spare */ X "","","","","","","","","","", /* 90-99 - spare */ X X X--- 82,91 ----- X "Too many processes", /* 67 - EPROCLIM */ X "Too many users", /* 68 - EUSERS */ X "Disc quota exceeded", /* 69 - EDQUOT */ X! "File is on remote host", /* 70 - EISREMOTE */ X! "Too many remote hosts defined", /* 71 - ETOOMANYREMOTE */ X! "No remote file system", /* 72 - ENOREMOTEFS */ X! "","","","","","","", /* 73-79 - spare */ X "","","","","","","","","","", /* 80-89 - spare */ X "","","","","","","","","","", /* 90-99 - spare */ X SHAREOF chmod 664 remote/usr.src.lib.libc/gen/pyr.errlst.c.diff # # remote/usr.src.lib.libc/gen/vax.errlst.c.diff # if [ -f remote/usr.src.lib.libc/gen/vax.errlst.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/gen/vax.errlst.c.diff or ^C to quit' read ans rm -f remote/usr.src.lib.libc/gen/vax.errlst.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/gen/vax.errlst.c.diff XThese changes being installed should be just fine if you were able to make Xthe earlier changes to h/errno.h. Otherwise, you must install these changes Xby hand. X*************** X*** 81,85 X "Too many processes", /* 67 - EPROCLIM */ X "Too many users", /* 68 - EUSERS */ X "Disc quota exceeded", /* 69 - EDQUOT */ X }; X int sys_nerr = { sizeof sys_errlist/sizeof sys_errlist[0] }; X X--- 81,88 ----- X "Too many processes", /* 67 - EPROCLIM */ X "Too many users", /* 68 - EUSERS */ X "Disc quota exceeded", /* 69 - EDQUOT */ X+ "File is on remote host", /* 70 - EISREMOTE */ X+ "Too many remote hosts defined", /* 71 - ETOOMANYREMOTE */ X+ "No remote file system", /* 72 - ENOREMOTEFS */ X }; X int sys_nerr = { sizeof sys_errlist/sizeof sys_errlist[0] }; SHAREOF chmod 664 remote/usr.src.lib.libc/gen/vax.errlst.c.diff