The xml output is dirty and marked as FIXME
[debian/dhcpd-pools.git] / src / dhcpd-pools.c
1 /*
2 ** Copyright (C) 2006- Sami Kerola <kerolasa@iki.fi>
3 **  
4 ** This program is free software; you can redistribute it and/or modify
5 ** it under the terms of the GNU General Public License as published by
6 ** the Free Software Foundation; either version 2 of the License, or
7 ** (at your option) any later version.
8 ** 
9 ** This program is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 ** GNU General Public License for more details.
13 ** 
14 ** You should have received a copy of the GNU General Public License
15 ** along with this program; if not, write to the Free Software 
16 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <stdio.h>
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27 #ifdef  HAVE_STDLIB_H
28 #include <stdlib.h>
29 #else                           /* Not STDC_HEADERS */
30 extern void exit();
31 extern char *malloc();
32 #endif                          /* STDC_HEADERS */
33 #ifdef  HAVE_STRING_H
34 #include <string.h>
35 #else
36 #include <strings.h>
37 #endif
38 #include <getopt.h>
39 #include <errno.h>
40
41 #include "dhcpd-pools.h"
42 #include "defaults.h"
43
44 int main(int argc, char **argv)
45 {
46         int c, sorts = 0;
47         int option_index = 0;
48         char *tmp;
49         struct range_t *tmp_ranges;
50
51         /* Options for getopt_long */
52         static struct option const long_options[] = {
53                 {"config", required_argument, 0, (int) 'c'},
54                 {"leases", required_argument, 0, (int) 'l'},
55                 {"format", required_argument, 0, (int) 'f'},
56                 {"sort", required_argument, 0, (int) 's'},
57                 {"reverse", no_argument, 0, (int) 'r'},
58                 {"output", required_argument, 0, (int) 'o'},
59                 {"limit", required_argument, 0, (int) 'L'},
60                 {"version", no_argument, 0, (int) 'v'},
61                 {"help", no_argument, 0, (int) 'h'},
62                 {0, 0, 0, 0}
63         };
64
65         program_name = argv[0];
66         atexit(clean_up);
67
68         /* TODO: make either dynamic or find out max path lenght that auto config
69          * provides */
70         config.dhcpdconf_file = safe_malloc(sizeof(char) * MAXLEN);
71         config.dhcpdlease_file = safe_malloc(sizeof(char) * MAXLEN);
72         config.output_file = safe_malloc(sizeof(char) * MAXLEN);
73
74         /* Make sure string has zero lenght if there is no command line
75          * option */
76         config.output_file[0] = '\0';
77
78         /* File location defaults */
79         strncpy(config.dhcpdconf_file, DHCPDCONF_FILE,
80                 (size_t) MAXLEN - 1);
81         strncpy(config.dhcpdlease_file, DHCPDLEASE_FILE,
82                 (size_t) MAXLEN - 1);
83         tmp = OUTPUT_LIMIT;
84         config.output_limit[0] = (int) (*tmp - '0');
85         tmp++;
86         config.output_limit[1] = (int) (*tmp - '0');
87         fullhtml = false;
88
89         /* Make sure some output format is selected by default */
90         strncpy(config.output_format, OUTPUT_FORMAT, (size_t) 1);
91
92         /* Default sort order is by IPs small to big */
93         config.reverse_order = false;
94
95         /* Parse command line options */
96         while (1) {
97                 c = getopt_long(argc, argv, "c:l:f:o:s:rL:vh",
98                                 long_options, &option_index);
99
100                 if (c == EOF)
101                         break;
102
103                 switch (c) {
104                 case 0:
105                         break;
106                 case 'c':
107                         /* config file */
108                         if (optarg != NULL) {
109                                 strncpy(config.dhcpdconf_file, optarg,
110                                         (size_t) MAXLEN - 1);
111                         } else {
112                                 eprintf
113                                     ("main: for argument configuration file parameter not set");
114                                 usage(EXIT_FAILURE);
115                         }
116                         break;
117                 case 'l':
118                         /* lease file */
119                         if (optarg != NULL) {
120                                 strncpy(config.dhcpdlease_file, optarg,
121                                         (size_t) MAXLEN - 1);
122                         } else {
123                                 eprintf
124                                     ("main: for argument lease file parameter not set");
125                                 usage(EXIT_FAILURE);
126                         }
127                         break;
128                 case 'f':
129                         /* Output format */
130                         if (optarg != NULL) {
131                                 strncpy(config.output_format, optarg,
132                                         (size_t) 1);
133                         } else {
134                                 eprintf
135                                     ("main: for argument output format parameter not set");
136                                 usage(EXIT_FAILURE);
137                         }
138                         break;
139                 case 's':
140                         /* Output sorting option */
141                         if (optarg != NULL) {
142                                 sorts = strlen(optarg);
143                                 if (5 < sorts) {
144                                         eprintf
145                                             ("main: only 5 first sort orders will be used");
146                                         strncpy(config.sort, optarg,
147                                                 (size_t) 5);
148                                         sorts = 5;
149                                 } else {
150                                         strncpy(config.sort, optarg,
151                                                 (size_t) sorts);
152                                 }
153                         } else {
154                                 eprintf
155                                     ("main: for argument sort order parameter not set");
156                                 usage(EXIT_FAILURE);
157                         }
158                         break;
159                 case 'r':
160                         /* What ever sort in reverse order */
161                         config.reverse_order = true;
162                         break;
163                 case 'o':
164                         /* Output file */
165                         if (optarg != NULL) {
166                                 strncpy(config.output_file, optarg,
167                                         (size_t) MAXLEN - 1);
168                         } else {
169                                 eprintf
170                                     ("main: for argument output file parameter not set");
171                                 usage(EXIT_FAILURE);
172                         }
173                         break;
174                 case 'L':
175                         /* Specification what will be printed */
176                         if (optarg != NULL) {
177                                 if (optarg[0] >= '0' && optarg[0] < '8') {
178                                         config.output_limit[0] =
179                                             (int) optarg[0] - '0';
180                                 } else {
181                                         eprintf
182                                             ("main: output mask %s illegal",
183                                              argv[optind]);
184                                         usage(EXIT_FAILURE);
185                                 }
186                                 if (optarg[1] >= '0' && optarg[1] < '8') {
187                                         config.output_limit[1] =
188                                             (int) optarg[1] - '0';
189                                 } else {
190                                         eprintf
191                                             ("main: output mask %s illegal",
192                                              optarg);
193                                         usage(EXIT_FAILURE);
194                                 }
195                         } else {
196                                 eprintf
197                                     ("main: for argument output mask parameter not set");
198                                 usage(EXIT_FAILURE);
199                         }
200                         break;
201                 case 'v':
202                         /* Print version */
203                         print_version();
204                         exit(EXIT_SUCCESS);
205                 case 'h':
206                         /* Print help */
207                         usage(EXIT_SUCCESS);
208                 default:
209                         usage(EXIT_FAILURE);
210                 }
211         }
212
213         /* Output function selection */
214         switch (config.output_format[0]) {
215         case 't':
216                 output_analysis = output_txt;
217                 break;
218         case 'h':
219                 output_analysis = output_html;
220                 break;
221         case 'H':
222                 output_analysis = output_html;
223                 fullhtml = true;
224                 break;
225         case 'x':
226                 output_analysis = output_xml;
227                 break;
228         case 'X':
229                 output_analysis = output_xml;
230                 break;
231         case 'c':
232                 output_analysis = output_csv;
233                 break;
234         case 's':
235                 /* output_analysis = output_snmp; */
236                 output_analysis = output_txt;
237                 break;
238         default:
239                 eprintf("main: unknown ouput format");
240                 usage(EXIT_FAILURE);
241         }
242
243         /* Do the job */
244         prepare_memory();
245         parse_config(true, config.dhcpdconf_file, shared_net_names,
246                      shared_net_names + strlen(shared_net_names) + 1,
247                      shared_networks);
248
249         /* FIXME: move to output.c and use FILE *outfile */
250         if ((config.output_format[0] == 'x')
251             || (config.output_format[0] == 'X')) {
252                 printf("<dhcpstatus>\n");
253         };
254
255         parse_leases();
256         prepare_data();
257         do_counting();
258         tmp_ranges = safe_malloc(sizeof(struct range_t) * num_ranges);
259         if (sorts != 0) {
260                 mergesort_ranges(ranges, num_ranges, tmp_ranges);
261         }
262         if (config.reverse_order == true) {
263                 flip_ranges(ranges, tmp_ranges);
264         }
265         free(tmp_ranges);
266         output_analysis();
267         /* After fopen in ouput ioctl does like /dev/null which
268          * cause ENOTTY, and clean_up will see that without this
269          * reset. At least linux does this, and possibly some
270          * other systems. There's a report from FreeBSD 8.0 which
271          * matches quite well with the symptom. */
272         if (errno == 25)
273                 errno = 0;
274
275         /* FIXME: move to output.c and use FILE *outfile */
276         if ((config.output_format[0] == 'x')
277             || (config.output_format[0] == 'X')) {
278                 printf("</dhcpstatus>\n");
279         };
280
281         exit(EXIT_SUCCESS);
282 }
283
284 /* Global allocations, counter resets etc */
285 int prepare_memory()
286 {
287         num_ranges = num_shared_networks = 0;
288         shared_networks =
289             safe_malloc(sizeof(struct shared_network_t) * SHARED_NETWORKS);
290         shared_net_names =
291             safe_malloc(sizeof(char) * SHARED_NETWORKS_NAMES);
292
293         ranges = safe_malloc(sizeof(struct range_t) * RANGES);
294
295         /* First shared network entry is all networks */
296         strcpy(shared_net_names, "All networks");
297         return 0;
298 }