home *** CD-ROM | disk | FTP | other *** search
- #include <fcntl.h>
- #include <errno.h>
- #include <stdio.h>
- #include "nels.h"
-
- /*
- * A unix process has a limited, usually small number of
- * file descriptors available to it.
- * A simulator for such a process which also uses file
- * descriptors itself, must stop the simulated process
- * from interfering with the simulator's file descriptors
- * but otherwise maintain as normal a set of file descriptors
- * for use by the process as possible.
- * The routines in this file attempt to accomplish this.
- */
-
- #define FD_CLOSED ((fd_t)-1)
- #define NFDOHEAD 2
-
- #define fd_valid_fd(fd) ((fd) >= 0 && (fd) < nfiles)
-
- typedef int fd_t;
-
- extern int setobuf();
-
- extern int errno;
- extern FILE *outfp;
-
- static int nfiles = -1;
- static fd_t *map; /* map: simfd -> realfd */
- static int fdoverhead[NFDOHEAD];
-
- int
- fd_hold()
- {
- int i;
-
- for (i = 0; i < nels(fdoverhead); i++)
- {
- if ((fdoverhead[i] = open("/dev/null", O_RDONLY)) == -1)
- {
- vcouldnot("open(\"/dev/null\", O_RDONLY)");
- return -1;
- }
-
- if (fcntl(fdoverhead[i], F_SETFD, 1) == -1)
- {
- vcouldnot("fcntl(%d, F_SETFD, 1)", fdoverhead[i]);
- (void)close(fdoverhead[i]);
- return -1;
- }
- }
-
- return 0;
- }
-
- int
- fd_release()
- {
- int i;
-
- for (i = 0; i < nels(fdoverhead); i++)
- {
- if (fdoverhead[i] != -1)
- {
- (void)close(fdoverhead[i]);
- fdoverhead[i] = -1;
- }
- }
-
- return 0;
- }
-
- #if 0
- static
- void
- fd_dump()
- {
- int fd;
-
- fprintf(outfp, "map (%d):", fileno(outfp));
- for (fd = 0; fd < nfiles; fd++)
- {
- if (map[fd] == FD_CLOSED)
- continue;
-
- if (map[fd] == fd)
- continue;
-
- fprintf(outfp, " %d->%d", fd, map[fd]);
- }
- fprintf(outfp, "\n");
- fflush(outfp);
- }
- #endif /* 0 */
-
- /*
- * Initialise our file descriptor map.
- * We record all file descriptors that
- * we have inherited at birth.
- * fd_init() must be called before the
- * simulator starts opening any files for its own
- * internal use.
- * 'outfd' != -1 iff the output file descriptor
- * has been explicitly passed to us via a
- * command line argument.
- */
- int
- fd_init(outfd)
- int outfd;
- {
- int fd;
-
- if ((nfiles = ulimit(4, 0)) == -1)
- {
- couldnot("get descriptor table size");
- return -1;
- }
-
- if ((map = (fd_t *)malloc(sizeof(fd_t) * nfiles)) == (fd_t *)0)
- {
- couldnot("allocate %d bytes for descriptor table map", sizeof(fd_t) * nfiles);
- return -1;
- }
-
- for (fd = 0; fd < nfiles; fd++)
- {
- if (fcntl(fd, F_GETFD, 0) == -1)
- {
- if (errno != EBADF)
- {
- couldnot("interpret error returned by fcntl(%d, F_GETFD, ..)", fd);
- return -1;
- }
- errno = 0;
-
- map[fd] = FD_CLOSED;
- }
- else
- map[fd] = fd;
- }
-
- if (outfd != -1)
- map[outfd] = FD_CLOSED;
-
- if (fd_hold() == -1)
- return -1;
-
- return 0;
- }
-
- int
- fd_sort()
- {
- int sim_outfd;
- int real_outfd;
- int fd;
- fd_t *rmap;
-
- #if 0
- fd_dump();
- #endif /* 0 */
-
- if (fd_release() == -1)
- return -1;
-
- if ((rmap = (fd_t *)malloc(sizeof(fd_t) * nfiles)) == (fd_t *)0)
- {
- vcouldnot("allocate %d bytes for reverse descriptor table map", sizeof(fd_t) * nfiles);
- return -1;
- }
-
- fflush(outfp);
- if ((sim_outfd = fd_open(fileno(outfp))) == -1)
- return -1;
-
- for (fd = 0; fd < nfiles; fd++)
- rmap[fd] = FD_CLOSED;
-
- for (fd = 0; fd < nfiles; fd++)
- {
- if (map[fd] != FD_CLOSED)
- rmap[map[fd]] = fd;
- }
-
- for (fd = 0; fd < nfiles; fd++)
- {
- if (rmap[fd] == fd)
- continue;
-
- if (rmap[fd] != FD_CLOSED)
- {
- int newfd;
-
- if ((newfd = dup(fd)) == -1)
- {
- vcouldnot("dup(%d)", fd);
- return -1;
- }
- rmap[newfd] = rmap[fd];
- map[rmap[fd]] = newfd;
- if (close(fd) == -1)
- {
- vcouldnot("close(%d)", fd);
- return -1;
- }
- rmap[fd] = FD_CLOSED;
- }
-
- if (map[fd] == FD_CLOSED)
- continue;
-
- if (dup2(map[fd], fd) == -1)
- {
- vcouldnot("dup2(%d, %d)", map[fd], fd);
- return -1;
- }
-
- rmap[fd] = fd;
- if (close(map[fd]) == -1)
- {
- vcouldnot("close(%d)", map[fd]);
- return -1;
- }
- rmap[map[fd]] = FD_CLOSED;
- map[fd] = fd;
- }
-
- real_outfd = map[sim_outfd];
-
- if (real_outfd != fileno(outfp))
- {
- FILE *newoutfp;
-
- if ((newoutfp = fdopen(real_outfd, "a")) == (FILE *)0)
- {
- vcouldnot("fdopen(%d, \"a\")", real_outfd);
- return -1;
- }
- (void)fclose(outfp);
- outfp = newoutfp;
-
- if (setobuf() == -1)
- return -1;
- }
-
- (void)fd_close(sim_outfd);
-
- (void)free((char *)rmap);
-
- if (fd_hold() == -1)
- return -1;
-
- #if 0
- fd_dump();
- #endif /* 0 */
-
- return 0;
- }
-
- /*
- * Given a good, real file descriptor,
- * return a simulated file descriptor and
- * mark it as allocated.
- */
- int
- fd_open(real_fd)
- int real_fd;
- {
- int sim_fd;
-
- for (sim_fd = 0; sim_fd < nfiles; sim_fd++)
- {
- if (map[sim_fd] == FD_CLOSED)
- {
- map[sim_fd] = real_fd;
- return sim_fd;
- }
- }
-
- vcouldnot("open real file descriptor %d: internal error: ran out of simulated file descriptors", real_fd);
- return -1;
- }
-
- /*
- * Given a good, real file descriptor,
- * and an unallocated simulated file descriptor,
- * mark it as allocated.
- */
- void
- fd_dopen(real_fd, sim_fd)
- int real_fd;
- int sim_fd;
- {
- map[sim_fd] = real_fd;
- }
-
- /*
- * Unmap a simulated file descriptor.
- */
- int
- fd_close(sim_fd)
- int sim_fd;
- {
- if (fd_valid_fd(sim_fd))
- map[sim_fd] = FD_CLOSED;
-
- return 0;
- }
-
- /*
- * Return the current mapping for a simulated
- * file descriptor, or -1 if it is not mapped.
- */
- int
- fd_lookup(sim_fd)
- int sim_fd;
- {
- if (fd_valid_fd(sim_fd) == 0)
- return -1;
-
- if (map[sim_fd] == FD_CLOSED)
- return -1;
-
- return map[sim_fd];
- }
-
- int
- fd_invalid(sim_fd)
- int sim_fd;
- {
- if (fd_valid_fd(sim_fd))
- return 0;
-
- errno = EBADF;
-
- return 1;
- }
-
- int
- fd_nfiles()
- {
- return nfiles;
- }
-