/* Bypass Copyright (C) 1999-2001 Douglas Thain http://www.cs.wisc.edu/condor/bypass This program is released under a BSD License. See the file COPYING for details. */ /* This Bypass file declares the major UNIX I/O calls as RPCs. With this module, a program can send all its I/O to be performed on the shadow. Notice that no agent_action or shadow_action is specified for any entry. The default agent_action is to perform an RPC, and the default shadow action is to invoke the procedure as normal. */ #ifdef linux #define POLL_NFDS_T unsigned long #define IOCTL_CMD_T unsigned long #else #define POLL_NFDS_T nfds_t #define IOCTL_CMD_T int #endif /* Operations on file descriptors */ int open( in string const char *path, int flags, [int mode] ); /* Close will refuse to close the Bypass private fd, even if a broken application attempts to do so. */ int close( int fd ) shadow_action {{ if(fd!=global_bypass_fd) { return close(fd); } else { return 0; } }}; ssize_t read( int fd, out opaque "length" void *data, size_t length ); ssize_t write( int fd, in opaque "length" const void *data, size_t length ); off_t lseek( int fd, off_t where, int whence ); int fstat( int fd, out struct stat *s ); int lstat( in string const char *path, out struct stat *s ); int dup( int ofd ); int dup2( int ofd, int nfd ); int fsync( int fd ); int ftruncate( int fd, off_t length ); int fchdir( int fd ); int isatty( int fd ); /* Note carefully that poll() is much more easily transported over the network. It does not depend particularly on the size of any data structure. On the other hand, select() depends on the size of fd_set, so it will not work between two systems that define fd_set differently. This could be better. One option here would be to define a remote select() in terms of a remote poll(). */ int poll( in out array "nfds" struct pollfd *ufds, POLL_NFDS_T nfds, int timeout ); int select( int nfds, in out opaque "sizeof(fd_set)" fd_set *r, in out opaque "sizeof(fd_set)" fd_set *w, in out opaque "sizeof(fd_set)" fd_set *e, in out struct timeval *timeout ); /* Operations on names */ int stat( in string const char *path, out struct stat *s ); int unlink( in string const char *name ); int rename( in string const char *oldname, in string const char *newname ); int chdir( in string const char *path ); int access( in string const char *path, int mode ); int link( in string const char *oldname, in string const char *newname ); int symlink( in string const char *oldname, in string const char *newname ); int chmod( in string const char *path, mode_t mode ); int chown( in string const char *path, uid_t owner, gid_t group ); int lchown( in string const char *path, uid_t owner, gid_t group ); int truncate( in string const char *path, off_t length ); int mkdir( in string const char *path, mode_t mode ); int rmdir( in string const char *path ); /* Operations on directories */ DIR *opendir( in string const char *dir ); int closedir( DIR *dir ); /* readdir() is somewhat complicated, for two reasons. First, it has a strange interface, returning a pointer to a static byffer, which is not very RPC friendly. To fix this, we simply add a helper function called internal_readdir which instead passes the pointed data as an argument. Second, it has a structure that varies drastically between platforms. It has a variety of subfields that vary in existence and meaning, as well as a string value that is sometimes declared with length zero. There is no way to pass this in standards-compliant manner, as POSIX only tells us that d_name field can be relied upon, yet all sorts of software relies on the other fields. So, for this call, we give up on portability and simply pass it as a an opaque buffer. */ struct dirent * readdir( DIR *dir ) agent_action {{ int result; static union { struct dirent d; char buffer[4096]; } u; memset(&u.d,0,sizeof(u)); result = bypass_shadow_internal_readdir(dir,&u.d,sizeof(u)); if(result==0) { return &u.d; } else { return 0; } }}; int internal_readdir( DIR *dir, out opaque "length" struct dirent *od, int length ) shadow_action {{ struct dirent *d; d = readdir(dir); if(d) { memcpy(od,d,length); return 0; } else { return -1; } }}; /* Unsupported operations */ int ioctl( int fd, IOCTL_CMD_T cmd, [int arg] ) agent_action {{ errno = EINVAL; return -1; }}; int fcntl( int fd, int cmd, [int arg] ) agent_action {{ errno = EINVAL; return -1; }};