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:
Michael Holzheu
2017-08-07 16:13:17 +02:00
commit b627b8d8e1
647 changed files with 168974 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
include ../common.mak
lib = libutil.a
examples = util_base_example \
util_panic_example \
util_path_example \
util_scandir_example \
util_file_example \
util_libc_example \
util_opt_example \
util_opt_command_example \
util_prg_example \
util_rec_example
all: $(lib) $(examples)
objects = util_base.o \
util_path.o \
util_scandir.o \
util_file.o \
util_libc.o \
util_list.o \
util_opt.o \
util_panic.o \
util_part.o \
util_prg.o \
util_proc.o \
util_rec.o
util_base_example: util_base_example.o $(rootdir)/libutil/libutil.a
util_panic_example: util_panic_example.o $(rootdir)/libutil/libutil.a
util_path_example: util_path_example.o $(rootdir)/libutil/libutil.a
util_scandir_example: util_scandir_example.o $(rootdir)/libutil/libutil.a
util_file_example: util_file_example.o $(rootdir)/libutil/libutil.a
util_libc_example: util_libc_example.o $(rootdir)/libutil/libutil.a
util_opt_example: util_opt_example.o $(rootdir)/libutil/libutil.a
util_opt_command_example: util_opt_command_example.o $(rootdir)/libutil/libutil.a
util_panic_example: util_panic_example.o $(rootdir)/libutil/libutil.a
util_prg_example: util_prg_example.o $(rootdir)/libutil/libutil.a
util_rec_example: util_rec_example.o $(rootdir)/libutil/libutil.a
$(lib): $(objects)
install: all
clean:
rm -f *.o $(lib) $(examples)
+93
View File
@@ -0,0 +1,93 @@
/*
* util - Utility function library
*
* General helper functions
*
* Copyright IBM Corp. 2013, 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 <string.h>
#include "lib/util_base.h"
#include "lib/util_libc.h"
/*
* Print hexdump for buffer with variable group parameter
*/
void util_hexdump_grp(FILE *fh, const char *tag, const void *data, int grp,
int count, int indent)
{
const char *buf = data;
int i, first = 1;
for (i = 0; i < count; i++) {
if (first) {
fprintf(fh, "%*s", indent, " ");
if (tag)
fprintf(fh, "%s: ", tag);
fprintf(fh, "%08x: ", i);
first = 0;
}
fprintf(fh, "%02x", buf[i]);
if (i % 16 == 15 || i + 1 == count) {
fprintf(fh, "\n");
first = 1;
} else if (i % grp == grp - 1) {
fprintf(fh, " ");
}
}
}
/*
* Print hexdump for buffer with fix grp parameter
*/
void util_hexdump(FILE *fh, const char *tag, const void *data, int count)
{
util_hexdump_grp(fh, tag, data, sizeof(long), count, 0);
}
#define MAX_CHARS_PER_LINE 80
/*
* Print string with indentation
*
* Print a string while accounting for a given indent value, characters per line
* limit, and line breaks ('\n') within the string. The first line has to be
* indented manually.
*
* @param[in] str String that should be printed
* @param[in] indent Indentation for printing
*/
void util_print_indented(const char *str, int indent)
{
char *word, *line, *desc, *desc_ptr;
int word_len, pos = indent;
desc = desc_ptr = util_strdup(str);
line = strsep(&desc, "\n");
while (line) {
word = strsep(&line, " ");
pos = indent;
while (word) {
word_len = strlen(word);
if (pos + word_len + 1 > MAX_CHARS_PER_LINE) {
printf("\n%*s", indent, "");
pos = indent;
}
if (pos == indent)
printf("%s", word);
else
printf(" %s", word);
pos += word_len + 1;
word = strsep(&line, " ");
}
if (desc)
printf("\n%*s", indent, "");
line = strsep(&desc, "\n");
}
printf("\n");
free(desc_ptr);
}
+38
View File
@@ -0,0 +1,38 @@
/**
* util_base_example - Example program for util_base
*
* 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.
*/
//! [code]
#include <stdio.h>
#include "lib/util_base.h"
#define INDENTATION 24
const char *msg =
"There is a theory which states that if ever anybody discovers exactly "
"what the Universe is for and why it is here, it will instantly disappear "
"and be replaced by something even more ...\n"
"\n"
" ... bizarre\n"
" ... and inexplicable.\n"
"\n"
"There is another theory which states that this has already happened.";
/*
* Demonstrate util_base functions
*/
int main(void)
{
printf("TEST: util_print_indented(msg, %d)\n", INDENTATION);
printf("----------------------------------\n");
printf("%-*s", INDENTATION, "Douglas Adams:");
util_print_indented(msg, INDENTATION);
return EXIT_SUCCESS;
}
//! [code]
+434
View File
@@ -0,0 +1,434 @@
/*
* util - Utility function library
*
* Read and write files
*
* Copyright IBM Corp. 2016, 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 <errno.h>
#include <limits.h>
#include <linux/limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "lib/util_base.h"
#include "lib/util_file.h"
#include "lib/util_libc.h"
#include "lib/util_panic.h"
#include "lib/util_prg.h"
/*
* Read the first line of a file into given buffer
*/
static int file_gets(char *str, size_t size, const char *path)
{
char *p, *end;
FILE *fp;
int rc;
/* In case of error we always return empty string */
str[0] = 0;
/* Read the string */
fp = fopen(path, "r");
if (!fp)
return -1;
p = fgets(str, size, fp);
if (p) {
/* Check for end of line */
end = memchr(str, '\n', size);
if (end)
*end = 0;
else
str[size - 1] = 0;
}
if (strlen(str) == 0) {
rc = -1;
goto out_fclose;
}
rc = 0;
out_fclose:
fclose(fp);
return rc;
}
/**
* Read the first line of a file
*
* If read is successful 'str' contains first line of a file without the
* trailing newline. If read fails, an empty string is returned for 'str'
* The resulting string will always be null-terminated.
*
* @param[out] str Result buffer
* @param[in] size Size of the result buffer
* @param[in] fmt Format string for generation of the path name
* @param[in] ... Parameters for format string
*
* @retval 0 File was read
* @retval -1 Error while reading file
*/
int util_file_read_line(char *const str, size_t size, const char *fmt, ...)
{
char path[PATH_MAX];
va_list ap;
/* Construct the file name */
UTIL_VSPRINTF(path, fmt, ap);
return file_gets(str, size, path);
}
/*
* Write string to a file
*/
static int file_puts(const char *str, const char *path)
{
FILE *fp;
int rc;
/* write the string */
fp = fopen(path, "w");
if (!fp)
return -1;
if (fputs(str, fp) == EOF) {
rc = -1;
goto out_fclose;
}
rc = 0;
out_fclose:
fclose(fp);
return rc;
}
/**
* Write string to a file without the terminating null byte
*
* @param[in] str Content is to be written
* @param[in] fmt Format string for generation of the path name
* @param[in] ... Parameters for format string
*
* @retval 0 Write was successful
* @retval -1 Error while writing file
*/
int util_file_write_s(const char *str, const char *fmt, ...)
{
char path[PATH_MAX];
va_list ap;
/* Construct the file name */
UTIL_VSPRINTF(path, fmt, ap);
return file_puts(str, path);
}
/**
* Write signed long value to a file according to given base
*
* @param[in] val Value is to be written
* @param[in] base Base for conversion, either 8, 10, or 16
* @param[in] fmt Format string for generation of the path name
* @param[in] ... Parameters for format string
*
* @retval 0 Write was successful
* @retval -1 Error while writing file
*/
int util_file_write_l(long val, int base, const char *fmt, ...)
{
char *str, path[PATH_MAX];
va_list ap;
int rc;
/* Construct the file name */
UTIL_VSPRINTF(path, fmt, ap);
switch (base) {
case 8:
util_asprintf(&str, "%lo", val);
break;
case 10:
util_asprintf(&str, "%ld", val);
break;
case 16:
util_asprintf(&str, "%lx", val);
break;
default:
util_panic("Invalid base: %d\n", base);
}
rc = file_puts(str, path);
free(str);
return rc;
}
/**
* Write signed long long value to a file according to given base
*
* @param[in] val Value is to be written
* @param[in] base Base for conversion, either 8, 10, or 16
* @param[in] fmt Format string for generation of the path name
* @param[in] ... Parameters for format string
*
* @retval 0 Write was successful
* @retval -1 Error while writing file
*/
int util_file_write_ll(long long val, int base, const char *fmt, ...)
{
char *str, path[PATH_MAX];
va_list ap;
int rc;
/* Construct the file name */
UTIL_VSPRINTF(path, fmt, ap);
switch (base) {
case 8:
util_asprintf(&str, "%llo", val);
break;
case 10:
util_asprintf(&str, "%lld", val);
break;
case 16:
util_asprintf(&str, "%llx", val);
break;
default:
util_panic("Invalid base: %d\n", base);
}
rc = file_puts(str, path);
free(str);
return rc;
}
/**
* Write unsigned long value to a file according to given base
*
* @param[in] val Value is to be written
* @param[in] base Base for conversion, either 8, 10, or 16
* @param[in] fmt Format string for generation of the path name
* @param[in] ... Parameters for format string
*
* @retval 0 Write was successful
* @retval -1 Error while writing file
*/
int util_file_write_ul(unsigned long val, int base, const char *fmt, ...)
{
char *str, path[PATH_MAX];
va_list ap;
int rc;
/* Construct the file name */
UTIL_VSPRINTF(path, fmt, ap);
switch (base) {
case 8:
util_asprintf(&str, "%lo", val);
break;
case 10:
util_asprintf(&str, "%lu", val);
break;
case 16:
util_asprintf(&str, "%lx", val);
break;
default:
util_panic("Invalid base: %d\n", base);
}
rc = file_puts(str, path);
free(str);
return rc;
}
/**
* Write unsigned long long value to a file according to given base
*
* @param[in] val Value is to be written
* @param[in] base Base for conversion, either 8, 10, or 16
* @param[in] fmt Format string for generation of the path name
* @param[in] ... Parameters for format string
*
* @retval 0 Write was successful
* @retval -1 Error while writing file
*/
int util_file_write_ull(unsigned long long val, int base, const char *fmt, ...)
{
char *str, path[PATH_MAX];
va_list ap;
int rc;
/* Construct the file name */
UTIL_VSPRINTF(path, fmt, ap);
switch (base) {
case 8:
util_asprintf(&str, "%llo", val);
break;
case 10:
util_asprintf(&str, "%llu", val);
break;
case 16:
util_asprintf(&str, "%llx", val);
break;
default:
util_panic("Invalid base: %d\n", base);
}
rc = file_puts(str, path);
free(str);
return rc;
}
/**
* Read a file and convert it to signed long according to given base
*
* @param[out] val Buffer for value
* @param[in] base Base for conversion, either 8, 10, or 16
* @param[in] fmt Format string for generation of the path name
* @param[in] ... Parameters for format string
*
* @retval 0 Long integer has been read correctly
* @retval -1 Error while reading file
*/
int util_file_read_l(long *val, int base, const char *fmt, ...)
{
char path[PATH_MAX], buf[512];
va_list ap;
int count;
/* Construct the file name */
UTIL_VSPRINTF(path, fmt, ap);
if (file_gets(buf, sizeof(buf), path))
return -1;
switch (base) {
case 8:
count = sscanf(buf, "%lo", val);
break;
case 10:
count = sscanf(buf, "%ld", val);
break;
case 16:
count = sscanf(buf, "%lx", val);
break;
default:
util_panic("Invalid base: %d\n", base);
}
return (count == 1) ? 0 : -1;
}
/**
* Read a file and convert it to signed long long according to given base
*
* @param[out] val Buffer for value
* @param[in] base Base for conversion, either 8, 10, or 16
* @param[in] fmt Format string for generation of the path name
* @param[in] ... Parameters for format string
*
* @retval 0 Long integer has been read correctly
* @retval -1 Error while reading file
*/
int util_file_read_ll(long long *val, int base, const char *fmt, ...)
{
char path[PATH_MAX], buf[512];
va_list ap;
int count;
/* Construct the file name */
UTIL_VSPRINTF(path, fmt, ap);
if (file_gets(buf, sizeof(buf), path))
return -1;
switch (base) {
case 8:
count = sscanf(buf, "%llo", val);
break;
case 10:
count = sscanf(buf, "%lld", val);
break;
case 16:
count = sscanf(buf, "%llx", val);
break;
default:
util_panic("Invalid base: %d\n", base);
}
return (count == 1) ? 0 : -1;
}
/**
* Read a file and convert it to unsigned long according to given base
*
* @param[out] val Buffer for value
* @param[in] base Base for conversion, either 8, 10, or 16
* @param[in] fmt Format string for generation of the path name
* @param[in] ... Parameters for format string
*
* @retval 0 Long integer has been read correctly
* @retval -1 Error while reading file
*/
int util_file_read_ul(unsigned long *val, int base, const char *fmt, ...)
{
char path[PATH_MAX], buf[512];
va_list ap;
int count;
/* Construct the file name */
UTIL_VSPRINTF(path, fmt, ap);
if (file_gets(buf, sizeof(buf), path))
return -1;
switch (base) {
case 8:
count = sscanf(buf, "%lo", val);
break;
case 10:
count = sscanf(buf, "%lu", val);
break;
case 16:
count = sscanf(buf, "%lx", val);
break;
default:
util_panic("Invalid base: %d\n", base);
}
return (count == 1) ? 0 : -1;
}
/**
* Read a file and convert it to unsigned long long according to given base
*
* @param[out] val Buffer for value
* @param[in] base Base for conversion, either 8, 10, or 16
* @param[in] fmt Format string for generation of the path name
* @param[in] ... Parameters for format string
*
* @retval 0 Long integer has been read correctly
* @retval -1 Error while reading file
*/
int util_file_read_ull(unsigned long long *val, int base, const char *fmt, ...)
{
char path[PATH_MAX], buf[512];
va_list ap;
int count;
/* Construct the file name */
UTIL_VSPRINTF(path, fmt, ap);
if (file_gets(buf, sizeof(buf), path))
return -1;
switch (base) {
case 8:
count = sscanf(buf, "%llo", val);
break;
case 10:
count = sscanf(buf, "%llu", val);
break;
case 16:
count = sscanf(buf, "%llx", val);
break;
default:
util_panic("Invalid base: %d\n", base);
}
return (count == 1) ? 0 : -1;
}
+74
View File
@@ -0,0 +1,74 @@
/**
* util_file_example - Example program for util_file
*
* Copyright IBM Corp. 2016, 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.
*/
//! [code]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "lib/util_file.h"
/*
* Write buffer to file and read it back again
*/
int main(void)
{
char buf_wr[4096], buf_rd[4096];
unsigned long long value_ull;
long value_l;
/* Generate input */
sprintf(buf_wr, "Say something interesting!\nSecond line\n");
printf("Write.....:\n%s", buf_wr);
/* Write string to file */
if (util_file_write_s(buf_wr, "/tmp/%s", "testfile")) {
perror("util_file_write_s failed\n");
return EXIT_FAILURE;
}
/* Read back first line of file */
if (util_file_read_line(buf_rd, sizeof(buf_rd), "/tmp/%s", "testfile")) {
perror("util_file_read_line failed\n");
return EXIT_FAILURE;
}
printf("Read......: %s\n", buf_rd);
/* Write long to file */
printf("Write.....: %ld\n", 4711L);
if (util_file_write_l(4711L, 10, "/tmp/%s", "testfile")) {
perror("util_file_write failed\n");
return EXIT_FAILURE;
}
/* Read back long from file */
if (util_file_read_l(&value_l, 10, "/tmp/%s", "testfile")) {
perror("util_file_read_l failed\n");
return EXIT_FAILURE;
}
printf("Read......: %ld\n", value_l);
/* Write long long hexadecimal to file */
printf("Write.....: 0x%llx\n", 0x4712ULL);
if (util_file_write_ull(0x4712ULL, 16, "/tmp/%s", "testfile")) {
perror("util_file_write failed\n");
return EXIT_FAILURE;
}
/* Read back long long hexadecimal from file */
if (util_file_read_ull(&value_ull, 16, "/tmp/%s", "testfile")) {
perror("util_file_read_ull failed\n");
return EXIT_FAILURE;
}
printf("Read......: 0x%llx\n", value_ull);
/* Remove file */
unlink("/tmp/testfile");
return EXIT_SUCCESS;
}
//! [code]
+200
View File
@@ -0,0 +1,200 @@
/*
* util - Utility function library
*
* Handle standard errors for libc functions
*
* Copyright IBM Corp. 2016, 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 <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lib/util_base.h"
#include "lib/util_libc.h"
#include "lib/util_panic.h"
/*
* Return size as string of largest unit, e.g. 1025 = "1 KiB"
*/
static void format_size(char *str, size_t size)
{
static const char * const unit_vec[] =
{"byte", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"};
unsigned int i;
for (i = 0; i < UTIL_ARRAY_SIZE(unit_vec); i++) {
if (size / 1024 == 0) {
sprintf(str, "%zu %s", size, unit_vec[i]);
return;
}
size /= 1024;
}
sprintf(str, "huge");
}
static void __util_oom(const char *func, const char *file, int line,
size_t size)
{
char size_str[256];
fprintf(stderr, "%s: Failed to allocate memory",
program_invocation_short_name);
if (size > 0) {
format_size(size_str, size);
fprintf(stderr, " (%s)", size_str);
}
fprintf(stderr, " at %s:%d %s()\n", file, line, func);
exit(EXIT_FAILURE);
}
/*
* Allocate memory or exit in case of failure
*/
void *__util_malloc(const char *func, const char *file, int line, size_t size)
{
void *buf;
buf = malloc(size);
if (buf == NULL)
__util_oom(func, file, line, size);
return buf;
}
/*
* Allocate zero-initialized memory or exit in case of failure
*/
void *__util_zalloc(const char *func, const char *file, int line, size_t size)
{
void *buf = __util_malloc(func, file, line, size);
memset(buf, 0, size);
return buf;
}
/*
* Re-allocate memory or exit in case of failure
*/
void *__util_realloc(const char *func, const char *file, int line,
void *ptr, size_t size)
{
void *buf;
buf = realloc(ptr, size);
if (buf == NULL)
__util_oom(func, file, line, size);
return buf;
}
/*
* Duplicate a string buffer or exit in case of failure
*/
void *__util_strdup(const char *func, const char *file, int line,
const char *str)
{
void *buf = strdup(str);
if (buf == NULL)
__util_oom(func, file, line, strlen(str) + 1);
return buf;
}
/**
* Concatenate two strings or exit in case of failure
*
* The first string \a str1 is resized and a copy of the second
* string \a str2 is appended to it.
*
* Therefore the first string \a str1 must either have been allocated
* using malloc(), calloc(), or realloc() or must be NULL.
*
* @param[in] str1 Pointer to first string to concatenate, which
* becomes invalid
* @param[in] str2 Constant pointer to second string to concatenate
*
* @returns Pointer to concatenated string
*/
char *util_strcat_realloc(char *str1, const char *str2)
{
char *buf;
if (str1) {
buf = util_realloc(str1, strlen(str1) + strlen(str2) + 1);
strcat(buf, str2);
} else {
buf = util_strdup(str2);
}
return buf;
}
/**
* Convert string to uppercase
*
* String \a str is converted to uppercase
*
* @param[in,out] str String to convert
*/
void util_str_toupper(char *str)
{
int i;
for (i = 0; str[i] != '\0'; i++)
str[i] = toupper(str[i]);
}
/*
* Print to newly allocated string or exit in case of failure
*/
int __util_vasprintf(const char *func, const char *file, int line,
char **strp, const char *fmt, va_list ap)
{
int rc;
rc = vasprintf(strp, fmt, ap);
if (rc == -1)
__util_oom(func, file, line, 0);
return rc;
}
/*
* Print to newly allocated string or exit in case of failure
*/
int __util_asprintf(const char *func, const char *file, int line,
char **strp, const char *fmt, ...)
{
va_list ap;
int rc;
va_start(ap, fmt);
rc = __util_vasprintf(func, file, line, strp, fmt, ap);
va_end(ap);
return rc;
}
/*
* Print to string buffer or exit in case of failure
*/
int __util_vsprintf(const char *func, const char *file, int line,
char *str, const char *fmt, va_list ap)
{
int rc;
rc = vsprintf(str, fmt, ap);
if (rc == -1)
__util_assert("rc != -1", func, file, line,
rc != -1, "Could not format string\n");
return rc;
}
+52
View File
@@ -0,0 +1,52 @@
/**
* util_libc_example - Example program for util_libc
*
* Copyright IBM Corp. 2016, 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.
*/
//! [code]
#include <stdio.h>
#include <stdlib.h>
#include "lib/util_libc.h"
#include "lib/util_panic.h"
/*
* Demonstrate that out of memory is automatically handled via panic()
*/
int main(void)
{
unsigned long ulong_max = (unsigned long)-1;
void *ptr;
char *zeroes, *str;
/* Use util_strcat_realloc() for string concatenation */
fprintf(stderr, "Try to concatenate \"Hello\", \", \" and \"world!\": ");
str = util_strdup("Hello");
str = util_strcat_realloc(str, ", ");
str = util_strcat_realloc(str, "world!");
fprintf(stderr, "result = \"%s\"\n", str);
free(str);
/* One byte allocation should work */
fprintf(stderr, "Try to allocate 1 byte: ");
ptr = util_malloc(1);
fprintf(stderr, "done\n");
/* One byte zeroed-allocation should work */
fprintf(stderr, "Try to allocate 1 byte initialized with zeroes: ");
zeroes = util_zalloc(1);
fprintf(stderr, "done\n");
util_assert(*zeroes == 0, "Garbage found in zero initialized memory\n");
/* The next allocation will probably fail */
fprintf(stderr, "Try to allocate %lu bytes:\n", ulong_max);
ptr = util_malloc(ulong_max);
fprintf(stderr, "You should not see me (ptr=%p)!\n", ptr);
return EXIT_FAILURE;
}
//! [code]
+260
View File
@@ -0,0 +1,260 @@
/*
* util - Utility function library
*
* Linked list functions
*
* Copyright IBM Corp. 2013, 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lib/util_list.h"
/*
* Node to entry
*/
static inline void *n2e(struct util_list *list, struct util_list_node *node)
{
return ((void *) node) - list->offset;
}
/*
* Entry to node
*/
static inline struct util_list_node *e2n(struct util_list *list, void *entry)
{
return entry + list->offset;
}
/*
* Initialize linked list
*/
void util_list_init_offset(struct util_list *list, unsigned long offset)
{
memset(list, 0, sizeof(*list));
list->offset = offset;
}
/*
* Create new linked list
*/
struct util_list *util_list_new_offset(unsigned long offset)
{
struct util_list *list = malloc(sizeof(*list));
if (!list)
return NULL;
util_list_init_offset(list, offset);
return list;
}
/*
* Free linked list
*/
void util_list_free(struct util_list *list)
{
free(list);
}
/*
* Add new element to end of list
*/
void util_list_add_tail(struct util_list *list, void *entry)
{
struct util_list_node *node = e2n(list, entry);
node->next = NULL;
if (!list->start) {
list->start = node;
node->prev = NULL;
} else {
list->end->next = node;
node->prev = list->end;
}
list->end = node;
}
/*
* Add new element to front of list
*/
void util_list_add_head(struct util_list *list, void *entry)
{
struct util_list_node *node = e2n(list, entry);
node->prev = NULL;
node->next = NULL;
if (!list->start) {
list->end = node;
} else {
list->start->prev = node;
node->next = list->start;
}
list->start = node;
}
/*
* Add new element (entry) after an existing element (list_entry)
*/
void util_list_add_next(struct util_list *list, void *entry, void *list_entry)
{
struct util_list_node *node = e2n(list, entry);
struct util_list_node *list_node = e2n(list, list_entry);
node->next = list_node->next;
node->prev = list_node;
if (list_node->next)
list_node->next->prev = node;
else
list->end = node;
list_node->next = node;
}
/*
* Add new element (entry) before an existing element (list_entry)
*/
void util_list_add_prev(struct util_list *list, void *entry, void *list_entry)
{
struct util_list_node *node = e2n(list, entry);
struct util_list_node *list_node = e2n(list, list_entry);
node->prev = list_node->prev;
node->next = list_node;
if (list_node->prev)
list_node->prev->next = node;
else
list->start = node;
list_node->prev = node;
}
/*
* Remove element from list
*/
void util_list_remove(struct util_list *list, void *entry)
{
struct util_list_node *node = e2n(list, entry);
if (list->start == node)
list->start = node->next;
if (list->end == node)
list->end = node->prev;
if (node->prev)
node->prev->next = node->next;
if (node->next)
node->next->prev = node->prev;
}
/*
* Get first element of list
*/
void *util_list_start(struct util_list *list)
{
if (!list->start)
return NULL;
return ((void *) list->start) - list->offset;
}
/*
* Get last element of list
*/
void *util_list_end(struct util_list *list)
{
if (!list->end)
return NULL;
return n2e(list, list->end);
}
/*
* Get next element after entry
*/
void *util_list_next(struct util_list *list, void *entry)
{
struct util_list_node *node;
if (!entry)
return NULL;
node = e2n(list, entry);
node = node->next;
if (!node)
return NULL;
return n2e(list, node);
}
/*
* Get previous element before entry
*/
void *util_list_prev(struct util_list *list, void *entry)
{
struct util_list_node *node;
if (!entry)
return NULL;
node = e2n(list, entry);
node = node->prev;
if (!node)
return NULL;
return n2e(list, node);
}
/*
* Get number of list entries
*/
unsigned long util_list_len(struct util_list *list)
{
unsigned long cnt = 0;
void *entry;
util_list_iterate(list, entry)
cnt++;
return cnt;
}
/*
* Sort table (bubble sort)
*/
void util_list_sort(struct util_list *list, util_list_cmp_fn cmp_fn,
void *data)
{
struct util_list_node *node1, *node2;
unsigned long list_cnt, i, j;
void *entry1, *entry2;
list_cnt = util_list_len(list);
for (i = 1; i < list_cnt; i++) {
node1 = list->start;
for (j = 0; j < list_cnt - i; j++) {
node2 = node1->next;
entry1 = n2e(list, node1);
entry2 = n2e(list, node2);
if (cmp_fn(entry1, entry2, data) > 0) {
node1->next = node2->next;
if (node1->next)
node1->next->prev = node1;
else
list->end = node1;
node2->next = node1;
node2->prev = node1->prev;
if (node2->prev)
node2->prev->next = node2;
else
list->start = node2;
node1->prev = node2;
} else {
node1 = node2;
}
}
}
}
/*
* Check if list is empty
*/
int util_list_is_empty(struct util_list *list)
{
return list->start == NULL;
}
+322
View File
@@ -0,0 +1,322 @@
/*
* util - Utility function library
*
* Parse the command line options
*
* Copyright IBM Corp. 2016, 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 <argz.h>
#include <libgen.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lib/util_base.h"
#include "lib/util_libc.h"
#include "lib/util_opt.h"
#include "lib/util_panic.h"
#include "lib/util_prg.h"
/*
* Private data
*/
/// @cond
static struct util_opt_l {
/* Option character string for getopt_long() */
char *opt_str;
/* Option array for getopt_long() */
struct option *option_vec;
/* Original util_opt array */
struct util_opt *opt_vec;
/* Length of longest option string */
int opt_max;
/* Command used for parsing */
const char *command;
} l;
struct util_opt_l *util_opt_l = &l;
/// @endcond
#define util_opt_iterate(opt) \
for (opt = &l.opt_vec[0]; opt->desc != NULL; opt++)
#define MAX_OPTLEN 256
static int opt_max_len(void);
/**
* Initialize the command line options
*
* Build short option string and long option array to be used for getopt_long().
* The ":" prefix is added to the short option string for handling of "missing
* required arguments".
*
* @param[in] opt_vec Option array
* @param[in] opt_prefix Optional option string prefix
*/
void util_opt_init(struct util_opt *opt_vec, const char *opt_prefix)
{
int i, j, count;
char *str;
size_t prefix_len = opt_prefix ? strlen(opt_prefix) : 0;
opterr = 0;
/* Get number of options */
for (count = 0; opt_vec[count].desc != NULL; count++);
/*
* Allocate short option string for worst case when all options have
* optional parameters e.g "x::" and long option string.
*/
l.opt_str = util_malloc(sizeof(char) * count * 3 + 2 + prefix_len);
l.option_vec = util_malloc(sizeof(struct option) * (count + 1));
l.opt_vec = opt_vec;
str = l.opt_str;
if (opt_prefix) {
strcpy(str, opt_prefix);
str += prefix_len;
}
/* Force getopt_long() to return ':' for missing required arguments */
*str++ = ':';
/* Construction of input structures for getopt_long() function. */
for (i = 0, j = 0; i < count; i++) {
if (opt_vec[i].flags & UTIL_OPT_FLAG_SECTION)
continue;
if (!(opt_vec[i].flags & UTIL_OPT_FLAG_NOLONG)) {
memcpy(&l.option_vec[j++], &opt_vec[i].option,
sizeof(struct option));
}
if (opt_vec[i].flags & UTIL_OPT_FLAG_NOSHORT)
continue;
*str++ = opt_vec[i].option.val;
switch (opt_vec[i].option.has_arg) {
case no_argument:
break;
case required_argument:
*str++ = ':';
break;
case optional_argument:
*str++ = ':';
*str++ = ':';
break;
default:
util_panic("Unexpected \"has_arg\" parameter: %d\n",
opt_vec[i].option.has_arg);
}
}
/* Add end marker to option array and short option string */
memset(&l.option_vec[j], 0, sizeof(struct option));
*str = '\0';
}
/**
* Set the current command for command line option processing
*
* @param[in] command The current command or NULL for no command
*/
void util_opt_set_command(const char *command)
{
l.command = command;
}
/*
* Return true, if option belongs to current command setting
*/
static bool opt_is_active(struct util_opt *opt)
{
if (!opt->command || !l.command)
return true;
return (strcmp(opt->command, l.command) == 0);
}
/**
* Wrapper for getopt_long
*
* @param[in] argc Count of command line parameters
* @param[in] argv Array of command line parameters
*/
int util_opt_getopt_long(int argc, char *argv[])
{
struct util_opt *opt;
int val;
val = getopt_long(argc, argv, l.opt_str, l.option_vec, NULL);
switch (val) {
case ':':
case '?':
case -1:
break;
default:
if (!l.command)
break;
util_opt_iterate(opt) {
if (!opt_is_active(opt))
continue;
if (opt->option.val == val)
goto out;
}
/* No valid option found for command */
val = '?';
if (optarg)
optind--;
break;
}
out:
return val;
}
/*
* Format option name: Add short, long option and argument (as applicable)
*/
static void format_opt(char *buf, size_t maxlen, const struct util_opt *opt)
{
int has_arg, flags, rc;
char val, *arg_str;
const char *name;
has_arg = opt->option.has_arg;
name = opt->option.name;
val = opt->option.val;
flags = opt->flags;
/* Prepare potential option argument string */
if (has_arg == optional_argument) {
if (flags & UTIL_OPT_FLAG_NOLONG)
util_asprintf(&arg_str, "[%s]", opt->argument);
else
util_asprintf(&arg_str, "[=%s]", opt->argument);
} else if (has_arg == required_argument) {
util_asprintf(&arg_str, " %s", opt->argument);
} else {
util_asprintf(&arg_str, "");
}
/* Format the option */
if (flags & UTIL_OPT_FLAG_NOLONG)
rc = snprintf(buf, maxlen, "-%c%s", val, arg_str);
else if (flags & UTIL_OPT_FLAG_NOSHORT)
rc = snprintf(buf, maxlen, " --%s%s", name, arg_str);
else
rc = snprintf(buf, maxlen, "-%c, --%s%s", val, name, arg_str);
util_assert(rc < (int)maxlen, "Option too long: %s\n", name);
free(arg_str);
}
/*
* Return true, if option is to be printed for the current command setting
*/
static bool should_print_opt(const struct util_opt *opt)
{
if (l.command) {
/* Print only options that belong to command */
return opt->command ? !strcmp(opt->command, l.command) : false;
} else {
/* Print only common options (standard for non-command tools) */
return opt->command ? false : true;
}
}
/*
* Return size of the longest formatted option
*/
static int opt_max_len(void)
{
const struct util_opt *opt;
unsigned int max = 0;
char opt_str[MAX_OPTLEN];
util_opt_iterate(opt) {
if (opt->flags & UTIL_OPT_FLAG_SECTION)
continue;
if (!should_print_opt(opt))
continue;
format_opt(opt_str, MAX_OPTLEN, opt);
max = MAX(max, strlen(opt_str));
}
return max;
}
/**
* Print an option name, followed by a description indented to fit the
* longest option name
*/
void util_opt_print_indented(const char *opt, const char *desc)
{
printf(" %-*s ", l.opt_max + 1, opt);
util_print_indented(desc, 3 + l.opt_max);
}
/**
* Print the usage of the command line options to the console
*/
void util_opt_print_help(void)
{
char opt_str[MAX_OPTLEN];
struct util_opt *opt;
int first = 1;
/*
* Create format string: " -%c, --%-<long opt size>s %s"
*
* Example:
*
* -p, --print STRING Print STRING to console
*/
l.opt_max = opt_max_len();
util_opt_iterate(opt) {
if (!should_print_opt(opt))
continue;
if (opt->flags & UTIL_OPT_FLAG_SECTION) {
printf("%s%s\n", first ? "" : "\n", opt->desc);
first = 0;
continue;
}
format_opt(opt_str, MAX_OPTLEN, opt);
util_opt_print_indented(opt_str, opt->desc);
}
}
/**
* Print option parsing error message
*
* This function should be used when the return code of the
* util_opt_getopt_long() function returns a character that does
* not match any of the expected options.
*
* @param[in] opt Short option returned by getopt_long()
* @param[in] argv Option array
*/
void util_opt_print_parse_error(char opt, char *argv[])
{
char optopt_str[3];
switch (opt) {
case ':':
/* A required option argument has not been specified */
util_prg_print_required_arg(argv[optind - 1]);
break;
case '?':
/* An invalid option has been specified */
if (optopt) {
/* Short option */
sprintf(optopt_str, "-%c", optopt);
util_prg_print_invalid_option(optopt_str);
} else {
/* Long option */
util_prg_print_invalid_option(argv[optind - 1]);
}
break;
default:
util_panic("Option '%c' should not be handled here\n", opt);
}
}
+207
View File
@@ -0,0 +1,207 @@
/*
* util_opt_command_example - Example program for util_opt with commands
*
* 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.
*/
//! [code]
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lib/util_opt.h"
#include "lib/util_prg.h"
#define OPT_NOSHORT 256
#define COMMAND_PULL "pull"
#define COMMAND_PUSH "push"
/*
* Define the command line options
*/
static struct util_opt opt_vec[] = {
{
.desc = "OPTIONS",
.flags = UTIL_OPT_FLAG_SECTION,
.command = COMMAND_PULL,
},
{
.option = { "single", no_argument, NULL, 's'},
.desc = "A single option without an argument",
.command = COMMAND_PULL,
},
{
.option = { "req_arg", required_argument, NULL, 'r'},
.argument = "REQ_ARG",
.desc = "Option with a required argument REQ_ARG",
.command = COMMAND_PULL,
},
{
.desc = "OPTIONS",
.flags = UTIL_OPT_FLAG_SECTION,
.command = COMMAND_PUSH,
},
{
.option = { "noshort", no_argument, NULL, OPT_NOSHORT},
.desc = "Option with only a long name",
.flags = UTIL_OPT_FLAG_NOSHORT,
.command = COMMAND_PUSH,
},
{
.option = { NULL, no_argument, NULL, 'l'},
.desc = "Option with only a short name",
.flags = UTIL_OPT_FLAG_NOLONG,
.command = "push",
},
UTIL_OPT_SECTION("COMMON OPTIONS"),
/* Standard option: -h,--help */
UTIL_OPT_HELP,
/* Standard option: -v,--version */
UTIL_OPT_VERSION,
/* End-marker for option vector */
UTIL_OPT_END
};
static char usage_global_start[] =
"Usage: util_opt_command_example [COMMAND] [OPTIONS]\n"
"\n"
"Demonstrate how programs with commands can use the \"util_opt\" library.\n"
"\n"
"COMMANDS\n"
" push Push some content to somewhere\n"
" pull Pull some content from somewhere\n";
static char usage_global_end[] =
"For more information use 'util_opt_command_example COMMAND --help'.\n";
static char usage_push_start[] =
"Usage: util_opt_command_example push [OPTIONS]\n"
"\n"
"Push some content to somewhere.\n";
static char usage_pull_start[] =
"Usage: util_opt_command_example pull [OPTIONS]\n"
"\n"
"Pull some content from somewhere.\n";
/*
* Print help header for command or program
*/
static void command_print_help_start(const char *command)
{
if (command == NULL)
printf("%s", usage_global_start);
else if (strcmp(command, COMMAND_PUSH) == 0)
printf("%s", usage_push_start);
else if (strcmp(command, COMMAND_PULL) == 0)
printf("%s", usage_pull_start);
printf("\n");
}
/*
* Print help footer
*/
static void command_print_help_end(const char *command)
{
if (command == NULL)
printf("\n%s", usage_global_end);
}
/*
* Parse the command line options with util_opt functions
*/
int main(int argc, char *argv[])
{
int c, my_argc = argc;
char **my_argv = argv;
char *command = NULL;
/* Install option vector */
util_opt_init(opt_vec, NULL);
/* The command name is the very first argument */
if (argc >= 2 && strncmp(argv[1], "-", 1) != 0) {
command = argv[1];
my_argc--;
my_argv = &argv[1];
if (strcasecmp(command, COMMAND_PULL) != 0 &&
strcasecmp(command, COMMAND_PUSH) != 0) {
fprintf(stderr, "%s: Invalid command '%s'\n",
program_invocation_short_name, argv[1]);
util_prg_print_parse_error();
return EXIT_FAILURE;
}
}
/* Set the current command (if any) */
util_opt_set_command(command);
util_prg_set_command(command);
/* Parse all options specified in my_argv[] */
while (1) {
/* Get the next option 'c' from my_argv[] */
c = util_opt_getopt_long(my_argc, my_argv);
/* No more options on command line? */
if (c == -1)
break;
/* Find the right action for option 'c' */
switch (c) {
case 'h':
command_print_help_start(command);
util_opt_print_help();
command_print_help_end(command);
return EXIT_SUCCESS;
case 'v':
printf("Specified: --version\n");
return EXIT_SUCCESS;
case 's':
printf("Specified: --single\n");
break;
case 'r':
printf("Specified: --req_arg %s\n", optarg);
break;
case OPT_NOSHORT:
printf("Specified: --noshort\n");
break;
case 'l':
printf("Specified: -l\n");
break;
default:
util_opt_print_parse_error(c, my_argv);
return EXIT_FAILURE;
}
}
if (optind < my_argc) {
util_prg_print_arg_error(my_argv[optind]);
return EXIT_FAILURE;
}
if (command == NULL) {
fprintf(stderr, "%s: Command is required\n",
program_invocation_short_name);
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (strcasecmp(command, COMMAND_PULL) == 0) {
printf("Run the pull command\n");
return EXIT_SUCCESS;
} else if (!strcasecmp(command, COMMAND_PUSH)) {
printf("Run the push command\n");
return EXIT_SUCCESS;
}
fprintf(stderr, "%s: Invalid command '%s'\n",
program_invocation_short_name, argv[1]);
util_prg_print_parse_error();
return EXIT_FAILURE;
}
//! [code]
+122
View File
@@ -0,0 +1,122 @@
/*
* util_opt_example - Example program for util_opt
*
* Copyright IBM Corp. 2016, 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.
*/
//! [code]
#include <stdio.h>
#include <stdlib.h>
#include "lib/util_opt.h"
#define OPT_NOSHORT 256
/*
* Define the command line options
*/
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("OPTION WITHOUT ARGUMENTS"),
/* Our own options */
{
.option = { "single", no_argument, NULL, 's'},
.desc = "A single option without an argument",
},
UTIL_OPT_SECTION("OPTIONS WITH ARGUMENTS"),
{
.option = { "req_arg", required_argument, NULL, 'r'},
.argument = "REQ_ARG",
.desc = "Option with a required argument REQ_ARG",
},
{
/*
* NOTE: For specifying an optional parameter OPT_ARG use
* either "-oOPT_ARG" or "--opt_arg=OPT_ARG" on the commandline.
* Specifying "-o OPT_ARG" or "--opt_arg OPT_ARG" will not work.
*/
.option = { "opt_arg", optional_argument, NULL, 'o'},
.argument = "OPT_ARG",
.desc = "Option with an optional argument OPT_ARG. " \
"We don't recommend using this feature.",
},
UTIL_OPT_SECTION("OPTION WITHOUT SHORT OPTION"),
{
.option = { "noshort", no_argument, NULL, OPT_NOSHORT},
.desc = "Option with only a long name",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
UTIL_OPT_SECTION("OPTION WITHOUT LONG OPTION"),
{
.option = { NULL, no_argument, NULL, 'l'},
.desc = "Option with only a short name",
.flags = UTIL_OPT_FLAG_NOLONG,
},
UTIL_OPT_SECTION("OPTION WITH MANUALLY FORMATTED DESCRIPTION"),
{
.option = { "manual", no_argument, NULL, 'm' },
.desc = "Option descriptions can be formatted\n" \
"using the new line character '\\n' to:\n" \
" - Display descriptions more meaningful\n" \
" - Create lists within the description",
},
UTIL_OPT_SECTION("STANDARD OPTIONS"),
/* Standard option: -h,--help */
UTIL_OPT_HELP,
/* Standard option: -v,--version */
UTIL_OPT_VERSION,
/* End-marker for option vector */
UTIL_OPT_END
};
/*
* Parse the command line options with util_opt functions
*/
int main(int argc, char *argv[])
{
int c;
/* Install option vector */
util_opt_init(opt_vec, NULL);
/* Parse all options specified in argv[] */
while (1) {
/* Get the next option 'c' from argv[] */
c = util_opt_getopt_long(argc, argv);
/* No more options on command line? */
if (c == -1)
break;
/* Find the right action for option 'c' */
switch (c) {
case 'h':
util_opt_print_help();
return EXIT_SUCCESS;
case 'v':
printf("Specified: --version\n");
return EXIT_SUCCESS;
case 's':
printf("Specified: --single\n");
break;
case 'o':
if (optarg != NULL)
printf("Specified: --opt_arg %s\n", optarg);
else
printf("Specified: --opt_arg [without arg]\n");
break;
case 'r':
printf("Specified: --req_arg %s\n", optarg);
break;
case OPT_NOSHORT:
printf("Specified: --noshort\n");
break;
default:
util_opt_print_parse_error(c, argv);
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
//! [code]
+121
View File
@@ -0,0 +1,121 @@
/*
* util - Utility function library
*
* Collect FFDC data for unexpected errors
*
* Copyright IBM Corp. 2016, 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 <execinfo.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/time.h>
#include "lib/util_base.h"
#include "lib/util_panic.h"
/*
* Obtain a backtrace and print it to stderr
*
* To get symbols, compile the code with "-rdynamic".
*/
static void print_backtrace(void)
{
void *array[256];
size_t i, size;
char **strings;
fprintf(stderr, "Backtrace:\n\n");
size = backtrace(array, UTIL_ARRAY_SIZE(array));
strings = backtrace_symbols(array, size);
if (strings == NULL) {
fprintf(stderr, " Could not obtain backtrace (ENOMEM)\n");
return;
}
for (i = 0; i < size; i++)
fprintf(stderr, " %s\n", strings[i]);
free(strings);
}
/*
* Check for core ulimit
*/
static void ulimit_core_check(void)
{
struct rlimit limit;
if (getrlimit(RLIMIT_CORE, &limit) != 0)
return;
if (limit.rlim_cur != 0)
return;
fprintf(stderr, "Core dump size is zero. To get a full core dump use 'ulimit -c unlimited'.\n");
}
/*
* Print FFDC data and then abort
*/
static void panic_finish(const char *func, const char *file, int line,
const char *fmt, va_list ap)
{
/* Write panic error string */
fprintf(stderr, "\n");
fprintf(stderr, "Error string:\n");
fprintf(stderr, "\n");
fprintf(stderr, " ");
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
/* Write file, line number, and function name */
fprintf(stderr, "Location:\n\n");
fprintf(stderr, " %s:%d: %s()\n", file, line, func);
fprintf(stderr, "\n");
/* Print the function backtrace */
print_backtrace();
fprintf(stderr, "\n");
ulimit_core_check();
fprintf(stderr, "----------------------------------------------------------------------->8-----\n");
abort();
}
/*
* Do panic processing if the assumption is not true
*/
void __util_assert(const char *assertion_str,
const char *func, const char *file, int line,
int assumption, const char *fmt, ...)
{
va_list ap;
if (assumption)
return;
va_start(ap, fmt);
fprintf(stderr, "---8<-------------------------------------------------------------------------\n");
fprintf(stderr, "ASSERTION FAILED: The application terminated due to an internal or OS error\n");
fprintf(stderr, "\n");
fprintf(stderr, "The following assumption was *not* true:\n");
fprintf(stderr, "\n");
fprintf(stderr, " %s\n", assertion_str);
panic_finish(func, file, line, fmt, ap);
}
/*
* Do panic processing
*/
void __noreturn __util_panic(const char *func, const char *file, int line,
const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "---8<-------------------------------------------------------------------------\n");
fprintf(stderr, "PANIC: The application terminated due to an unrecoverable error\n");
panic_finish(func, file, line, fmt, ap);
while(1);
}
+95
View File
@@ -0,0 +1,95 @@
/**
* util_panic_example - Example program for util_panic
*
* Copyright IBM Corp. 2016, 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.
*/
//! [code]
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/time.h>
#include "lib/util_panic.h"
/* Make functions noinline to have a nice backtrace */
#define __noinline __attribute__((noinline))
/*
* Test util_panic()
*/
__noinline void panic_test_func(void)
{
fprintf(stderr, "Testing util_panic() now\n");
util_panic("Adieu beautiful world ...\n");
fprintf(stderr, "You should not see this\n");
}
/*
* Test util_panic() with errno handling
*/
__noinline void panic_errno_test_func(void)
{
const char *file = "i_do_not_exist";
if (fopen("i_do_not_exist", "r") == NULL) {
util_panic("Open file \"%s\" failed: %s\n",
file, strerror(errno));
}
fprintf(stderr, "You should not see this\n");
}
/*
* Test util_assert()
*/
__noinline void assert_test_func(void)
{
char *drink_actual = "beer";
fprintf(stderr, "Testing util_assert() now\n");
util_assert(strcmp(drink_actual, "water") == 0,
"We expected \"%s\" but got \"%s\"\n",
"water", drink_actual);
fprintf(stderr, "You should not see this\n");
}
/*
* Demonstrate util_panic() and util_assert()
*/
int main(int argc, char *argv[])
{
struct rlimit rlim_unlimited = {-1, -1};
struct rlimit rlim_zero = {0, 0};
if (argc != 2)
goto fail;
if (strcmp(argv[1], "util_panic") == 0) {
fprintf(stderr, "Disable core files: ulimit -c 0\n");
setrlimit(RLIMIT_CORE, &rlim_zero);
/* Do the panic */
panic_test_func();
} else if (strcmp(argv[1], "util_panic_errno") == 0) {
setrlimit(RLIMIT_CORE, &rlim_unlimited);
/* Do the panic */
panic_errno_test_func();
} else if (strcmp(argv[1], "util_assert") == 0) {
fprintf(stderr, "Enable core files: ulimit -c unlimited\n");
setrlimit(RLIMIT_CORE, &rlim_unlimited);
/* Do the assertion */
assert_test_func();
}
fail:
fprintf(stderr, "Usage: %s util_panic|util_panic_errno|util_assert\n", argv[0]);
return EXIT_FAILURE;
}
//! [code]
+288
View File
@@ -0,0 +1,288 @@
/*
* util - Utility function library
*
* Partition detection functions
*
* Copyright IBM Corp. 2013, 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 <endian.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "lib/util_part.h"
#define GPT_SIGNATURE 0x4546492050415254ULL /* EFI PART */
#define MBR_SIGNATURE 0x55aa
#define MBR_PART_TYPE_DOS_EXT 0x05 /* DOS extended partition */
#define MBR_PART_TYPE_WIN98_EXT 0x0f /* Windows 98 extended partition */
#define MBR_PART_TYPE_LINUX_EXT 0x85 /* Linux extended partition */
#define MBR_PART_TYPE_GPT 0xee /* GPT partition */
#define MBR_EXT_PART_NUM_FIRST 5 /* Partition number for first logical vol */
/*
* MBR/MSDOS partition entry
*/
struct mbr_part_entry {
uint8_t status;
uint8_t chs_start[3];
uint8_t type;
uint8_t chs_end[3];
uint32_t blk_start;
uint32_t blk_cnt;
} __attribute__((packed));
/*
* Master Boot Record (MBR)
*/
struct mbr {
uint8_t reserved[0x1be];
struct mbr_part_entry part_entry_vec[4];
uint16_t signature;
} __attribute__((packed));
/*
* GUID Partition Table (GPT) header
*/
struct gpt {
uint64_t signature;
uint32_t version;
uint32_t hdr_size;
uint32_t hdr_crc;
uint32_t reserved1;
uint64_t blk_cur;
uint64_t blk_back;
uint64_t blk_first;
uint64_t blk_last;
uint8_t guid[16];
uint64_t part_tab_blk_start;
uint32_t part_tab_cnt;
uint32_t part_tab_entry_size;
uint32_t part_tab_crc;
} __attribute__((packed));
/*
* GPT partition entry
*/
struct gpt_part_entry {
uint8_t type[16];
uint8_t guid[16];
uint64_t blk_start;
uint64_t blk_end;
uint64_t attr;
char name[72];
} __attribute__((packed));
/*
* Check for extended partition
*/
static int mbr_part_is_ext(uint8_t type)
{
if ((type == MBR_PART_TYPE_DOS_EXT) ||
(type == MBR_PART_TYPE_WIN98_EXT) ||
(type == MBR_PART_TYPE_LINUX_EXT))
return 1;
return 0;
}
/*
* Check if disk has a classic MBR partion table
*/
static int mbr_table_valid(struct mbr *mbr)
{
return mbr->signature == MBR_SIGNATURE;
}
/*
* Search partition in logical volumes of an extended partition
*/
static int mbr_table_ext_search(int fh, size_t blk_start_mbr,
size_t blk_start, size_t blk_cnt,
size_t blk_size, int part_num)
{
size_t start, cnt, start_next;
struct mbr mbr;
/* Read MBR for logical volume */
if (lseek(fh, blk_start_mbr * blk_size, SEEK_SET) == (off_t)-1)
return -1;
if (read(fh, &mbr, sizeof(mbr)) == -1)
return -1;
/* Check for invalid MBR or last entry */
if (mbr.signature != MBR_SIGNATURE)
return -1;
if (mbr.part_entry_vec[0].blk_start == 0)
return -1;
/* First entry contains a relative offset for current logical volume */
start = blk_start_mbr + le32toh(mbr.part_entry_vec[0].blk_start);
cnt = le32toh(mbr.part_entry_vec[0].blk_cnt);
if ((start == blk_start) && (cnt == blk_cnt))
return part_num;
/* Second entry contains relative offset for next logical volume */
start_next = le32toh(mbr.part_entry_vec[1].blk_start);
if (start_next == 0)
return 0;
start_next += blk_start_mbr;
/* Recursively search for next logical volume in chain */
return mbr_table_ext_search(fh, start_next, blk_start, blk_cnt,
blk_size, part_num + 1);
}
/*
* Search partition in MBR partition table
*/
static int mbr_table_search(int fh, struct mbr *mbr, size_t blk_start,
size_t blk_cnt, size_t blk_size, int *part_ext)
{
int part_num_ext, part_num;
size_t start, cnt;
uint8_t type;
for (part_num = 1; part_num <= 4; part_num++) {
type = mbr->part_entry_vec[part_num - 1].type;
start = le32toh(mbr->part_entry_vec[part_num - 1].blk_start);
cnt = le32toh(mbr->part_entry_vec[part_num - 1].blk_cnt);
if (start == 0) /* Empty slot */
continue;
/*
* The kernel sets count for extended partitions explicitly.
* Therefore we do not check count here.
*/
if (mbr_part_is_ext(type) && (start == blk_start)) {
*part_ext = 1;
return part_num;
}
if ((start == blk_start) && (cnt == blk_cnt))
return part_num;
if (!mbr_part_is_ext(type))
continue;
part_num_ext = mbr_table_ext_search(fh, start, blk_start,
blk_cnt, blk_size,
MBR_EXT_PART_NUM_FIRST);
if (part_num_ext != 0)
return part_num_ext;
}
return 0;
}
/*
* Search partition in GPT partition table
*/
static int gpt_table_search(int fh, struct gpt *gpt, size_t blk_start,
size_t blk_cnt, size_t blk_size)
{
size_t start, end, part_tab_blk_start, blk_end;
uint32_t part_tab_cnt, part_tab_entry_size;
struct gpt_part_entry *part_entry;
unsigned int part_num;
blk_end = blk_start + blk_cnt - 1;
part_tab_entry_size = le32toh(gpt->part_tab_entry_size);
part_tab_cnt = le32toh(gpt->part_tab_cnt);
part_tab_blk_start = le64toh(gpt->part_tab_blk_start);
if (lseek(fh, part_tab_blk_start * blk_size, SEEK_SET) == (off_t)-1)
return -1;
for (part_num = 1; part_num <= part_tab_cnt; part_num++) {
char buf[part_tab_entry_size];
part_entry = (struct gpt_part_entry *) buf;
if (read(fh, buf, sizeof(buf)) == -1)
return -1;
start = le64toh(part_entry->blk_start);
end = le64toh(part_entry->blk_end);
if (start == 0) /* Empty slot */
continue;
if ((start == blk_start) && (end == blk_end))
return part_num;
}
return 0;
}
/*
* Check if disk has a GPT partition table
*/
static int gpt_table_valid(struct gpt *gpt, struct mbr *mbr)
{
int cnt, part_num;
uint32_t start;
uint8_t type;
if (gpt->signature != GPT_SIGNATURE)
return 0;
/* Check for protective MBR (one reserved GPT partition) */
for (part_num = 1, cnt = 0; part_num <= 4; part_num++) {
start = le32toh(mbr->part_entry_vec[part_num - 1].blk_start);
type = mbr->part_entry_vec[part_num - 1].type;
if (!start)
continue;
if (type != MBR_PART_TYPE_GPT)
return 0;
if (++cnt > 1)
return 0;
}
return 1;
}
/*
* Search for partition with given start block and count
*
* Return partition number when found, 0 when not found, and on error -1
* Set "part_ext" to 1 for extended partitions otherwise to 0.
*/
int util_part_search_fh(int fh, size_t blk_start, size_t blk_cnt,
size_t blk_size, int *part_ext)
{
struct gpt gpt;
struct mbr mbr;
if (lseek(fh, 0, SEEK_SET) == (off_t)-1)
return -1;
if (read(fh, &mbr, sizeof(mbr)) == -1)
return -1;
if (lseek(fh, blk_size, SEEK_SET) == (off_t)-1)
return -1;
if (read(fh, &gpt, sizeof(gpt)) == -1)
return -1;
*part_ext = 0;
if (gpt_table_valid(&gpt, &mbr))
return gpt_table_search(fh, &gpt, blk_start, blk_cnt, blk_size);
if (mbr_table_valid(&mbr))
return mbr_table_search(fh, &mbr, blk_start, blk_cnt, blk_size,
part_ext);
return -1;
}
/*
* Search for partition with given start block and count
*
* Return partition number when found, 0 when not found, and on error -1
* Set "part_ext" to 1 for extended partitions otherwise to 0.
*/
int util_part_search(const char *device, size_t blk_start, size_t blk_cnt,
size_t blk_size, int *part_ext)
{
int rc, fh;
fh = open(device, O_RDONLY);
if (fh == -1)
return -1;
rc = util_part_search_fh(fh, blk_start, blk_cnt, blk_size, part_ext);
close(fh);
return rc;
}
+196
View File
@@ -0,0 +1,196 @@
/*
* util - Utility function library
*
* Work with paths
*
* Copyright IBM Corp. 2016, 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 <err.h>
#include <stdarg.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "lib/util_base.h"
#include "lib/util_libc.h"
#include "lib/util_path.h"
#include "lib/util_prg.h"
#include "lib/util_proc.h"
/*
* Verify that directory exists
*/
static void verify_dir(const char *dir)
{
struct stat sb;
int rc;
rc = stat(dir, &sb);
if (rc < 0)
err(EXIT_FAILURE, "Could not access directory: %s", dir);
if (!S_ISDIR(sb.st_mode))
errx(EXIT_FAILURE, "Is not a directory: %s", dir);
}
/*
* Return sysfs mount point
*/
static char *sys_mount_point(void)
{
struct util_proc_mnt_entry mnt_entry;
static char *mount_point;
char *dir;
if (mount_point)
return mount_point;
/* Check the environment variable */
dir = getenv("SYSFS_ROOT");
if (dir) {
mount_point = util_strdup(dir);
} else {
if (util_proc_mnt_get_entry("/proc/mounts", "sysfs",
&mnt_entry))
errx(EXIT_FAILURE, "No mount point found for sysfs");
mount_point = util_strdup(mnt_entry.file);
util_proc_mnt_free_entry(&mnt_entry);
}
verify_dir(mount_point);
return mount_point;
}
/**
* Construct a sysfs path
*
* The arguments of the function are used to specify a subdirectory under
* sysfs root.
*
* @param[in] fmt Format string for path
* @param[in] ... Variable arguments for format string
*
* @returns Allocated path
*/
char *util_path_sysfs(const char *fmt, ...)
{
char *path, *fmt_tot;
va_list ap;
util_asprintf(&fmt_tot, "%s/%s", sys_mount_point(), fmt);
/* Format and return full sysfs path */
va_start(ap, fmt);
util_vasprintf(&path, fmt_tot, ap);
va_end(ap);
free(fmt_tot);
return path;
}
/**
* Test if path exists and is readable
*
* This function has the same semantics as "-r path" in bash.
*
* @param[in] fmt Format string for path to test
* @param[in] ... Variable arguments for format string
*
* @returns true Path exists and is readable
* false Otherwise
*/
bool util_path_is_readable(const char *fmt, ...)
{
va_list ap;
char *path;
bool rc;
UTIL_VASPRINTF(&path, fmt, ap);
rc = access(path, R_OK) == 0 ? true : false;
free(path);
return rc;
}
/**
* Test if path exists and is writable
*
* This function has the same semantics as "-w path" in bash.
*
* @param[in] fmt Format string for path to test
* @param[in] ... Variable arguments for format string
*
* @returns true Path exists and is writable
* false Otherwise
*/
bool util_path_is_writable(const char *fmt, ...)
{
va_list ap;
char *path;
bool rc;
UTIL_VASPRINTF(&path, fmt, ap);
rc = access(path, W_OK) == 0 ? true : false;
free(path);
return rc;
}
/**
* Test if path exists and is a regular file
*
* This function has the same semantics as "-f path" in bash.
*
* @param[in] fmt Format string for path to test
* @param[in] ... Variable arguments for format string
*
* @returns true Path exists and is a regular file
* false Otherwise
*/
bool util_path_is_reg_file(const char *fmt, ...)
{
struct stat sb;
va_list ap;
char *path;
bool rc;
UTIL_VASPRINTF(&path, fmt, ap);
if (stat(path, &sb)) {
rc = false;
goto free_str;
}
rc = (sb.st_mode & S_IFREG) ? true : false;
free_str:
free(path);
return rc;
}
/**
* Test if path exists and is a directory
*
* This function has the same semantics as "-d path" in bash.
*
* @param[in] fmt Format string for path to test
* @param[in] ... Variable arguments for format string
*
* @returns true Path exists and is a directory
* false Otherwise
*/
bool util_path_is_dir(const char *fmt, ...)
{
struct stat sb;
va_list ap;
char *path;
bool rc;
UTIL_VASPRINTF(&path, fmt, ap);
if (stat(path, &sb)) {
rc = false;
goto free_str;
}
rc = (sb.st_mode & S_IFDIR) ? true : false;
free_str:
free(path);
return rc;
}
+112
View File
@@ -0,0 +1,112 @@
/**
* util_path_example - Example program for util_path
*
* Copyright IBM Corp. 2016, 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.
*/
//! [code]
#include <dirent.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lib/util_path.h"
#include "lib/util_prg.h"
/*
* Define program description
*/
const struct util_prg prg = {
.desc = "Sample for util_dirlibrary",
.copyright_vec = {
{
.owner = "IBM Corp.",
.pub_first = 2001,
.pub_last = 2016,
},
UTIL_PRG_COPYRIGHT_END
}
};
/*
* Test util_path_sysfs()
*/
static void test_util_path_sysfs(void)
{
const char * const subsys_vec[] = {"cpu", "memory"};
char *path;
int i;
/* Construct sysfs paths for the subsystems */
for (i = 0; i < 2; i++) {
path = util_path_sysfs("devices/system/%s", subsys_vec[i]);
printf("Path for %6s: \"%s\"\n", subsys_vec[i], path);
free(path);
}
}
/*
* Test path
*/
static void test_path(const char *path)
{
printf("%-20s: ", path);
if (util_path_is_readable(path))
printf("read=yes, ");
else
printf("read=no , ");
if (util_path_is_writable(path))
printf("write=yes, ");
else
printf("write=no , ");
if (util_path_is_reg_file(path))
printf("reg_file=yes");
else
printf("reg_file=no ");
if (util_path_is_dir(path))
printf("dir=yes");
else
printf("dir=no ");
printf("\n");
}
/*
* Test util_path_is_xxx()
*/
static void test_util_path_is_xxx(void)
{
test_path("util_path_example.c");
test_path("/tmp");
test_path("i_do_not_exist");
}
/*
* Usage: util_path_example [sysfs mount point] | "is_xxx"
*/
int main(int argc, char *argv[])
{
util_prg_init(&prg);
if (argc < 2)
goto out_fail;
if (strcmp(argv[1], "sysfs") == 0) {
if (argc == 3) {
/* Change sysfs path via SYSFS_ROOT env variable */
setenv("SYSFS_ROOT", argv[2], 1);
}
test_util_path_sysfs();
} else if (strcmp(argv[1], "is_xxx") == 0) {
test_util_path_is_xxx();
} else {
goto out_fail;
}
return EXIT_SUCCESS;
out_fail:
errx(EXIT_FAILURE, "Usage: %s sysfs <path> | is_xxx", argv[0]);
}
//! [code]
+136
View File
@@ -0,0 +1,136 @@
/*
* util - Utility function library
*
* Print standard program messages
*
* Copyright IBM Corp. 2016, 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 <errno.h>
#include <stdio.h>
#include "lib/util_base.h"
#include "lib/util_prg.h"
#include "lib/zt_common.h"
/*
* Private data
*/
static struct util_prg_l {
const struct util_prg *prg;
/* Command used for parsing */
const char *command;
} l;
struct util_prg_l *util_prg_l = &l;
/**
* Set the current command for command line option processing
*
* @param[in] command The current command or NULL for no command
*/
void util_prg_set_command(const char *command)
{
l.command = command;
}
/**
* Print program usage information for the --help option
*/
void util_prg_print_help(void)
{
/* Print usage */
printf("Usage: %s", program_invocation_short_name);
if (l.prg->command_args)
printf(" %s", l.prg->command_args);
printf(" [OPTIONS]");
if (l.prg->args)
printf(" %s", l.prg->args);
/* Print usage description */
printf("\n\n");
util_print_indented(l.prg->desc, 0);
printf("\n");
}
/**
* Print program version information for the --version option
*/
void util_prg_print_version(void)
{
const struct util_prg_copyright *copyright;
printf("%s version %s\n", program_invocation_short_name,
RELEASE_STRING);
copyright = l.prg->copyright_vec;
while (copyright->owner) {
if (copyright->pub_first == copyright->pub_last)
printf("Copyright %s %d\n", copyright->owner,
copyright->pub_first);
else
printf("Copyright %s %d, %d\n", copyright->owner,
copyright->pub_first, copyright->pub_last);
copyright++;
}
}
/*
* Ask user to use the --help option
*/
void util_prg_print_parse_error(void)
{
if (l.command)
fprintf(stderr, "Try '%s %s --help' for more information.\n",
program_invocation_short_name, l.command);
else
fprintf(stderr, "Try '%s --help' for more information.\n",
program_invocation_short_name);
}
/**
* An option has been specified that is not supported
*
* @param[in] option Option string (short or long)
*/
void util_prg_print_invalid_option(const char *opt_name)
{
fprintf(stderr, "%s: Invalid option '%s'\n",
program_invocation_short_name, opt_name);
util_prg_print_parse_error();
}
/**
* A required argument for an option is missing
*
* @param[in] option Option string
*/
void util_prg_print_required_arg(const char *opt_name)
{
fprintf(stderr, "%s: Option '%s' requires an argument\n",
program_invocation_short_name, opt_name);
util_prg_print_parse_error();
}
/**
* A superfluous invalid positional argument has been specified
*
* @param[in] arg_name Name of the invalid argument
*/
void util_prg_print_arg_error(const char *arg_name)
{
fprintf(stderr, "%s: Invalid argument '%s'\n",
program_invocation_short_name, arg_name);
util_prg_print_parse_error();
}
/**
* Initialize the program module
*
* @param[in] prg Program description
*/
void util_prg_init(const struct util_prg *prg)
{
l.prg = prg;
}
+91
View File
@@ -0,0 +1,91 @@
/**
* util_prg_example - Example program for util_prg
*
* Copyright IBM Corp. 2016, 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.
*/
//! [code]
#include <getopt.h>
#include <stdlib.h>
#include "lib/util_prg.h"
/*
* Program description
*/
const struct util_prg prg = {
.desc = "Sample for util_prg library.",
.args = "[POS_ARGS]",
.copyright_vec = {
{
.owner = "IBM Corp.",
.pub_first = 2001,
.pub_last = 2016,
},
{
.owner = "Another Corp.",
.pub_first = 2016,
.pub_last = 2016,
},
UTIL_PRG_COPYRIGHT_END
}
};
/*
* Demonstrate the util_prg_print() functions
*/
int main(int argc, char *argv[])
{
const char *file_name = "i_do_not_exist";
char optopt_str[3];
FILE *fp;
int opt;
/* Disable the getopt_long() error messages */
opterr = 0;
util_prg_init(&prg);
while ((opt = getopt(argc, argv, "vhe")) != -1) {
switch (opt) {
case 'v':
util_prg_print_version();
return EXIT_SUCCESS;
case 'h':
util_prg_print_help();
printf(" -e Try to open non-exisiting file\n");
printf(" -h Print this help, then exit\n");
printf(" -v Print version information, then exit\n");
return EXIT_SUCCESS;
case 'e':
fp = fopen(file_name, "r");
if (!fp) {
err(EXIT_FAILURE, "Open of '%s' failed",
file_name);
}
return EXIT_SUCCESS;
case ':':
/* Option requires an argument */
util_prg_print_required_arg(argv[optind - 1]);
return EXIT_FAILURE;
case '?':
sprintf(optopt_str, "-%c", optopt);
util_prg_print_invalid_option(optopt_str);
return EXIT_FAILURE;
}
}
if (argc > 2) {
util_prg_print_arg_error(argv[2]);
return EXIT_FAILURE;
}
if (argc == 2) {
printf("Positional parameter specified: %s\n", argv[1]);
return EXIT_SUCCESS;
}
errx(EXIT_FAILURE, "Specify either -h, -v, -e, or one positional "
"parameter");
}
//! [code]
+473
View File
@@ -0,0 +1,473 @@
/*
* s390-tools/zipl/src/proc.c
* Scanner for the /proc/ files
*
* Copyright IBM Corp. 2001, 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 <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <unistd.h>
#include "lib/util_proc.h"
static const char util_proc_part_filename[] = "/proc/partitions";
static const char util_proc_dev_filename[] = "/proc/devices";
struct file_buffer {
char *buffer;
off_t pos;
size_t length;
};
#define INITIAL_FILE_BUFFER_SIZE 1024
/* Read file into buffer without querying its size (necessary for reading files
* from /proc). Upon success, return zero and set BUFFER to point to
* the file buffer and SIZE (if non-null) to contain the file size. Return
* non-zero otherwise. Add a null-byte at the end of the buffer if
* NIL_TERMINATE is non-zero. */
static int
util_proc_read_special_file(const char *filename, char **buffer, size_t *size,
int nil_terminate)
{
FILE *file;
char *data;
char *new_data;
size_t count;
size_t current_size;
int current;
file = fopen(filename, "r");
if (file == NULL) {
printf("Could not open %s\n",
filename);
return -1;
}
current_size = INITIAL_FILE_BUFFER_SIZE;
count = 0;
data = (char *) malloc(current_size);
if (data == NULL) {
printf("Could not allocate %zu bytes of memory", current_size);
fclose(file);
return -1;
}
current = fgetc(file);
while (current != EOF || nil_terminate) {
if (current == EOF) {
current = 0;
nil_terminate = 0;
}
data[count++] = (char) current;
if (count >= current_size) {
new_data = (char *) malloc(current_size * 2);
if (new_data == NULL) {
printf("Could not allocate %zu bytes of memory",
current_size * 2);
free(data);
fclose(file);
return -1;
}
memcpy(new_data, data, current_size);
free(data);
data = new_data;
current_size *= 2;
}
current = fgetc(file);
}
fclose(file);
*buffer = data;
if (size)
*size = count;
return 0;
}
/* Get the contents of a file and fill in the respective fields of
* FILE. Return 0 on success, non-zero otherwise. */
static int
get_file_buffer(struct file_buffer *file, const char *filename)
{
int rc;
rc = util_proc_read_special_file(filename, &file->buffer,
&file->length, 0);
file->pos = 0;
return rc;
}
/* Free resources allocated for file buffer identified by
* FILE. */
static void
free_file_buffer(struct file_buffer *file)
{
if (file->buffer != NULL) {
free(file->buffer);
file->buffer = NULL;
file->pos = 0;
file->length = 0;
}
}
/* Return character at current FILE buffer position or EOF if at end of
* file. */
static int
current_char(struct file_buffer *file)
{
if (file->buffer != NULL)
if (file->pos < (off_t) file->length)
return file->buffer[file->pos];
return EOF;
}
/* Advance the current file pointer of file buffer FILE until the current
* character is no longer a whitespace or until the end of line or file is
* reached. Return 0 if at least one whitespace character was encountered,
* non-zero otherwise. */
static int
skip_whitespaces(struct file_buffer *file)
{
int rc;
rc = -1;
while ((current_char(file) != '\n') && isspace(current_char(file))) {
rc = 0;
file->pos++;
}
return rc;
}
/* Scan a positive integer number at the current position of file buffer FILE
* and advance the position respectively. Upon success, return zero and set
* NUMBER to contain the scanned number. Return non-zero otherwise. */
static int
scan_number(struct file_buffer *file, size_t *number)
{
int rc;
size_t old_number;
*number = 0;
rc = -1;
while (isdigit(current_char(file))) {
rc = 0;
old_number = *number;
*number = *number * 10 + current_char(file) - '0';
/* Check for overflow */
if (old_number > *number) {
rc = -1;
break;
}
file->pos++;
}
return rc;
}
/* Scan a device node name at the current position of file buffer FILE and
* advance the position respectively. Upon success, return zero and set
* NAME to contain a copy of the scanned name. Return non-zero otherwise. */
static int
scan_name(struct file_buffer *file, char **name)
{
off_t start_pos;
start_pos = file->pos;
while (!isspace(current_char(file)) &&
(current_char(file) != EOF))
file->pos++;
if (file->pos > start_pos) {
*name = (char *) malloc(file->pos - start_pos + 1);
if (*name == NULL)
return -1;
memcpy((void *) *name, (void *) &file->buffer[start_pos],
file->pos - start_pos);
(*name)[file->pos - start_pos] = 0;
return 0;
} else
return -1;
}
/* Scan for the specified STRING at the current position of file buffer FILE
* and advance the position respectively. Upon success, return zero. Return
* non-zero otherwise. */
static int
scan_string(struct file_buffer *file, const char *string)
{
int i;
i = 0;
for (i = 0; string[i] && (current_char(file) == string[i]);
i++, file->pos++)
;
if (string[i] == '\0')
return 0;
return -1;
}
/* Advance the current file position to beginning of next line in file buffer
* FILE or to end of file. */
static void
skip_line(struct file_buffer *file)
{
while ((current_char(file) != '\n') && (current_char(file) != EOF))
file->pos++;
if (current_char(file) == '\n')
file->pos++;
}
/* Return non-zero if the current file position of file buffer FILE is at the
* end of file. Return zero otherwise. */
static int
eof(struct file_buffer *file)
{
return file->pos >= (off_t) file->length;
}
/* Scan a line of the specified /proc/partitions FILE buffer and advance the
* current file position pointer respectively. If the current line matches
* the correct pattern, fill in the corresponding data into ENTRY and return 0.
* Return non-zero otherwise. */
static int
scan_part_entry(struct file_buffer *file, struct util_proc_part_entry *entry)
{
int rc;
size_t dev_major;
size_t dev_minor;
size_t blockcount;
char *name;
/* Scan for: (\s*)(\d+)(\s+)(\d+)(\s+)(\d+)(\s+)(\S+)(\.*)$ */
skip_whitespaces(file);
rc = scan_number(file, &dev_major);
if (rc)
return rc;
rc = skip_whitespaces(file);
if (rc)
return rc;
rc = scan_number(file, &dev_minor);
if (rc)
return rc;
rc = skip_whitespaces(file);
if (rc)
return rc;
rc = scan_number(file, &blockcount);
if (rc)
return rc;
rc = skip_whitespaces(file);
if (rc)
return rc;
rc = scan_name(file, &name);
if (rc)
return rc;
skip_line(file);
entry->device = makedev(dev_major, dev_minor);
entry->blockcount = blockcount;
entry->name = name;
return 0;
}
/* Release resources associated with ENTRY. */
void
util_proc_part_free_entry(struct util_proc_part_entry *entry)
{
if (entry->name != NULL) {
free(entry->name);
entry->name = NULL;
}
}
/* Scan a line of the specified /proc/devices FILE buffer and advance the
* current file position pointer respectively. If the current line matches
* the correct pattern, fill in the corresponding data into ENTRY and return 0.
* Return non-zero otherwise. */
static int
scan_dev_entry(struct file_buffer *file, struct util_proc_dev_entry *entry,
int blockdev)
{
int rc;
size_t dev_major;
char *name;
/* Scan for: (\s*)(\d+)(\s+)(\S+)(\.*)$ */
skip_whitespaces(file);
rc = scan_number(file, &dev_major);
if (rc)
return rc;
rc = skip_whitespaces(file);
if (rc)
return rc;
rc = scan_name(file, &name);
if (rc)
return rc;
skip_line(file);
entry->device = makedev(dev_major, 0);
entry->name = name;
entry->blockdev = blockdev;
return 0;
}
/* Release resources associated with ENTRY. */
void
util_proc_dev_free_entry(struct util_proc_dev_entry *entry)
{
if (entry->name != NULL) {
free(entry->name);
entry->name = NULL;
}
}
/* Parse one record. */
static int
scan_mnt_entry(struct file_buffer *file, struct util_proc_mnt_entry *entry)
{
int rc;
skip_whitespaces(file);
rc = scan_name(file, &entry->spec);
if (rc)
return rc;
skip_whitespaces(file);
rc = scan_name(file, &entry->file);
if (rc)
return rc;
skip_whitespaces(file);
rc = scan_name(file, &entry->vfstype);
if (rc)
return rc;
skip_whitespaces(file);
rc = scan_name(file, &entry->mntOpts);
if (rc)
return rc;
skip_whitespaces(file);
rc = scan_name(file, &entry->dump);
if (rc)
return rc;
skip_whitespaces(file);
rc = scan_name(file, &entry->passno);
if (rc)
return rc;
skip_line(file);
return 0;
}
/* Free the memory allocated for one record. */
void
util_proc_mnt_free_entry(struct util_proc_mnt_entry *entry)
{
free(entry->spec);
free(entry->file);
free(entry->vfstype);
free(entry->mntOpts);
free(entry->dump);
free(entry->passno);
memset(entry, 0, sizeof(*entry));
}
/* Scan /proc/partitions for an entry matching DEVICE. When there is a match,
* store entry data in ENTRY and return 0. Return non-zero otherwise. */
int
util_proc_part_get_entry(dev_t device, struct util_proc_part_entry *entry)
{
struct file_buffer file;
int rc;
rc = get_file_buffer(&file, util_proc_part_filename);
if (rc)
return rc;
rc = -1;
while (!eof(&file)) {
if (scan_part_entry(&file, entry) == 0) {
if (entry->device == device) {
rc = 0;
break;
}
util_proc_part_free_entry(entry);
} else
skip_line(&file);
}
free_file_buffer(&file);
return rc;
}
/* Scan /proc/devices for a blockdevice (BLOCKDEV is 1) or a character
* device (BLOCKDEV is 0) with a major number matching the major number of DEV.
* When there is a match, store entry data in ENTRY and return 0. Return
* non-zero otherwise. */
int
util_proc_dev_get_entry(dev_t device, int blockdev,
struct util_proc_dev_entry *entry)
{
struct file_buffer file;
int rc;
int scan_blockdev = 0;
rc = get_file_buffer(&file, util_proc_dev_filename);
if (rc)
return rc;
rc = -1;
while (!eof(&file)) {
if (scan_string(&file, "Block") == 0) {
skip_line(&file);
scan_blockdev = 1;
continue;
} else if (scan_dev_entry(&file, entry, scan_blockdev) == 0) {
if ((major(entry->device) == major(device)) &&
blockdev == scan_blockdev) {
rc = 0;
break;
}
util_proc_dev_free_entry(entry);
} else
skip_line(&file);
}
free_file_buffer(&file);
return rc;
}
/*
* Provide one record form a /proc/mounts like file
*
* The parameter file_name distinguishes the file form procfs which
* is read, the parameter spec is the selector for the record.
*/
int util_proc_mnt_get_entry(const char *file_name, const char *spec,
struct util_proc_mnt_entry *entry)
{
struct file_buffer file;
int rc;
rc = get_file_buffer(&file, file_name);
if (rc)
return rc;
rc = -1;
while (!eof(&file)) {
rc = scan_mnt_entry(&file, entry);
if (rc)
goto out_free;
if (!strcmp(entry->spec, spec)) {
rc = 0;
goto out_free;
}
util_proc_mnt_free_entry(entry);
}
out_free:
free_file_buffer(&file);
return rc;
}
+539
View File
@@ -0,0 +1,539 @@
/**
* util - Utility function library
*
* Print records in different output formats
*
* Copyright IBM Corp. 2016, 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 <argz.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lib/util_base.h"
#include "lib/util_libc.h"
#include "lib/util_list.h"
#include "lib/util_panic.h"
#include "lib/util_prg.h"
#include "lib/util_rec.h"
/*
* Field structure containing the string value and secondary information
*/
struct util_rec_fld {
char *key; /* Name of the filed */
char *hdr; /* Content of the header */
size_t len; /* Length of string argz array */
char *val; /* The value of the field */
enum util_rec_align align; /* Alignment of the field */
int width; /* Field width */
struct util_list_node node; /* Pointers to previous and next field */
};
/*
* Print formats
*/
struct rec_fmt {
enum {
REC_FMT_WIDE,
REC_FMT_LONG,
REC_FMT_CSV,
} type;
union {
struct wide_p {
char *hdr_sep;
char *col_sep;
int argz_sep;
} wide_p;
struct long_p {
char *hdr_sep;
char *col_sep;
int argz_sep;
char *key;
int key_size;
int val_size;
} long_p;
struct csv_p {
char *col_sep;
int argz_sep;
} csv_p;
} d;
};
/*
* Record structure (internal representation)
*/
/// @cond
struct util_rec {
struct util_list *list; /* List of the fields */
struct rec_fmt fmt; /* Output format */
};
/// @endcond
struct util_list *__util_rec_get_list(struct util_rec *rec)
{
return rec->list;
}
/*
* Get the field according to a distinct key
*/
static struct util_rec_fld *rec_get_fld(struct util_rec *rec, const char *key)
{
struct util_rec_fld *fld;
util_list_iterate(rec->list, fld) {
if (!strcmp(fld->key, key))
return fld;
}
return NULL;
}
/**
* Return the key name of a field
*
* @param[in] fld Field for query
*
* @returns Pointer to key string
*/
const char *util_rec_fld_get_key(struct util_rec_fld *fld)
{
return fld->key;
}
/**
* Create a new record with "wide" output format
*
* @param[in] hdr_sep Header separator
*
* @returns Pointer to the created record
*/
struct util_rec *util_rec_new_wide(const char *hdr_sep)
{
struct util_rec *rec = util_malloc(sizeof(struct util_rec));
rec->list = util_list_new(struct util_rec_fld, node);
rec->fmt.type = REC_FMT_WIDE;
rec->fmt.d.wide_p.hdr_sep = util_strdup(hdr_sep);
rec->fmt.d.wide_p.argz_sep = ',';
return rec;
}
/*
* Print record header in "wide" output format
*/
static void rec_print_wide_hdr(struct util_rec *rec)
{
const char *hdr_sep = rec->fmt.d.wide_p.hdr_sep;
int col_nr = 0, size = 0, field_count = 0;
struct util_rec_fld *fld;
char *buf;
util_list_iterate(rec->list, fld) {
if (col_nr)
printf(" ");
if (fld->hdr) {
if (fld->align == UTIL_REC_ALIGN_LEFT)
printf("%-*s", fld->width, fld->hdr);
else
printf("%*s", fld->width, fld->hdr);
size += fld->width;
field_count++;
}
col_nr++;
}
printf("\n");
if (!hdr_sep)
return;
size += field_count - 1;
if (hdr_sep) {
buf = util_malloc(size + 1);
memset(buf, (int)hdr_sep[0], size);
buf[size] = 0;
printf("%s\n", buf);
free(buf);
}
}
/*
* Print record field values in "wide" output format
*/
void rec_print_wide(struct util_rec *rec)
{
const char argz_sep = rec->fmt.d.wide_p.argz_sep;
struct util_rec_fld *fld;
char argz_str[PAGE_SIZE];
int fld_count = 0;
char *entry;
util_list_iterate(rec->list, fld) {
if (!fld->hdr)
continue;
if (fld_count)
printf(" ");
entry = fld->val;
if (argz_count(fld->val, fld->len) > 1) {
strcpy(argz_str, entry);
while ((entry = argz_next(fld->val, fld->len, entry)))
strcat(strncat(argz_str, &argz_sep, 1), entry);
entry = argz_str;
}
if (fld->align == UTIL_REC_ALIGN_LEFT)
printf("%-*s", fld->width, entry);
else
printf("%*s", fld->width, entry);
fld_count++;
}
printf("\n");
}
/*
* Free private memory of record
*/
static void rec_free_wide(struct util_rec *rec)
{
free(rec->fmt.d.wide_p.hdr_sep);
}
/**
* Create a new record with "long" output format
*
* @param[in] hdr_sep Header separator
* @param[in] col_sep Column separator
* @param[in] key Primary key of record
* @param[in] key_size Width of left column i.e. keys
* @param[in] val_size Width of right column i.e. values
*
* @returns Pointer to the created record
*/
struct util_rec *util_rec_new_long(const char *hdr_sep, const char *col_sep,
const char *key, int key_size, int val_size)
{
struct util_rec *rec = util_malloc(sizeof(struct util_rec));
rec->list = util_list_new(struct util_rec_fld, node);
rec->fmt.type = REC_FMT_LONG;
rec->fmt.d.long_p.hdr_sep = util_strdup(hdr_sep);
rec->fmt.d.long_p.col_sep = util_strdup(col_sep);
rec->fmt.d.long_p.key = util_strdup(key);
rec->fmt.d.long_p.key_size = key_size;
rec->fmt.d.long_p.val_size = val_size;
rec->fmt.d.long_p.argz_sep = ' ';
return rec;
}
/*
* Print field header in "long" output format
*/
static void rec_print_long_hdr(struct util_rec *rec)
{
struct long_p *p = &rec->fmt.d.long_p;
struct util_rec_fld *fld;
int len = 0;
char *buf;
fld = rec_get_fld(rec, p->key);
util_assert(fld != NULL, "Record not found\n");
util_assert(fld->hdr != NULL, "Header for field not found\n");
if (p->col_sep) {
printf("%-*s %s %-*s\n", p->key_size, fld->hdr,
p->col_sep, fld->width, fld->val);
len = p->key_size + p->val_size + 3;
} else {
printf("%-*s %-*s\n", p->key_size, fld->hdr, fld->width,
fld->val);
len = p->key_size + p->val_size + 1;
}
if (!p->hdr_sep)
return;
buf = util_malloc(len + 1);
memset(buf, p->hdr_sep[0], len);
buf[len] = 0;
printf("%s\n", buf);
free(buf);
}
/*
* Print record field values in "long" output format
*/
static void rec_print_long(struct util_rec *rec)
{
struct long_p *p = &rec->fmt.d.long_p;
struct util_rec_fld *fld;
char *item = NULL;
rec_print_long_hdr(rec);
util_list_iterate(rec->list, fld) {
if (!fld->hdr)
continue;
if (!strcmp(p->key, fld->key))
continue;
if (!fld->val)
continue;
item = argz_next(fld->val, fld->len, item);
if (p->col_sep) {
printf(" %-*s %s %s\n",
p->key_size - 8, fld->hdr, p->col_sep, item);
while ((item = argz_next(fld->val, fld->len, item)))
printf(" %-*s %c %s\n",
p->key_size - 8, "", p->argz_sep, item);
} else {
printf(" %-*s %s\n",
p->key_size - 8, fld->hdr, fld->val);
while ((item = argz_next(fld->val, fld->len, item)))
printf(" %-*s %s\n",
p->key_size - 8, "", item);
}
}
printf("\n");
}
/*
* Free private memory of record
*/
static void rec_free_long(struct util_rec *rec)
{
free(rec->fmt.d.long_p.hdr_sep);
free(rec->fmt.d.long_p.col_sep);
free(rec->fmt.d.long_p.key);
}
/**
* Create a new record with "csv" output format
*
* @param[in] col_sep Column separator
*
* @returns Pointer to the created record
*/
struct util_rec *util_rec_new_csv(const char *col_sep)
{
struct util_rec *rec = util_malloc(sizeof(struct util_rec));
rec->list = util_list_new(struct util_rec_fld, node);
rec->fmt.type = REC_FMT_CSV;
rec->fmt.d.csv_p.col_sep = util_strdup(col_sep);
rec->fmt.d.csv_p.argz_sep = ' ';
return rec;
}
/*
* Print record header in "csv" output format
*/
void rec_print_csv_hdr(struct util_rec *rec)
{
const char *col_sep = rec->fmt.d.csv_p.col_sep;
struct util_rec_fld *fld;
int fld_count = 0;
util_list_iterate(rec->list, fld) {
if (fld_count)
printf("%c", *col_sep);
if (fld->hdr) {
printf("%s", fld->hdr);
fld_count++;
}
}
printf("\n");
}
/*
* Print record field values in "csv" output format
*/
void rec_print_csv(struct util_rec *rec)
{
const char argz_sep = rec->fmt.d.csv_p.argz_sep;
const char *col_sep = rec->fmt.d.csv_p.col_sep;
struct util_rec_fld *fld;
int fld_count = 0;
char *item = NULL;
util_list_iterate(rec->list, fld) {
item = argz_next(fld->val, fld->len, item);
if (fld_count)
printf("%c", *col_sep);
if (fld->hdr) {
printf("%s", item);
while ((item = argz_next(fld->val, fld->len, item)))
printf("%c%s", argz_sep, item);
fld_count++;
}
}
printf("\n");
}
/*
* Free private memory of record
*/
static void rec_free_csv(struct util_rec *rec)
{
free(rec->fmt.d.csv_p.col_sep);
}
/**
* Define a new field for the record
*
* @param[in] rec Pointer of the record
* @param[in] key Key of the filed is to be created. It should be unique
* within the record.
* @param[in] align Alignment of field
* @param[in] width Width of field
* @param[in] hdr This information is printed in record headers. If it is
* NULL, the field is prohibited form printing completely.
*/
void util_rec_def(struct util_rec *rec, const char *key,
enum util_rec_align align, int width, const char *hdr)
{
struct util_rec_fld *fld = util_malloc(sizeof(struct util_rec_fld));
fld->key = util_strdup(key);
fld->hdr = util_strdup(hdr);
fld->val = NULL;
fld->align = align;
fld->width = width;
util_list_add_tail(rec->list, fld);
}
/**
* Free record and associated fields
*
* @param[in] rec Record pointer
*/
void util_rec_free(struct util_rec *rec)
{
struct util_rec_fld *fld, *tmp;
util_list_iterate_safe(rec->list, fld, tmp) {
util_list_remove(rec->list, fld);
free(fld->key);
free(fld->hdr);
free(fld->val);
free(fld);
}
util_list_free(rec->list);
switch (rec->fmt.type) {
case REC_FMT_WIDE:
rec_free_wide(rec);
break;
case REC_FMT_LONG:
rec_free_long(rec);
break;
case REC_FMT_CSV:
rec_free_csv(rec);
break;
}
free(rec);
}
/**
* Print record field values according to output format
*
* @param[in] rec Record pointer
*/
void util_rec_print(struct util_rec *rec)
{
switch (rec->fmt.type) {
case REC_FMT_WIDE:
rec_print_wide(rec);
break;
case REC_FMT_LONG:
rec_print_long(rec);
break;
case REC_FMT_CSV:
rec_print_csv(rec);
break;
}
}
/**
* Print record header according to output format
*
* @param[in] rec Record pointer
*/
void util_rec_print_hdr(struct util_rec *rec)
{
switch (rec->fmt.type) {
case REC_FMT_WIDE:
rec_print_wide_hdr(rec);
break;
case REC_FMT_LONG:
break;
case REC_FMT_CSV:
rec_print_csv_hdr(rec);
break;
}
}
/**
* Set a field value to an argz vector
*
* @param[in] rec Record pointer
* @param[in] key Key of the desired field
* @param[in] argz Pointer to the series of strings
* @param[in] len Length of the argz buffer
*/
void util_rec_set_argz(struct util_rec *rec, const char *key, const char *argz,
size_t len)
{
struct util_rec_fld *fld;
char *val;
fld = rec_get_fld(rec, key);
if (!fld)
return;
val = util_malloc(len);
val = memcpy(val, argz, len);
free(fld->val);
fld->val = val;
fld->len = len;
}
/**
* Set a field value to a formatted string
*
* @param[in] rec Record pointer
* @param[in] key Key of the desired field
* @param[in] fmt Format string for generation of value string
* @param[in] ... Parameters for format string
*
* @returns Pointer to the field which was modified or NULL in the case of
* any error.
*/
void util_rec_set(struct util_rec *rec, const char *key, const char *fmt, ...)
{
struct util_rec_fld *fld;
va_list ap;
char *str;
util_assert(fmt != NULL, "Parameter 'fmt' pointer must not be NULL\n");
fld = rec_get_fld(rec, key);
if (!fld)
return;
UTIL_VASPRINTF(&str, fmt, ap);
free(fld->val);
fld->val = str;
fld->len = strlen(str) + 1;
}
/**
* Return the string value of a desired field. If the field value stored in argz
* format, pointer to the first argz element is returned.
*
* @param[in] rec Record pointer
* @param[in] key Key of the field
*
* @returns If the desired field was found, the pointer to its value.
* NULL in the case of any error or if the field is empty.
*/
const char *util_rec_get(struct util_rec *rec, const char *key)
{
struct util_rec_fld *fld = rec_get_fld(rec, key);
return (fld != NULL) ? fld->val : NULL;
}
+86
View File
@@ -0,0 +1,86 @@
/**
* util_rec_example - Example program for util_rec
*
* Copyright IBM Corp. 2016, 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.
*/
//! [code]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lib/util_rec.h"
/*
* Print three records in specified format
*/
static void print_records(const char *format, struct util_rec *rec)
{
static const char * const size_vec[] = {"small", "medium", "large"};
static const char * const name_vec[] = {"zero", "one", "two"};
int i;
printf("###########################################################\n");
printf("# %s\n\n", format);
/* Define fields of record */
util_rec_def(rec, "number", UTIL_REC_ALIGN_LEFT, 6, "Number");
util_rec_def(rec, "name", UTIL_REC_ALIGN_LEFT, 10, "Name");
util_rec_def(rec, "size", UTIL_REC_ALIGN_RIGHT, 15, "Size");
/* Print record header (is a nop for long format) */
util_rec_print_hdr(rec);
for (i = 0; i < 3; i++) {
/* Fill fields of record with values */
util_rec_set(rec, "number", "%d", i);
util_rec_set(rec, "name", name_vec[i]);
util_rec_set(rec, "size", size_vec[i]);
/* Print the record */
util_rec_print(rec);
}
printf("\n");
}
/*
* Print keys for record fields
*/
static void print_fields(struct util_rec *rec)
{
struct util_rec_fld *fld;
int i = 1;
printf("###########################################################\n");
printf("# Keys of record fields\n");
util_rec_iterate(rec, fld) {
printf("Field %d : %s\n", i++, util_rec_fld_get_key(fld));
}
}
/*
* Print records in "wide", "long", and "csv" format
*/
int main(void)
{
struct util_rec *rec;
rec = util_rec_new_wide("-");
print_records("Wide format", rec);
util_rec_free(rec);
rec = util_rec_new_long("-", ":", "number", 30, 20);
print_records("Long format", rec);
util_rec_free(rec);
rec = util_rec_new_csv(",");
print_records("CSV format", rec);
print_fields(rec);
util_rec_free(rec);
return EXIT_SUCCESS;
}
//! [code]
+175
View File
@@ -0,0 +1,175 @@
/*
* util - Utility function library
*
* Scan a directory for matching entries
*
* Copyright IBM Corp. 2016, 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 <dirent.h>
#include <errno.h>
#include <libgen.h>
#include <regex.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "lib/util_base.h"
#include "lib/util_libc.h"
#include "lib/util_panic.h"
#include "lib/util_scandir.h"
#include "lib/zt_common.h"
/// @cond
struct util_scandir_filter {
regex_t reg_buf;
};
/// @endcond
/*
* Check directory entry
*/
static int filter_regexp(const struct dirent *de, void *data)
{
struct util_scandir_filter *filter = data;
regmatch_t pmatch[1];
if (regexec(&filter->reg_buf, de->d_name, (size_t) 1, pmatch, 0) == 0)
return 1;
return 0;
}
typedef int (*__compar_fn_t) (const void *, const void *);
/*
* Return sorted "struct dirent" array for entries that match "filter_fn"
*/
static int __scandir(struct dirent ***de_vec, const char *path,
int (*filter_fn)(const struct dirent *, void *),
void *filter_data,
int (*compar_fn)(const struct dirent **,
const struct dirent **))
{
struct dirent *de, *de_new, **de_vec_new = NULL;
int count = 0;
DIR *dirp;
dirp = opendir(path);
if (!dirp)
return -1;
while ((de = readdir(dirp))) {
if (filter_fn(de, filter_data) == 0)
continue;
de_new = util_malloc(sizeof(*de_new));
*de_new = *de;
de_vec_new = realloc(de_vec_new, sizeof(void *) * (count + 1));
de_vec_new[count++] = de_new;
}
closedir(dirp);
if (compar_fn)
qsort(de_vec_new, count, sizeof(void *),
(__compar_fn_t) compar_fn);
*de_vec = de_vec_new;
return count;
}
/*
* Return sorted "struct dirent" array for entries that match "pattern"
*/
static int scandir_regexp(struct dirent ***de_vec, const char *path,
const char *pattern,
int compar_fn(const struct dirent **,
const struct dirent **))
{
struct util_scandir_filter filter;
char err_buf[256];
int count, rc;
rc = regcomp(&filter.reg_buf, pattern, REG_EXTENDED);
if (rc) {
regerror(rc, &filter.reg_buf, err_buf, sizeof(err_buf));
util_panic("Function regcomp(%s) failed: %s\n", pattern,
err_buf);
}
count = __scandir(de_vec, path, filter_regexp, &filter, compar_fn);
regfree(&filter.reg_buf);
return count;
}
/**
* Compare two hexadecimal string dirents numerically
*
* @param[in] de1 First directory entry
* @param[in] de2 Second directory entry
*
* @retval -1 de1 < de2
* @retval 0 de1 = de2
* @retval 1 de1 > de2
*/
int util_scandir_hexsort(const struct dirent **de1, const struct dirent **de2)
{
unsigned long val1 = strtoul((*de1)->d_name, NULL, 16);
unsigned long val2 = strtoul((*de2)->d_name, NULL, 16);
if (val1 < val2)
return -1;
if (val1 == val2)
return 0;
return 1;
}
/**
* Construct a list of direcotry entries using POSIX regular expressions
*
* A desired directory in sysfs is scanned for entries of a given name
* pattern. The name pattern is constructed with sprintf() using a format
* string and variable argument list. After constructing the pattern it
* is used with regcomp() and regexec() to find matching entries.
* The returned list of matches consist of an array of pointers to
* directory entries. The entries as well as the pointer array itself are
* allocated by the function and has to be released by the user via free.
*
* @param[out] de_vec Vector of matched directory entries
* @param[in] compar_fn Callback function for sorting the entry list
* @param[in] path Path to the directory to scan
* @param[in] fmt Format string, describes the search pattern as POSIX regex
* @param[in] ... Values for format string
*
* @returns Number of returned directory entries
*/
int util_scandir(struct dirent ***de_vec,
int compar_fn(const struct dirent **first,
const struct dirent **second),
const char *path,
const char *fmt, ...)
{
char *pattern;
va_list ap;
int rc;
va_start(ap, fmt);
rc = vasprintf(&pattern, fmt, ap);
va_end(ap);
if (rc < 0)
return -1;
rc = scandir_regexp(de_vec, path, pattern, compar_fn);
free(pattern);
return rc;
}
/**
* Free list of directory entries
*
* @param[in] de_vec Vector of directory entries
* @param[in] count Count of directory entries
*/
void util_scandir_free(struct dirent **de_vec, int count)
{
util_ptr_vec_free((void **) de_vec, count);
}
+69
View File
@@ -0,0 +1,69 @@
/**
* util_dir_example - Example program for util_dir
*
* Copyright IBM Corp. 2016, 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.
*/
//! [code]
#include <stdio.h>
#include <stdlib.h>
#include "lib/util_scandir.h"
/*
* Print real sysfs cpu directory contents
*/
static void show_cpu_dir(const char *sys_cpu_path)
{
char cmd_ls[256];
sprintf(cmd_ls, "ls -l %s", sys_cpu_path);
printf("$ %s\n", cmd_ls);
fflush(stdout);
if (system(cmd_ls)) {
perror("system() failed");
exit(EXIT_FAILURE);
}
printf("\n");
}
/*
* Show all CPUs on Linux system
*/
int main(void)
{
struct dirent **de_vec;
int count, i;
const char *path = "/sys/devices/system/cpu";
const char *prefix = "cpu";
show_cpu_dir(path);
/*
* Process all files that match regular expression "cpu[0-9]+"
* and sort them alphabetically. Note that the regular expression
* is constructed with a variable argument list.
*/
count = util_scandir(&de_vec, alphasort, path, "%s[0-9]+", prefix);
if (count == -1) {
perror("util_dir_scan failed");
return EXIT_FAILURE;
}
/* Print all directories */
printf("Found cpus:\n\n");
for (i = 0; i < count; i++) {
if (de_vec[i]->d_type != DT_DIR)
continue;
printf(" - %s\n", de_vec[i]->d_name);
}
/* Free directory entries */
util_scandir_free(de_vec, count);
return EXIT_SUCCESS;
}
//! [code]