libvmcp: Add common vmcp code to the lib

This patch prevents code duplication in vmcp related programs.
Some applications such as vmur, vmcp, and lsqeth
use z/VM CP commands to query information. Each program
uses its own defines and code.

Supply a library and common header file to use common code.

Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Thomas Richter
2018-02-22 14:30:36 +00:00
committed by Jan Höppner
parent 37c3752b31
commit eaa2ef6ba4
7 changed files with 275 additions and 1 deletions

1
.gitignore vendored
View File

@@ -46,6 +46,7 @@ libutil/util_prg_example
libutil/util_rec_example
libutil/util_scandir_example
libzds/libzds.a
libvmcp/vmcp_example
mon_tools/mon_fsstatd
mon_tools/mon_procd
osasnmpd/osasnmpd

View File

@@ -3,7 +3,7 @@ ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/ar
# Include common definitions
include common.mak
LIB_DIRS = libvtoc libu2s libutil libzds libdasd libvmdump libccw
LIB_DIRS = libvtoc libu2s libutil libzds libdasd libvmdump libccw libvmcp
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \

View File

@@ -338,6 +338,10 @@ $(rootdir)/libvmdump/libvmdump.a: $(rootdir)/libvmdump
$(MAKE) -C $(rootdir)/libvmdump/ libvmdump.a
.PHONY: $(rootdir)/libvmdump
$(rootdir)/libvmcp/libvmcp.a: $(rootdir)/libvmcp
$(MAKE) -C $(rootdir)/libvmcp/ libvmcp.a
.PHONY: $(rootdir)/libvmcp
$(rootdir)/zipl/boot/data.o:
$(MAKE) -C $(rootdir)/zipl/boot/ data.o

52
include/lib/vmcp.h Normal file
View File

@@ -0,0 +1,52 @@
/*
* vmcp - z/VM CP command library
*
* Copyright IBM Corp. 2005, 2018
*
* 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 LIB_VMCP_H
#define LIB_VMCP_H
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
#define VMCP_DEVICE_NODE "/dev/vmcp" /* VMCP device name */
#define VMCP_DEFAULT_BUFSZ 0x4000 /* VMCP default buffer size */
/*
* Error codes returned by vmcp() function. This enables the caller
* to emit a detailed error message on the type of failure.
*/
#define VMCP_SUCCESS 0 /* VMCP operation completed successfully */
#define VMCP_ERR_OPEN (-1) /* Error Open of VMCP device */
#define VMCP_ERR_SETBUF (-2) /* Error VMCP_SETBUF ioctl */
#define VMCP_ERR_READ (-3) /* Error VMCP read system call */
#define VMCP_ERR_GETCODE (-4) /* Error VMCP_GETCODE ioctl */
#define VMCP_ERR_GETSIZE (-5) /* Error VMCP_GETSIZE ioctl */
#define VMCP_ERR_TOOSMALL (-6) /* Error VMCP buffer too small for
* response
*/
#define VMCP_ERR_WRITE (-7) /* Error VMCP write system call */
struct vmcp_parm {
const char *cpcmd;
unsigned int buffer_size;
bool do_upper;
int cprc;
char *response;
unsigned int response_size;
};
int vmcp(struct vmcp_parm *cp);
#ifdef __cplusplus
}
#endif
#endif

18
libvmcp/Makefile Normal file
View File

@@ -0,0 +1,18 @@
include ../common.mak
lib = libvmcp.a
examples = vmcp_example
all: $(lib) $(examples)
objects = vmcp.o
$(lib): $(objects)
install: all
vmcp_example: vmcp_example.o $(lib) $(rootdir)/libutil/libutil.a
clean:
rm -f *.o $(lib) $(examples)

134
libvmcp/vmcp.c Normal file
View File

@@ -0,0 +1,134 @@
/*
* vmcp - z/VM CP function library
*
* Copyright IBM Corp. 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include "lib/util_libc.h"
#include "lib/vmcp.h"
#define VMCP_DEVICE_NODE "/dev/vmcp"
#define VMCP_GETSIZE _IOR(0x10, 3, int)
#define VMCP_SETBUF _IOW(0x10, 2, int)
#define VMCP_GETCODE _IOR(0x10, 1, int)
/*
* 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, ssize_t count)
{
ssize_t ret, 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;
}
/**
* Submit a command to z/VM CP and return the response, the size in bytes
* of the response and CP command response code.
*
* The member response contains the response from CP. It is a pointer
* to a malloc'ed buffer which must be freed by the caller when the return
* code is zero or VMCP_ERR_TOOSMALL.
*
* @param[in,out] cmd Pointer to struct vmcp_parm.
* @param[in] cpcmd Pointer to CP command string.
* @param[in] do_upper If true convert cpcmd string to upper case.
* @param[out] cprc Return code of the CP command.
* @param[out] response Return buffer, has been allocated via malloc()
* must be freed by caller, see below.
* @param[out] response_size Size of the response in bytes, can be larger
* than buffer_size.
*
* @returns Zero on success or a negative error number on failure.
* @retval VMCP_SUCCESS Success valid members: cprc, response,
* response_size
* @retval VMCP_ERR_OPEN Error opening VMCP device, valid members: none
* @retval VMCP_ERR_SETBUF Error setting buffer, valid members: none
* @retval VMCP_ERR_GETCODE Error getting cp exit code, valid members: none
* @retval VMCP_ERR_WRITE Error write CP command, valid members: none
* @retval VMCP_ERR_GETSIZE Error reading response size,
* valid members: cprc
* @retval VMCP_ERR_READ Error reading resp
* @retval VMCP_ERR_TOOSMALL Error response buffer too small, response
* truncated, valid members: cprc, response,
* response_size
*/
int vmcp(struct vmcp_parm *cmd)
{
int rc = VMCP_SUCCESS, fd, len;
char *cpcmd;
cmd->response = NULL;
cmd->response_size = 0;
cmd->cprc = 0;
fd = open(VMCP_DEVICE_NODE, O_RDWR);
if (fd == -1)
return VMCP_ERR_OPEN;
cpcmd = util_strdup(cmd->cpcmd); /* Exits on failure */
if (cmd->do_upper)
util_str_toupper(cpcmd);
if (ioctl(fd, VMCP_SETBUF, &cmd->buffer_size) == -1) {
rc = VMCP_ERR_SETBUF;
goto fail;
}
if (write(fd, cpcmd, strlen(cpcmd)) == -1) {
rc = VMCP_ERR_WRITE;
goto fail;
}
if (ioctl(fd, VMCP_GETCODE, &cmd->cprc) == -1) {
rc = VMCP_ERR_GETCODE;
goto fail;
}
if (ioctl(fd, VMCP_GETSIZE, &cmd->response_size) == -1) {
rc = VMCP_ERR_GETSIZE;
goto fail;
}
if (cmd->response_size <= cmd->buffer_size) {
len = cmd->response_size;
} else {
len = cmd->buffer_size;
rc = VMCP_ERR_TOOSMALL;
}
/* Exits on failure */
cmd->response = (char *)util_zalloc(len + 1);
if (read_buffer(fd, cmd->response, len) == -1) {
rc = VMCP_ERR_READ;
free(cmd->response);
cmd->response = NULL;
}
fail:
close(fd);
free(cpcmd);
return rc;
}

65
libvmcp/vmcp_example.c Normal file
View File

@@ -0,0 +1,65 @@
/**
* vmcp_example - Example program for vmcp.c
*
* Copyright 2018 IBM Corp.
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
//! [code]
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include "lib/vmcp.h"
/*
* Demonstrate vmcp() function usage
*/
int main(void)
{
struct vmcp_parm cp;
int rc;
cp.cpcmd = "q osa";
cp.buffer_size = VMCP_DEFAULT_BUFSZ;
cp.do_upper = true;
rc = vmcp(&cp);
switch (rc) {
case VMCP_SUCCESS:
printf("%s\n", cp.response);
free(cp.response);
break;
case VMCP_ERR_OPEN:
errx(EXIT_FAILURE, "Could not open device %s", VMCP_DEVICE_NODE);
break;
case VMCP_ERR_SETBUF:
errx(EXIT_FAILURE, "Could not set buffer size");
break;
case VMCP_ERR_GETCODE:
errx(EXIT_FAILURE, "Could not query return code");
break;
case VMCP_ERR_GETSIZE:
errx(EXIT_FAILURE, "Could not query response size");
break;
case VMCP_ERR_WRITE:
errx(EXIT_FAILURE, "Could not issue CP command");
break;
case VMCP_ERR_READ:
errx(EXIT_FAILURE, "Could not read CP response");
break;
case VMCP_ERR_TOOSMALL:
free(cp.response);
printf("Response truncated (requires %u bytes)\n",
cp.response_size);
errx(EXIT_FAILURE, "Response buffer (%u bytes) too small",
cp.buffer_size);
break;
}
return EXIT_SUCCESS;
}
//! [code]