From 6e8bdf3efe4ac9ccc679a21f9e486463f300d53e Mon Sep 17 00:00:00 2001
From: chrfranke <chrfranke@4ea69e1a-61f1-4043-bf83-b5c94c648137>
Date: Wed, 7 Apr 2004 20:55:46 +0000
Subject: [PATCH] Added option -c FILE, --configfile=FILE to smartd

git-svn-id: https://smartmontools.svn.sourceforge.net/svnroot/smartmontools/trunk@1654 4ea69e1a-61f1-4043-bf83-b5c94c648137
---
 sm5/CHANGELOG   |  5 ++++-
 sm5/smartd.8.in | 18 ++++++++++++++++--
 sm5/smartd.c    | 49 +++++++++++++++++++++++++++++++++++++------------
 sm5/smartd.cpp  | 49 +++++++++++++++++++++++++++++++++++++------------
 4 files changed, 94 insertions(+), 27 deletions(-)

diff --git a/sm5/CHANGELOG b/sm5/CHANGELOG
index 8c01d7bc3..7ff2960d2 100644
--- a/sm5/CHANGELOG
+++ b/sm5/CHANGELOG
@@ -1,6 +1,6 @@
 CHANGELOG for smartmontools
 
-$Id: CHANGELOG,v 1.393 2004/04/07 16:41:42 card_captor Exp $
+$Id: CHANGELOG,v 1.394 2004/04/07 20:55:32 chrfranke Exp $
 
 The most recent version of this file is:
 http://cvs.sourceforge.net/viewcvs.py/smartmontools/sm5/CHANGELOG?sortby=date&view=markup
@@ -27,6 +27,9 @@ NOTES FOR FUTURE RELEASES: see TODO file.
 
 <ADDITIONS TO THE CHANGE LOG SHOULD BE ADDED JUST BELOW HERE, PLEASE>
 
+  [CF] Added option -c FILE, --configfile=FILE to smartd to specify
+       an alternate configuration FILE or '-' for standard input.
+
   [KS] configure.in now searches for -lnsl and -lsocket for Solaris.
 
   [CF] Win32/native smartd: Added thread to combine several syslog output
diff --git a/sm5/smartd.8.in b/sm5/smartd.8.in
index 66eb0f66e..2725736c2 100644
--- a/sm5/smartd.8.in
+++ b/sm5/smartd.8.in
@@ -1,7 +1,7 @@
 .ig
 Copyright (C) 2002-4 Bruce Allen <smartmontools-support@lists.sourceforge.net>
  
-$Id: smartd.8.in,v 1.52 2004/04/07 16:53:45 ballen4705 Exp $
+$Id: smartd.8.in,v 1.53 2004/04/07 20:55:46 chrfranke Exp $
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -113,6 +113,20 @@ start-up.
 OPTIONS
 Long options are not supported on all systems.  Use \fB\'smartd
 \-h\'\fP to see the available options.
+.TP
+.B \-c FILE, \-\-configfile=FILE
+Use FILE instead of \fB/etc/smartd.conf\fP to read the configuration
+directives. If the FILE does not exist, \fBsmartd\fP will print an
+error message and exit. Therefore, '-c /etc/smartd.conf' can be
+used to enforce the existence of the default configuration file.
+
+By specifying '-' as FILE, the configuration is read from standard
+input. This is useful for commands like:
+.nf
+.B echo /dev/hdb -m user@home -M test | smartd -c - -q onecheck
+.fi
+to perform ad hoc checks without a configuration file.
+
 .TP
 .B \-d, \-\-debug
 Runs \fBsmartd\fP in "debug" mode. In this mode, it displays status
@@ -1588,4 +1602,4 @@ smartmontools home page at \fBhttp://smartmontools.sourceforge.net/\fP .
 
 .SH
 CVS ID OF THIS PAGE:
-$Id: smartd.8.in,v 1.52 2004/04/07 16:53:45 ballen4705 Exp $
+$Id: smartd.8.in,v 1.53 2004/04/07 20:55:46 chrfranke Exp $
diff --git a/sm5/smartd.c b/sm5/smartd.c
index 6d48a9cca..1bbaa8de5 100644
--- a/sm5/smartd.c
+++ b/sm5/smartd.c
@@ -98,7 +98,7 @@ int getdomainname(char *, int); /* no declaration in header files! */
 extern const char *atacmdnames_c_cvsid, *atacmds_c_cvsid, *ataprint_c_cvsid, *escalade_c_cvsid, 
                   *knowndrives_c_cvsid, *os_XXXX_c_cvsid, *scsicmds_c_cvsid, *utility_c_cvsid;
 
-static const char *filenameandversion="$Id: smartd.c,v 1.307 2004/04/07 19:27:33 ballen4705 Exp $";
+static const char *filenameandversion="$Id: smartd.c,v 1.308 2004/04/07 20:55:31 chrfranke Exp $";
 #ifdef NEED_SOLARIS_ATA_CODE
 extern const char *os_solaris_ata_s_cvsid;
 #endif
@@ -109,7 +109,7 @@ extern const char *syslog_win32_c_cvsid;
 extern const char *int64_vc6_c_cvsid;
 #endif
 #endif
-const char *smartd_c_cvsid="$Id: smartd.c,v 1.307 2004/04/07 19:27:33 ballen4705 Exp $" 
+const char *smartd_c_cvsid="$Id: smartd.c,v 1.308 2004/04/07 20:55:31 chrfranke Exp $" 
 ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID
 KNOWNDRIVES_H_CVSID SCSICMDS_H_CVSID SMARTD_H_CVSID
 #ifdef SYSLOG_H_CVSID
@@ -139,6 +139,10 @@ static char* configfile = SMARTMONTOOLS_SYSCONFDIR "/" CONFIGFILENAME ;
 #else
 static char* configfile = "./" CONFIGFILENAME ;
 #endif
+// configuration file "name" if read from stdin
+static /*const*/ char * const configfile_stdin = "<stdin>";
+// allocated memory for alternate configuration file name
+static char* configfile_alt = NULL;
 
 // command-line: when should we exit?
 static int quit=0;
@@ -409,6 +413,9 @@ void Goodbye(void){
   // delete PID file, if one was created
   RemovePidFile();
 
+  // remove alternate configfile name
+  configfile_alt=FreeNonZero(configfile_alt, -1,__LINE__,filenameandversion);
+
   // useful for debugging -- have we managed memory correctly?
   if (debugmode || (bytes && exitstatus!=EXIT_NOMEM))
     PrintOut(LOG_INFO, "Memory still allocated for devices at exit is %lld bytes.\n", bytes);
@@ -967,8 +974,10 @@ void Directives() {
    arguments to the option opt or NULL on failure. */
 const char *GetValidArgList(char opt) {
   switch (opt) {
+  case 'c':
+    return "<FILE_NAME>, -";
   case 's':
-    return "valid_regular_expresssion";
+    return "valid_regular_expression";
   case 'l':
     return "daemon, local0, local1, local2, local3, local4, local5, local6, local7";
   case 'q':
@@ -988,6 +997,8 @@ const char *GetValidArgList(char opt) {
 void Usage (void){
   PrintOut(LOG_INFO,"Usage: smartd [options]\n\n");
 #ifdef HAVE_GETOPT_LONG
+  PrintOut(LOG_INFO,"  -c NAME|-, --configfile=NAME|-\n");
+  PrintOut(LOG_INFO,"        Read configuration file NAME or stdin [default is %s]\n\n", configfile);
   PrintOut(LOG_INFO,"  -d, --debug\n");
   PrintOut(LOG_INFO,"        Start smartd in debug mode\n\n");
   PrintOut(LOG_INFO,"  -D, --showdirectives\n");
@@ -1015,6 +1026,7 @@ void Usage (void){
   PrintOut(LOG_INFO,"  -V, --version, --license, --copyright\n");
   PrintOut(LOG_INFO,"        Print License, Copyright, and version information\n");
 #else
+  PrintOut(LOG_INFO,"  -c NAME|-  Read configuration file NAME or stdin [default is %s]\n", configfile);
   PrintOut(LOG_INFO,"  -d         Start smartd in debug mode\n");
   PrintOut(LOG_INFO,"  -D         Print the configuration file Directives and exit\n");
   PrintOut(LOG_INFO,"  -h         Display this help and exit\n");
@@ -2902,7 +2914,8 @@ int ParseConfigLine(int entry, int lineno,char *line){
 // clean up utility for ParseConfigFile()
 void cleanup(FILE **fpp){
   if (*fpp){
-    fclose(*fpp);
+    if (*fpp != stdin)
+      fclose(*fpp);
     *fpp=NULL;
   }
 
@@ -2925,14 +2938,18 @@ int ParseConfigFile(){
   char line[MAXLINELEN+2];
   char fullline[MAXCONTLINE+1];
 
-  // Open config file, if it exists
-  fp=fopen(configfile,"r");
-  if (fp==NULL && errno!=ENOENT){
-    // file exists but we can't read it
-    PrintOut(LOG_CRIT,"%s: Unable to open configuration file %s\n",
-             strerror(errno),configfile);
-    return -1;
+  // Open config file, if it exists and is not <stdin>
+  if (configfile != configfile_stdin) {
+    fp=fopen(configfile,"r");
+    if (fp==NULL && (errno!=ENOENT || configfile_alt)) {
+      // file exists but we can't read it or it should exist due to '-c' option
+      PrintOut(LOG_CRIT,"%s: Unable to open configuration file %s\n",
+               strerror(errno),configfile);
+      return -1;
+    }
   }
+  else // read from stdin ('-c -' option)
+    fp = stdin;
   
   // No configuration file found -- use fake one
   if (fp==NULL) {
@@ -3085,11 +3102,12 @@ void ParseOpts(int argc, char **argv){
   char *tailptr;
   long lchecktime;
   // Please update GetValidArgList() if you edit shortopts
-  const char *shortopts = "l:q:dDi:p:r:Vh?";
+  const char *shortopts = "c:l:q:dDi:p:r:Vh?";
 #ifdef HAVE_GETOPT_LONG
   char *arg;
   // Please update GetValidArgList() if you edit longopts
   struct option longopts[] = {
+    { "configfile",     required_argument, 0, 'c' },
     { "logfacility",    required_argument, 0, 'l' },
     { "quit",           required_argument, 0, 'q' },
     { "debug",          no_argument,       0, 'd' },
@@ -3217,6 +3235,13 @@ void ParseOpts(int argc, char **argv){
         s=CheckFree(s, __LINE__,filenameandversion);
       }
       break;
+    case 'c':
+      // alternate configuration file
+      if (strcmp(optarg,"-"))
+        configfile=configfile_alt=CustomStrDup(optarg, 1, __LINE__,filenameandversion);
+      else // read from stdin
+        configfile=configfile_stdin;
+      break;
     case 'p':
       // output file with PID number
       pid_file=CustomStrDup(optarg, 1, __LINE__,filenameandversion);
diff --git a/sm5/smartd.cpp b/sm5/smartd.cpp
index fccb06ed1..a28f54489 100644
--- a/sm5/smartd.cpp
+++ b/sm5/smartd.cpp
@@ -98,7 +98,7 @@ int getdomainname(char *, int); /* no declaration in header files! */
 extern const char *atacmdnames_c_cvsid, *atacmds_c_cvsid, *ataprint_c_cvsid, *escalade_c_cvsid, 
                   *knowndrives_c_cvsid, *os_XXXX_c_cvsid, *scsicmds_c_cvsid, *utility_c_cvsid;
 
-static const char *filenameandversion="$Id: smartd.cpp,v 1.307 2004/04/07 19:27:33 ballen4705 Exp $";
+static const char *filenameandversion="$Id: smartd.cpp,v 1.308 2004/04/07 20:55:31 chrfranke Exp $";
 #ifdef NEED_SOLARIS_ATA_CODE
 extern const char *os_solaris_ata_s_cvsid;
 #endif
@@ -109,7 +109,7 @@ extern const char *syslog_win32_c_cvsid;
 extern const char *int64_vc6_c_cvsid;
 #endif
 #endif
-const char *smartd_c_cvsid="$Id: smartd.cpp,v 1.307 2004/04/07 19:27:33 ballen4705 Exp $" 
+const char *smartd_c_cvsid="$Id: smartd.cpp,v 1.308 2004/04/07 20:55:31 chrfranke Exp $" 
 ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID
 KNOWNDRIVES_H_CVSID SCSICMDS_H_CVSID SMARTD_H_CVSID
 #ifdef SYSLOG_H_CVSID
@@ -139,6 +139,10 @@ static char* configfile = SMARTMONTOOLS_SYSCONFDIR "/" CONFIGFILENAME ;
 #else
 static char* configfile = "./" CONFIGFILENAME ;
 #endif
+// configuration file "name" if read from stdin
+static /*const*/ char * const configfile_stdin = "<stdin>";
+// allocated memory for alternate configuration file name
+static char* configfile_alt = NULL;
 
 // command-line: when should we exit?
 static int quit=0;
@@ -409,6 +413,9 @@ void Goodbye(void){
   // delete PID file, if one was created
   RemovePidFile();
 
+  // remove alternate configfile name
+  configfile_alt=FreeNonZero(configfile_alt, -1,__LINE__,filenameandversion);
+
   // useful for debugging -- have we managed memory correctly?
   if (debugmode || (bytes && exitstatus!=EXIT_NOMEM))
     PrintOut(LOG_INFO, "Memory still allocated for devices at exit is %lld bytes.\n", bytes);
@@ -967,8 +974,10 @@ void Directives() {
    arguments to the option opt or NULL on failure. */
 const char *GetValidArgList(char opt) {
   switch (opt) {
+  case 'c':
+    return "<FILE_NAME>, -";
   case 's':
-    return "valid_regular_expresssion";
+    return "valid_regular_expression";
   case 'l':
     return "daemon, local0, local1, local2, local3, local4, local5, local6, local7";
   case 'q':
@@ -988,6 +997,8 @@ const char *GetValidArgList(char opt) {
 void Usage (void){
   PrintOut(LOG_INFO,"Usage: smartd [options]\n\n");
 #ifdef HAVE_GETOPT_LONG
+  PrintOut(LOG_INFO,"  -c NAME|-, --configfile=NAME|-\n");
+  PrintOut(LOG_INFO,"        Read configuration file NAME or stdin [default is %s]\n\n", configfile);
   PrintOut(LOG_INFO,"  -d, --debug\n");
   PrintOut(LOG_INFO,"        Start smartd in debug mode\n\n");
   PrintOut(LOG_INFO,"  -D, --showdirectives\n");
@@ -1015,6 +1026,7 @@ void Usage (void){
   PrintOut(LOG_INFO,"  -V, --version, --license, --copyright\n");
   PrintOut(LOG_INFO,"        Print License, Copyright, and version information\n");
 #else
+  PrintOut(LOG_INFO,"  -c NAME|-  Read configuration file NAME or stdin [default is %s]\n", configfile);
   PrintOut(LOG_INFO,"  -d         Start smartd in debug mode\n");
   PrintOut(LOG_INFO,"  -D         Print the configuration file Directives and exit\n");
   PrintOut(LOG_INFO,"  -h         Display this help and exit\n");
@@ -2902,7 +2914,8 @@ int ParseConfigLine(int entry, int lineno,char *line){
 // clean up utility for ParseConfigFile()
 void cleanup(FILE **fpp){
   if (*fpp){
-    fclose(*fpp);
+    if (*fpp != stdin)
+      fclose(*fpp);
     *fpp=NULL;
   }
 
@@ -2925,14 +2938,18 @@ int ParseConfigFile(){
   char line[MAXLINELEN+2];
   char fullline[MAXCONTLINE+1];
 
-  // Open config file, if it exists
-  fp=fopen(configfile,"r");
-  if (fp==NULL && errno!=ENOENT){
-    // file exists but we can't read it
-    PrintOut(LOG_CRIT,"%s: Unable to open configuration file %s\n",
-             strerror(errno),configfile);
-    return -1;
+  // Open config file, if it exists and is not <stdin>
+  if (configfile != configfile_stdin) {
+    fp=fopen(configfile,"r");
+    if (fp==NULL && (errno!=ENOENT || configfile_alt)) {
+      // file exists but we can't read it or it should exist due to '-c' option
+      PrintOut(LOG_CRIT,"%s: Unable to open configuration file %s\n",
+               strerror(errno),configfile);
+      return -1;
+    }
   }
+  else // read from stdin ('-c -' option)
+    fp = stdin;
   
   // No configuration file found -- use fake one
   if (fp==NULL) {
@@ -3085,11 +3102,12 @@ void ParseOpts(int argc, char **argv){
   char *tailptr;
   long lchecktime;
   // Please update GetValidArgList() if you edit shortopts
-  const char *shortopts = "l:q:dDi:p:r:Vh?";
+  const char *shortopts = "c:l:q:dDi:p:r:Vh?";
 #ifdef HAVE_GETOPT_LONG
   char *arg;
   // Please update GetValidArgList() if you edit longopts
   struct option longopts[] = {
+    { "configfile",     required_argument, 0, 'c' },
     { "logfacility",    required_argument, 0, 'l' },
     { "quit",           required_argument, 0, 'q' },
     { "debug",          no_argument,       0, 'd' },
@@ -3217,6 +3235,13 @@ void ParseOpts(int argc, char **argv){
         s=CheckFree(s, __LINE__,filenameandversion);
       }
       break;
+    case 'c':
+      // alternate configuration file
+      if (strcmp(optarg,"-"))
+        configfile=configfile_alt=CustomStrDup(optarg, 1, __LINE__,filenameandversion);
+      else // read from stdin
+        configfile=configfile_stdin;
+      break;
     case 'p':
       // output file with PID number
       pid_file=CustomStrDup(optarg, 1, __LINE__,filenameandversion);
-- 
GitLab