parse_leases: exit at read error
[debian/dhcpd-pools.git] / src / output.c
1 /*
2  * The dhcpd-pools has BSD 2-clause license which also known as "Simplified
3  * BSD License" or "FreeBSD License".
4  *
5  * Copyright 2006- Sami Kerola. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are
9  * met:
10  *
11  *    1. Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *
14  *    2. Redistributions in binary form must reproduce the above copyright
15  *       notice, this list of conditions and the following disclaimer in the
16  *       documentation and/or other materials provided with the
17  *       distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS
20  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
29  * THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * The views and conclusions contained in the software and documentation are
32  * those of the authors and should not be interpreted as representing
33  * official policies, either expressed or implied, of Sami Kerola.
34  */
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #include <arpa/inet.h>
41 #include <err.h>
42 #include <netinet/in.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45
46 #include "dhcpd-pools.h"
47
48 int output_txt(void)
49 {
50         unsigned int i;
51         struct in_addr first, last;
52         struct range_t *range_p;
53         struct shared_network_t *shared_p;
54         int ret;
55         FILE *outfile;
56
57         if (config.output_file[0]) {
58                 outfile = fopen(config.output_file, "w+");
59                 if (outfile == NULL) {
60                         err(EXIT_FAILURE, "output_txt: %s",
61                             config.output_file);
62                 }
63         } else {
64                 outfile = stdout;
65         }
66
67         range_p = ranges;
68         shared_p = shared_networks;
69
70         if (config.output_limit[0] & output_limit_bit_1) {
71                 fprintf(outfile, "Ranges:\n");
72                 fprintf
73                     (outfile,
74                      "shared net name     first ip           last ip            max   cur    percent  touch   t+c  t+c perc");
75                 if (0 < num_backups) {
76                         fprintf(outfile, "     bu  bu perc");
77                 }
78                 fprintf(outfile, "\n");
79         }
80         if (config.output_limit[1] & output_limit_bit_1) {
81                 for (i = 0; i < num_ranges; i++) {
82                         first.s_addr = ntohl(range_p->first_ip + 1);
83                         last.s_addr = ntohl(range_p->last_ip - 1);
84
85                         if (range_p->shared_net) {
86                                 fprintf(outfile, "%-20s",
87                                         range_p->shared_net->name);
88                         } else {
89                                 fprintf(outfile, "not_defined         ");
90                         }
91                         fprintf(outfile, "%-16s", inet_ntoa(first));
92                         fprintf(outfile,
93                                 " - %-16s %5lu %5lu %10.3f  %5lu %5lu %9.3f",
94                                 inet_ntoa(last),
95                                 range_p->last_ip - range_p->first_ip - 1,
96                                 range_p->count,
97                                 (float) (100 * range_p->count) /
98                                 (range_p->last_ip - range_p->first_ip - 1),
99                                 range_p->touched,
100                                 range_p->touched + range_p->count,
101                                 (float) (100 *
102                                          (range_p->touched +
103                                           range_p->count)) /
104                                 (range_p->last_ip - range_p->first_ip -
105                                  1));
106                         if (0 < num_backups) {
107                                 fprintf(outfile, "%7lu %8.3f",
108                                         range_p->backups,
109                                         (float) (100 * range_p->backups) /
110                                         (range_p->last_ip -
111                                          range_p->first_ip - 1));
112                         }
113                         fprintf(outfile, "\n");
114                         range_p++;
115                 }
116         }
117         if (config.output_limit[1] & output_limit_bit_1
118             && config.output_limit[0] & output_limit_bit_2) {
119                 fprintf(outfile, "\n");
120         }
121         if (config.output_limit[0] & output_limit_bit_2) {
122                 fprintf(outfile, "Shared networks:\n");
123                 fprintf(outfile,
124                         "name                   max   cur     percent  touch    t+c  t+c perc");
125                 if (0 < num_backups) {
126                         fprintf(outfile, "     bu  bu perc");
127                 }
128                 fprintf(outfile, "\n");
129         }
130         if (config.output_limit[1] & output_limit_bit_2) {
131                 for (i = 0; i < num_shared_networks; i++) {
132                         shared_p++;
133                         fprintf(outfile,
134                                 "%-20s %5lu %5lu %10.3f %7lu %6lu %9.3f",
135                                 shared_p->name, shared_p->available,
136                                 shared_p->used,
137                                 (float) (100 * shared_p->used) /
138                                 shared_p->available, shared_p->touched,
139                                 shared_p->touched + shared_p->used,
140                                 (float) (100 *
141                                          (shared_p->touched +
142                                           shared_p->used)) /
143                                 shared_p->available);
144                         if (0 < num_backups) {
145                                 fprintf(outfile, "%7lu %8.3f",
146                                         shared_p->backups,
147                                         (float) (100 * shared_p->backups) /
148                                         shared_p->available);
149                         }
150
151                         fprintf(outfile, "\n");
152                 }
153         }
154         if (config.output_limit[1] & output_limit_bit_2
155             && config.output_limit[0] & output_limit_bit_3) {
156                 fprintf(outfile, "\n");
157         }
158         if (config.output_limit[0] & output_limit_bit_3) {
159                 fprintf(outfile, "Sum of all ranges:\n");
160                 fprintf(outfile,
161                         "name                   max   cur     percent  touch    t+c  t+c perc");
162
163                 if (0 < num_backups) {
164                         fprintf(outfile, "     bu  bu perc");
165                 }
166                 fprintf(outfile, "\n");
167         }
168         if (config.output_limit[1] & output_limit_bit_3) {
169                 fprintf(outfile, "%-20s %5lu %5lu %10.3f %7lu %6lu %9.3f",
170                         shared_networks->name,
171                         shared_networks->available,
172                         shared_networks->used,
173                         (float) (100 * shared_networks->used) /
174                         shared_networks->available,
175                         shared_networks->touched,
176                         shared_networks->touched + shared_networks->used,
177                         (float) (100 *
178                                  (shared_networks->touched +
179                                   shared_networks->used)) /
180                         shared_networks->available);
181
182                 if (0 < num_backups) {
183                         fprintf(outfile, "%7lu %8.3f",
184                                 shared_networks->backups,
185                                 (float) (100 * shared_networks->backups) /
186                                 shared_networks->available);
187                 }
188                 fprintf(outfile, "\n");
189         }
190         if (outfile == stdout) {
191                 ret = fflush(stdout);
192                 if (ret) {
193                         warn("output_txt: fflush");
194                 }
195         } else {
196                 ret = fclose(outfile);
197                 if (ret) {
198                         warn("output_txt: fclose");
199                 }
200         }
201
202         return 0;
203 }
204
205 int output_xml(void)
206 {
207         unsigned int i;
208         struct in_addr first, last;
209         struct range_t *range_p;
210         struct shared_network_t *shared_p;
211         struct macaddr_t *macaddr_p;
212         int ret;
213         FILE *outfile;
214
215         if (config.output_file[0]) {
216                 outfile = fopen(config.output_file, "w+");
217                 if (outfile == NULL) {
218                         err(EXIT_FAILURE, "output_xml: %s",
219                             config.output_file);
220                 }
221         } else {
222                 outfile = stdout;
223         }
224
225         range_p = ranges;
226         shared_p = shared_networks;
227
228         fprintf(outfile, "<dhcpstatus>\n");
229
230         if (macaddr != NULL) {
231                 for (macaddr_p = macaddr; macaddr_p->next != NULL;
232                      macaddr_p = macaddr_p->next) {
233                         fprintf(outfile,
234                                 "<active_lease>\n\t<ip>%s</ip>\n\t<macaddress>%s</macaddress>\n</active_lease>\n",
235                                 macaddr_p->ip, macaddr_p->ethernet);
236                 }
237         }
238
239         if (config.output_limit[1] & output_limit_bit_1) {
240                 for (i = 0; i < num_ranges; i++) {
241                         first.s_addr = ntohl(range_p->first_ip + 1);
242                         last.s_addr = ntohl(range_p->last_ip - 1);
243                         fprintf(outfile, "<subnet>\n");
244                         if (range_p->shared_net) {
245                                 fprintf(outfile,
246                                         "\t<location>%s</location>\n",
247                                         range_p->shared_net->name);
248                         } else {
249                                 fprintf(outfile,
250                                         "\t<location></location>\n");
251                         }
252
253                         fprintf(outfile, "\t<network></network>\n");
254                         fprintf(outfile, "\t<netmask></netmask>\n");
255                         fprintf(outfile, "\t<range>%s ", inet_ntoa(first));
256                         fprintf(outfile, "- %s</range>\n",
257                                 inet_ntoa(last));
258                         fprintf(outfile, "\t<gateway></gateway>\n");
259                         fprintf(outfile, "\t<defined>%lu</defined>\n",
260                                 range_p->last_ip - range_p->first_ip - 1);
261                         fprintf(outfile, "\t<used>%lu</used>\n",
262                                 range_p->count);
263                         fprintf(outfile, "\t<free>%lu</free>\n",
264                                 range_p->last_ip - range_p->first_ip - 1 -
265                                 range_p->count);
266                         range_p++;
267                         fprintf(outfile, "</subnet>\n");
268                 }
269         }
270
271         if (config.output_limit[1] & output_limit_bit_2) {
272                 for (i = 0; i < num_shared_networks; i++) {
273                         shared_p++;
274                         fprintf(outfile, "<shared-network>\n");
275                         fprintf(outfile, "\t<location>%s</location>\n",
276                                 shared_p->name);
277                         fprintf(outfile, "\t<defined>%lu</defined>\n",
278                                 shared_p->available);
279                         fprintf(outfile, "\t<used>%lu</used>\n",
280                                 shared_p->used);
281                         fprintf(outfile, "\t<free>%lu</free>\n",
282                                 shared_p->available - shared_p->used);
283                         fprintf(outfile, "</shared-network>\n");
284                 }
285         }
286
287         if (config.output_limit[0] & output_limit_bit_3) {
288                 fprintf(outfile, "<summary>\n");
289                 fprintf(outfile, "\t<location>%s</location>\n",
290                         shared_networks->name);
291                 fprintf(outfile, "\t<defined>%lu</defined>\n",
292                         shared_networks->available);
293                 fprintf(outfile, "\t<used>%lu</used>\n",
294                         shared_networks->used);
295                 fprintf(outfile, "\t<free>%lu</free>\n",
296                         shared_networks->available -
297                         shared_networks->used);
298                 fprintf(outfile, "</summary>\n");
299         }
300
301         fprintf(outfile, "</dhcpstatus>\n");
302         if (outfile == stdout) {
303                 ret = fflush(stdout);
304                 if (ret) {
305                         warn("output_xml: fflush");
306                 }
307         } else {
308                 ret = fclose(outfile);
309                 if (ret) {
310                         warn("output_xml: fclose");
311                 }
312         }
313
314         return 0;
315 }
316
317 void html_header(FILE * f)
318 {
319         fprintf(f,
320                 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \n");
321         fprintf(f, "  \"http://www.w3.org/TR/html4/strict.dtd\">\n");
322         fprintf(f, "<html>\n");
323         fprintf(f, "<head>\n");
324         fprintf(f, "<meta http-equiv=\"Content-Type\" ");
325         fprintf(f, "content=\"text/html; charset=iso-8859-1\">\n");
326         fprintf(f, "  <title>ISC dhcpd stats</title>\n");
327         fprintf(f, "  <style  TYPE=\"text/css\">\n");
328         fprintf(f, "  <!--\n");
329         fprintf(f, "    table.dhcpd-pools {\n");
330         fprintf(f, "      color: black;\n");
331         fprintf(f, "      vertical-align: middle;\n");
332         fprintf(f, "      text-align: center;\n");
333         fprintf(f, "    }\n");
334         fprintf(f, "    table.dhcpd-pools th.section {\n");
335         fprintf(f, "      color: black;\n");
336         fprintf(f, "      font-size: large;\n");
337         fprintf(f, "      vertical-align: middle;\n");
338         fprintf(f, "      text-align: left;\n");
339         fprintf(f, "    }\n");
340         fprintf(f, "    table.dhcpd-pools th.calign {\n");
341         fprintf(f, "      color: black;\n");
342         fprintf(f, "      vertical-align: middle;\n");
343         fprintf(f, "      text-align: center;\n");
344         fprintf(f, "      text-decoration: underline;\n");
345         fprintf(f, "    }\n");
346         fprintf(f, "    table.dhcpd-pools th.ralign {\n");
347         fprintf(f, "      color: black;\n");
348         fprintf(f, "      vertical-align: middle;\n");
349         fprintf(f, "      text-align: right;\n");
350         fprintf(f, "      text-decoration: underline;\n");
351         fprintf(f, "    }\n");
352         fprintf(f, "    table.dhcpd-pools td.calign {\n");
353         fprintf(f, "      color: black;\n");
354         fprintf(f, "      vertical-align: middle;\n");
355         fprintf(f, "      text-align: center;\n");
356         fprintf(f, "    }\n");
357         fprintf(f, "    table.dhcpd-pools td.ralign {\n");
358         fprintf(f, "      color: black;\n");
359         fprintf(f, "      vertical-align: middle;\n");
360         fprintf(f, "      text-align: right;\n");
361         fprintf(f, "    }\n");
362         fprintf(f, "    p.created {\n");
363         fprintf(f, "      font-size: small;\n");
364         fprintf(f, "      color: grey;\n");
365         fprintf(f, "    }\n");
366         fprintf(f, "    p.updated {\n");
367         fprintf(f, "      font-size: small;\n");
368         fprintf(f, "      color: grey;\n");
369         fprintf(f, "      font-style: italic;\n");
370         fprintf(f, "    }\n");
371         fprintf(f, "  -->\n");
372         fprintf(f, "  </style>\n");
373         fprintf(f, "</head>\n");
374         fprintf(f, "<body>\n");
375 }
376
377 void html_footer(FILE * f)
378 {
379         fprintf(f, "<p><br></p>\n");
380         fprintf(f, "<hr>\n");
381         fprintf(f, "<p class=created>\nData generated by ");
382         fprintf(f, "<a href=\"%s\">", PACKAGE_URL);
383         fprintf(f, "dhcpd-pools</a>.\n</p>\n");
384         fprintf(f, "<p class=updated>\n");
385         fprintf(f, "<script type=\"text/javascript\">\n");
386         fprintf(f, "  document.write(\"Last Updated On \" + ");
387         fprintf(f, "document.lastModified + \".\")\n");
388         fprintf(f, "</script>\n<br>\n</p>\n");
389         fprintf(f, "</body>\n");
390         fprintf(f, "</html>\n");
391 }
392
393 void newrow(FILE * f)
394 {
395         fprintf(f, "<tr>\n");
396 }
397
398 void endrow(FILE * f)
399 {
400         fprintf(f, "</tr>\n\n");
401 }
402
403 void output_line(FILE * f, char *type, char *class, char *text)
404 {
405         fprintf(f, "  <%s class=%s>%s</%s>\n", type, class, text, type);
406 }
407
408 void output_long(FILE * f, char *type, unsigned long unlong)
409 {
410         fprintf(f, "  <%s class=ralign>%lu</%s>\n", type, unlong, type);
411 }
412
413 void output_float(FILE * f, char *type, float fl)
414 {
415         fprintf(f, "  <%s class=ralign>%.3f</%s>\n", type, fl, type);
416 }
417
418 void table_start(FILE * f)
419 {
420         fprintf(f, "<table width=\"75%%\" ");
421         fprintf(f, "class=\"dhcpd-pools\" ");
422         fprintf(f, "summary=\"ISC dhcpd pool usage report\">\n");
423 }
424
425 void table_end(FILE * f)
426 {
427         fprintf(f, "</table>\n");
428 }
429
430 void newsection(FILE * f, char *title)
431 {
432         newrow(f);
433         output_line(f, "td", "calign", "&nbsp;");
434         endrow(f);
435         newrow(f);
436         output_line(f, "th", "section", title);
437         endrow(f);
438 }
439
440 int output_html(void)
441 {
442         unsigned int i;
443         struct in_addr first, last;
444         struct range_t *range_p;
445         struct shared_network_t *shared_p;
446         int ret;
447         FILE *outfile;
448         if (config.output_file[0]) {
449                 outfile = fopen(config.output_file, "w+");
450                 if (outfile == NULL) {
451                         err(EXIT_FAILURE, "output_html: %s",
452                             config.output_file);
453                 }
454         } else {
455                 outfile = stdout;
456         }
457
458         range_p = ranges;
459         shared_p = shared_networks;
460         if (fullhtml) {
461                 html_header(outfile);
462         }
463         table_start(outfile);
464         if (config.output_limit[0] & output_limit_bit_1) {
465                 newsection(outfile, "Ranges:");
466                 newrow(outfile);
467                 output_line(outfile, "th", "calign", "shared net name");
468                 output_line(outfile, "th", "calign", "first ip");
469                 output_line(outfile, "th", "calign", "last ip");
470                 output_line(outfile, "th", "ralign", "max");
471                 output_line(outfile, "th", "ralign", "cur");
472                 output_line(outfile, "th", "ralign", "percent");
473                 output_line(outfile, "th", "ralign", "touch");
474                 output_line(outfile, "th", "ralign", "t+c");
475                 output_line(outfile, "th", "ralign", "t+c perc");
476                 if (0 < num_backups) {
477                         output_line(outfile, "th", "ralign", "bu");
478                         output_line(outfile, "th", "ralign", "bu perc");
479                 }
480                 endrow(outfile);
481         }
482         if (config.output_limit[1] & output_limit_bit_1) {
483                 for (i = 0; i < num_ranges; i++) {
484                         first.s_addr = ntohl(range_p->first_ip + 1);
485                         last.s_addr = ntohl(range_p->last_ip - 1);
486                         newrow(outfile);
487                         if (range_p->shared_net) {
488                                 output_line(outfile, "td", "calign",
489                                             range_p->shared_net->name);
490                         } else {
491                                 output_line(outfile, "td", "calign",
492                                             "not_defined");
493                         }
494                         output_line(outfile, "td", "calign",
495                                     inet_ntoa(first));
496                         output_line(outfile, "td", "calign",
497                                     inet_ntoa(last));
498                         output_long(outfile, "td",
499                                     range_p->last_ip - range_p->first_ip -
500                                     1);
501                         output_long(outfile, "td", range_p->count);
502                         output_float(outfile, "td",
503                                      (float) (100 * range_p->count) /
504                                      (range_p->last_ip -
505                                       range_p->first_ip - 1));
506                         output_long(outfile, "td", range_p->touched);
507                         output_long(outfile, "td",
508                                     range_p->touched + range_p->count);
509                         output_float(outfile, "td",
510                                      (float) (100 *
511                                               (range_p->touched +
512                                                range_p->count)) /
513                                      (range_p->last_ip -
514                                       range_p->first_ip - 1));
515                         if (0 < num_backups) {
516                                 output_long(outfile, "td",
517                                             range_p->backups);
518                                 output_float(outfile, "td",
519                                              (float) (100 *
520                                                       range_p->backups) /
521                                              (range_p->last_ip -
522                                               range_p->first_ip - 1));
523                         }
524                         endrow(outfile);
525                         range_p++;
526                 }
527         }
528         table_end(outfile);
529         table_start(outfile);
530         if (config.output_limit[0] & output_limit_bit_2) {
531                 newsection(outfile, "Shared networks:");
532                 newrow(outfile);
533                 output_line(outfile, "th", "calign", "name");
534                 output_line(outfile, "th", "ralign", "max");
535                 output_line(outfile, "th", "ralign", "cur");
536                 output_line(outfile, "th", "ralign", "percent");
537                 output_line(outfile, "th", "ralign", "touch");
538                 output_line(outfile, "th", "ralign", "t+c");
539                 output_line(outfile, "th", "ralign", "t+c perc");
540                 if (0 < num_backups) {
541                         output_line(outfile, "th", "ralign", "bu");
542                         output_line(outfile, "th", "ralign", "bu perc");
543                 }
544                 endrow(outfile);
545         }
546         if (config.output_limit[1] & output_limit_bit_2) {
547                 for (i = 0; i < num_shared_networks; i++) {
548                         shared_p++;
549                         newrow(outfile);
550                         output_line(outfile, "td", "calign",
551                                     shared_p->name);
552                         output_long(outfile, "td", shared_p->available);
553                         output_long(outfile, "td", shared_p->used);
554                         output_float(outfile, "td",
555                                      (float) (100 * shared_p->used) /
556                                      shared_p->available);
557                         output_long(outfile, "td", shared_p->touched);
558                         output_long(outfile, "td",
559                                     shared_p->touched + shared_p->used);
560                         output_float(outfile, "td",
561                                      (float) (100 *
562                                               (shared_p->touched +
563                                                shared_p->used)) /
564                                      shared_p->available);
565                         if (0 < num_backups) {
566                                 output_long(outfile, "td",
567                                             shared_p->backups);
568                                 output_float(outfile, "td",
569                                              (float) (100 *
570                                                       shared_p->backups) /
571                                              shared_p->available);
572                         }
573
574                         endrow(outfile);
575                 }
576         }
577         if (config.output_limit[0] & output_limit_bit_3) {
578                 newsection(outfile, "Sum of all ranges:");
579                 newrow(outfile);
580                 output_line(outfile, "th", "calign", "name");
581                 output_line(outfile, "th", "ralign", "max");
582                 output_line(outfile, "th", "ralign", "cur");
583                 output_line(outfile, "th", "ralign", "percent");
584                 output_line(outfile, "th", "ralign", "touch");
585                 output_line(outfile, "th", "ralign", "t+c");
586                 output_line(outfile, "th", "ralign", "t+c perc");
587                 if (0 < num_backups) {
588                         output_line(outfile, "th", "ralign", "bu");
589                         output_line(outfile, "th", "ralign", "bu perc");
590                 }
591
592                 endrow(outfile);
593         }
594         if (config.output_limit[1] & output_limit_bit_3) {
595                 newrow(outfile);
596                 output_line(outfile, "td", "calign",
597                             shared_networks->name);
598                 output_long(outfile, "td", shared_networks->available);
599                 output_long(outfile, "td", shared_networks->used);
600                 output_float(outfile, "td",
601                              (float) (100 * shared_networks->used) /
602                              shared_networks->available);
603                 output_long(outfile, "td", shared_networks->touched);
604                 output_long(outfile, "td",
605                             shared_networks->touched +
606                             shared_networks->used);
607                 output_float(outfile, "td",
608                              (float) (100 *
609                                       (shared_networks->touched +
610                                        shared_networks->used)) /
611                              shared_networks->available);
612                 if (0 < num_backups) {
613                         output_long(outfile, "td",
614                                     shared_networks->backups);
615                         output_float(outfile, "td",
616                                      (float) (100 *
617                                               shared_networks->backups) /
618                                      shared_networks->available);
619                 }
620                 endrow(outfile);
621         }
622         table_end(outfile);
623         if (fullhtml) {
624                 html_footer(outfile);
625         }
626         if (outfile == stdout) {
627                 ret = fflush(stdout);
628                 if (ret) {
629                         warn("output_html: fflush");
630                 }
631         } else {
632                 ret = fclose(outfile);
633                 if (ret) {
634                         warn("output_html: fclose");
635                 }
636         }
637         return 0;
638 }
639
640 int output_csv(void)
641 {
642         unsigned int i;
643         struct in_addr first, last;
644         struct range_t *range_p;
645         struct shared_network_t *shared_p;
646         FILE *outfile;
647         int ret;
648         if (config.output_file[0]) {
649                 outfile = fopen(config.output_file, "w+");
650                 if (outfile == NULL) {
651                         err(EXIT_FAILURE, "output_csv: %s",
652                             config.output_file);
653                 }
654         } else {
655                 outfile = stdout;
656         }
657
658         range_p = ranges;
659         shared_p = shared_networks;
660         if (config.output_limit[0] & output_limit_bit_1) {
661                 fprintf(outfile, "\"Ranges:\"\n");
662                 fprintf
663                     (outfile,
664                      "\"shared net name\",\"first ip\",\"last ip\",\"max\",\"cur\",\"percent\",\"touch\",\"t+c\",\"t+c perc\"");
665                 if (0 < num_backups) {
666                         fprintf(outfile, ",\"bu\",\"bu perc\"");
667                 }
668                 fprintf(outfile, "\n");
669         }
670         if (config.output_limit[1] & output_limit_bit_1) {
671                 for (i = 0; i < num_ranges; i++) {
672                         first.s_addr = ntohl(range_p->first_ip + 1);
673                         last.s_addr = ntohl(range_p->last_ip - 1);
674                         if (range_p->shared_net) {
675                                 fprintf(outfile, "\"%s\",",
676                                         range_p->shared_net->name);
677                         } else {
678                                 fprintf(outfile, "\"not_defined\",");
679                         }
680                         fprintf(outfile, "\"%s\",", inet_ntoa(first));
681                         fprintf(outfile,
682                                 "\"%s\",\"%lu\",\"%lu\",\"%.3f\",\"%lu\",\"%lu\",\"%.3f\"",
683                                 inet_ntoa(last),
684                                 range_p->last_ip - range_p->first_ip - 1,
685                                 range_p->count,
686                                 (float) (100 * range_p->count) /
687                                 (range_p->last_ip - range_p->first_ip - 1),
688                                 range_p->touched,
689                                 range_p->touched + range_p->count,
690                                 (float) (100 *
691                                          (range_p->touched +
692                                           range_p->count)) /
693                                 (range_p->last_ip - range_p->first_ip -
694                                  1));
695                         if (0 < num_backups) {
696                                 fprintf(outfile, ",\"%lu\",\"%.3f\"",
697                                         range_p->backups,
698                                         (float) (100 * range_p->backups) /
699                                         (range_p->last_ip -
700                                          range_p->first_ip - 1));
701                         }
702
703                         fprintf(outfile, "\n");
704                         range_p++;
705                 }
706                 fprintf(outfile, "\n");
707         }
708         if (config.output_limit[0] & output_limit_bit_2) {
709                 fprintf(outfile, "\"Shared networks:\"\n");
710                 fprintf(outfile,
711                         "\"name\",\"max\",\"cur\",\"percent\",\"touch\",\"t+c\",\"t+c perc\"");
712                 if (0 < num_backups) {
713                         fprintf(outfile, ",\"bu\",\"bu perc\"");
714                 }
715                 fprintf(outfile, "\n");
716         }
717         if (config.output_limit[1] & output_limit_bit_2) {
718
719                 for (i = 0; i < num_shared_networks; i++) {
720                         shared_p++;
721                         fprintf(outfile,
722                                 "\"%s\",\"%lu\",\"%lu\",\"%.3f\",\"%lu\",\"%lu\",\"%.3f\"",
723                                 shared_p->name, shared_p->available,
724                                 shared_p->used,
725                                 (float) (100 * shared_p->used) /
726                                 shared_p->available, shared_p->touched,
727                                 shared_p->touched + shared_p->used,
728                                 (float) (100 *
729                                          (shared_p->touched +
730                                           shared_p->used)) /
731                                 shared_p->available);
732                         if (0 < num_backups) {
733                                 fprintf(outfile, ",\"%lu\",\"%.3f\"",
734                                         shared_p->backups,
735                                         (float) (100 * shared_p->backups) /
736                                         shared_p->available);
737                         }
738
739                         fprintf(outfile, "\n");
740                 }
741                 fprintf(outfile, "\n");
742         }
743         if (config.output_limit[0] & output_limit_bit_3) {
744                 fprintf(outfile, "\"Sum of all ranges:\"\n");
745                 fprintf(outfile,
746                         "\"name\",\"max\",\"cur\",\"percent\",\"touch\",\"t+c\",\"t+c perc\"");
747                 if (0 < num_backups) {
748                         fprintf(outfile, ",\"bu\",\"bu perc\"");
749                 }
750                 fprintf(outfile, "\n");
751         }
752         if (config.output_limit[1] & output_limit_bit_3) {
753
754                 fprintf(outfile,
755                         "\"%s\",\"%lu\",\"%lu\",\"%.3f\",\"%lu\",\"%lu\",\"%.3f\"",
756                         shared_networks->name, shared_networks->available,
757                         shared_networks->used,
758                         (float) (100 * shared_networks->used) /
759                         shared_networks->available,
760                         shared_networks->touched,
761                         shared_networks->touched + shared_networks->used,
762                         (float) (100 *
763                                  (shared_networks->touched +
764                                   shared_networks->used)) /
765                         shared_networks->available);
766                 if (0 < num_backups) {
767                         fprintf(outfile, "%7lu %8.3f",
768                                 shared_networks->backups,
769                                 (float) (100 * shared_networks->backups) /
770                                 shared_networks->available);
771                 }
772                 fprintf(outfile, "\n");
773         }
774         if (outfile == stdout) {
775                 ret = fflush(stdout);
776                 if (ret) {
777                         warn("output_cvs: fflush");
778                 }
779
780         } else {
781                 ret = fclose(outfile);
782                 if (ret) {
783                         warn("output_cvs: fclose");
784                 }
785
786         }
787         return 0;
788 }