mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Initial s390-tools-2.0.0 import
This commit is based on the s390-tools-1.39.0 version. Changes on top of s390-tools-1.39.0: - Add MIT license to all source files - Add LICENSE file - Transform REAMDE to README.md (markdown) - Add AUTHORS.md file - Add CONTRIBUTING.md file - Move changelog from README to CHANGELOG.md file Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com> Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
include ../common.mak
|
||||
|
||||
all: vmcp
|
||||
|
||||
vmcp: vmcp.o
|
||||
|
||||
install: all
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 vmcp $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 vmcp.8 \
|
||||
$(DESTDIR)$(MANDIR)/man8
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ vmcp core
|
||||
|
||||
.PHONY: all install clean
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
.\" Copyright 2017 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.
|
||||
.\"
|
||||
.TH vmcp "8" "Apr 2006" "s390-tools"
|
||||
.SH NAME
|
||||
vmcp \- send commands to the z/VM control program
|
||||
.SH SYNOPSIS
|
||||
.BI vmcp
|
||||
[\fI-k\fR] [\fI-b <size>\fR] command
|
||||
|
||||
.BI vmcp
|
||||
[\fI-h|-v\fR]
|
||||
|
||||
|
||||
.SH DESCRIPTION
|
||||
vmcp allows Linux users to send commands to the control program of z/VM.
|
||||
The normal usage is to invoke vmcp with the command you want to
|
||||
execute. If the
|
||||
.BI -k
|
||||
option is not specified, the whole command line is automatically translated
|
||||
into uppercase. The response of z/VM is written to the standard output.
|
||||
|
||||
.BI vmcp
|
||||
needs a kernel feature represented by the device node /dev/vmcp.
|
||||
The kernel module defines a buffer size, which limits the length of the
|
||||
response. Every output larger than the compiled buffer size is
|
||||
silently dropped.
|
||||
Depending on you shell, please remember to escape special characters
|
||||
like * using \\* instead.
|
||||
.SH RETURN CODES
|
||||
vmcp writes the response to stdout and any error message to stderr.
|
||||
Depending on the success one of the following return codes is returned:
|
||||
.TP
|
||||
.BR "0"
|
||||
No problem in vmcp or CP.
|
||||
|
||||
.TP
|
||||
.BR "1"
|
||||
CP returned a non-zero response code.
|
||||
|
||||
The message
|
||||
|
||||
.B Error: non-zero CP response for command '<command>': #<num>"
|
||||
|
||||
is written to stderr.
|
||||
.I <num>
|
||||
contains the numerical value of the response
|
||||
code and
|
||||
.I <command>
|
||||
contains the commands as send to CP.
|
||||
|
||||
.TP
|
||||
.BR "2"
|
||||
The specified buffer was not large enough to hold CP's response. The command
|
||||
was executed, nevertheless, and the response was truncated. You can use the
|
||||
--buffer option to increase the response buffer. The message
|
||||
|
||||
.B Error: output (<num> bytes) was truncated, try --buffer to increase size
|
||||
|
||||
is written to stderr.
|
||||
.I <num>
|
||||
contains the necessary buffer size in bytes.
|
||||
|
||||
.TP
|
||||
.BR "3"
|
||||
Linux reported an error to vmcp. See the error message for details.
|
||||
|
||||
.TP
|
||||
.BR "4"
|
||||
The options passed to vmcp were erroneous. See the error messages for details.
|
||||
|
||||
|
||||
|
||||
|
||||
.SH EXAMPLES
|
||||
To get your user id
|
||||
.IP
|
||||
.nf
|
||||
vmcp query userid
|
||||
.fi
|
||||
.P
|
||||
|
||||
To attach the device 1234 to your guest
|
||||
.IP
|
||||
.nf
|
||||
vmcp attach 1234 \\*
|
||||
.fi
|
||||
.P
|
||||
|
||||
If add the following line to /etc/sudoers
|
||||
|
||||
.BI "ALL ALL=NOPASSWD: /sbin/vmcp indicate"
|
||||
|
||||
every user on the system can run the indicate command
|
||||
.IP
|
||||
.nf
|
||||
sudo vmcp indicate
|
||||
.fi
|
||||
.P
|
||||
|
||||
|
||||
.SH CREDITS
|
||||
The basic idea of vmcp is based on cpint of Neale Fergusson.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BR "\-h" " or " "--help"
|
||||
Print usage information, then exit
|
||||
|
||||
.TP
|
||||
.BR "\-v" " or " "--version"
|
||||
Print version information, then exit
|
||||
|
||||
.TP
|
||||
.BR "\-k" " or " "--keepcase"
|
||||
Using this option, vmcp does not convert the command to uppercase.
|
||||
(The default is to translate the command string to uppercase)
|
||||
|
||||
.TP
|
||||
.BR "\-b <size>" " or " "--buffer=<size>"
|
||||
Specify a buffer size for the response. The buffer size can be specified
|
||||
from 4096 bytes (4k) to 1048576 Bytes (1M). The default size is 2 pages
|
||||
(8192 Bytes). You can also use k/K/m/M for kilobytes and Megabytes
|
||||
|
||||
.SH "SEE ALSO"
|
||||
sudo(8)
|
||||
+264
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* vmcp - Send commands to the z/VM control program
|
||||
*
|
||||
* Tool for accessing the control program of z/VM using the
|
||||
* kernel module vmcp
|
||||
* return codes:
|
||||
* 0: everything was fine (VMCP_OK)
|
||||
* 1: CP returned a nn zero response code (VMCP_CP)
|
||||
* 2: the response buffer was not large enough (VMCP_BUF)
|
||||
* 3: an internal Linux error occurred (VMCP_LIN)
|
||||
* 4: invalid options (VMCP_OPT)
|
||||
*
|
||||
* CREDITS: The idea is based on cpint of Neale Fergusson
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "vmcp.h"
|
||||
|
||||
static int keep_case = 0;
|
||||
static int buffersize = 8192;
|
||||
static char command[MAXCMDLEN + 1];
|
||||
|
||||
static void print_help(const char *name)
|
||||
{
|
||||
printf("%s: z/VM CP command interface.\n%s", name, help_text);
|
||||
}
|
||||
|
||||
static void print_version(const char *name)
|
||||
{
|
||||
printf("%s: z/VM CP command interface version %s\n"
|
||||
"Copyright IBM Corp. 2005, 2017\n",
|
||||
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)
|
||||
{
|
||||
char *suffix;
|
||||
long bytes;
|
||||
|
||||
bytes = strtol(string, &suffix, 10);
|
||||
if (strlen(suffix) > 1)
|
||||
return -1;
|
||||
switch (*suffix) {
|
||||
case 'k':
|
||||
case 'K':
|
||||
bytes *= 1024;
|
||||
break;
|
||||
case 'm':
|
||||
case 'M':
|
||||
bytes *= 1048576;
|
||||
break;
|
||||
case '\0':
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
if ((bytes < MINBUFFER) || (bytes > MAXBUFFER))
|
||||
return -1;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/* Parse tool parameters. Fill in global variables keep_case, buffersize and
|
||||
* command according to parameters. Return VMCP_OK on success, VMCP_OPT
|
||||
* in case of parameter errors. In case of --help or --version, print
|
||||
* respective text to stdout and exit. */
|
||||
static int parse_args(int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
int index;
|
||||
|
||||
do {
|
||||
opt = getopt_long(argc, argv, opt_string, options, NULL);
|
||||
switch (opt) {
|
||||
case -1:
|
||||
/* Reached end of parameter list. */
|
||||
break;
|
||||
case 'h':
|
||||
print_help(argv[0]);
|
||||
exit(VMCP_OK);
|
||||
case 'v':
|
||||
print_version(argv[0]);
|
||||
exit(VMCP_OK);
|
||||
case 'k':
|
||||
keep_case = 1;
|
||||
break;
|
||||
case 'b':
|
||||
buffersize = (int) parse_buffersize(optarg);
|
||||
if (buffersize == -1) {
|
||||
fprintf(stderr, "Error: Invalid buffersize "
|
||||
"(needs to be between %d and %d)\n",
|
||||
MINBUFFER, MAXBUFFER);
|
||||
return VMCP_OPT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Try 'vmcp --help' for more"
|
||||
" information.\n");
|
||||
return VMCP_OPT;
|
||||
}
|
||||
} while (opt != -1);
|
||||
/* Merge remaining argv contents into command string. */
|
||||
for (index = optind; index < argc; index++) {
|
||||
if (strlen(command) + (strlen(command) == 0 ? 0 : 1) +
|
||||
strlen(argv[index]) > MAXCMDLEN) {
|
||||
fprintf(stderr, "Error: Command too long (cannot be "
|
||||
"longer than %d characters)\n", MAXCMDLEN);
|
||||
return VMCP_OPT;
|
||||
}
|
||||
if (strlen(command) > 0)
|
||||
strcat(command, " ");
|
||||
strcat(command, argv[index]);
|
||||
}
|
||||
if (strlen(command) == 0) {
|
||||
print_help(argv[0]);
|
||||
return VMCP_OPT;
|
||||
}
|
||||
return VMCP_OK;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
ssize_t ret;
|
||||
ssize_t done;
|
||||
|
||||
for (done = 0; done < (ssize_t) count; done += ret) {
|
||||
ret = write(fd, &buf[done], count - done);
|
||||
if (ret == -1 && errno == EINTR)
|
||||
continue;
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
if (ret == 0)
|
||||
break;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
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);
|
||||
|
||||
buffer = malloc(buffersize);
|
||||
if (!buffer) {
|
||||
linux_error("Could not allocate return buffer");
|
||||
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) {
|
||||
linux_error("Could not set buffer size");
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return VMCP_LIN;
|
||||
}
|
||||
if (write(fd, command, strlen(command)) == -1) {
|
||||
linux_error("Could not issue CP command");
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return VMCP_LIN;
|
||||
}
|
||||
if (ioctl(fd, VMCP_GETCODE, &response_code) == -1) {
|
||||
linux_error("Could not query return code");
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return VMCP_LIN;
|
||||
}
|
||||
if (ioctl(fd, VMCP_GETSIZE, &response_size) == -1) {
|
||||
linux_error("Could not query response size");
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return VMCP_LIN;
|
||||
}
|
||||
ret = read_buffer(fd, buffer, buffersize);
|
||||
if (ret == -1) {
|
||||
linux_error("Could not read CP response");
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return VMCP_LIN;
|
||||
}
|
||||
write_buffer(STDOUT_FILENO, buffer, ret);
|
||||
if (response_size > buffersize) {
|
||||
fprintf(stderr, "Error: output (%d bytes) was truncated, try "
|
||||
"--buffer to increase size\n", response_size);
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return VMCP_BUF;
|
||||
}
|
||||
if (response_code > 0) {
|
||||
fprintf(stderr, "Error: non-zero CP response for command '%s': "
|
||||
"#%d\n", command, response_code);
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return VMCP_CP;
|
||||
}
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return VMCP_OK;
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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 <getopt.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#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 <size>] 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 <size> or :defines the buffer size for the response\n"
|
||||
"--buffer=<size> valid values are from 4096 to 1048576 bytes\n"
|
||||
" the k and M suffixes are also supported\n";
|
||||
#endif
|
||||
Reference in New Issue
Block a user