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