procps 010114
This commit is contained in:
437
sysctl.c
Normal file
437
sysctl.c
Normal file
@ -0,0 +1,437 @@
|
||||
|
||||
/*
|
||||
* Sysctl 1.01 - A utility to read and manipulate the sysctl parameters
|
||||
*
|
||||
*
|
||||
* "Copyright 1999 George Staikos
|
||||
* This file may be used subject to the terms and conditions of the
|
||||
* GNU General Public License Version 2, or any later version
|
||||
* at your option, as published by the Free Software Foundation.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details."
|
||||
*
|
||||
* Changelog:
|
||||
* v1.01:
|
||||
* - added -p <preload> to preload values from a file
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
/*
|
||||
* Additional types we might need.
|
||||
*/
|
||||
typedef int bool;
|
||||
|
||||
static bool true = 1;
|
||||
static bool false = 0;
|
||||
|
||||
|
||||
/*
|
||||
* Function Prototypes
|
||||
*/
|
||||
int Usage(const char *name);
|
||||
void Preload(const char *filename);
|
||||
int WriteSetting(const char *setting);
|
||||
int ReadSetting(const char *setting);
|
||||
int DisplayAll(const char *path, bool ShowTableUtil);
|
||||
|
||||
|
||||
/*
|
||||
* Globals...
|
||||
*/
|
||||
|
||||
const char *PROC_PATH = "/proc/sys/";
|
||||
const char *DEFAULT_PRELOAD = "/etc/sysctl.conf";
|
||||
static bool PrintName;
|
||||
static bool PrintNewline;
|
||||
|
||||
/* error messages */
|
||||
const char *ERR_UNKNOWN_PARAMETER = "error: Unknown parameter '%s'\n";
|
||||
const char *ERR_MALFORMED_SETTING = "error: Malformed setting '%s'\n";
|
||||
const char *ERR_NO_EQUALS = "error: '%s' must be of the form name=value\n";
|
||||
const char *ERR_INVALID_KEY = "error: '%s' is an unknown key\n";
|
||||
const char *ERR_UNKNOWN_WRITING = "error: unknown error %d setting key '%s'\n";
|
||||
const char *ERR_UNKNOWN_READING = "error: unknown error %d reading key '%s'\n";
|
||||
const char *ERR_PERMISSION_DENIED = "error: permission denied on key '%s'\n";
|
||||
const char *ERR_OPENING_DIR = "error: unable to open directory '%s'\n";
|
||||
const char *ERR_PRELOAD_FILE = "error: unable to open preload file '%s'\n";
|
||||
const char *WARN_BAD_LINE = "warning: %s(%d): invalid syntax, continuing...\n";
|
||||
|
||||
|
||||
#define DOTSLASH(x) do{ \
|
||||
char *p_ = (x); \
|
||||
for(;;){ \
|
||||
p_ = strchr(p_, '.'); \
|
||||
if(!p_) break; \
|
||||
*p_ = '/'; \
|
||||
} \
|
||||
}while(0)
|
||||
|
||||
#define SLASHDOT(x) do{ \
|
||||
char *p_ = (x); \
|
||||
for(;;){ \
|
||||
p_ = strchr(p_, '.'); \
|
||||
if(!p_) break; \
|
||||
*p_ = '/'; \
|
||||
} \
|
||||
}while(0)
|
||||
|
||||
|
||||
/*
|
||||
* Main...
|
||||
*
|
||||
*/
|
||||
int main(int argc, char **argv) {
|
||||
const char *me = (const char *)basename(argv[0]);
|
||||
bool SwitchesAllowed = true;
|
||||
bool WriteMode = false;
|
||||
int ReturnCode = 0;
|
||||
const char *preloadfile = DEFAULT_PRELOAD;
|
||||
|
||||
PrintName = true;
|
||||
PrintNewline = true;
|
||||
|
||||
if (argc < 2) {
|
||||
return Usage(me);
|
||||
} /* endif */
|
||||
|
||||
argv++;
|
||||
|
||||
for (; argv && *argv && **argv; argv++) {
|
||||
if (SwitchesAllowed && **argv == '-') { /* we have a switch */
|
||||
switch((*argv)[1]) {
|
||||
case 'b':
|
||||
/* This is "binary" format, which means more for BSD. */
|
||||
PrintNewline = false;
|
||||
/* FALL THROUGH */
|
||||
case 'n':
|
||||
PrintName = false;
|
||||
break;
|
||||
case 'w':
|
||||
SwitchesAllowed = false;
|
||||
WriteMode = true;
|
||||
break;
|
||||
case 'p':
|
||||
argv++;
|
||||
if (argv && *argv && **argv) {
|
||||
preloadfile = *argv;
|
||||
} /* endif */
|
||||
|
||||
Preload(preloadfile);
|
||||
return(0);
|
||||
break;
|
||||
case 'a': /* string and integer values (for Linux, all of them) */
|
||||
case 'A': /* the above, including "opaques" (would be unprintable) */
|
||||
case 'X': /* the above, with opaques completly printed in hex */
|
||||
SwitchesAllowed = false;
|
||||
return DisplayAll(PROC_PATH, ((*argv)[1] == 'a') ? false : true);
|
||||
case 'h':
|
||||
case '?':
|
||||
return Usage(me);
|
||||
default:
|
||||
fprintf(stderr, ERR_UNKNOWN_PARAMETER, *argv);
|
||||
return Usage(me);
|
||||
} /* end switch */
|
||||
} else {
|
||||
SwitchesAllowed = false;
|
||||
if (WriteMode)
|
||||
ReturnCode = WriteSetting(*argv);
|
||||
else ReadSetting(*argv);
|
||||
} /* end if */
|
||||
} /* end for */
|
||||
|
||||
return ReturnCode;
|
||||
} /* end main */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Display the usage format
|
||||
*
|
||||
*/
|
||||
int Usage(const char *name) {
|
||||
printf("usage: %s [-n] variable ... \n"
|
||||
" %s [-n] -w variable=value ... \n"
|
||||
" %s [-n] -a \n"
|
||||
" %s [-n] -p <file> (default /etc/sysctl.conf) \n"
|
||||
" %s [-n] -A\n", name, name, name, name, name);
|
||||
return -1;
|
||||
} /* end Usage() */
|
||||
|
||||
|
||||
/*
|
||||
* Strip the leading and trailing spaces from a string
|
||||
*
|
||||
*/
|
||||
char *StripLeadingAndTrailingSpaces(char *oneline) {
|
||||
char *t;
|
||||
|
||||
if (!oneline || !*oneline)
|
||||
return oneline;
|
||||
|
||||
t = oneline;
|
||||
t += strlen(oneline)-1;
|
||||
|
||||
while ((*t == ' ' || *t == '\t' || *t == '\n' || *t == '\r') && t != oneline)
|
||||
*t-- = 0;
|
||||
|
||||
t = oneline;
|
||||
|
||||
while ((*t == ' ' || *t == '\t') && *t != 0)
|
||||
t++;
|
||||
|
||||
return t;
|
||||
} /* end StripLeadingAndTrailingSpaces() */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Preload the sysctl's from the conf file
|
||||
* - we parse the file and then reform it (strip out whitespace)
|
||||
*
|
||||
*/
|
||||
void Preload(const char *filename) {
|
||||
FILE *fp;
|
||||
char oneline[257];
|
||||
char buffer[257];
|
||||
char *t;
|
||||
int n = 0;
|
||||
char *name, *value;
|
||||
|
||||
if (!filename || ((fp = fopen(filename, "r")) == NULL)) {
|
||||
fprintf(stderr, ERR_PRELOAD_FILE, filename);
|
||||
return;
|
||||
} /* endif */
|
||||
|
||||
while (fgets(oneline, 256, fp)) {
|
||||
oneline[256] = 0;
|
||||
n++;
|
||||
t = StripLeadingAndTrailingSpaces(oneline);
|
||||
|
||||
if (strlen(t) < 2)
|
||||
continue;
|
||||
|
||||
if (*t == '#' || *t == ';')
|
||||
continue;
|
||||
|
||||
name = strtok(t, "=");
|
||||
if (!name || !*name) {
|
||||
fprintf(stderr, WARN_BAD_LINE, filename, n);
|
||||
continue;
|
||||
} /* endif */
|
||||
|
||||
StripLeadingAndTrailingSpaces(name);
|
||||
|
||||
value = strtok(NULL, "\n\r");
|
||||
if (!value || !*value) {
|
||||
fprintf(stderr, WARN_BAD_LINE, filename, n);
|
||||
continue;
|
||||
} /* endif */
|
||||
|
||||
while ((*value == ' ' || *value == '\t') && *value != 0)
|
||||
value++;
|
||||
|
||||
sprintf(buffer, "%s=%s", name, value);
|
||||
WriteSetting(buffer);
|
||||
} /* endwhile */
|
||||
|
||||
fclose(fp);
|
||||
} /* end Preload() */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Write a sysctl setting
|
||||
*
|
||||
*/
|
||||
int WriteSetting(const char *setting) {
|
||||
int rc = 0;
|
||||
const char *name = setting;
|
||||
const char *value;
|
||||
const char *equals;
|
||||
char *tmpname;
|
||||
FILE *fp;
|
||||
char *outname;
|
||||
|
||||
if (!name) { /* probably dont' want to display this err */
|
||||
return 0;
|
||||
} /* end if */
|
||||
|
||||
equals = index(setting, '=');
|
||||
|
||||
if (!equals) {
|
||||
fprintf(stderr, ERR_NO_EQUALS, setting);
|
||||
return -1;
|
||||
} /* end if */
|
||||
|
||||
value = equals + sizeof(char); /* point to the value in name=value */
|
||||
|
||||
if (!*name || !*value || name == equals) {
|
||||
fprintf(stderr, ERR_MALFORMED_SETTING, setting);
|
||||
return -2;
|
||||
} /* end if */
|
||||
|
||||
tmpname = (char *)malloc((equals-name+1+strlen(PROC_PATH))*sizeof(char));
|
||||
outname = (char *)malloc((equals-name+1)*sizeof(char));
|
||||
|
||||
strcpy(tmpname, PROC_PATH);
|
||||
strncat(tmpname, name, (int)(equals-name));
|
||||
tmpname[equals-name+strlen(PROC_PATH)] = 0;
|
||||
strncpy(outname, name, (int)(equals-name));
|
||||
outname[equals-name] = 0;
|
||||
|
||||
DOTSLASH(tmpname); /* change . to / */
|
||||
SLASHDOT(outname); /* change / to . */
|
||||
|
||||
fp = fopen(tmpname, "w");
|
||||
|
||||
if (!fp) {
|
||||
switch(errno) {
|
||||
case ENOENT:
|
||||
fprintf(stderr, ERR_INVALID_KEY, outname);
|
||||
break;
|
||||
case EACCES:
|
||||
fprintf(stderr, ERR_PERMISSION_DENIED, outname);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, ERR_UNKNOWN_WRITING, errno, outname);
|
||||
break;
|
||||
} /* end switch */
|
||||
rc = -1;
|
||||
} else {
|
||||
fprintf(fp, "%s\n", value);
|
||||
fclose(fp);
|
||||
if (PrintName) {
|
||||
fprintf(stdout, "%s = %s\n", outname, value);
|
||||
} else {
|
||||
if (PrintNewline)
|
||||
fprintf(stdout, "%s\n", value);
|
||||
else
|
||||
fprintf(stdout, "%s", value);
|
||||
}
|
||||
} /* endif */
|
||||
|
||||
free(tmpname);
|
||||
free(outname);
|
||||
return rc;
|
||||
} /* end WriteSetting() */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Read a sysctl setting
|
||||
*
|
||||
*/
|
||||
int ReadSetting(const char *setting) {
|
||||
int rc = 0;
|
||||
char *tmpname, *outname;
|
||||
char inbuf[1025];
|
||||
const char *name = setting;
|
||||
FILE *fp;
|
||||
|
||||
if (!setting || !*setting) {
|
||||
fprintf(stderr, ERR_INVALID_KEY, setting);
|
||||
} /* endif */
|
||||
|
||||
tmpname = (char *)malloc((strlen(name)+strlen(PROC_PATH)+1)*sizeof(char));
|
||||
outname = (char *)malloc((strlen(name)+1)*sizeof(char));
|
||||
|
||||
strcpy(tmpname, PROC_PATH);
|
||||
strcat(tmpname, name);
|
||||
strcpy(outname, name);
|
||||
|
||||
|
||||
DOTSLASH(tmpname); /* change . to / */
|
||||
SLASHDOT(outname); /* change / to . */
|
||||
|
||||
fp = fopen(tmpname, "r");
|
||||
|
||||
if (!fp) {
|
||||
switch(errno) {
|
||||
case ENOENT:
|
||||
fprintf(stderr, ERR_INVALID_KEY, outname);
|
||||
break;
|
||||
case EACCES:
|
||||
fprintf(stderr, ERR_PERMISSION_DENIED, outname);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, ERR_UNKNOWN_READING, errno, outname);
|
||||
break;
|
||||
} /* end switch */
|
||||
rc = -1;
|
||||
} else {
|
||||
while(fgets(inbuf, 1024, fp)) {
|
||||
/* already has the \n in it */
|
||||
if (PrintName) {
|
||||
fprintf(stdout, "%s = %s", outname, inbuf);
|
||||
} else {
|
||||
if (!PrintNewline) {
|
||||
char *nlptr = strchr(inbuf,'\n');
|
||||
if(nlptr) *nlptr='\0';
|
||||
}
|
||||
fprintf(stdout, "%s", inbuf);
|
||||
}
|
||||
} /* endwhile */
|
||||
fclose(fp);
|
||||
} /* endif */
|
||||
|
||||
free(tmpname);
|
||||
free(outname);
|
||||
return rc;
|
||||
} /* end ReadSetting() */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Display all the sysctl settings
|
||||
*
|
||||
*/
|
||||
int DisplayAll(const char *path, bool ShowTableUtil) {
|
||||
int rc = 0;
|
||||
int rc2;
|
||||
DIR *dp;
|
||||
struct dirent *de;
|
||||
char *tmpdir;
|
||||
struct stat ts;
|
||||
|
||||
dp = opendir(path);
|
||||
|
||||
if (!dp) {
|
||||
fprintf(stderr, ERR_OPENING_DIR, path);
|
||||
rc = -1;
|
||||
} else {
|
||||
readdir(dp); readdir(dp); /* skip . and .. */
|
||||
while (( de = readdir(dp) )) {
|
||||
tmpdir = (char *)malloc(strlen(path)+strlen(de->d_name)+2);
|
||||
sprintf(tmpdir, "%s%s", path, de->d_name);
|
||||
rc2 = stat(tmpdir, &ts); /* should check this return code */
|
||||
if (rc2 != 0) {
|
||||
perror(tmpdir);
|
||||
} else {
|
||||
if (S_ISDIR(ts.st_mode)) {
|
||||
strcat(tmpdir, "/");
|
||||
DisplayAll(tmpdir, ShowTableUtil);
|
||||
} else {
|
||||
rc |= ReadSetting(tmpdir+strlen(PROC_PATH));
|
||||
} /* endif */
|
||||
} /* endif */
|
||||
free(tmpdir);
|
||||
} /* end while */
|
||||
closedir(dp);
|
||||
} /* endif */
|
||||
|
||||
return rc;
|
||||
} /* end DisplayAll() */
|
||||
|
Reference in New Issue
Block a user