Branch oldpackages for 14.07
[14.07/packages.git] / utils / wattsup / src / wattsup.c
1 /*
2  *      wattsup - Program for controlling the Watts Up? Pro Device
3  *
4  *
5  *      Copyright (c) 2005 Patrick Mochel
6  *
7  *      This program is released under the GPLv2
8  *
9  *
10  *      Compiled with:
11  *
12  *      gcc -O2 -Wall -o wattsup wattsup.c
13  *
14  */
15
16 #define _GNU_SOURCE
17 #include<stdio.h>
18 #include<stdlib.h>
19 #include<stdarg.h>
20 #include<string.h>
21 #include<errno.h>
22 #include<unistd.h>
23 #include<fcntl.h>
24 #include<termios.h>
25 #include<ctype.h>
26 #include<getopt.h>
27 #include<signal.h>
28 #include<time.h>
29
30 #include<sys/stat.h>
31
32 static const char * wu_version = "0.02";
33
34
35 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
36
37 static const char * prog_name = "wattsup";
38
39 static const char * sysfs_path_start = "/sys/class/tty";
40
41 static char * wu_device = "ttyUSB0";
42 static int wu_fd = 0;
43 static int wu_count = 0;
44 static int wu_debug = 0;
45 static char *wu_delim = ", ";
46 static int wu_final = 0;
47 static int wu_interval = 1;
48 static int wu_label = 0;
49 static int wu_newline = 0;
50 static int wu_suppress = 0;
51
52 static int wu_localtime = 0;
53 static int wu_gmtime = 0;
54
55 static int wu_info_all = 0;
56 static int wu_no_data = 0;
57 static int wu_set_only = 0;
58
59 #define wu_strlen       256
60 #define wu_num_fields   18
61 #define wu_param_len    16
62
63 struct wu_packet {
64         unsigned int    cmd;
65         unsigned int    sub_cmd;
66         unsigned int    count;
67         char    buf[wu_strlen];
68         int     len;
69         char    * field[wu_num_fields];
70         char    * label[wu_num_fields];
71 };
72
73
74 struct wu_data {
75         unsigned int    watts;
76         unsigned int    volts;
77         unsigned int    amps;
78         unsigned int    watt_hours;
79
80         unsigned int    cost;
81         unsigned int    mo_kWh;
82         unsigned int    mo_cost;
83         unsigned int    max_watts;
84
85         unsigned int    max_volts;
86         unsigned int    max_amps;
87         unsigned int    min_watts;
88         unsigned int    min_volts;
89
90         unsigned int    min_amps;
91         unsigned int    power_factor;
92         unsigned int    duty_cycle;
93         unsigned int    power_cycle;
94 };
95
96 struct wu_options {
97         char    * longopt;
98         int     shortopt;
99         int     param;
100         int     flag;
101         char    * value;
102
103         char    * descr;
104         char    * option;
105         char    * format;
106
107         int     (*show)(int dev_fd);
108         int     (*store)(int dev_fd);
109 };
110
111 enum {
112         wu_option_help = 0,
113         wu_option_version,
114
115         wu_option_debug,
116
117         wu_option_count,
118         wu_option_final,
119
120         wu_option_delim,
121         wu_option_newline,
122         wu_option_localtime,
123         wu_option_gmtime,
124         wu_option_label,
125
126         wu_option_suppress,
127
128         wu_option_cal,
129         wu_option_header,
130
131         wu_option_interval,
132         wu_option_mode,
133         wu_option_user,
134
135         wu_option_info_all,
136         wu_option_no_data,
137         wu_option_set_only,
138 };
139
140
141 static char * wu_option_value(unsigned int index);
142
143
144 enum {
145         wu_field_watts          = 0,
146         wu_field_volts,
147         wu_field_amps,
148
149         wu_field_watt_hours,
150         wu_field_cost,
151         wu_field_mo_kwh,
152         wu_field_mo_cost,
153
154         wu_field_max_watts,
155         wu_field_max_volts,
156         wu_field_max_amps,
157
158         wu_field_min_watts,
159         wu_field_min_volts,
160         wu_field_min_amps,
161
162         wu_field_power_factor,
163         wu_field_duty_cycle,
164         wu_field_power_cycle,
165 };
166
167 struct wu_field {
168         unsigned int    enable;
169         char            * name;
170         char            * descr;
171 };
172
173 static struct wu_field wu_fields[wu_num_fields] = {
174         [wu_field_watts]        = {
175                 .name   = "watts",
176                 .descr  = "Watt Consumption",
177         },
178
179         [wu_field_min_watts]    = {
180                 .name   = "min-watts",
181                 .descr  = "Minimum Watts Consumed",
182         },
183
184         [wu_field_max_watts]    = {
185                 .name   = "max-watts",
186                 .descr  = "Maxium Watts Consumed",
187         },
188
189         [wu_field_volts]        = {
190                 .name   = "volts",
191                 .descr  = "Volts Consumption",
192         },
193
194         [wu_field_min_volts]    = {
195                 .name   = "max-volts",
196                 .descr  = "Minimum Volts Consumed",
197         },
198
199         [wu_field_max_volts]    = {
200                 .name   = "min-volts",
201                 .descr  = "Maximum Volts Consumed",
202         },
203
204         [wu_field_amps]         = {
205                 .name   = "amps",
206                 .descr  = "Amp Consumption",
207         },
208
209         [wu_field_min_amps]     = {
210                 .name   = "min-amps",
211                 .descr  = "Minimum Amps Consumed",
212         },
213
214         [wu_field_max_amps]     = {
215                 .name   = "max-amps",
216                 .descr  = "Maximum Amps Consumed",
217         },
218
219         [wu_field_watt_hours]   = {
220                 .name   = "kwh",
221                 .descr  = "Average KWH",
222         },
223
224         [wu_field_mo_kwh]       = {
225                 .name   = "mo-kwh",
226                 .descr  = "Average monthly KWH",
227         },
228
229         [wu_field_cost]         = {
230                 .name   = "cost",
231                 .descr  = "Cost per watt",
232         },
233
234         [wu_field_mo_cost]      = {
235                 .name   = "mo-cost",
236                 .descr  = "Monthly Cost",
237         },
238
239         [wu_field_power_factor] = {
240                 .name   = "power-factor",
241                 .descr  = "Ratio of Watts vs. Volt Amps",
242         },
243
244         [wu_field_duty_cycle]   = {
245                 .name   = "duty-cycle",
246                 .descr  = "Percent of the Time On vs. Time Off",
247         },
248
249         [wu_field_power_cycle]  = {
250                 .name   = "power-cycle",
251                 .descr  = "Indication of power cycle",
252         },
253
254 };
255
256
257
258 static void msg_start(const char * fmt, ...)
259 {
260         va_list(ap);
261         va_start(ap, fmt);
262         vprintf(fmt, ap);
263         va_end(ap);
264 }
265
266 static void msg_end(void)
267 {
268         printf("\n");
269 }
270
271 static void msg(const char * fmt, ...)
272 {
273         va_list ap;
274
275         va_start(ap, fmt);
276         vprintf(fmt, ap);
277         va_end(ap);
278 }
279
280 static void dbg(const char * fmt, ...)
281 {
282         va_list ap;
283
284         if (wu_debug) {
285                 va_start(ap, fmt);
286                 msg_start("%s: [debug] ", prog_name);
287                 vprintf(fmt, ap);
288                 msg_end();
289                 va_end(ap);
290         }
291 }
292
293 static void err(const char * fmt, ...)
294 {
295         va_list ap;
296
297         va_start(ap, fmt);
298         fprintf(stderr, "%s: [error] ", prog_name);
299         vfprintf(stderr, fmt, ap);
300         fprintf(stderr, "\n");
301         va_end(ap);
302 }
303
304 static void perr(const char * fmt, ...)
305 {
306         char buf[1024];
307         int n;
308         va_list ap;
309
310         va_start(ap, fmt);
311         n = sprintf(buf, "%s: [error] ", prog_name);
312         vsnprintf(buf + n, sizeof(buf) - n, fmt, ap);
313         perror(buf);
314         va_end(ap);
315 }
316
317 static int ret_err(int err)
318 {
319         errno = err;
320         return -1;
321 }
322
323
324 static void print_packet(struct wu_packet * p, char * str)
325 {
326         int i;
327
328         if (!wu_suppress)
329                 msg_start("Watts Up? %s\n", str);
330         for (i = 0; i<  p->count; i++) {
331                 if (i)
332                         msg("%s", wu_newline ? "\n" : wu_delim);
333                 if (wu_label)
334                         msg("[%s] ", p->label[i]);
335                 msg(p->field[i]);
336         }
337         msg_end();
338 }
339
340
341 static void print_time(void)
342 {
343         time_t t;
344         struct tm * tm;
345
346         if (wu_localtime || wu_gmtime) {
347                 time(&t);
348
349                 if (wu_localtime)
350                         tm = localtime(&t);
351                 else
352                         tm = gmtime(&t);
353
354                 msg("[%02d:%02d:%02d] ",
355                     tm->tm_hour, tm->tm_min, tm->tm_sec);
356         }
357 }
358
359 static void print_packet_filter(struct wu_packet * p,
360                                 int (*filter_ok)(struct wu_packet * p, int i, char * str))
361 {
362         char buf[256];
363         int printed;
364         int i;
365
366         print_time();
367         for (i = 0, printed = 0; i<  p->count; i++) {
368                 if (!filter_ok(p, i, buf))
369                         continue;
370
371                 if (printed++)
372                         msg("%s", wu_newline ? "\n" : wu_delim);
373                 if (wu_label)
374                         msg("[%s] ", p->label[i]);
375                 msg(buf);
376         }
377         msg_end();
378 }
379
380
381 /*
382  * Device should be something like "ttyS0"
383  */
384
385 static int open_device(char * device_name, int * dev_fd)
386 {
387         struct stat s;
388         int ret;
389         int cur_fd;
390
391         cur_fd = open(".", O_RDONLY);
392         if (cur_fd<  0) {
393                 perr("Could not open current directory.");
394                 return cur_fd;
395         }
396
397         ret = chdir(sysfs_path_start);
398         if (ret) {
399                 perr(sysfs_path_start);
400                 return ret;
401         }
402
403         /*
404          * First, check if /sys/class/tty/<name>/ exists.
405          */
406
407         dbg("Checking sysfs path: %s/%s", sysfs_path_start, device_name);
408
409         ret = stat(device_name,&s);
410         if (ret<  0) {
411                 perr(device_name);
412                 goto Done;
413         }
414
415         if (!S_ISDIR(s.st_mode)) {
416                 errno = -ENOTDIR;
417                 err("%s is not a TTY device.", device_name);
418                 goto Done;
419         }
420
421         dbg("%s is a registered TTY device", device_name);
422
423         fchdir(cur_fd);
424
425
426         /*
427          * Check if device node exists and is writable
428          */
429         chdir("/dev");
430
431         ret = stat(device_name,&s);
432         if (ret<  0) {
433                 perr("/dev/%s (device node)", device_name);
434                 goto Done;
435         }
436
437         if (!S_ISCHR(s.st_mode)) {
438                 errno = -ENOTTY;
439                 ret = -1;
440                 err("%s is not a TTY character device.", device_name);
441                 goto Done;
442         }
443
444         dbg("%s has a device node", device_name);
445
446         ret = access(device_name, R_OK | W_OK);
447         if (ret) {
448                 perr("%s: Not writable?", device_name);
449                 goto Done;
450         }
451
452         ret = open(device_name, O_RDWR | O_NONBLOCK);
453         if (ret<  0) {
454                 perr("Could not open %s");
455                 goto Done;
456         }
457         *dev_fd = ret;
458         ret = 0;
459 Done:
460         fchdir(cur_fd);
461         close(cur_fd);
462         return ret;
463 }
464
465
466 static int setup_serial_device(int dev_fd)
467 {
468         struct termios t;
469         int ret;
470
471         ret = tcgetattr(dev_fd,&t);
472         if (ret)
473                 return ret;
474
475         cfmakeraw(&t);
476         cfsetispeed(&t, B115200);
477         cfsetospeed(&t, B115200);
478         tcflush(dev_fd, TCIFLUSH);
479
480         t.c_iflag |= IGNPAR;
481         t.c_cflag&= ~CSTOPB;
482         ret = tcsetattr(dev_fd, TCSANOW,&t);
483
484         if (ret) {
485                 perr("setting terminal attributes");
486                 return ret;
487         }
488
489         return 0;
490 }
491
492
493 static int wu_write(int fd, struct wu_packet * p)
494 {
495         int ret;
496         int n;
497         int i;
498         char * s = p->buf;
499
500         memset(p->buf, 0, sizeof(p->buf));
501         n = sprintf(p->buf, "#%c,%c,%d", p->cmd, p->sub_cmd, p->count);
502         p->len = n;
503         s = p->buf + n;
504
505         for (i = 0; i<  p->count; i++) {
506                 if ((p->len + strlen(p->field[i]) + 4)>= sizeof(p->buf)) {
507                         err("Overflowed command string");
508                         return ret_err(EOVERFLOW);
509                 }
510                 n = sprintf(s, ",%s", p->field[i]);
511                 s += n;
512                 p->len += n;
513         }
514         p->buf[p->len++] = ';';
515
516         dbg("Writing '%s' (strlen = %d) (len = %d) to device",
517             p->buf, strlen(p->buf), p->len);
518         ret = write(fd, p->buf, p->len);
519         if (ret != p->len)
520                 perr("Writing to device");
521         
522         return ret>= 0 ? 0 : ret;
523 }
524
525
526 static void dump_packet(struct wu_packet * p)
527 {
528         int i;
529
530         dbg("Packet - Command '%c' %d parameters", p->cmd, p->count);
531         
532         for (i = 0; i<  p->count; i++)
533                 dbg("[%2d] [%20s] = \"%s\"", i, p->label[i], p->field[i]);
534 }
535
536
537 static int parse_packet(struct wu_packet * p)
538 {
539         char * s, *next;
540         int i;
541
542         p->buf[p->len] = '\0';
543
544         dbg("Parsing Packet, Raw buffer is (%d bytes) [%s]",
545             p->len, p->buf);
546
547         s = p->buf;
548
549         /*
550          * First character should be '#'
551          */
552         if (s) {
553                 s = strchr(s, '#');
554                 if (s)
555                         s++;
556                 else {
557                         dbg("Invalid packet");
558                         return ret_err(EFAULT);
559                 }
560         } else {
561                 dbg("Invalid packet");
562                 return ret_err(EFAULT);
563         }
564
565         /*
566          * Command character is first
567          */
568         next = strchr(s, ',');
569         if (next) {
570                 p->cmd = *s;
571                 s = ++next;
572         } else {
573                 dbg("Invalid Command field [%s]", s);
574                 return ret_err(EFAULT);
575         }
576
577         /*
578          * Next character is the subcommand, and should be '-'
579          * Though, it doesn't matter, because we just
580          * discard it anyway.
581          */
582         next = strchr(s, ',');
583         if (next) {
584                 p->sub_cmd = *s;
585                 s = ++next;
586         } else {
587                 dbg("Invalid 2nd field");
588                 return ret_err(EFAULT);
589         }
590
591         /*
592          * Next is the number of parameters,
593          * which should always be>  0.
594          */
595         next = strchr(s, ',');
596         if (next) {
597                 *next++ = '\0';
598                 p->count = atoi(s);
599                 s = next;
600         } else {
601                 dbg("Couldn't determine number of parameters");
602                 return ret_err(EFAULT);
603         }
604         
605         dbg("Have %d parameter%s (cmd = '%c')",
606             p->count, p->count>  1 ? "s" : "", p->cmd);
607
608         /*
609          * Now, we loop over the rest of the string,
610          * storing a pointer to each in p->field[].
611          *
612          * The last character was originally a ';', but may have been
613          * overwritten with a '\0', so we make sure to catch
614          * that when converting the last parameter.
615          */
616         for (i = 0; i<  p->count; i++) {
617                 next = strpbrk(s, ",;");
618                 if (next) {
619                         *next++ = '\0';
620                 } else {
621                         if (i<  (p->count - 1)) {
622                                 dbg("Malformed parameter string [%s]", s);
623                                 return ret_err(EFAULT);
624                         }
625                 }
626
627                 /*
628                  * Skip leading white space in fields
629                  */
630                 while (isspace(*s))
631                         s++;
632                 p->field[i] = s;
633                 s = next;
634         }
635         dump_packet(p);
636         return 0;
637 }
638
639
640 static int wu_read(int fd, struct wu_packet * p)
641 {
642         fd_set read_fd;
643         struct timeval tv;
644         int ret;
645
646         FD_ZERO(&read_fd);
647         FD_SET(fd,&read_fd);
648         
649         tv.tv_sec = 2;
650         tv.tv_usec = 0;
651
652         ret = select(fd + 1,&read_fd, NULL, NULL,&tv);
653         if (ret<  0) {
654                 perr("select on terminal device");
655                 return ret;
656         } else if (ret>  0) {
657
658                 ret = read(fd, p->buf, wu_strlen);
659                 if (ret<  0) {
660                         perr("Reading from device");
661                         return ret;
662                 }
663                 p->len = ret;
664         } else {
665                 dbg("Device timed out while reading");
666                 return ret_err(ETIME);
667         }
668         return parse_packet(p);
669 }
670
671
672 static int wu_show_header(int fd)
673 {
674         struct wu_packet p = {
675                 .cmd            = 'H',
676                 .sub_cmd        = 'R',
677                 .count          = 0,
678                 .label = {
679                         [0] = "watts header",
680                         [1] = "volts header",
681                         [2] = "amps header",
682                         [3] = "kWh header",
683                         [4] = "cost header",
684                         [5] = "mo. kWh header",
685                         [6] = "mo. cost header",
686                         [7] = "max watts header",
687                         [8] = "max volts header",
688                         [9] = "max amps header",
689                         [10] = "min watts header",
690                         [11] = "min volts header",
691                         [12] = "min amps header",
692                         [13] = "power factor header",
693                         [14] = "duty cycle header",
694                         [15] = "power cycle header",
695                 }
696         };
697         int ret;
698
699         ret = wu_write(fd,&p);
700         if (ret) {
701                 perr("Requesting header strings");
702                 return ret;
703         }
704         sleep(1);
705
706         ret = wu_read(fd,&p);
707         if (ret) {
708                 perr("Reading header strings");
709                 return ret;
710         }
711
712         print_packet(&p, "Header Record");
713
714         return 0;
715 }
716
717
718 static int wu_show_cal(int fd)
719 {
720         struct wu_packet p = {
721                 .cmd            = 'F',
722                 .sub_cmd        = 'R',
723                 .count          = 0,
724                 .label = {
725                         [0] = "flags",
726                         [1] = "sample count",
727                         [2] = "volts gain",
728                         [3] = "volts bias",
729                         [4] = "amps gain",
730                         [5] = "amps bias",
731                         [6] = "amps offset",
732                         [7] = "low amps gain",
733                         [8] = "low amps bias",
734                         [9] = "low amps offset",
735                         [10] = "watts gain",
736                         [11] = "watts offset",
737                         [12] = "low watts gain",
738                         [13] = "low watts offset",
739                 },
740         };
741         int ret;
742
743         ret = wu_write(fd,&p);
744         if (ret) {
745                 perr("Requesting calibration parameters");
746                 return ret;
747         }
748         sleep(1);
749
750         ret = wu_read(fd,&p);
751         if (ret) {
752                 perr("Reading header strings");
753                 return ret;
754         }
755         print_packet(&p, "Calibration Settings");
756
757         return 0;
758 }
759
760 static int wu_start_log(void)
761 {
762         struct wu_packet p = {
763                 .cmd            = 'L',
764                 .sub_cmd        = 'W',
765                 .count          = 3,
766                 .field          = {
767                         [0] = "E",
768                         [1] = "1",
769                         [2] = "1",
770                 },
771         };
772         int ret;
773
774         /*
775          * Start up logging
776          */
777         ret = wu_write(wu_fd,&p);
778         if (!ret)
779                 sleep(1);
780         else {
781                 perr("Starting External Logging");
782                 return ret;
783         }
784         return ret;
785 }
786
787 static int wu_stop_log(void)
788 {
789         struct wu_packet p = {
790                 .cmd            = 'L',
791                 .sub_cmd        = 'R',
792                 .count          = 0,
793                 .label = {
794                         [0] = "time stamp",
795                         [1] = "interval",
796                 },
797         };
798         int ret;
799
800         /*
801          * Stop logging and read time stamp.
802          */
803         ret = wu_write(wu_fd,&p);
804         if (ret) {
805                 perr("Stopping External Logging");
806                 return ret;
807         }
808         sleep(1);
809
810         ret = wu_read(wu_fd,&p);
811         if (ret) {
812                 perr("Reading final time stamp");
813                 return ret;
814         }
815         if (wu_final)
816                 print_packet(&p, "Final Time Stamp and Interval");
817         return ret;
818 }
819
820 static int filter_data(struct wu_packet * p, int i, char * buf)
821 {
822         if (i<  wu_num_fields) {
823                 if (wu_fields[i].enable) {
824                         double val = strtod(p->field[i], NULL);
825                         snprintf(buf, 256, "%.1f", val / 10.0);
826                         return 1;
827                 }
828         }
829         return 0;
830 }
831
832 static int wu_clear(int fd)
833 {
834         struct wu_packet p = {
835                 .cmd            = 'R',
836                 .sub_cmd        = 'W',
837                 .count          = 0,
838         };
839         int ret;
840
841         /*
842          * Clear the memory
843          */
844         ret = wu_write(fd,&p);
845         if (ret)
846                 perr("Clearing memory");
847         else
848                 sleep(2);
849         
850         /*
851          * Dummy read
852          */
853         wu_read(fd,&p);
854         return ret;
855
856 }
857
858 static int wu_read_data(int fd)
859 {
860         struct wu_packet p = {
861                 .label = {
862                         [0] = "watts",
863                         [1] = "volts",
864                         [2] = "amps",
865                         [3] = "watt hours",
866                         [4] = "cost",
867                         [5] = "mo. kWh",
868                         [6] = "mo. cost",
869                         [7] = "max watts",
870                         [8] = "max volts",
871                         [9] = "max amps",
872                         [10] = "min watts",
873                         [11] = "min volts",
874                         [12] = "min amps",
875                         [13] = "power factor",
876                         [14] = "duty cycle",
877                         [15] = "power cycle",
878                 },
879         };
880         int num_read = 0;
881         int retry = 0;
882         int ret;
883         int i;
884
885         static const int wu_max_retry = 2;
886
887         i = 0;
888         while (1) {
889                 
890                 ret = wu_read(fd,&p);
891                 if (ret) {
892                         if (++retry<  wu_max_retry) {
893                                 dbg("Bad record back, retrying\n");
894                                 sleep(wu_interval);
895                                 continue;
896                         } else if (retry == wu_max_retry) {
897                                 dbg("Still couldn't get a good record, resetting\n");
898                                 wu_stop_log();
899                                 wu_clear(fd);
900                                 wu_start_log();
901                                 num_read = 0;
902                                 sleep(wu_interval);
903                                 continue;
904                         }
905                         perr("Blech. Giving up on read");
906                         break;
907                 } else if (retry)
908                         retry = 0;
909
910                 dbg("[%d] ", num_read);
911                 num_read++;
912                 print_packet_filter(&p, filter_data);
913
914                 if (wu_count&&  (++i == wu_count))
915                         break;
916                 
917                 sleep(wu_interval);
918         }
919         return 0;
920
921 }
922
923
924 static int wu_show_interval(int fd)
925 {
926         struct wu_packet p = {
927                 .cmd            = 'S',
928                 .sub_cmd        = 'R',
929                 .count          = 0,
930                 .label = {
931                         [0] = "reserved",
932                         [1] = "interval",
933                 },
934         };
935         int ret;
936         
937         ret = wu_write(fd,&p);
938         if (ret) {
939                 perr("Requesting interval");
940                 return ret;
941         }
942         sleep(1);
943
944         ret = wu_read(fd,&p);
945         if (ret) {
946                 perr("Reading interval");
947                 return ret;
948         }
949         print_packet(&p, "Interval Settings");
950
951         return 0;
952 }
953
954 static int wu_write_interval(int fd, unsigned int seconds,
955                              unsigned int interval)
956 {
957         char str_seconds[wu_param_len];
958         char str_interval[wu_param_len];
959         struct wu_packet p = {
960                 .cmd            = 'S',
961                 .sub_cmd        = 'W',
962                 .count          = 2,
963                 .field          = {
964                         [0] = str_seconds,
965                         [1] = str_interval,
966                 },
967         };
968         int ret;
969
970         snprintf(str_seconds, wu_param_len, "%ud", seconds);
971         snprintf(str_interval, wu_param_len, "%ud", interval);
972
973         ret = wu_write(fd,&p);
974         if (ret) {
975                 perr("Setting Sampling Interval");
976                 return ret;
977         }
978         sleep(1);
979         return 0;
980 }
981
982 static int wu_store_interval(int fd)
983 {
984         char * s = wu_option_value(wu_option_interval);
985         char * end;
986
987         wu_interval = strtol(s,&end, 0);
988         if (*end) {
989                 err("Invalid interval: %s", s);
990                 return ret_err(EINVAL);
991         }
992         return wu_write_interval(fd, 1, wu_interval);
993 }
994
995 static int wu_show_mode(int fd)
996 {
997         struct wu_packet p = {
998                 .cmd            = 'M',
999                 .sub_cmd        = 'R',
1000                 .count          = 0,
1001                 .label          = {
1002                         [0] = "display mode",
1003                 },
1004         };
1005         int ret;
1006
1007         ret = wu_write(fd,&p);
1008         if (ret) {
1009                 perr("Requesting device display mode");
1010                 return ret;
1011         }
1012
1013         ret = wu_read(fd,&p);
1014         if (ret) {
1015                 perr("Reaing device display mode");
1016                 return ret;
1017         }
1018         dump_packet(&p);
1019         return ret;
1020 }
1021
1022 static int wu_write_mode(int fd, int mode)
1023 {
1024         char str_mode[wu_param_len];
1025         struct wu_packet p = {
1026                 .cmd            = 'M',
1027                 .sub_cmd        = 'W',
1028                 .count          = 1,
1029                 .field          = {
1030                         [0] = str_mode,
1031                 },
1032         };
1033         int ret;
1034         
1035         snprintf(str_mode, wu_param_len, "%ud", mode);
1036         ret = wu_write(fd,&p);
1037         if (ret)
1038                 perr("Setting device display mode");
1039         else
1040                 sleep(1);
1041         return ret;
1042 }
1043
1044 static int wu_store_mode(int fd)
1045 {
1046         char * s = wu_option_value(wu_option_mode);
1047         char * end;
1048         unsigned int mode;
1049
1050         mode = strtol(s,&end, 0);
1051         if (*end) {
1052                 err("Invalid mode: %s", s);
1053                 return ret_err(EINVAL);
1054         }
1055         return wu_write_mode(fd, mode);
1056 }
1057
1058
1059
1060 static int wu_show_user(int fd)
1061 {
1062         struct wu_packet p = {
1063                 .cmd            = 'U',
1064                 .sub_cmd        = 'R',
1065                 .count          = 0,
1066                 .label          = {
1067                         [0] = "cost per kWh",
1068                         [1] = "2nd tier cost",
1069                         [2] = "2nd tier threshold",
1070                         [3] = "duty cycle threshold",
1071                 },
1072         };
1073         int ret;
1074
1075         ret = wu_write(fd,&p);
1076         if (ret) {
1077                 perr("Requesting user parameters");
1078                 return ret;
1079         }
1080         sleep(1);
1081
1082         ret = wu_read(fd,&p);
1083         if (ret) {
1084                 perr("Reading user parameters");
1085                 return ret;
1086         }
1087         print_packet(&p, "User Settings");
1088         return 0;
1089 }
1090
1091
1092 static int wu_write_user(int fd, unsigned int kwh_cost,
1093                          unsigned int second_tier_cost,
1094                          unsigned int second_tier_threshold,
1095                          unsigned int duty_cycle_threshold)
1096 {
1097         char str_kwh_cost[wu_param_len];
1098         char str_2nd_tier_cost[wu_param_len];
1099         char str_2nd_tier_threshold[wu_param_len];
1100         char str_duty_cycle_threshold[wu_param_len];
1101
1102         struct wu_packet p = {
1103                 .cmd            = 'U',
1104                 .sub_cmd        = 'R',
1105                 .count          = 0,
1106                 .label          = {
1107                         [0] = str_kwh_cost,
1108                         [1] = str_2nd_tier_cost,
1109                         [2] = str_2nd_tier_threshold,
1110                         [3] = str_duty_cycle_threshold,
1111                 },
1112         };
1113         int ret;
1114
1115         snprintf(str_kwh_cost, wu_param_len, "%ud", kwh_cost);
1116         snprintf(str_2nd_tier_cost, wu_param_len, "%ud",
1117                  second_tier_cost);
1118         snprintf(str_2nd_tier_threshold, wu_param_len, "%ud",
1119                  second_tier_threshold);
1120         snprintf(str_duty_cycle_threshold, wu_param_len, "%ud",
1121                  duty_cycle_threshold);
1122
1123         ret = wu_write(fd,&p);
1124         if (ret)
1125                 perr("Writing user parameters");
1126         else
1127                 sleep(1);
1128         return ret;
1129 }
1130
1131 static int wu_store_user(int fd)
1132 {
1133         unsigned int kwh_cost;
1134         unsigned int second_tier_cost;
1135         unsigned int second_tier_threshold;
1136         unsigned int duty_cycle_threshold;
1137         char * buf = wu_option_value(wu_option_user);
1138         char * s = buf;
1139         char * next;
1140
1141         if (!buf) {
1142                 err("No user parameters?");
1143                 return ret_err(EINVAL);
1144         }
1145
1146         kwh_cost = strtoul(s,&next, 0);
1147         if (next == s) {
1148                 err("Incomplete user parameters");
1149                 return ret_err(EINVAL);
1150         }
1151
1152         s = next;
1153         while (s&&  !isdigit(*s))
1154                 s++;
1155         if (!s) {
1156                 err("Incomplete user parameters");
1157                 return ret_err(EINVAL);
1158         }
1159
1160
1161         second_tier_cost = strtoul(s,&next, 0);
1162         if (next == s) {
1163                 err("Incomplete user parameters");
1164                 return ret_err(EINVAL);
1165         }
1166
1167         s = next;
1168         while (s&&  !isdigit(*s))
1169                 s++;
1170         if (!s) {
1171                 err("Incomplete user parameters");
1172                 return ret_err(EINVAL);
1173         }
1174
1175
1176         second_tier_threshold = strtoul(s,&next, 0);
1177         if (next == s) {
1178                 err("Incomplete user parameters");
1179                 return ret_err(EINVAL);
1180         }
1181
1182         s = next;
1183         while (s&&  !isdigit(*s))
1184                 s++;
1185         if (!s) {
1186                 err("Incomplete user parameters");
1187                 return ret_err(EINVAL);
1188         }
1189
1190
1191         duty_cycle_threshold = strtoul(s,&next, 0);
1192         if (next == s) {
1193                 err("Incomplete user parameters");
1194                 return ret_err(EINVAL);
1195         }
1196
1197         s = next;
1198         while (s&&  !isdigit(*s))
1199                 s++;
1200         if (!s) {
1201                 err("Incomplete user parameters");
1202                 return ret_err(EINVAL);
1203         }
1204
1205         return wu_write_user(fd, kwh_cost, second_tier_cost,
1206                              second_tier_threshold, duty_cycle_threshold);
1207 }
1208
1209
1210 static void enable_field(char * name)
1211 {
1212         int i;
1213
1214         for (i = 0; i<  wu_num_fields; i++) {
1215                 if (!strcasecmp(wu_fields[i].name, name)) {
1216                         wu_fields[i].enable = 1;
1217                         break;
1218                 }
1219         }
1220 }
1221
1222 static void enable_all_fields(void)
1223 {
1224         int i;
1225
1226         for (i = 0; i<  wu_num_fields; i++)
1227                 wu_fields[i].enable = 1;
1228 }
1229
1230
1231
1232 static int wu_show_help(int);
1233 static int wu_show_version(int);
1234
1235
1236
1237 static int wu_store_count(int unused)
1238 {
1239         char * s = wu_option_value(wu_option_count);
1240         char * end;
1241
1242         if (s) {
1243                 wu_count = strtol(s,&end, 0);
1244                 if (*end) {
1245                         err("Bad count field");
1246                         return ret_err(EINVAL);
1247                 }
1248         }
1249         return 0;
1250 }
1251
1252 static int wu_store_debug(int unused)
1253 {
1254         wu_debug = 1;
1255         return 0;
1256 }
1257
1258 static int wu_store_delim(int unused)
1259 {
1260         char * s = wu_option_value(wu_option_delim);
1261         
1262         if (s)
1263                 wu_delim = s;
1264         return 0;
1265 }
1266
1267 static int wu_store_final(int unused)
1268 {
1269         wu_final = 1;
1270         return 0;
1271 }
1272
1273 static int wu_store_label(int unused)
1274 {
1275         wu_label = 1;
1276         return 0;
1277 }
1278
1279 static int wu_store_newline(int unused)
1280 {
1281         wu_newline = 1;
1282         return 0;
1283 }
1284
1285 static int wu_store_suppress(int unused)
1286 {
1287         wu_suppress = 1;
1288         return 0;
1289 }
1290
1291 static int wu_store_localtime(int unused)
1292 {
1293         wu_localtime = 1;
1294         return 0;
1295 }
1296
1297 static int wu_store_gmtime(int unused)
1298 {
1299         wu_gmtime = 1;
1300         return 0;
1301 }
1302
1303 static int wu_store_info_all(int unused)
1304 {
1305         wu_info_all = 1;
1306         return 0;
1307 }
1308
1309 static int wu_store_no_data(int unused)
1310 {
1311         wu_no_data = 1;
1312         return 0;
1313 }
1314
1315 static int wu_store_set_only(int unused)
1316 {
1317         wu_set_only = 1;
1318         return 0;
1319 }
1320
1321
1322 /**
1323  *      wu_options - command line options and their associated flags
1324  *
1325  */
1326 static struct wu_options wu_options[] = {
1327
1328         /*
1329          * Help!
1330          */
1331         [wu_option_help] = {
1332                 .longopt        = "help",
1333                 .shortopt       = 'h',
1334                 .param          = 0,
1335                 .descr          = "Display help text and exit",
1336                 .show           = wu_show_help,
1337         },
1338
1339         [wu_option_version] = {
1340                 .longopt        = "version",
1341                 .shortopt       = 'V',
1342                 .param          = 0,
1343                 .descr          = "Display version information and exit",
1344                 .show           = wu_show_version,
1345         },
1346
1347         /*
1348          * Modifies the output for all other options
1349          */
1350         [wu_option_debug] = {
1351                 .longopt        = "debug",
1352                 .shortopt       = 'd',
1353                 .param          = 0,
1354                 .descr          = "Print out debugging messages",
1355                 .store          = wu_store_debug,
1356         },
1357
1358         /*
1359          * For data reading..
1360          */
1361         [wu_option_count] = {
1362                 .longopt        = "count",
1363                 .shortopt       = 'c',
1364                 .param          = 1,
1365                 .descr          = "Specify number of data samples",
1366                 .option         = "<n>",
1367                 .store          = wu_store_count,
1368         },
1369
1370         [wu_option_final] = {
1371                 .longopt        = "final",
1372                 .shortopt       = 'z',
1373                 .param          = 0,
1374                 .descr          = "Print final interval information",
1375                 .store          = wu_store_final,
1376         },
1377
1378         /*
1379          * Modifies output for each option (most relevant for data)
1380          */
1381         [wu_option_delim] = {
1382                 .longopt        = "delim",
1383                 .shortopt       = 'f',
1384                 .param          = 1,
1385                 .descr          = "Set field delimiter (default \", \")",
1386                 .option         = "<str>",
1387                 .store          = wu_store_delim,
1388         },
1389
1390         [wu_option_newline] = {
1391                 .longopt        = "newline",
1392                 .shortopt       = 'n',
1393                 .param          = 0,
1394                 .descr          = "Use '\\n' as delimter instead",
1395                 .store          = wu_store_newline,
1396         },
1397
1398         [wu_option_localtime] = {
1399                 .longopt        = "localtime",
1400                 .shortopt       = 't',
1401                 .param          = 0,
1402                 .descr          = "Print localtime with each data reading",
1403                 .store          = wu_store_localtime,
1404         },
1405
1406         [wu_option_gmtime] = {
1407                 .longopt        = "gmtime",
1408                 .shortopt       = 'g',
1409                 .param          = 0,
1410                 .descr          = "Print GMT time with each data reading",
1411                 .store          = wu_store_gmtime,
1412         },
1413
1414         [wu_option_label] = {
1415                 .longopt        = "label",
1416                 .shortopt       = 'l',
1417                 .param          = 0,
1418                 .descr          = "Show labels of each field",
1419                 .store          = wu_store_label,
1420         },
1421
1422         /*
1423          * Relevant for each of the fields below
1424          */
1425         [wu_option_suppress] = {
1426                 .longopt        = "suppress",
1427                 .shortopt       = 's',
1428                 .param          = 0,
1429                 .descr          = "Suppress printing of the field description",
1430                 .store          = wu_store_suppress,
1431         },
1432
1433         /*
1434          * These options print values from the device and exit.
1435          */
1436         [wu_option_cal] = {
1437                 .longopt        = "calibrate",
1438                 .shortopt       = 'b',
1439                 .param          = 0,
1440                 .descr          = "Print calibration parameters",
1441                 .show           = wu_show_cal,
1442         },
1443
1444         [wu_option_header] = {
1445                 .longopt        = "header",
1446                 .shortopt       = 'r',
1447                 .param          = 0,
1448                 .descr          = "Print data field names (as read from device)",
1449                 .show           = wu_show_header,
1450         },
1451
1452         /*
1453          * These options have an optional parameter.
1454          * W/o that parameter, they print values from the device.
1455          * W/ that parameter, they set that option and read data.
1456          *
1457          * Except when the 'set-only' parameter is used, then the
1458          * parameters are set, then re-read and printed.
1459          */
1460         [wu_option_interval] = {
1461                 .longopt        = "interval",
1462                 .shortopt       = 'i',
1463                 .param          = 2,
1464                 .descr          = "Get/Set sampling interval",
1465                 .option         = "<n>",
1466                 .show           = wu_show_interval,
1467                 .store          = wu_store_interval,
1468         },
1469
1470         [wu_option_mode] = {
1471                 .longopt        = "mode",
1472                 .shortopt       = 'm',
1473                 .param          = 2,
1474                 .descr          = "Get/Set display mode",
1475                 .option         = "<n>",
1476                 .show           = wu_show_mode,
1477                 .store          = wu_store_mode,
1478         },
1479
1480         [wu_option_user] = {
1481                 .longopt        = "user",
1482                 .shortopt       = 'u',
1483                 .param          = 2,
1484                 .descr          = "Get/Set user parameters",
1485                 .option         = "<str>",
1486                 .format         = "<cost per kwh>,<2nd tier cost>,"
1487                                   "<2nd tier threshold>,"
1488                                   "<duty cycle threshold>",
1489                 .show           = wu_show_user,
1490                 .store          = wu_store_user,
1491         },
1492
1493         [wu_option_info_all] = {
1494                 .longopt        = "show-all",
1495                 .shortopt       = 'a',
1496                 .param          = 0,
1497                 .descr          = "Show all device parameters",
1498                 .store          = wu_store_info_all,
1499         },
1500
1501         [wu_option_no_data] = {
1502                 .longopt        = "no-data",
1503                 .shortopt       = 'N',
1504                 .param          = 0,
1505                 .descr          = "Don't read any data (just read device info)",
1506                 .store          = wu_store_no_data,
1507         },
1508
1509         [wu_option_set_only] = {
1510                 .longopt        = "set-only",
1511                 .shortopt       = 'S',
1512                 .param          = 0,
1513                 .descr          = "Set parameters only (don't read them back)",
1514                 .store          = wu_store_set_only,
1515         },
1516 };
1517
1518 #define wu_num_options ARRAY_SIZE(wu_options)
1519
1520 static int wu_show_version(int unused)
1521 {
1522         printf("%s Version %s\n", prog_name, wu_version);
1523         return 0;
1524 }
1525
1526 static int wu_show_help(int unused)
1527 {
1528         int i;
1529         int n;
1530
1531         wu_show_version(unused);
1532         printf("  A program for interfacing with the Watts Up? Power Meter\n");
1533         printf("\n");
1534
1535         printf("Usage: %s [<options>  ... ]<device>  [<values>  ... ]\n",
1536                prog_name);
1537         printf("\n");
1538         
1539         printf("<device>  is the serial port the device is connected at.\n");
1540         printf("\n");
1541
1542         printf("<options>  are any of the following:\n");
1543         for (i = 0; i<  wu_num_options; i++) {
1544                 n = printf("  -%c", wu_options[i].shortopt);
1545
1546                 if (wu_options[i].param == 0)
1547                         n = printf(" ");
1548                 else if (wu_options[i].param == 1)
1549                         n = printf(" %s", wu_options[i].option);
1550                 else if (wu_options[i].param == 2)
1551                         n = printf(" [%s]", wu_options[i].option);
1552
1553                 n += printf("%*c| ", n - 12, ' ');
1554                 n += printf("--%s", wu_options[i].longopt);
1555
1556                 if (wu_options[i].param == 0)
1557                         n += printf(" ");
1558                 else if (wu_options[i].param == 1)
1559                         n += printf("=%s", wu_options[i].option);
1560                 else if (wu_options[i].param == 2)
1561                         n += printf("[=%s]", wu_options[i].option);
1562
1563                 printf("%*c%s\n",
1564                        40 - n, ' ', wu_options[i].descr);
1565         }
1566         printf("\n");
1567         printf("<value>  specifies which of these to print out (default: ALL)\n");
1568         for (i = 0; i<  wu_num_fields; i++) {
1569                 printf("%12s -- %s\n", wu_fields[i].name, wu_fields[i].descr);
1570         }
1571         printf("\n");
1572
1573         return 0;
1574 }
1575
1576
1577 static char * wu_option_value(unsigned int index)
1578 {
1579         return (index<  wu_num_options) ? wu_options[index].value : NULL;
1580 }
1581
1582
1583 static int wu_check_option_show(int index)
1584 {
1585         /*
1586          * Return 1 if we need to print something out for
1587          * a particular option.
1588          */
1589         if (index<  wu_num_options) {
1590                 if (wu_options[index].flag) {
1591                         return 1;
1592                 }
1593         }
1594         return 0;
1595 }
1596
1597 static int wu_check_option_store(int index)
1598 {
1599         /*
1600          * Return a 1 if this option is set.
1601          */
1602
1603         if (index<  wu_num_options) {
1604                 if (wu_options[index].flag) {
1605                         return 1;
1606                 }
1607         }
1608         return 0;
1609 }
1610
1611
1612 static int wu_show(int index, int dev_fd)
1613 {
1614         if (wu_options[index].show)
1615                 return wu_options[index].show(dev_fd);
1616         return 0;
1617 }
1618
1619 /*
1620  * Check if the option is set, and call its method if so.
1621  * Return whether or not we did anything..
1622  */
1623
1624 static int wu_check_show(int index, int dev_fd)
1625 {
1626         if (wu_check_option_show(index)) {
1627                 wu_show(index, dev_fd);
1628                 return 1;
1629         }
1630         return 0;
1631 }
1632
1633
1634 /*
1635  * Check if the option is set and if so, call it
1636  * Return the value from the ->store() method.
1637  */
1638
1639 static int wu_check_store(int index, int dev_fd)
1640 {
1641         if (wu_check_option_store(index)) {
1642                 if (wu_options[index].store)
1643                         return wu_options[index].store(dev_fd);
1644         }
1645         return 0;
1646 }
1647
1648
1649 static void make_longopt(struct option * l)
1650 {
1651         int i;
1652
1653         for (i = 0; i<  wu_num_options; i++) {
1654                 l[i].name = wu_options[i].longopt;
1655                 l[i].has_arg = wu_options[i].param;
1656                 l[i].flag =&wu_options[i].flag;
1657                 l[i].val = 0;
1658         }
1659 }
1660
1661 static void make_shortopt(char * str)
1662 {
1663         int i;
1664         char * s = str;
1665         
1666         for (i = 0; i<  wu_num_options; i++) {
1667                 *s++ = wu_options[i].shortopt;
1668                 if (wu_options[i].param)
1669                         *s++ = wu_options[i].param == 1 ? ':' : ';';
1670         }
1671 }
1672
1673 static void enable_short_option(int c, char * arg)
1674 {
1675         int i;
1676
1677         /*
1678          * Friggin' getopt_long() will return the
1679          * character if we get a short option (e.g. '-h'),
1680          * instead of returning 0 like it does when it
1681          * gets a long option (e.g. "--help"). Ugh.
1682          */
1683         for (i = 0; i<  wu_num_options; i++) {
1684                 if (wu_options[i].shortopt == c) {
1685                         wu_options[i].flag = 1;
1686                         if (arg)
1687                                 wu_options[i].value = strdup(arg);
1688                         break;
1689                 }
1690         }
1691 }
1692
1693 static int parse_args(int argc, char ** argv)
1694 {
1695         struct option longopts[wu_num_options + 1] = { };
1696         char shortopts[wu_num_options * 2] = "";
1697
1698         make_longopt(longopts);
1699         make_shortopt(shortopts);
1700
1701
1702         while (1) {
1703                 int c;
1704                 int index;
1705
1706                 c = getopt_long(argc, argv, shortopts,
1707                                 longopts,&index);
1708                 if (c == -1)
1709                         break;
1710                 
1711                 switch (c) {
1712                 case 0:
1713                         wu_options[index].flag = 1;
1714                         if (optarg)
1715                                 wu_options[index].value = strdup(optarg);
1716                         
1717                         printf("long option: val = %c, optarg = %s\n",
1718                                wu_options[index].shortopt, optarg);
1719                         break;
1720                 case '?':
1721                         err("Bad parameter");
1722                         return ret_err(EINVAL);
1723                         break;
1724                 default:
1725                         enable_short_option(c, optarg);
1726                         break;
1727                 }
1728         }
1729
1730         /*
1731          * Check for help request now and bail after
1732          * printing it, if it's set.
1733          */
1734         if (wu_check_show(wu_option_help, 0))
1735                 exit(0);
1736
1737         if (wu_check_show(wu_option_version, 0))
1738                 exit(0);
1739
1740         /*
1741          * Fields to print out
1742          */
1743         if (optind<  argc) {
1744                 int i;
1745
1746                 wu_device = argv[optind++];
1747
1748                 if (optind<  argc) {
1749                         for (i = optind; i<  argc; i++)
1750                                 enable_field(argv[i]);
1751                 } else
1752                         enable_all_fields();
1753
1754         } else {
1755                 wu_show(wu_option_help, 0);
1756                 return ret_err(EINVAL);
1757         }
1758         return 0;
1759 }
1760
1761
1762 int main(int argc, char ** argv)
1763 {
1764         int ret;
1765         int fd = 0;
1766
1767         ret = parse_args(argc, argv);
1768         if (ret)
1769                 return 0;
1770
1771         /*
1772          * Try to enable debugging early
1773          */
1774         if ((ret = wu_check_store(wu_option_debug, 0)))
1775                 goto Close;
1776
1777         ret = open_device(wu_device,&fd);
1778         if (ret)
1779                 return ret;
1780
1781         dbg("%s: Open for business", wu_device);
1782
1783         ret = setup_serial_device(fd);
1784         if (ret)
1785                 goto Close;
1786
1787         wu_clear(fd);
1788
1789         wu_fd = fd;
1790
1791         /*
1792          * Set delimeter before we print out any fields.
1793          */
1794         if ((ret = wu_check_store(wu_option_delim, fd)))
1795                 goto Close;
1796
1797         /*
1798          * Ditto for 'label' and 'newline' flags.
1799          */
1800         if ((ret = wu_check_store(wu_option_label, fd)))
1801                 goto Close;
1802
1803         if ((ret = wu_check_store(wu_option_newline, fd)))
1804                 goto Close;
1805
1806         if ((ret = wu_check_store(wu_option_suppress, fd)))
1807                 goto Close;
1808
1809         if ((ret = wu_check_store(wu_option_localtime, fd)))
1810                 goto Close;
1811
1812         if ((ret = wu_check_store(wu_option_gmtime, fd)))
1813                 goto Close;
1814
1815         if ((ret = wu_check_store(wu_option_set_only, fd)))
1816                 goto Close;
1817
1818         if ((ret = wu_check_store(wu_option_no_data, fd)))
1819                 goto Close;
1820
1821         if ((ret = wu_check_store(wu_option_info_all, fd)))
1822                 goto Close;
1823
1824
1825         /*
1826          * Options to set device parameters.
1827          */
1828         if ((ret = wu_check_store(wu_option_interval, fd)))
1829                 goto Close;
1830
1831         if ((ret = wu_check_store(wu_option_mode, fd)))
1832                 goto Close;
1833
1834         if ((ret = wu_check_store(wu_option_user, fd)))
1835                 goto Close;
1836
1837         /*
1838          * Check for options to print device info
1839          */
1840         if (wu_info_all) {
1841                 wu_show(wu_option_cal, fd);
1842                 wu_show(wu_option_header, fd);
1843                 wu_show(wu_option_interval, fd);
1844                 wu_show(wu_option_mode, fd);
1845                 wu_show(wu_option_user, fd);
1846         } else {
1847                 wu_check_show(wu_option_cal, fd);
1848                 wu_check_show(wu_option_header, fd);
1849
1850                 if (!wu_set_only) {
1851                         wu_check_show(wu_option_interval, fd);
1852                         wu_check_show(wu_option_mode, fd);
1853                         wu_check_show(wu_option_user, fd);
1854                 }
1855         }
1856
1857         if (!wu_no_data) {
1858
1859                 if ((ret = wu_check_store(wu_option_count, fd)))
1860                         goto Close;
1861
1862                 if ((ret = wu_check_store(wu_option_final, fd)))
1863                         goto Close;
1864
1865                 if ((ret = wu_start_log()))
1866                         goto Close;
1867         
1868                 wu_read_data(fd);
1869                 
1870                 wu_stop_log();
1871         }
1872 Close:
1873         close(fd);
1874         return ret;
1875 }
1876
1877