-
Notifications
You must be signed in to change notification settings - Fork 683
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1174 from steveschnepp/plugin/smart_
Adding a new C plugin : smart_
- Loading branch information
Showing
4 changed files
with
348 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
smart_: smart_.o common.o | ||
|
||
.PHONY: clean | ||
|
||
clean: | ||
rm -f smart_ smart_.o common.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
/* | ||
* Copyright (C) 2008-2013 Helmut Grohne <helmut@subdivi.de> - All rights reserved. | ||
* | ||
* This copyrighted material is made available to anyone wishing to use, | ||
* modify, copy, or redistribute it subject to the terms and conditions | ||
* of the GNU General Public License v.2 or v.3. | ||
*/ | ||
#include <errno.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <unistd.h> | ||
#include "common.h" | ||
|
||
extern char **environ; | ||
|
||
int writeyes(void) | ||
{ | ||
puts("yes"); | ||
return 0; | ||
} | ||
|
||
int autoconf_check_readable(const char *path) | ||
{ | ||
if (0 == access(path, R_OK)) | ||
return writeyes(); | ||
else { | ||
printf("no (%s is not readable, errno=%d)\n", path, errno); | ||
return 0; | ||
} | ||
} | ||
|
||
int getenvint(const char *name, int defvalue) | ||
{ | ||
const char *value; | ||
value = getenv(name); | ||
if (value == NULL) | ||
return defvalue; | ||
return atoi(value); | ||
} | ||
|
||
static | ||
/*@null@ */ | ||
/*@observer@ */ | ||
const char *getenv_composed(const char *name1, const char *name2) | ||
{ | ||
char **p; | ||
size_t len1 = strlen(name1), len2 = strlen(name2); | ||
for (p = environ; *p; ++p) { | ||
if (0 == strncmp(*p, name1, len1) && | ||
0 == strncmp(len1 + *p, name2, len2) && | ||
(*p)[len1 + len2] == '=') | ||
return len1 + len2 + 1 + *p; | ||
} | ||
return NULL; | ||
} | ||
|
||
void print_warning(const char *name) | ||
{ | ||
const char *p; | ||
p = getenv_composed(name, "_warning"); | ||
if (p == NULL) | ||
p = getenv("warning"); | ||
if (p == NULL) | ||
return; | ||
|
||
printf("%s.warning %s\n", name, p); | ||
} | ||
|
||
void print_critical(const char *name) | ||
{ | ||
const char *p; | ||
p = getenv_composed(name, "_critical"); | ||
if (p == NULL) | ||
p = getenv("critical"); | ||
if (p == NULL) | ||
return; | ||
|
||
printf("%s.critical %s\n", name, p); | ||
} | ||
|
||
void print_warncrit(const char *name) | ||
{ | ||
print_warning(name); | ||
print_critical(name); | ||
} | ||
|
||
int fail(const char *message) | ||
{ | ||
fputs(message, stderr); | ||
fputc('\n', stderr); | ||
return 1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* | ||
* Copyright (C) 2008 Helmut Grohne <helmut@subdivi.de> - All rights reserved. | ||
* | ||
* This copyrighted material is made available to anyone wishing to use, | ||
* modify, copy, or redistribute it subject to the terms and conditions | ||
* of the GNU General Public License v.2 or v.3. | ||
*/ | ||
#ifndef COMMON_H | ||
#define COMMON_H | ||
|
||
#define PROC_STAT "/proc/stat" | ||
|
||
/** Write yes to stdout and return 0. The intended use is give an autoconf | ||
* response like "return writeyes();". | ||
* @returns a success state to be passed on as the return value from main */ | ||
int writeyes(void); | ||
|
||
/** Answer an autoconf request by checking the readability of the given file. | ||
*/ | ||
int autoconf_check_readable(const char *); | ||
|
||
/** Obtain an integer value from the environment. In the absence of the | ||
* variable the given defaultvalue is returned. */ | ||
int getenvint(const char *, int defaultvalue); | ||
|
||
/** Print a name.warning line using the "name_warning" or "warning" environment | ||
* variables. */ | ||
void print_warning(const char *name); | ||
|
||
/** Print a name.critical line using the "name_critical" or "critical" | ||
* environment variables. */ | ||
void print_critical(const char *name); | ||
|
||
/** Print both name.warning and name.critical lines using environment | ||
* variables. */ | ||
void print_warncrit(const char *name); | ||
|
||
/** Fail by printing the given message and a newline to stderr. | ||
* @returns a failure state to be passed on as the return value from main */ | ||
int fail(const char *message); | ||
|
||
#define xisspace(x) isspace((int)(unsigned char) x) | ||
#define xisdigit(x) isdigit((int)(unsigned char) x) | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
/* | ||
* Copyright (C) 2017 Bastiaan van Kesteren <bas@edeation.nl> - All rights reserved. | ||
* | ||
* This copyrighted material is made available to anyone wishing to use, | ||
* modify, copy, or redistribute it subject to the terms and conditions | ||
* of the GNU General Public License v.2 or v.3. | ||
*/ | ||
|
||
#include <stdlib.h> | ||
#include <stdio.h> | ||
#include <unistd.h> | ||
#include <string.h> | ||
#include <libgen.h> | ||
#include <sys/wait.h> | ||
#include "common.h" | ||
|
||
static char getitem(char *input, unsigned char item, char *output) | ||
{ | ||
unsigned char i = 0; | ||
unsigned char seperators = 0; | ||
char know_this_seperator = 0; | ||
unsigned char start = 0; | ||
unsigned char stop = 0; | ||
|
||
/* Trim starting spaces */ | ||
while (input[i] == ' ') { | ||
i++; | ||
} | ||
|
||
/* If we're requested to return the very first item... */ | ||
if (seperators == item) { | ||
start = i; | ||
} | ||
|
||
while (input[i] && seperators < item + 1) { | ||
if (input[i] == ' ') { | ||
if (know_this_seperator == 0) { | ||
know_this_seperator = 1; | ||
seperators++; | ||
if (seperators == item + 1) { | ||
stop = i; | ||
break; | ||
} | ||
} | ||
} else if (know_this_seperator) { | ||
know_this_seperator = 0; | ||
if (seperators == item) { | ||
start = i; | ||
} | ||
} else if (input[i] == '\n') { | ||
input[i] = 0; | ||
break; | ||
} | ||
|
||
i++; | ||
} | ||
|
||
if (stop) { | ||
/* Found stop, means we have a start aswell */ | ||
strncpy(output, &input[start], stop - start); | ||
return 1; | ||
} else if (start) { | ||
/* Have a start, no stop. We're returning the last item of the string */ | ||
strcpy(output, &input[start]); | ||
return 1; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
char command[50]; | ||
char output[255]; | ||
char label[25][100]; | ||
char value[25][25]; | ||
unsigned char attribute = 0; | ||
FILE *f; | ||
unsigned int i; | ||
|
||
/* Prepare and execute command */ | ||
snprintf(command, sizeof(command), | ||
"smartctl -A -d ata /dev/%s -n standby", | ||
&basename(argv[0])[6]); | ||
if ((f = popen(command, "r")) == 0) { | ||
return fail("cannot initiate command execution"); | ||
} | ||
|
||
/* Process command output */ | ||
while (fgets(output, sizeof(output), f) != NULL) { | ||
printf("#%s", output); | ||
/* Filter out attribute lines; look for lines starting with an attribute ID */ | ||
if ((output[0] >= '0' && output[0] <= '9') || | ||
(output[0] == ' ' | ||
&& (output[1] >= '0' && output[1] <= '9')) | ||
|| (output[0] == ' ' && output[1] == ' ' | ||
&& (output[2] >= '0' && output[2] <= '9'))) { | ||
/* Now, print the 2nd column (attribute name) and the 10th (raw value) */ | ||
|
||
getitem(output, 1, label[attribute]); | ||
getitem(output, 9, value[attribute]); | ||
attribute++; | ||
if (attribute == 25) { | ||
break; | ||
} | ||
} | ||
} | ||
|
||
/* Close command (this is where we get the exit code! */ | ||
{ | ||
int status = pclose(f); /* using an explicit temp var, to be compatible with macos & openbsd */ | ||
i = WEXITSTATUS(status); | ||
} | ||
if (i == 1 || /* smartctl command did not parse */ | ||
/*i == 2 || *//* smartctl device open failed */ | ||
i == 127) { /* command not found */ | ||
return fail("command execution failed"); | ||
} | ||
|
||
/* Setup for caching */ | ||
snprintf(command, sizeof(command), "/mnt/ram/smart_%s", | ||
&basename(argv[0])[6]); | ||
|
||
if (attribute == 0) { | ||
printf("#Cached attributes\n"); | ||
/* No output from command, try to fetch attribute-list from disk with NaN values */ | ||
if ((f = fopen(command, "r")) == 0) { | ||
return | ||
fail | ||
("command did not return data, no cached attribute-list"); | ||
return 0; | ||
} | ||
} | ||
|
||
if (argc > 1) { | ||
if (strcmp(argv[1], "config") == 0) { | ||
printf | ||
("graph_title S.M.A.R.T values for drive %s\n" | ||
"graph_args --base 1000 --lower-limit 0\n" | ||
"graph_vlabel Attribute S.M.A.R.T value\n" | ||
"graph_category disk\n", | ||
&basename(argv[0])[6]); | ||
|
||
if (attribute == 0) { | ||
while (fgets(output, sizeof(output), f) != | ||
NULL) { | ||
for (i = 0; i < strlen(output); | ||
i++) { | ||
if (output[i] == '\n') { | ||
output[i] = '\0'; | ||
break; | ||
} | ||
} | ||
printf("%s.label %s\n", output, | ||
output); | ||
} | ||
fclose(f); | ||
} else { | ||
f = fopen(command, "w"); | ||
do { | ||
attribute--; | ||
printf("%s.label %s\n", | ||
label[attribute], | ||
label[attribute]); | ||
if (f) { | ||
fprintf(f, "%s\n", | ||
label[attribute]); | ||
} | ||
} while (attribute); | ||
|
||
if (f) { | ||
fclose(f); | ||
} | ||
} | ||
printf("standby.label standby\n"); | ||
return 0; | ||
} | ||
} | ||
|
||
/* Asking for a fetch */ | ||
if (attribute == 0) { | ||
/* No data, use cached info */ | ||
while (fgets(output, sizeof(output), f) != NULL) { | ||
for (i = 0; i < strlen(output); i++) { | ||
if (output[i] == '\n') { | ||
output[i] = '\0'; | ||
break; | ||
} | ||
} | ||
printf("%s.value U\n", output); | ||
} | ||
printf("standby.value 1\n"); | ||
fclose(f); | ||
} else { | ||
do { | ||
attribute--; | ||
printf("%s.value %s\n", label[attribute], | ||
value[attribute]); | ||
} while (attribute); | ||
printf("standby.value 0\n"); | ||
} | ||
|
||
return 0; | ||
} |