sysctl: options handling & usage output
The sysctl now uses getopt_long and has help screen which be user friendly. Rest of the modernization is left later, since this is a command is used in scripts, and changing for instance error printing to use warn & warnx could break stuff. Signed-off-by: Sami Kerola <kerolasa@iki.fi>
This commit is contained in:
parent
d50884788d
commit
81df8e2630
219
sysctl.c
219
sysctl.c
@ -22,20 +22,21 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <libgen.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <dirent.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <libgen.h>
|
|
||||||
#include "proc/procps.h"
|
#include "proc/procps.h"
|
||||||
#include "proc/version.h"
|
#include "proc/version.h"
|
||||||
|
|
||||||
|
|
||||||
// Proof that C++ causes brain damage:
|
/* Proof that C++ causes brain damage: */
|
||||||
typedef int bool;
|
typedef int bool;
|
||||||
static bool true = 1;
|
static bool true = 1;
|
||||||
static bool false = 0;
|
static bool false = 0;
|
||||||
@ -53,7 +54,6 @@ static bool IgnoreError;
|
|||||||
static bool Quiet;
|
static bool Quiet;
|
||||||
|
|
||||||
/* error messages */
|
/* error messages */
|
||||||
static const char ERR_UNKNOWN_PARAMETER[] = "error: Unknown parameter \"%s\"\n";
|
|
||||||
static const char ERR_MALFORMED_SETTING[] = "error: Malformed setting \"%s\"\n";
|
static const char ERR_MALFORMED_SETTING[] = "error: Malformed setting \"%s\"\n";
|
||||||
static const char ERR_NO_EQUALS[] = "error: \"%s\" must be of the form name=value\n";
|
static const char ERR_NO_EQUALS[] = "error: \"%s\" must be of the form name=value\n";
|
||||||
static const char ERR_INVALID_KEY[] = "error: \"%s\" is an unknown key\n";
|
static const char ERR_INVALID_KEY[] = "error: \"%s\" is an unknown key\n";
|
||||||
@ -83,15 +83,33 @@ static void slashdot(char *restrict p, char old, char new){
|
|||||||
* Display the usage format
|
* Display the usage format
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int Usage(const char *restrict const name) {
|
static void __attribute__ ((__noreturn__))
|
||||||
printf("usage: %s [-n] [-e] variable ... \n"
|
Usage(FILE * out)
|
||||||
" %s [-n] [-e] [-q] -w variable=value ... \n"
|
{
|
||||||
" %s [-n] [-e] -a \n"
|
fprintf(out,
|
||||||
" %s [-n] [-e] [-q] -p <file> (default /etc/sysctl.conf) \n"
|
"\nUsage: %s [options] [variable[=value] ...]\n"
|
||||||
" %s [-n] [-e] -A\n", name, name, name, name, name);
|
"\nOptions:\n", program_invocation_short_name);
|
||||||
return -1;
|
fprintf(out,
|
||||||
}
|
" -a, --all display all variables\n"
|
||||||
|
" -A alias of -a\n"
|
||||||
|
" -X alias of -a\n"
|
||||||
|
" -b, --binary print value without new line\n"
|
||||||
|
" -e, --ignore ignore unknown variables errors\n"
|
||||||
|
" -N, --names print variable names without values\n"
|
||||||
|
" -n, --values print only values of a variables\n"
|
||||||
|
" -p, --load[=<file>] read values from file\n"
|
||||||
|
" -f alias of -p\n"
|
||||||
|
" -q, --quiet do not echo variable set\n"
|
||||||
|
" -w, --write enable writing a value to variable\n"
|
||||||
|
" -o does nothing\n"
|
||||||
|
" -x does nothing\n"
|
||||||
|
" -h, --help display this help text\n"
|
||||||
|
" -d alias of -h\n"
|
||||||
|
" -V, --version display version information and exit\n");
|
||||||
|
fprintf(out, "\nFor more information see sysctl(8).\n");
|
||||||
|
|
||||||
|
exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Strip the leading and trailing spaces from a string
|
* Strip the leading and trailing spaces from a string
|
||||||
@ -460,106 +478,113 @@ static int Preload(const char *restrict const filename) {
|
|||||||
* Main...
|
* Main...
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[])
|
||||||
const char *me = (const char *)basename(argv[0]);
|
{
|
||||||
bool SwitchesAllowed = true;
|
bool SwitchesAllowed = true;
|
||||||
bool WriteMode = false;
|
bool WriteMode = false;
|
||||||
bool DisplayAllOpt = false;
|
bool DisplayAllOpt = false;
|
||||||
|
bool preloadfileOpt = false;
|
||||||
int ReturnCode = 0;
|
int ReturnCode = 0;
|
||||||
|
int c;
|
||||||
const char *preloadfile = DEFAULT_PRELOAD;
|
const char *preloadfile = DEFAULT_PRELOAD;
|
||||||
|
|
||||||
|
static const struct option longopts[] = {
|
||||||
|
{"all", no_argument, NULL, 'a'},
|
||||||
|
{"binary", no_argument, NULL, 'b'},
|
||||||
|
{"ignore", no_argument, NULL, 'e'},
|
||||||
|
{"names", no_argument, NULL, 'N'},
|
||||||
|
{"values", no_argument, NULL, 'n'},
|
||||||
|
{"load", optional_argument, NULL, 'p'},
|
||||||
|
{"quiet", no_argument, NULL, 'q'},
|
||||||
|
{"write", no_argument, NULL, 'w'},
|
||||||
|
{"help", no_argument, NULL, 'h'},
|
||||||
|
{"version", no_argument, NULL, 'V'},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
PrintName = true;
|
PrintName = true;
|
||||||
PrintNewline = true;
|
PrintNewline = true;
|
||||||
IgnoreError = false;
|
IgnoreError = false;
|
||||||
Quiet = false;
|
Quiet = false;
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
return Usage(me);
|
Usage(stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
argv++;
|
while ((c =
|
||||||
|
getopt_long(argc, argv, "bneNwfpqoxaAXVdh", longopts,
|
||||||
for (; argv && *argv && **argv; argv++) {
|
NULL)) != -1)
|
||||||
if (SwitchesAllowed && **argv == '-') { /* we have a switch */
|
switch (c) {
|
||||||
if ((*argv)[1] && (*argv)[2]){ // don't yet handle "sysctl -ew"
|
case 'b':
|
||||||
if (!strcmp("--help",*argv)) {
|
/* This is "binary" format, which means more for BSD. */
|
||||||
Usage(me);
|
PrintNewline = false;
|
||||||
exit(0);
|
/* FALL THROUGH */
|
||||||
}
|
case 'n':
|
||||||
if (!strcmp("--version",*argv)) {
|
PrintName = false;
|
||||||
fprintf(stdout, "sysctl (%s)\n",procps_version);
|
break;
|
||||||
exit(0);
|
case 'e':
|
||||||
}
|
/*
|
||||||
fprintf(stderr, ERR_UNKNOWN_PARAMETER, *argv);
|
* For FreeBSD, -e means a "%s=%s\n" format. ("%s: %s\n" default)
|
||||||
return Usage(me);
|
* We (and NetBSD) use "%s = %s\n" always, and -e to ignore errors.
|
||||||
}
|
*/
|
||||||
switch((*argv)[1]) {
|
IgnoreError = true;
|
||||||
case 'b':
|
break;
|
||||||
/* This is "binary" format, which means more for BSD. */
|
case 'N':
|
||||||
PrintNewline = false;
|
NameOnly = true;
|
||||||
/* FALL THROUGH */
|
break;
|
||||||
case 'n':
|
case 'w':
|
||||||
PrintName = false;
|
SwitchesAllowed = false;
|
||||||
|
WriteMode = true;
|
||||||
|
break;
|
||||||
|
case 'f': /* the NetBSD way */
|
||||||
|
case 'p':
|
||||||
|
preloadfileOpt = true;
|
||||||
|
if (optarg)
|
||||||
|
preloadfile = optarg;
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'q':
|
||||||
// For FreeBSD, -e means a "%s=%s\n" format. ("%s: %s\n" default)
|
Quiet = true;
|
||||||
// We (and NetBSD) use "%s = %s\n" always, and -e to ignore errors.
|
break;
|
||||||
IgnoreError = true;
|
case 'o': /* BSD: binary values too, 1st 16 bytes in hex */
|
||||||
|
case 'x': /* BSD: binary values too, whole thing in hex */
|
||||||
|
/* does nothing */ ;
|
||||||
|
break;
|
||||||
|
case 'a': /* string and integer values (for Linux, all of them) */
|
||||||
|
case 'A': /* same as -a -o */
|
||||||
|
case 'X': /* same as -a -x */
|
||||||
|
DisplayAllOpt = true;
|
||||||
break;
|
break;
|
||||||
case 'N':
|
case 'V':
|
||||||
NameOnly = true;
|
fprintf(stdout, "sysctl (%s)\n",procps_version);
|
||||||
break;
|
exit(0);
|
||||||
case 'w':
|
case 'd': /* BSD: print description ("vm.kvm_size: Size of KVM") */
|
||||||
SwitchesAllowed = false;
|
case 'h': /* BSD: human-readable (did FreeBSD 5 make -e default?) */
|
||||||
WriteMode = true;
|
case '?':
|
||||||
break;
|
Usage(stdout);
|
||||||
case 'f': // the NetBSD way
|
default:
|
||||||
case 'p':
|
Usage(stderr);
|
||||||
argv++;
|
|
||||||
if (argv && *argv && **argv) {
|
|
||||||
preloadfile = *argv;
|
|
||||||
}
|
|
||||||
return Preload(preloadfile);
|
|
||||||
case 'q':
|
|
||||||
Quiet = true;
|
|
||||||
break;
|
|
||||||
case 'o': // BSD: binary values too, 1st 16 bytes in hex
|
|
||||||
case 'x': // BSD: binary values too, whole thing in hex
|
|
||||||
/* does nothing */ ;
|
|
||||||
break;
|
|
||||||
case 'a': // string and integer values (for Linux, all of them)
|
|
||||||
case 'A': // same as -a -o
|
|
||||||
case 'X': // same as -a -x
|
|
||||||
DisplayAllOpt = true;
|
|
||||||
break;
|
|
||||||
case 'V':
|
|
||||||
fprintf(stdout, "sysctl (%s)\n",procps_version);
|
|
||||||
exit(0);
|
|
||||||
case 'd': // BSD: print description ("vm.kvm_size: Size of KVM")
|
|
||||||
case 'h': // BSD: human-readable (did FreeBSD 5 make -e default?)
|
|
||||||
case '?':
|
|
||||||
return Usage(me);
|
|
||||||
default:
|
|
||||||
fprintf(stderr, ERR_UNKNOWN_PARAMETER, *argv);
|
|
||||||
return Usage(me);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (NameOnly && Quiet) // nonsense
|
|
||||||
return Usage(me);
|
|
||||||
if (DisplayAllOpt) // We cannot have values with -a
|
|
||||||
return Usage(me);
|
|
||||||
SwitchesAllowed = false;
|
|
||||||
if (WriteMode || strchr(*argv, '='))
|
|
||||||
ReturnCode = WriteSetting(*argv);
|
|
||||||
else
|
|
||||||
ReturnCode = ReadSetting(*argv);
|
|
||||||
}
|
}
|
||||||
}
|
if (DisplayAllOpt)
|
||||||
if (DisplayAllOpt) {
|
|
||||||
if (Quiet)
|
|
||||||
return Usage(me);
|
|
||||||
return DisplayAll(PROC_PATH);
|
return DisplayAll(PROC_PATH);
|
||||||
}
|
if (preloadfileOpt)
|
||||||
|
return Preload(preloadfile);
|
||||||
|
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
if (argc < 1) {
|
||||||
|
warnx("no variables specified");
|
||||||
|
Usage(stderr);
|
||||||
|
}
|
||||||
|
if (NameOnly && Quiet) {
|
||||||
|
warnx("options -N and -q can not coexist");
|
||||||
|
Usage(stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WriteMode || index(*argv, '='))
|
||||||
|
ReturnCode = WriteSetting(*argv);
|
||||||
|
else
|
||||||
|
ReturnCode = ReadSetting(*argv);
|
||||||
|
|
||||||
return ReturnCode;
|
return ReturnCode;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user