diff options
author | Joe Hunkeler <jhunkeler@gmail.com> | 2015-08-11 16:51:37 -0400 |
---|---|---|
committer | Joe Hunkeler <jhunkeler@gmail.com> | 2015-08-11 16:51:37 -0400 |
commit | 40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch) | |
tree | 4464880c571602d54f6ae114729bf62a89518057 /unix/os/zfiobf.c | |
download | iraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz |
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'unix/os/zfiobf.c')
-rw-r--r-- | unix/os/zfiobf.c | 888 |
1 files changed, 888 insertions, 0 deletions
diff --git a/unix/os/zfiobf.c b/unix/os/zfiobf.c new file mode 100644 index 00000000..d3fd18ff --- /dev/null +++ b/unix/os/zfiobf.c @@ -0,0 +1,888 @@ +/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <ctype.h> +#include <unistd.h> + +# ifndef O_NDELAY +#include <fcntl.h> +# endif + +#include <errno.h> +#include <stdio.h> + +#define import_kernel +#define import_knames +#define import_zfstat +#define import_spp +#include <iraf.h> + +/* + * ZFIOBF -- FIO interface to UNIX 4.1BSD binary files. + * This is the interface to general, random access disk resident binary + * files (as opposed to text files). The basic strategy is very simple. + * FIO will request an asynchronous read or write of N device blocks at + * a given offset. The offset (one-indexed) is guaranteed by FIO to be + * aligned on a device block boundary, and to be in bounds. The size of + * a device block and of a file are determined at open time by FIO, which + * calls the zsttbf status routine. + * + * FIO ASSUMES that it can extend a file by writing at EOF in an ordinary + * zawrbf call with the appropriate one-indexed byte offset. If the last + * block in the file is a partial block, FIO will write at some device + * block offset within the file, after first reading the partial block + * into the FIO buffer. FIO will never write a partial block within + * a file, but assumes it can do so at the end of the file. If the OS + * does not support irregular length files, the interface routines should + * simulate it somehow. The FIO buffer is an integral number of SPP chars + * in size, and read requests (in units of bytes) will always be for an integral + * number of chars. + * + * In UNIX 4.1BSD, there is no such thing as asynchronous i/o, so we have + * to fake it. Also, the UNIX i/o interface is sequential/seek, while the + * FIO interface is absolute offset, so we have to keep track of the file + * position to avoid a seek on every i/o access. + */ + +int _u_fmode (int mode); +int vm_access (char *fname, int mode); +int vm_reservespace (long nbytes); +int vm_largefile (long nbytes); +int vm_directio (int fd, int flag); + + +/* ZOPNBF -- Open a binary file. The file must exist for modes RO, WO, RW. + * A new file will always be created for mode NF, and a file will be created + * if it does not exist for mode AP. Append mode is write-only at EOF. + * It is also legal to open RW and append by seeking to EOF and writing, + * if more generality is required. + */ +int +ZOPNBF ( + PKCHAR *osfn, /* UNIX name of file */ + XINT *mode, /* file access mode */ + XINT *chan /* file number (output) */ +) +{ + register int fd; + struct stat filstat; + + /* Open or create file with given access mode. + */ + switch (*mode) { + case READ_ONLY: + /* The O_NDELAY is necessary for some types of special devices, + * e.g., a FIFO, and should be harmless for other file types. + */ + if ((fd = open ((char *)osfn, O_RDONLY|O_NDELAY)) != ERR) + fcntl (fd, F_SETFL, O_RDONLY); + break; + case WRITE_ONLY: + if ((fd = open ((char *)osfn, O_WRONLY|O_NDELAY)) != ERR) + fcntl (fd, F_SETFL, O_WRONLY); + break; + + case READ_WRITE: + fd = open ((char *)osfn, O_RDWR); + break; + + case NEW_FILE: + /* Create file and then reopen for read-write access. + */ + if ((fd = creat ((char *)osfn, _u_fmode(FILE_MODEBITS))) != ERR) { + close (fd); + fd = open ((char *)osfn, 2); + } + break; + + case APPEND: + /* It is legal to append to a nonexistent file. We merely create + * a new, zero length file and append to it. Read access is + * required on a binary file opened for appending, since FIO has + * to read the partial block at the end of the file before it can + * append to it. + */ + if (access ((char *)osfn, 0) == ERR) + close (creat ((char *)osfn, _u_fmode(FILE_MODEBITS))); + fd = open ((char *)osfn, 2); + break; + + default: + fd = ERR; + } + + /* Initialize the kernel file descriptor. Seeks are illegal if the + * device is a character special device; the device is a "streaming" + * file (blksize=1) if it can only be accessed sequentially. + */ + if (fd != ERR && stat ((char *)osfn, &filstat) == ERR) { + close (fd); + fd = ERR; + } + + /* Don't set *chan until we have successfully finished opening the + * file, otherwise any error occuring during the open will try to + * close the partially opened file. + */ + if (fd == ERR) { + *chan = XERR; + } else if (fd >= MAXOFILES) { + close (fd); + if (*mode == NEW_FILE) + unlink ((char *)osfn); + *chan = XERR; + } else { + zfd[fd].fp = NULL; + zfd[fd].fpos = 0L; + zfd[fd].nbytes = 0; + zfd[fd].flags = (filstat.st_mode & S_IFCHR) ? KF_NOSEEK : 0; + zfd[fd].filesize = filstat.st_size; + if (!vm_access ((char *)osfn, *mode)) + zfd[fd].flags |= KF_DIRECTIO; + *chan = fd; + } + + return (*chan); +} + + +/* ZCLSBF -- Close a binary file. + */ +int +ZCLSBF (XINT *fd, XINT *status) +{ + extern int errno; + + /* This is a bit of a kludge, but closing a FIFO pipe opened for + * reading (probably attempting the close before the writer has + * closed the connection) causes an EPERM error on the close. + * This is harmless and only causes the VOS task to report an + * error, so ignore the error. + */ + if ((*status = (close (*fd) == ERR) ? XERR : XOK) == XERR) + if (errno == EPERM) + *status = XOK; + + return (*status); +} + + +/* ZARDBF -- "Asynchronous" binary block read. Initiate a read of at most + * maxbytes bytes from the file FD into the buffer BUF. Status is returned + * in a subsequent call to ZAWTBF. + */ +int +ZARDBF ( + XINT *chan, /* UNIX file number */ + XCHAR *buf, /* output buffer */ + XINT *maxbytes, /* max bytes to read */ + XLONG *offset /* 1-indexed file offset to read at */ +) +{ + register struct fiodes *kfp; + register int fd; + off_t fileoffset; + int aligned; + off_t lseek(); + + fd = *chan; + kfp = &zfd[fd]; + fileoffset = *offset - 1L; + + /* If reading from a device on which seeks are illegal, offset should + * be zero (as when called by ZARDCL). Otherwise, we must seek to + * the desired position. + */ + if (*offset > 0 && kfp->fpos != fileoffset) { + if ((kfp->fpos = lseek(fd,fileoffset,0)) == ERR) { + kfp->nbytes = ERR; + return (XERR); + } + } + + /* Disable direct i/o if transfers are not block aligned. */ + aligned = (!(fileoffset % SZ_DISKBLOCK) && !(*maxbytes % SZ_DISKBLOCK)); + if ((kfp->flags & KF_DIRECTIO) && !aligned) + kfp->flags &= ~KF_DIRECTIO; + + if (kfp->flags & KF_DIRECTIO) + vm_directio (fd, 1); + + if ((kfp->nbytes = read (fd, (char *)buf, *maxbytes)) > 0) + kfp->fpos += kfp->nbytes; + + if (kfp->flags & KF_DIRECTIO && aligned) + vm_directio (fd, 0); + + return (XOK); +} + + +/* ZAWRBF -- "Asynchronous" binary block write. Initiate a write of exactly + * nbytes bytes from the buffer BUF to the file FD. Status is returned in a + * subsequent call to ZAWTBF. + */ +int +ZAWRBF ( + XINT *chan, /* UNIX file number */ + XCHAR *buf, /* buffer containing data */ + XINT *nbytes, /* nbytes to be written */ + XLONG *offset /* 1-indexed file offset */ +) +{ + register int fd; + register struct fiodes *kfp; + off_t fileoffset; + off_t lseek(); + int aligned; + + fd = *chan; + kfp = &zfd[fd]; + fileoffset = *offset - 1L; + + /* If writing to a device on which seeks are illegal, offset should + * be zero (as when called by ZAWRCL). Otherwise, we must seek to + * the desired position. + */ + if (*offset > 0 && kfp->fpos != fileoffset) + if ((kfp->fpos = lseek(fd,fileoffset,0)) == ERR) { + kfp->nbytes = ERR; + return (XERR); + } + + /* Disable direct i/o if transfers are not block aligned. */ + aligned = (!(fileoffset % SZ_DISKBLOCK) && !(*nbytes % SZ_DISKBLOCK)); + if ((kfp->flags & KF_DIRECTIO) && !aligned) + kfp->flags &= ~KF_DIRECTIO; + + if (kfp->flags & KF_DIRECTIO) { + vm_directio (fd, 1); + } else if (vm_largefile((long)offset) || vm_largefile((long)*nbytes)) { + /* Reserve VM space if writing at EOF. */ + struct stat st; + if (!fstat(fd,&st) && fileoffset >= st.st_size) + vm_reservespace (fileoffset + *nbytes - st.st_size); + } + + if ((kfp->nbytes = write (fd, (char *)buf, *nbytes)) > 0) + kfp->fpos += kfp->nbytes; + + if (kfp->flags & KF_DIRECTIO) + vm_directio (fd, 0); + + /* Invalidate cached file size, forcing a UNIX system call to determine + * the file size the next time ZSTTBF is called. + */ + kfp->filesize = -1; + + return (XOK); +} + + +/* ZAWTBF -- "Wait" for an "asynchronous" read or write to complete, and + * return the number of bytes read or written, or ERR. + */ +int +ZAWTBF (XINT *fd, XINT *status) +{ + if ((*status = zfd[*fd].nbytes) == ERR) + *status = XERR; + + return (*status); +} + + +/* ZSTTBF -- Return status on a binary file. The same status routine is used + * for both blocked (random access) and streaming (sequential) binary files. + * All character special devices are considered to be streaming files, although + * such is not necessarily the case. Seeks are illegal on character special + * devices. The test for file type is made when the file is opened. + */ +int +ZSTTBF (XINT *fd, XINT *param, XLONG *lvalue) +{ + register struct fiodes *kfp = &zfd[*fd]; + struct stat filstat; + + switch (*param) { + case FSTT_BLKSIZE: + /* If all disk devices do not have the same block size then + * device dependent code should be substituted for the reference + * to SZ_DISKBLOCK below. + */ + if (kfp->flags & KF_NOSEEK) + (*lvalue) = 1L; + else + (*lvalue) = SZ_DISKBLOCK; + break; + + case FSTT_FILSIZE: + /* The file size is undefined if the file is a streaming file. + * For blocked files the file size is determined at open time + * and cached in the kernel file descriptor. The cached value + * is updated when we are called and invalidated whenever the file + * is written to. It is not worthwhile trying to keep track of + * the file size in the kernel because FIO only calls us to + * determine the filesize once, at open time. Caching the size + * saves us one FSTAT system call at open time. + */ + if (kfp->flags & KF_NOSEEK) + (*lvalue) = 0L; + else if ((*lvalue = kfp->filesize) < 0) { + if (fstat ((int)*fd, &filstat) == ERR) + (*lvalue) = XERR; + else + (*lvalue) = kfp->filesize = filstat.st_size; + } + break; + + case FSTT_OPTBUFSIZE: + /* On some systems this parameter may be device dependent in which + * case device dependent code should be substituted here. + */ + (*lvalue) = BF_OPTBUFSIZE; + break; + + case FSTT_MAXBUFSIZE: + /* On some systems this parameter may be device dependent in which + * case device dependent code should be substituted here. + */ + (*lvalue) = BF_MAXBUFSIZE; + break; + + default: + (*lvalue) = XERR; + break; + } + + return (XOK); +} + + +/* _U_FMODE -- Compute the effective file mode, taking into account the + * current process umask. (A no-op at present). + */ +int _u_fmode (int mode) +{ + return (mode); +} + + +/* + * VMcache client interface + * + * vm_access (fname, mode) + * vm_reservespace (nbytes) + * vm_directio (fd, flag) + * + * This small interface implements a subset of the client commands provided + * by the VMcache daemon (virtual memory cache controller). The client + * interface handles connection to the VMcache daemon (if any) transparently + * within the interface. + */ +#include <signal.h> + +#ifdef LINUX +#define USE_SIGACTION +#endif + +#define DEF_ACCESSVAL 1 +#define ENV_VMPORT "VMPORT" +#define ENV_VMCLIENT "VMCLIENT" +#define DEF_VMTHRESH (1024*1024*8) +#define DEF_DIOTHRESH (1024*1024*8) +#define DEF_VMPORT 8677 +#define SZ_CMDBUF 2048 +#define SZ_CNAME 32 + +#ifdef MACOSX +static int vm_enabled = 0; +static int vm_dioenabled = 1; +#else +static int vm_enabled = 1; +static int vm_dioenabled = 0; +#endif + +static int vm_debug = 0; +static int vm_server = 0; +static int vm_initialized = 0; +static int vm_threshold = DEF_VMTHRESH; +static int dio_threshold = DEF_DIOTHRESH; +static int vm_port = DEF_VMPORT; +static char vm_client[SZ_CNAME+1]; + +extern char *getenv(); +extern char *realpath(); +static void vm_initialize(); +static void vm_shutdown(); +static void vm_identify(); +static int vm_write(); +static int vm_connect(); +static int getstr(); + + + +/* VM_ACCESS -- Access a file via the VM subsystem. A return value of 1 + * indicates that the file is (or will be) "cached" in virtual memory, i.e., + * that normal virtual memory file system (normal file i/o) should be used + * to access the file. A return value of 0 indicates that direct i/o should + * be used to access the file, bypassing the virtual memory file system. + */ +int +vm_access (char *fname, int mode) +{ + struct stat st; + char *modestr = NULL, buf[SZ_COMMAND]; + char pathname[SZ_PATHNAME]; + int status; + + + /* One-time process initialization. */ + if (!vm_initialized) + vm_initialize(); + + if (stat (fname, &st) < 0) { + status = DEF_ACCESSVAL; + goto done; + } + + /* If directio is enabled and the file exceeds the directio threshold + * use directio to access the file (access=0). If vmcache is + * disabled use normal VM-based i/o to access the file (access=1). + * If VMcache is enabled we still only use it if the file size + * exceeds vm_threshold. + */ + if (vm_dioenabled) { + status = (st.st_size >= dio_threshold) ? 0 : 1; + goto done; + } else if (!vm_enabled || st.st_size < vm_threshold) { + status = DEF_ACCESSVAL; + goto done; + } + + /* Use of VMcache is enabled and the file equals or exceeds the + * minimum size threshold. Initialization has already been performed. + * Open a VMcache daemon server connection if we don't already have + * one. If the server connection fails we are done, but we will try + * to open a connection again in the next file access. + */ + if (!vm_server) + if (vm_connect() < 0) { + status = DEF_ACCESSVAL; + goto done; + } + + /* Compute the mode string for the server request. */ + switch (mode) { + case READ_ONLY: + modestr = "ro"; + break; + case NEW_FILE: + case READ_WRITE: + case APPEND: + modestr = "rw"; + break; + } + + /* Format and send the file access directive to the VMcache daemon. + * The status from the server is returned as an ascii integer value + * on the same socket. + */ + sprintf (buf, "access %s %s\n", realpath(fname,pathname), modestr); + if (vm_write (vm_server, buf, strlen(buf)) < 0) { + vm_shutdown(); + status = DEF_ACCESSVAL; + goto done; + } + if (read (vm_server, buf, SZ_CMDBUF) <= 0) { + if (vm_debug) + fprintf (stderr, + "vmclient (%s): server not responding\n", vm_client); + vm_shutdown(); + status = DEF_ACCESSVAL; + goto done; + } + + status = atoi (buf); +done: + if (vm_debug) + fprintf (stderr, "vmclient (%s): access `%s' -> %d\n", + vm_client, fname, status); + + return (status < 0 ? DEF_ACCESSVAL : status); +} + + +/* VM_DELETE -- Delete any VM space used by a file, e.g., because the file + * is being physically deleted. This should be called before the file is + * actually deleted so that the cache can determine its device and inode + * values. + */ +int +vm_delete (char *fname, int force) +{ + struct stat st; + char buf[SZ_COMMAND]; + char pathname[SZ_PATHNAME]; + int status = 0; + + /* One-time process initialization. */ + if (!vm_initialized) + vm_initialize(); + + if (stat (fname, &st) < 0) { + status = -1; + goto done; + } + + /* If VMcache is not being used we are done. */ + if (vm_dioenabled && (st.st_size >= dio_threshold)) + goto done; + else if (!vm_enabled || st.st_size < vm_threshold) + goto done; + + /* Don't delete the VM space used by the file if it has hard links + * and only a link is being deleted (force flag will override). + */ + if (st.st_nlink > 1 && !force) + goto done; + + /* Connect to the VMcache server if not already connected. */ + if (!vm_server) + if (vm_connect() < 0) { + status = -1; + goto done; + } + + /* Format and send the delete directive to the VMcache daemon. + * The status from the server is returned as an ascii integer value + * on the same socket. + */ + sprintf (buf, "delete %s\n", realpath(fname,pathname)); + if (vm_write (vm_server, buf, strlen(buf)) < 0) { + vm_shutdown(); + status = -1; + goto done; + } + if (read (vm_server, buf, SZ_CMDBUF) <= 0) { + if (vm_debug) + fprintf (stderr, + "vmclient (%s): server not responding\n", vm_client); + vm_shutdown(); + status = -1; + goto done; + } + + status = atoi (buf); +done: + if (vm_debug) + fprintf (stderr, "vmclient (%s): delete `%s' -> %d\n", + vm_client, fname, status); + + return (status < 0 ? -1 : status); +} + + +/* VM_RESERVESPACE -- Reserve VM space for file data. This directive is + * useful if VM is being used but the VM space could not be preallocated + * at file access time, e.g., when opening a new file. + */ +int +vm_reservespace (long nbytes) +{ + char buf[SZ_CMDBUF]; + int status; + + if (!vm_initialized) + vm_initialize(); + if (!vm_enabled || vm_dioenabled) + return (-1); + if (vm_connect() < 0) + return (-1); + + /* Format and send the file access directive to the VMcache daemon. + * The status from the server is returned as an ascii integer value + * on the same socket. + */ + sprintf (buf, "reservespace %ld\n", nbytes); + if (vm_debug) + fprintf (stderr, "vmclient (%s): %s", vm_client, buf); + + if (vm_write (vm_server, buf, strlen(buf)) < 0) { + vm_shutdown(); + return (-1); + } + if (read (vm_server, buf, SZ_CMDBUF) <= 0) { + if (vm_debug) + fprintf (stderr, + "vmclient (%s): server not responding\n", vm_client); + vm_shutdown(); + return (-1); + } + + status = atoi (buf); + return (status); +} + + +/* VM_IDENTIFY -- Identify the current process to the VM cache server when + * opening a new client connection. + */ +static void +vm_identify (void) +{ + char buf[SZ_CMDBUF]; + + if (vm_write (vm_server, vm_client, strlen(vm_client)) < 0) + vm_shutdown(); + + if (read (vm_server, buf, SZ_CMDBUF) <= 0) { + if (vm_debug) + fprintf (stderr, + "vmclient (%s): server not responding\n", vm_client); + vm_shutdown(); + } +} + + +/* VM_LARGEFILE -- Test if the given offset or file size exceeds the VMcache + * threshold. Zero (false) is returned if the offset is below the threshold + * or if VMcache is disabled. + */ +int +vm_largefile (long nbytes) +{ + return (vm_enabled && nbytes >= vm_threshold); +} + + +/* VM_DIRECTIO -- Turn direct i/o on or off for a file. Direct i/o is raw + * i/o from the device to process memory, bypassing system virtual memory. + */ +int +vm_directio (int fd, int flag) +{ +#ifdef SOLARIS + /* Currently direct i/o is implemented only for Solaris. */ + if (vm_debug > 1) + fprintf (stderr, "vmclient (%s): directio=%d\n", vm_client, flag); + return (directio (fd, flag)); +#else + return (-1); +#endif +} + + +/* VM_INITIALIZE -- Called once per process to open a connection to the + * vmcache daemon. The connection is kept open and is used for all + * subsequent vmcache requests by the process. + */ +static void +vm_initialize (void) +{ + register int ch; + register char *ip, *op; + char token[SZ_FNAME], value[SZ_FNAME]; + extern char os_process_name[]; + char *argp, buf[SZ_FNAME]; + + + /* Extract the process name minus the file path. */ + for (ip=os_process_name, op=vm_client; (*op++ = (ch = *ip)); ip++) { + if (ch == '/') + op = vm_client; + } + + /* Get the server socket port if set in the user environment. */ + if ((argp = getenv (ENV_VMPORT))) + vm_port = atoi (argp); + + /* Get the VM client parameters if an initialization string is + * defined in the user environment. + */ + if ((argp = getenv (ENV_VMCLIENT))) { + while (getstr (&argp, buf, SZ_FNAME, ',') > 0) { + char *modchar, *cp = buf; + int haveval; + + /* Parse "token[=value]" */ + if (getstr (&cp, token, SZ_FNAME, '=') <= 0) + continue; + haveval = (getstr (&cp, value, SZ_FNAME, ',') > 0); + + if (strcmp (token, "enable") == 0) { + vm_enabled = 1; + } else if (strcmp (token, "disable") == 0) { + vm_enabled = 0; + + } else if (strcmp (token, "debug") == 0) { + vm_debug = 1; + if (haveval) + vm_debug = strtol (value, &modchar, 10); + + } else if (strcmp (token, "threshold") == 0 && haveval) { + vm_threshold = strtol (value, &modchar, 10); + if (*modchar == 'k' || *modchar == 'K') + vm_threshold *= 1024; + else if (*modchar == 'm' || *modchar == 'M') + vm_threshold *= (1024 * 1024); + + } else if (strcmp (token, "directio") == 0) { + vm_dioenabled = 1; + if (haveval) { + dio_threshold = strtol (value, &modchar, 10); + if (*modchar == 'k' || *modchar == 'K') + dio_threshold *= 1024; + else if (*modchar == 'm' || *modchar == 'M') + dio_threshold *= (1024 * 1024); + } + } + } + } + + if (vm_debug) { + fprintf (stderr, "vmclient (%s): vm=%d dio=%d ", + vm_client, vm_enabled, vm_dioenabled); + fprintf (stderr, "vmth=%d dioth=%d port=%d\n", + vm_threshold, dio_threshold, vm_port); + } + + /* Attempt to open a connection to the VMcache server. */ + if (vm_enabled && !vm_dioenabled) + vm_connect(); + +#ifdef SUNOS + on_exit (vm_shutdown, NULL); +#else + atexit (vm_shutdown); +#endif + vm_initialized++; +} + + +/* VM_CONNECT -- Connect to the VMcache server. + */ +static int +vm_connect (void) +{ + XINT acmode = READ_WRITE; + char osfn[SZ_FNAME]; + int fd, status = 0; + + extern int ZOPNND(); + + + /* Already connected? */ + if (vm_server) + return (0); + + sprintf (osfn, "inet:%d::", vm_port); + if (vm_debug) + fprintf (stderr, + "vmclient (%s): open server connection `%s' -> ", + vm_client, osfn); + + ZOPNND (osfn, &acmode, &fd); + if (fd == XERR) { + if (vm_debug) + fprintf (stderr, "failed\n"); + status = -1; + } else { + vm_server = fd; + if (vm_debug) + fprintf (stderr, "fd=%d\n", fd); + vm_identify(); + } + + return (status); +} + + +/* VM_SHUTDOWN -- Called at process exit to shutdown the VMcached server + * connection. + */ +static void +vm_shutdown (void) +{ + int status; + extern int ZCLSND(); + + if (vm_server) { + if (vm_debug) + fprintf (stderr, + "vmclient (%s): shutdown server connection\n", vm_client); + vm_write (vm_server, "bye\n", 4); + ZCLSND (&vm_server, &status); + } + vm_server = 0; +} + + +/* VM_WRITE -- Write to the server. We need to encapsulate write so that + * SIGPIPE can be disabled for the duration of the write. We don't want the + * calling process to abort if the VMcache server goes away. + */ +static int +vm_write (int fd, char *buf, int nbytes) +{ + int status; +#ifdef USE_SIGACTION + struct sigaction oldact; +#else + SIGFUNC oldact; +#endif + + if (vm_debug > 1) { + fprintf (stderr, "vmclient (%s):: %s", vm_client, buf); + if (buf[nbytes-1] != '\n') + fprintf (stderr, "\n"); + } + +#ifdef USE_SIGACTION + sigaction (SIGPIPE, NULL, &oldact); + status = write (fd, buf, nbytes); + sigaction (SIGPIPE, &oldact, NULL); +#else + oldact = (SIGFUNC) signal (SIGPIPE, SIG_IGN); + status = write (fd, buf, nbytes); + signal (SIGPIPE, oldact); +#endif + + if (vm_debug && status < 0) + fprintf (stderr, + "vmclient (%s): server not responding\n", vm_client); + + return (status); +} + + +/* GETSTR -- Internal routine to extract a metacharacter delimited substring + * from a formatted string. The metacharacter to be taken as the delimiter + * is passed as an argument. Any embedded whitespace between the tokens is + * stripped. The number of characters in the output token is returned as + * the function value, or zero if EOS or the delimiter is reached. + */ +static int +getstr (char **ipp, char *obuf, int maxch, int delim) +{ + register char *op, *ip = *ipp; + register char *otop = obuf + maxch; + + while (*ip && isspace(*ip)) + ip++; + for (op=obuf; *ip; ip++) { + if (*ip == delim) { + ip++; + break; + } else if (op < otop && !isspace(*ip)) + *op++ = *ip; + } + + *op = '\0'; + *ipp = ip; + + return (op - obuf); +} |