b250f191c84590530c5240f556e536926b663d1f
[debian/dhcpd-pools.git] / src / dhcpd-pools.c
1 /* http://dhcpd-pools.sourceforge.net/
2 ** Copyright 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 3 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, see <http://www.gnu.org/licenses/>.
16 */
17
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
21
22 #include <stdio.h>
23 #ifdef HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26 #ifdef  HAVE_STDLIB_H
27 #include <stdlib.h>
28 #else                           /* Not STDC_HEADERS */
29 extern char *malloc();
30 #endif                          /* STDC_HEADERS */
31 #ifdef  HAVE_STRING_H
32 #include <string.h>
33 #else
34 #include <strings.h>
35 #endif
36 #include <getopt.h>
37 #include <errno.h>
38 #include <err.h>
39
40 #include "dhcpd-pools.h"
41 #include "defaults.h"
42
43 int main(int argc, char **argv)
44 {
45         int i, c, sorts = 0;
46         int option_index = 0;
47         char *tmp;
48         struct range_t *tmp_ranges;
49
50         /* Options for getopt_long */
51         static struct option const long_options[] = {
52                 {"config", required_argument, 0, (int) 'c'},
53                 {"leases", required_argument, 0, (int) 'l'},
54                 {"format", required_argument, 0, (int) 'f'},
55                 {"sort", required_argument, 0, (int) 's'},
56                 {"reverse", no_argument, 0, (int) 'r'},
57                 {"output", required_argument, 0, (int) 'o'},
58                 {"limit", required_argument, 0, (int) 'L'},
59                 {"version", no_argument, 0, (int) 'v'},
60                 {"help", no_argument, 0, (int) 'h'},
61                 {0, 0, 0, 0}
62         };
63
64         /* FIXME: make these allocations dynamic up on need. */
65         config.dhcpdconf_file = safe_malloc(sizeof(char) * MAXLEN);
66         config.dhcpdlease_file = safe_malloc(sizeof(char) * MAXLEN);
67         config.output_file = safe_malloc(sizeof(char) * MAXLEN);
68
69         /* Make sure string has zero lenght if there is no
70          * command line option */
71         config.output_file[0] = '\0';
72
73         /* File location defaults */
74         strncpy(config.dhcpdconf_file, DHCPDCONF_FILE,
75                 (size_t) MAXLEN - 1);
76         strncpy(config.dhcpdlease_file, DHCPDLEASE_FILE,
77                 (size_t) MAXLEN - 1);
78         tmp = OUTPUT_LIMIT;
79         config.output_limit[0] = (int) (*tmp - '0');
80         tmp++;
81         config.output_limit[1] = (int) (*tmp - '0');
82         fullhtml = false;
83
84         /* Make sure some output format is selected by default */
85         strncpy(config.output_format, OUTPUT_FORMAT, (size_t) 1);
86
87         /* Default sort order is by IPs small to big */
88         config.reverse_order = false;
89
90         /* Parse command line options */
91         while (1) {
92                 c = getopt_long(argc, argv, "c:l:f:o:s:rL:vh",
93                                 long_options, &option_index);
94
95                 if (c == EOF)
96                         break;
97
98                 switch (c) {
99                 case 'c':
100                         /* config file */
101                         strncpy(config.dhcpdconf_file, optarg,
102                                 (size_t) MAXLEN - 1);
103                         break;
104                 case 'l':
105                         /* lease file */
106                         strncpy(config.dhcpdlease_file, optarg,
107                                 (size_t) MAXLEN - 1);
108                         break;
109                 case 'f':
110                         /* Output format */
111                         strncpy(config.output_format, optarg, (size_t) 1);
112                         break;
113                 case 's':
114                         /* Output sorting option */
115                         sorts = strlen(optarg);
116                         if (5 < sorts) {
117                                 warnx
118                                     ("main: only first 5 sort orders will be used");
119                                 strncpy(config.sort, optarg, (size_t) 5);
120                                 sorts = 5;
121                         } else {
122                                 strncpy(config.sort, optarg,
123                                         (size_t) sorts);
124                         }
125                         for (i = 0; i < sorts; i++) {
126                                 field_selector(config.sort[i]);
127                         }
128                         break;
129                 case 'r':
130                         /* What ever sort in reverse order */
131                         config.reverse_order = true;
132                         break;
133                 case 'o':
134                         /* Output file */
135                         strncpy(config.output_file, optarg,
136                                 (size_t) MAXLEN - 1);
137                         break;
138                 case 'L':
139                         /* Specification what will be printed */
140                         for (i = 0; i < 2; i++) {
141                                 if (optarg[i] >= '0' && optarg[i] < '8') {
142                                         config.output_limit[i] =
143                                             (int) optarg[i] - '0';
144                                 } else {
145                                         errx(EXIT_FAILURE,
146                                              "main: output mask `%s' is illegal",
147                                              optarg);
148                                 }
149                         }
150                         break;
151                 case 'v':
152                         /* Print version */
153                         print_version();
154                         return (EXIT_SUCCESS);
155                 case 'h':
156                         /* Print help */
157                         usage(EXIT_SUCCESS);
158                 default:
159                         errx(EXIT_FAILURE,
160                              "Try `%s --help' for more information.",
161                              program_invocation_short_name);
162                 }
163         }
164
165         /* Output function selection */
166         switch (config.output_format[0]) {
167         case 't':
168                 output_analysis = output_txt;
169                 break;
170         case 'h':
171                 output_analysis = output_html;
172                 break;
173         case 'H':
174                 output_analysis = output_html;
175                 fullhtml = true;
176                 break;
177         case 'x':
178                 output_analysis = output_xml;
179                 break;
180         case 'X':
181                 output_analysis = output_xml;
182                 break;
183         case 'c':
184                 output_analysis = output_csv;
185                 break;
186         default:
187                 errx(EXIT_FAILURE, "main: unknown output format `%c'",
188                      config.output_format[0]);
189         }
190
191         /* Do the job */
192         prepare_memory();
193         parse_config(true, config.dhcpdconf_file, shared_net_names,
194                      shared_net_names + strlen(shared_net_names) + 1,
195                      shared_networks);
196
197         parse_leases();
198         prepare_data();
199         do_counting();
200         tmp_ranges = safe_malloc(sizeof(struct range_t) * num_ranges);
201         if (sorts != 0) {
202                 mergesort_ranges(ranges, num_ranges, tmp_ranges);
203         }
204         if (config.reverse_order == true) {
205                 flip_ranges(ranges, tmp_ranges);
206         }
207         free(tmp_ranges);
208         output_analysis();
209         /* After fopen in output ioctl does like /dev/null which
210          * cause ENOTTY, and clean_up will see that without this
211          * reset. At least linux does this, and possibly some
212          * other systems. There's a report from FreeBSD 8.0 which
213          * matches quite well with this symptom. */
214         if (errno == 25)
215                 errno = 0;
216
217         clean_up();
218         return (EXIT_SUCCESS);
219 }
220
221 /* Global allocations, counter resets etc */
222 int prepare_memory()
223 {
224         num_ranges = num_shared_networks = 0;
225         shared_networks =
226             safe_malloc(sizeof(struct shared_network_t) * SHARED_NETWORKS);
227         shared_net_names =
228             safe_malloc(sizeof(char) * SHARED_NETWORKS_NAMES);
229
230         ranges = safe_malloc(sizeof(struct range_t) * RANGES);
231         macaddr = NULL;
232
233         /* First shared network entry is all networks */
234         strcpy(shared_net_names, "All networks");
235         return 0;
236 }