1 /*
2  * options.c
3  *
4  * Command line options parsing routine for apcupsd.
5  */
6 
7 /*
8  * Copyright (C) 2000-2004 Kern Sibbald
9  * Copyright (C) 1999-2000 Riccardo Facchetti <riccardo@master.oasi.gpa.it>
10  * Copyright (C) 1996-99 Andre M. Hedrick <andre@suse.com>
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of version 2 of the GNU General
14  * Public License as published by the Free Software Foundation.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public
22  * License along with this program; if not, write to the Free
23  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
24  * MA 02110-1335, USA.
25  */
26 
27 #include "apc.h"
28 
29 static const char *const shortoptions = "bhRtTVf:d:pP:ko";
30 
31 enum {
32    OPT_NOARG,
33    OPT_HELP,
34    OPT_VERSION,
35    OPT_CFGFILE,
36    OPT_DEBUG,
37    OPT_HIBERNATE,
38    OPT_POWEROFF,
39    OPT_TERMONPWRFAIL,
40    OPT_KILLONPWRFAIL,
41    OPT_PIDFILE
42 };
43 
44 static const struct option longoptions[] = {
45    {"help",                no_argument,       NULL, OPT_HELP},
46    {"version",             no_argument,       NULL, OPT_VERSION},
47    {"config-file",         required_argument, NULL, OPT_CFGFILE},
48    {"debug",               required_argument, NULL, OPT_DEBUG},
49    {"killpower",           no_argument,       NULL, OPT_HIBERNATE},
50    {"hibernate",           no_argument,       NULL, OPT_HIBERNATE},
51    {"power-off",           no_argument,       NULL, OPT_POWEROFF},
52    {"term-on-powerfail",   no_argument,       NULL, OPT_TERMONPWRFAIL},
53    {"kill-on-powerfail",   no_argument,       NULL, OPT_KILLONPWRFAIL},
54    {"pid-file",            required_argument, NULL, OPT_PIDFILE},
55    {0,                     no_argument,       NULL, OPT_NOARG}
56 };
57 
58 /* Globals used by command line options. */
59 int show_version = FALSE;
60 char *cfgfile = NULL;
61 int terminate_on_powerfail = FALSE;
62 int kill_on_powerfail = FALSE;
63 int dumb_mode_test = FALSE;        /* for testing dumb mode */
64 int go_background = TRUE;
65 extern char *pidfile;
66 extern bool trace;
67 
print_usage(char * argv[])68 static void print_usage(char *argv[])
69 {
70    printf("usage: apcupsd [options]\n"
71          "  Options are as follows:\n"
72          "  -b,                           don't go into background\n"
73          "  -d, --debug <level>           set debug level (>0)\n"
74          "  -f, --config-file <file>      load specified config file\n"
75          "  -k, --killpower, --hibernate  put UPS into hibernation mode [*]\n"
76          "  -o, --power-off               turn off UPS completely [*]\n"
77          "  -P, --pid-file                specify name of PID file\n"
78          "  -p, --kill-on-powerfail       hibernate UPS on powerfail\n"
79          "  -R,                           put SmartUPS into dumb mode\n"
80          "  -t, --term-on-powerfail       terminate when battery power fails\n"
81          "  -T                            send debug to ./apcupsd.trace\n"
82          "  -V, --version                 display version info\n"
83          "  -h, --help                    display this help\n"
84          "\n"
85          "  [*] Only one parameter of this kind and apcupsd must not already be running.\n"
86          "\n"
87          "Copyright (C) 2004-2009 Adam Kropelin\n"
88          "Copyright (C) 1999-2005 Kern Sibbald\n"
89          "Copyright (C) 1996-1999 Andre Hedrick\n"
90          "Copyright (C) 1999-2001 Riccardo Facchetti\n"
91          "apcupsd is free software and comes with ABSOLUTELY NO WARRANTY\n"
92          "under the terms of the GNU General Public License\n"
93          "\n"
94          "Report bugs to apcupsd Support Center:\n"
95          "  apcupsd-users@lists.sourceforge.net\n");
96 }
97 
parse_options(int argc,char * argv[])98 int parse_options(int argc, char *argv[])
99 {
100    int options = 0;
101    int oneshot = FALSE;
102    int option_index;
103    int errflag = 0;
104    int c;
105 
106    while (!errflag &&
107           (c = getopt_long(argc, argv, shortoptions,
108             longoptions, &option_index)) != -1) {
109       options++;
110 
111       switch (c) {
112       case 'b':                   /* do not become daemon */
113          go_background = FALSE;
114          break;
115       case 'R':
116          dumb_mode_test = TRUE;
117          break;
118       case 'V':
119       case OPT_VERSION:
120          show_version = TRUE;
121          oneshot = TRUE;
122          break;
123       case 'f':
124       case OPT_CFGFILE:
125          if (optarg[0] == '-') {
126             /* Following option: no argument set for -f */
127             errflag++;
128             break;
129          }
130 
131          /*
132           * The reason for this is that loading a different config file
133           * is not something dangerous when we are doing `oneshot' things
134           * and we may even want to load a different config file during
135           * `oneshot's.
136           */
137          options--;
138          cfgfile = optarg;
139          break;
140       case 'P':
141       case OPT_PIDFILE:
142          if (optarg[0] == '-') {
143             /* Following option: no argument set for -P */
144             errflag++;
145             break;
146          }
147          options--;
148          pidfile = optarg;
149          break;
150       case 'd':
151       case OPT_DEBUG:
152          if (optarg[0] == '-') {
153             /* Following option: no argument set for -d */
154             errflag++;
155             break;
156          }
157          /*
158           * The reason of this, is that enabling debugging is
159           * not something dangerous when we are doing `oneshot's
160           */
161          options--;
162          debug_level = atoi(optarg);
163          break;
164       case 'p':
165       case OPT_KILLONPWRFAIL:
166          kill_on_powerfail = TRUE;
167          break;
168       case 't':
169       case OPT_TERMONPWRFAIL:
170          terminate_on_powerfail = TRUE;
171          break;
172       case 'T':
173          trace = true;
174          break;
175       case 'k':
176       case OPT_HIBERNATE:
177          hibernate_ups = TRUE;
178          oneshot = TRUE;
179          break;
180       case 'o':
181       case OPT_POWEROFF:
182          shutdown_ups = TRUE;
183          oneshot = TRUE;
184          break;
185       case 'h':
186       case OPT_HELP:
187       default:
188          errflag++;
189       }
190    }
191 
192 /* Win32-specific dynamic path handling... */
193 #ifdef HAVE_MINGW
194    extern char sbindir[MAXSTRING];
195 
196    /* Obtain full path to this executable */
197    DWORD len = GetModuleFileName(NULL, sbindir, sizeof(sbindir)-1);
198    sbindir[len] = '\0';
199    Dmsg(200, "Exepath: %s\n", sbindir);
200    if (len == 0) {
201       /* Failed to get path, so make an assumption */
202       asnprintf(sbindir, sizeof(sbindir), "C:\\apcupsd\\bin\\apcupsd.exe");
203    }
204 
205    /* Strip trailing filename component */
206    char *ptr = strrchr(sbindir, '\\');
207    if (ptr)
208       *ptr = '\0';
209    else
210       sbindir[0] = '\0';
211 
212    /*
213     * If the user did not provide a -f argument to specify
214     * the location of apcupsd.conf, simulate one relative to current
215     * executable path.
216     */
217    if (cfgfile == APCCONF) {
218       asnprintf(APCCONF, sizeof(APCCONF),
219          "%s\\..\\etc\\apcupsd%s", sbindir, APCCONF_FILE);
220    }
221 #endif
222 
223    if ((oneshot == TRUE) && options > 1) {
224       fprintf(stderr, "\nError: too many arguments.\n\n");
225       errflag++;
226    }
227 
228    if (errflag)
229       print_usage(argv);
230 
231    return errflag;
232 }
233