diff --git a/vmcp/Makefile b/vmcp/Makefile index 2c5e5f38..b0b5ce66 100644 --- a/vmcp/Makefile +++ b/vmcp/Makefile @@ -2,7 +2,9 @@ include ../common.mak all: vmcp -vmcp: vmcp.o +libs = $(rootdir)/libvmcp/libvmcp.a $(rootdir)/libutil/libutil.a + +vmcp: vmcp.o $(libs) install: all $(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8 diff --git a/vmcp/vmcp.c b/vmcp/vmcp.c index 58df739c..5677e12b 100644 --- a/vmcp/vmcp.c +++ b/vmcp/vmcp.c @@ -28,12 +28,48 @@ #include #include #include +#include #include -#include "vmcp.h" +#include "lib/zt_common.h" +#include "lib/vmcp.h" + +#define MAXBUFFER 1048576 +#define MINBUFFER 4096 +#define MAXCMDLEN 240 + +#define VMCP_OK 0 +#define VMCP_CP 1 +#define VMCP_BUF 2 +#define VMCP_LIN 3 +#define VMCP_OPT 4 + +static struct option options[] = { + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + {"keepcase", no_argument, NULL, 'k'}, + {"buffer", required_argument, NULL, 'b'}, + {NULL, 0, NULL, 0} +}; + +static const char opt_string[] = "+hvkb:"; + +static const char help_text[] = + "Usage:\n" + "vmcp [-k] [-b ] command\n" + "vmcp [-h|-v]\n\n" + "Options:\n" + "-h or --help :Print usage information, then exit\n" + "-v or --version :Print version information, then exit\n" + "-k or --keepcase :Using this option, vmcp does not convert the command\n" + " to uppercase. The default is to translate the command\n" + " string.\n" + "-b or :defines the buffer size for the response\n" + "--buffer= valid values are from 4096 to 1048576 bytes\n" + " the k and M suffixes are also supported\n"; static int keep_case = 0; -static int buffersize = 8192; +static int buffersize = VMCP_DEFAULT_BUFSZ; static char command[MAXCMDLEN + 1]; static void print_help(const char *name) @@ -48,14 +84,6 @@ static void print_version(const char *name) name, RELEASE_STRING); } -static void uppercase(char *string) -{ - while (*string != '\0') { - *string = toupper(*string); - string++; - } -} - /* Parse STRING for buffer size in bytes, allowing size modifier suffix 'k' and * 'm'. Return buffer size in bytes on success, -1 on error. */ static long parse_buffersize(char *string) @@ -148,25 +176,6 @@ static inline void linux_error(const char *message) fprintf(stderr, "Error: %s: %s\n", message, strerror(errno)); } -/* Read at most COUNT bytes from FD into memory at location BUF. Return - * number of bytes read on success, -1 on error. */ -static ssize_t read_buffer(int fd, char *buf, size_t count) -{ - ssize_t ret; - ssize_t done; - - for (done = 0; done < (ssize_t) count; done += ret) { - ret = read(fd, &buf[done], count - done); - if (ret == -1 && errno == EINTR) - continue; - if (ret == -1) - return -1; - if (ret == 0) - break; - } - return done; -} - /* Write COUNT bytes to FD from memory at location BUF. Return number of bytes * written on success, -1 otherwise. */ static ssize_t write_buffer(int fd, const char *buf, size_t count) @@ -188,77 +197,51 @@ static ssize_t write_buffer(int fd, const char *buf, size_t count) int main(int argc, char **argv) { + struct vmcp_parm cp; int ret; - int fd; - int response_code; - int response_size; - char *buffer; ret = parse_args(argc, argv); if (ret != VMCP_OK) return ret; - if (!keep_case) - uppercase(command); + cp.buffer_size = buffersize; + cp.cpcmd = command; + cp.do_upper = !keep_case; - buffer = malloc(buffersize); - if (!buffer) { - linux_error("Could not allocate return buffer"); + ret = vmcp(&cp); + + switch (ret) { + case VMCP_ERR_OPEN: + linux_error("Could not open device " VMCP_DEVICE_NODE); return VMCP_LIN; - } - fd = open(DEVICE_NODE, O_RDWR); - if (fd == -1) { - linux_error("Could not open device " DEVICE_NODE); - free(buffer); - return VMCP_LIN; - } - if (ioctl(fd, VMCP_SETBUF, &buffersize) == -1) { + case VMCP_ERR_SETBUF: linux_error("Could not set buffer size"); - free(buffer); - close(fd); return VMCP_LIN; - } - if (write(fd, command, strlen(command)) == -1) { + case VMCP_ERR_WRITE: linux_error("Could not issue CP command"); - free(buffer); - close(fd); return VMCP_LIN; - } - if (ioctl(fd, VMCP_GETCODE, &response_code) == -1) { + case VMCP_ERR_GETCODE: linux_error("Could not query return code"); - free(buffer); - close(fd); return VMCP_LIN; - } - if (ioctl(fd, VMCP_GETSIZE, &response_size) == -1) { + case VMCP_ERR_GETSIZE: linux_error("Could not query response size"); - free(buffer); - close(fd); return VMCP_LIN; - } - ret = read_buffer(fd, buffer, buffersize); - if (ret == -1) { + case VMCP_ERR_READ: linux_error("Could not read CP response"); - free(buffer); - close(fd); return VMCP_LIN; } - write_buffer(STDOUT_FILENO, buffer, ret); - if (response_size > buffersize) { + write_buffer(STDOUT_FILENO, cp.response, + MIN(cp.response_size, cp.buffer_size)); + free(cp.response); + if (ret == VMCP_ERR_TOOSMALL) { fprintf(stderr, "Error: output (%d bytes) was truncated, try " - "--buffer to increase size\n", response_size); - free(buffer); - close(fd); + "--buffer to increase size\n", cp.response_size); return VMCP_BUF; } - if (response_code > 0) { + if (cp.cprc > 0) { fprintf(stderr, "Error: non-zero CP response for command '%s': " - "#%d\n", command, response_code); - free(buffer); - close(fd); + "#%d\n", command, cp.cprc); return VMCP_CP; } - free(buffer); - close(fd); return VMCP_OK; } diff --git a/vmcp/vmcp.h b/vmcp/vmcp.h deleted file mode 100644 index 1f4f2044..00000000 --- a/vmcp/vmcp.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * vmcp - Send commands to the z/VM control program - * - * Definitions used by vmcp - * - * Copyright IBM Corp. 2005, 2017 - * - * s390-tools is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See LICENSE for details. - */ - -#ifndef __vmcp_h__ -#define __vmcp_h__ - -#include -#include - -#include "lib/zt_common.h" - -#define DEVICE_NODE "/dev/vmcp" - -#define VMCP_GETCODE _IOR(0x10, 1, int) -#define VMCP_SETBUF _IOW(0x10, 2, int) -#define VMCP_GETSIZE _IOR(0x10, 3, int) - -#define MAXBUFFER 1048576 -#define MINBUFFER 4096 -#define MAXCMDLEN 240 - -#define VMCP_OK 0 -#define VMCP_CP 1 -#define VMCP_BUF 2 -#define VMCP_LIN 3 -#define VMCP_OPT 4 - -static struct option options[] = { - {"help", no_argument, NULL, 'h'}, - {"version", no_argument, NULL, 'v'}, - {"keepcase", no_argument, NULL, 'k'}, - {"buffer", required_argument, NULL, 'b'}, - {NULL, 0, NULL, 0} -}; - -static const char opt_string[] = "+hvkb:"; - -static const char help_text[] = - "Usage:\n" - "vmcp [-k] [-b ] command\n" - "vmcp [-h|-v]\n\n" - "Options:\n" - "-h or --help :Print usage information, then exit\n" - "-v or --version :Print version information, then exit\n" - "-k or --keepcase :Using this option, vmcp does not convert the command\n" - " to uppercase. The default is to translate the command\n" - " string.\n" - "-b or :defines the buffer size for the response\n" - "--buffer= valid values are from 4096 to 1048576 bytes\n" - " the k and M suffixes are also supported\n"; -#endif