]> CyberLeo.Net >> Repos - SourceForge/eyefi-config.git/blob - eyefi-config.c
add help message for log command
[SourceForge/eyefi-config.git] / eyefi-config.c
1 /*
2  * eyefitest.c
3  *
4  * Copyright (C) 2008 Dave Hansen <dave@sr71.net>
5  *
6  * This software may be redistributed and/or modified under the terms of
7  * the GNU General Public License ("GPL") version 2 as published by the
8  * Free Software Foundation.
9  */
10
11 #include <assert.h>
12 #include <string.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <getopt.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <errno.h>
21
22 #define O_DIRECT        00040000        /* direct disk access hint */
23
24 #define MOUNT "/media/EYE-FI/"
25 #define PATH MOUNT "eyefi/"
26 #define REQC PATH "REQC"
27 #define REQM PATH "REQM"
28 #define RSPC PATH "RSPC"
29 #define RSPM PATH "RSPM"
30
31 #define BUFSZ 16384
32 #define EYEFI_BUF_SIZE 16384
33 char unaligned_buf[BUFSZ*10];
34 void *buf;
35
36
37 int debug_level = 1;
38 #define debug_printf(level, args...) do {       \
39         if ((level) <= debug_level)             \
40                 fprintf(stderr, ## args);       \
41         } while(0)
42
43 /*
44  * Do some kernel-style types to make
45  * definitions shorter.
46  */
47 typedef unsigned long u32;
48 typedef unsigned char u8;
49
50 static inline u32 swap_bytes(u32 src)
51 {
52         unsigned int dest = 0;
53         dest |= (src & 0xff000000) >> 24;
54         dest |= (src & 0x00ff0000) >>  8;
55         dest |= (src & 0x0000ff00) <<  8;
56         dest |= (src & 0x000000ff) << 24;
57         return dest;
58 }
59
60 /*
61  * Just a few functions so that I can't easily forget about
62  * endinness.
63  */
64 struct __be32 {
65         u32 val;
66 } __attribute__((packed));
67 typedef struct __be32 be32;
68
69 /*
70  * These two obviously need to get fixed for
71  * big endian machines.
72  */
73 u32 be32_to_u32(be32 src)
74 {
75         return swap_bytes(src.val);
76 }
77 be32 u32_to_be32(u32 src)
78 {
79         be32 ret;
80         ret.val = swap_bytes(src);
81         return ret;
82 }
83
84 void dumpbuf(const char *buffer, int bytesToWrite)
85 {
86     int i;
87     static char linebuf[500];
88
89     for (i=0; i < bytesToWrite; i += 16) {
90         char *tmpbuf = &linebuf[0];
91         unsigned long sum = 0;
92         int j;
93 #define lprintf(args...)        do {            \
94         tmpbuf += sprintf(tmpbuf, ## args);\
95 } while (0)
96
97         lprintf("[%03d]: ", i);
98         for (j=0; j < 16; j++) {
99                 u8 c = ((unsigned char *)buffer)[i+j];
100                 lprintf("%02x ", (unsigned int)c);
101                 sum += c;
102         }
103         lprintf(" |");
104         for (j=0; j < 16; j++) {
105                 u8 c = ((unsigned char *)buffer)[i+j];
106                 if (c >= 'a' && c <= 'z')
107                         lprintf("%c", c);
108                 else if (c >= 'A' && c <= 'Z')
109                         lprintf("%c", c);
110                 else if (c >= '0' && c <= '9')
111                         lprintf("%c", c);
112                 else if (c >= 0x20 && c <= 127)
113                         lprintf("%c", c);
114                 else
115                         lprintf(".");
116         }
117         lprintf("|\n");
118         if (sum == 0)
119                 continue;
120         printf("%s", linebuf);
121         //if (i > 200)
122         //      break;
123     }
124 }
125
126 struct card_seq_num {
127         u32 seq;
128 } __attribute__((packed));
129
130 void read_from(char *file);
131 void write_to(char *file, void *stuff, int len);
132 struct card_seq_num read_seq_from(char *file)
133 {
134         struct card_seq_num *ret;
135         read_from(file);
136         ret = buf;
137         return *ret;
138 }
139
140 /*
141  * For O_DIRECT writes to files, we need
142  * to be 512 byte aligned on Linux, I think.
143  * So, just align this to something big
144  * and be done with it.  FIXME :)
145  */
146 void align_buf(void)
147 {
148         unsigned long addr = (unsigned long)&unaligned_buf[BUFSZ];
149         addr &= ~(BUFSZ-1);
150         buf = (void *)addr;
151         debug_printf(4, "buf: %p\n", buf);
152         debug_printf(4, "unaligned: %p\n", &unaligned_buf[0]);
153 }
154
155 struct card_seq_num seq;
156
157 /*
158  * The real manager does this so we might
159  * as well, too.
160  */
161 void zero_card_files(void)
162 {
163         write_to(REQM, buf, BUFSZ);
164         write_to(REQC, buf, BUFSZ);
165         write_to(RSPM, buf, BUFSZ);
166         write_to(RSPC, buf, BUFSZ);
167
168         read_from(REQM);
169         read_from(REQC);
170         read_from(RSPM);
171         read_from(RSPC);
172 }
173
174 void init_card()
175 {
176         if (buf != NULL)
177                 return;
178
179         align_buf();
180         zero_card_files();
181         seq = read_seq_from(RSPC);
182         if (seq.seq == 0)
183                 seq.seq = 0x1234;
184 }
185
186 void open_error(char *file)
187 {
188         fprintf(stderr, "unable to open '%s'\n", file);
189         fprintf(stderr, "Is the Eye-Fi card inserted and mounted at: %s ?\n", MOUNT);
190         fprintf(stderr, "Do you have write permissions to it?\n");
191         if (debug_level > 1)
192                 perror("bad open");
193         exit(1);
194 }
195
196 void read_from(char *file)
197 {
198         u8 c;
199         int i;
200         int ret, retcntl;
201         int fd;
202         int zeros = 0;
203         
204         init_card();
205
206         fd = open(file, O_RDONLY);
207         if (fd < 0) 
208                 open_error(file);
209         retcntl = fcntl(fd, F_SETFL, O_DIRECT);
210         if (retcntl < 0) {
211                 perror("bad fcntl");
212                 exit(1);
213         }
214         ret = read(fd, buf, BUFSZ);
215         if (debug_level > 3)
216                 dumpbuf(buf, 128);
217         if (ret < 0) {
218                 perror("bad read");
219                 exit(1);
220         }
221         debug_printf(3, "read '%s': bytes: %d fcntl: %d\n", file, ret, retcntl);
222         for (i=0; i < BUFSZ; i++) {
223                 c = ((char *)buf)[i];
224                 if (c == '\0') {
225                         zeros++;
226                         continue;
227                 }
228         }
229         //if (zeros)
230         //      printf(" zeros: %d", zeros);
231         //fsync(fd);
232         close(fd);
233 }
234
235 void write_to(char *file, void *stuff, int len)
236 {
237         //printf("not writing to '%s'\n", file);
238         //return;
239         int ret;
240         int fd;
241         init_card();
242         if (len == -1)
243                 len = strlen(stuff);
244
245         if (debug_level > 3)
246                 dumpbuf(stuff, len);
247         memset(buf, 0, BUFSZ);
248         memcpy(buf, stuff, len);
249         fd = open(file, O_RDWR|O_DIRECT|O_CREAT, 0600);
250         //ret = lseek(fd, 0, SEEK_SET);
251         if (fd < 0)
252                 open_error(file);
253         if (debug_level > 3)
254                 dumpbuf(buf, 128);
255         ret = write(fd, buf, BUFSZ);
256         //fsync(fd);
257         close(fd);
258         debug_printf(3, "wrote %d bytes to '%s' (string was %d bytes)\n", ret, file, len);
259         if (ret < 0)
260                 exit(ret);
261 }       
262
263 /*
264  * Most of the eyefi strings are pascal-style with
265  * a length byte preceeding content.  (Did pascal
266  * have just a byte for length or more??)
267  */
268 struct pascal_string {
269         u8 length;
270         u8 value[32];
271 } __attribute__((packed));
272
273 void print_pascal_string(struct pascal_string *str)
274 {
275         int i;
276         for (i = 0; i < str->length; i++)
277                 printf("%c", str->value[i]);
278 }
279
280 /*
281  * The 'o' command has several sub-commands:
282  */
283 enum card_info_subcommand {
284         MAC_ADDRESS   = 1,
285         FIRMWARE_INFO = 2,
286         CARD_KEY      = 3,
287         API_URL       = 4,
288         UNKNOWN1      = 5, // Chris says these are 
289         UNKNOWN2      = 6, // checksums
290         LOG_LEN       = 7,
291 };
292
293 struct card_info_req {
294         u8 o;
295         u8 subcommand;
296 } __attribute__((packed));
297
298 struct card_info_rsp_key {
299         struct pascal_string key;
300 };
301
302 #define MAC_BYTES 6
303 struct mac_address {
304         u8 length;
305         u8 mac[MAC_BYTES];
306 } __attribute__((packed));
307
308 struct card_info_api_url {
309         struct pascal_string key;
310 };
311
312 struct card_info_log_len {
313         u8 len;
314         be32 val;
315 } __attribute__((packed));
316
317 #define write_struct(file, s) write_to((file), s, sizeof(*(s)))
318
319 void print_mac(struct mac_address *mac)
320 {
321         int i;
322         for (i=0; i < MAC_BYTES-1; i++) {
323                 printf("%02x:", mac->mac[i]);
324         }
325         printf("%02x\n", mac->mac[i]);
326 }
327
328 void inc_seq(void)
329 {
330         //u32 tmpseq = be32_to_u32(seq.seq);
331         //seq.seq = u32_to_be32(tmpseq+1);
332         seq.seq++;
333         write_struct(REQC, &seq);
334 }
335
336 u32 current_seq(void)
337 {
338         return seq.seq;
339 }
340
341 void wait_for_response(void)
342 {
343         int i;
344         debug_printf(3, "waiting for response...\n");
345         inc_seq();
346         for (i = 0; i < 50; i++) {
347                 struct card_seq_num cardseq = read_seq_from(RSPC);
348                 u32 rsp = cardseq.seq;
349                 debug_printf(3, "read rsp code: %lx, looking for: %lx raw: %lx\n", rsp, current_seq(),
350                                 cardseq.seq);
351                 if (rsp == current_seq())
352                         break;
353                 usleep(300000);
354         }
355         debug_printf(3, "got good seq, reading RSPM...\n");
356         read_from(RSPM);
357         debug_printf(3, "done reading RSPM\n");
358 }
359 struct byte_response {
360         u8 response;
361 };
362
363 enum net_type {
364         UNSECURED,
365         WEP,
366         WPA,
367         WPA2
368 };
369
370 #define ESSID_LEN 32
371 struct scanned_net {
372         char essid[ESSID_LEN];
373         signed char strength;
374         u8 type;
375 } __attribute__((packed));
376
377 struct scanned_net_list {
378         u8 nr;
379         struct scanned_net nets[100];
380 } __attribute__((packed));
381
382 struct configured_net {
383         char essid[ESSID_LEN];
384 } __attribute__((packed));
385
386 struct configured_net_list {
387         u8 nr;
388         struct configured_net nets[100];
389 } __attribute__((packed));
390
391 char *net_test_states[] = {
392         "not scanning",
393         "locating network",
394         "verifying network key",
395         "waiting for DHCP",
396         "testing connection to Eye-Fi server",
397         "success",
398 };
399
400 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
401
402 char *net_test_state_name(u8 state)
403 {
404         int size = ARRAY_SIZE(net_test_states);
405         if (state >= size)
406                 return "unknown";
407         return net_test_states[state];
408 }
409
410 char *net_types[] = {
411         "No security",
412         "WEP",
413         "WPA",
414         "unknown1",
415         "WPA2",
416 };
417
418 char *net_type_name(u8 type)
419 {
420         int size = ARRAY_SIZE(net_types);
421         if (type >= size)
422                 return "unknown";
423         return net_types[type];
424 }
425
426 #define WPA_KEY_BYTES 32
427 struct wpa_key {
428         u8 key[WPA_KEY_BYTES];
429 } __attribute((packed));
430
431 #define WEP_KEY_BYTES 32
432 struct wep_key {
433         u8 key[WEP_KEY_BYTES];
434 } __attribute((packed));
435
436 struct network_key {
437         u8 len;
438         union {
439                 struct wpa_key wpa;
440                 struct wep_key wep;
441         };
442 } __attribute((packed));
443
444 #define KEY_LEN 32
445 struct net_request {
446         char req;
447         u8 essid_len;
448         char essid[ESSID_LEN];
449         struct network_key key;
450 } __attribute((packed));
451
452 char lower(char c)
453 {
454         if ((c >= 'A') && (c <= 'Z'))
455                 c += ('a' - 'A');
456         return c;
457 }
458
459 int atoh(char c)
460 {
461         char lc = lower(c);
462         if ((c >= '0') && (c <= '9'))
463                 return c - '0';
464         else if ((c >= 'a') && (c <= 'z'))
465                 return (c - 'a') + 10;
466         debug_printf(0, "non-hex character: '%c'/'%c'\n", c, lc);
467         return 0;
468 }
469
470 /*
471  * Take a string like "0ab1" and make it
472  * a series of bytes: { 0x0a, 0xb1 }
473  *
474  * Destroys the original string.
475  */
476 char *convert_ascii_to_hex(char *ascii, int len)
477 {
478         int i;
479         if (len%2) {
480                 fprintf(stderr, "%s() must be even number of bytes: %d\n",
481                 __func__, len);
482                 exit(2);
483         }
484         for (i=0; i < len; i+=2) {
485                 u8 high = atoh(ascii[i]);
486                 u8 low  = atoh(ascii[i+1]);
487                 u8 byte = (high<<4 | low);
488                 debug_printf(6, "high: %02x low: %02x, both: %02x\n", high, low, byte);
489                 ascii[i/2] = byte;
490         }
491         for (i=len/2; i < len; i++)
492                 ascii[i] = '\0';
493         return &ascii[0];
494 }
495
496 #define PASSPHRASE_PROG "wpa_passphrase"
497
498 struct wpa_key *make_wpa_key(char *essid, char *pass)
499 {
500         char program[] = PASSPHRASE_PROG;
501         // 7 for 2 spaces, 4 quotes and a \0
502         char redirect[] = " 2> /dev/null";
503         char *cmdbuf = malloc(strlen(essid) + strlen(pass) + strlen(program) + 7 + 
504                         strlen(redirect));
505
506         if (!cmdbuf)
507                 return NULL;
508
509         sprintf(cmdbuf, "%s '%s' '%s' %s", program, essid, pass, redirect);
510         FILE *pipe = popen(cmdbuf, "r");
511         if (!pipe) {
512                 perror("\nunable to execute " PASSPHRASE_PROG);
513                 return NULL;
514         }
515         
516         int key_chars = WPA_KEY_BYTES*2;
517         char hex_key_in_ascii[key_chars+1];
518         char line[1024];
519         int read = 0;
520         while (fgets(&line[0], 1023, pipe)) {
521                 debug_printf(4, "read from %s: '%s'\n", PASSPHRASE_PROG, line);
522                 read = sscanf(&line[0], "       psk=%64s", &hex_key_in_ascii[0]);
523                 if (read == 0)
524                         continue;
525                 break;
526         }
527         int exit_code = pclose(pipe);
528         if (!read || exit_code) {
529                 fprintf(stderr, "\nunable to read wpa key from %s\n", PASSPHRASE_PROG);
530                 fprintf(stderr, "Is wpa_supplicant installed?\n");
531                 exit(4);
532         }
533         debug_printf(4, "ascii key: '%s'\n", hex_key_in_ascii);
534         char *hex_key = convert_ascii_to_hex(hex_key_in_ascii, key_chars);
535         struct wpa_key *key = malloc(sizeof(*key));
536         memcpy(&key->key[0], hex_key, WPA_KEY_BYTES);
537         free(cmdbuf);
538         return key;
539 }
540
541 void card_info_cmd(enum card_info_subcommand cmd)
542 {
543         struct card_info_req cir;
544         cir.o = 'o';
545         cir.subcommand = cmd;
546
547         write_struct(REQM, &cir);
548         wait_for_response();
549 }
550
551 u32 fetch_log_length(void)
552 {
553         card_info_cmd(LOG_LEN);
554         struct card_info_log_len *loglen = buf;
555         return be32_to_u32(loglen->val);
556 }
557
558 void print_log_len(void)
559 {
560         u32 len = fetch_log_length();
561         printf("log len: %08lx\n", len);
562 }
563
564 void print_card_mac(void)
565 {
566         debug_printf(2, "%s()\n", __func__);
567         card_info_cmd(MAC_ADDRESS);
568         struct mac_address *mac = buf;
569         assert(mac->length == MAC_BYTES);
570         printf("card mac address: ");
571         print_mac(mac);
572 }
573
574 void print_card_key(void)
575 {
576         debug_printf(2, "%s()\n", __func__);
577         card_info_cmd(CARD_KEY);
578         struct card_info_rsp_key *foo = buf;
579         printf("card key (len: %d): '", foo->key.length);
580         print_pascal_string(&foo->key);
581         printf("'\n");
582 }
583
584 struct noarg_request {
585         u8 req;
586 };
587
588 void issue_noarg_command(u8 cmd)
589 {
590         struct noarg_request req;
591         req.req = cmd;
592         write_struct(REQM, &req);
593         wait_for_response();
594 }
595
596 void scan_print_nets(void)
597 {
598         int i;
599
600         debug_printf(2, "%s()\n", __func__);
601         issue_noarg_command('g');
602         struct scanned_net_list *scanned = buf;
603         if (scanned->nr == 0) {
604                 printf("unable to detect any wireless networks\n");
605                 return;
606         }
607         printf("Scanned wireless networks:\n");
608         for (i=0; i < scanned->nr; i++) {
609                 struct scanned_net *net = &scanned->nets[i];
610                 printf("'%s' type(%d): %s, strength: %d\n", net->essid,
611                                 net->type,
612                                 net_type_name(net->type),
613                                 net->strength);
614         }
615 }
616
617 void print_configured_nets(void)
618 {
619         int i;
620         struct configured_net_list *configured;
621
622         debug_printf(2, "%s()\n", __func__);
623         issue_noarg_command('l');
624         configured = buf;
625         if (configured->nr == 0) {
626                 printf("No wireless networks configured on card\n");
627                 return;
628         }
629         printf("configured wireless networks:\n");
630         for (i=0; i < configured->nr; i++) {
631                 struct configured_net *net = &configured->nets[i];
632                 printf("'%s'\n", net->essid);
633         }
634 }
635
636 void reboot_card(void)
637 {
638         debug_printf(2, "%s()\n", __func__);
639         issue_noarg_command('b');
640 }
641
642 void copy_wep_key(struct wep_key *dst, struct wep_key *src)
643 {
644         memcpy(&dst->key, &src->key, sizeof(*dst));
645 }
646
647 void copy_wpa_key(struct wpa_key *dst, struct wpa_key *src)
648 {
649         memcpy(&dst->key, &src->key, sizeof(*dst));
650 }
651
652 void network_action(char cmd, char *essid, char *wpa_ascii)
653 {
654         struct net_request nr;
655         memset(&nr, 0, sizeof(nr));
656
657         nr.req = cmd;
658         strcpy(&nr.essid[0], essid);
659         nr.essid_len = strlen(essid);
660         struct wpa_key *wpakey;
661         if (wpa_ascii) {
662                 wpakey = make_wpa_key(essid, wpa_ascii);
663                 nr.key.len = sizeof(*wpakey);
664                 copy_wpa_key(&nr.key.wpa, wpakey);
665         }
666         write_struct(REQM, &nr);
667         wait_for_response();
668 }
669
670 void add_network(char *essid, char *wpa_ascii)
671 {
672         debug_printf(2, "%s()\n", __func__);
673         network_action('a', essid, wpa_ascii);
674 }
675
676 void remove_network(char *essid)
677 {
678         debug_printf(2, "%s()\n", __func__);
679         network_action('d', essid, NULL);
680 }
681
682 int try_connection_to(char *essid, char *wpa_ascii)
683 {
684         int i;
685         int ret = -1;
686
687         char *type = net_type_name(WPA);
688         if (!wpa_ascii)
689                 type = net_type_name(UNSECURED);
690         printf("trying to connect to %s network: '%s'", type, essid);
691         if (wpa_ascii)
692                 printf(" with passphrase: '%s'", wpa_ascii);
693         fflush(NULL);
694
695         // test network
696         network_action('t', essid, wpa_ascii);
697         u8 last_rsp = -1;
698
699         char rsp = '\0';
700         for (i=0; i < 200; i++) {
701                 struct byte_response *r;
702                 issue_noarg_command('s');
703                 r = buf;
704                 rsp = r->response;
705                 char *state = net_test_state_name(rsp);
706                 if (rsp == last_rsp) {
707                         printf(".");
708                         fflush(NULL);;
709                 } else {
710                         if (rsp)
711                                 printf("\nTesting connecion to '%s' (%d): %s", essid, rsp, state);
712                         last_rsp = rsp;
713                 }
714                 
715                 if (!strcmp("success", state)) {
716                         ret = 0;
717                         break;
718                 }
719                 if (!strcmp("not scanning", state))
720                         break;
721                 if (!strcmp("unknown", state))
722                         break;
723         }
724         printf("\n");
725         if (!ret) {
726                 printf("Succeeded connecting to: '%s'\n", essid);
727         } else {
728                 printf("Unable to connect to: '%s' (final state: %d/'%s')\n", essid,
729                                 rsp, net_test_state_name(rsp));
730         }
731         return ret;
732 }
733
734 struct fetch_log_cmd {
735         char m;
736         be32 offset;
737 } __attribute__((packed));
738
739 /*
740  * When you ask for the log at offset 0x0, you
741  * get back 8 bytes of offsets into the rest of
742  * the data
743  */
744 struct first_log_response {
745         be32 log_end;
746         be32 log_start;
747         u8 data[EYEFI_BUF_SIZE-8];
748 } __attribute__((packed));
749
750 struct rest_log_response {
751         u8 data[EYEFI_BUF_SIZE];
752 } __attribute__((packed));
753
754 unsigned char *get_log_at_offset(u32 offset)
755 {
756         struct fetch_log_cmd cmd;
757         cmd.m = 'm';
758         cmd.offset = u32_to_be32(offset);
759
760         debug_printf(2, "getting log at offset: %08lx\n", offset);
761         write_struct(REQM, &cmd);
762         wait_for_response();
763         return buf;
764 }
765
766 int get_log(void)
767 {
768         int total_bytes = 0;
769         int i;
770         u32 log_start;
771         u32 log_end;
772         u32 log_size = fetch_log_length();
773         char *resbuf = malloc(log_size);
774
775         int nr_bufs_per_log = log_size/EYEFI_BUF_SIZE;
776         for (i = 0; i < log_size/EYEFI_BUF_SIZE; i++) {
777                 debug_printf(1, "fetching EyeFi card log part %d/%d...",
778                                 i+1, nr_bufs_per_log);
779                 fflush(NULL);
780                 get_log_at_offset(EYEFI_BUF_SIZE*i);
781                 debug_printf(1, "done\n");
782                 u32 log_size;
783                 u8 *log_data;
784                 if (i == 0) {
785                         struct first_log_response *log = buf;
786                         log_end = be32_to_u32(log->log_end);
787                         log_start = be32_to_u32(log->log_start);
788                         debug_printf(2, "log end:   0x%04lx\n", log_end);
789                         debug_printf(2, "log start: 0x%04lx\n", log_start);
790                         log_data = &log->data[0];
791                         log_size = ARRAY_SIZE(log->data);
792                 } else {
793                         struct rest_log_response *log = buf;
794                         log_data = &log->data[0];
795                         log_size = ARRAY_SIZE(log->data);
796                 }
797                 debug_printf(3, "writing %ld bytes to resbuf[%d]\n",
798                                 log_size, total_bytes);
799                 memcpy(&resbuf[total_bytes], log_data, log_size);
800                 total_bytes += log_size;
801         }
802         // The last byte *should* be a null, and the 
803         // official software does not print it.
804         for (i = 0; i < total_bytes-1; i++) {
805                 int offset = (log_start+i)%total_bytes;
806                 char c = resbuf[offset];
807                 // the official software converts UNIX to DOS-style
808                 // line breaks, so we'll do the same
809                 if (c == '\n')
810                         printf("%c", '\r');
811                 printf("%c", c);
812         }
813         printf("\n");
814         // just some simple sanity checking to make sure what
815         // we are fetching looks valid
816         int null_bytes_left = 20;
817         if (resbuf[log_end] != 0) {
818                 fprintf(stderr, "error: unexpected last byte (%ld/0x%lx) of log: %02x\n",
819                                 log_end, log_end, resbuf[log_end]);
820                 for (i=0; i<log_size; i++) {
821                         if (resbuf[i])
822                                 continue;
823                         if (null_bytes_left <= 0)
824                                 continue;
825                         null_bytes_left--;
826                         debug_printf(2, "null byte %d\n", i);
827                 }
828         }
829         free(resbuf);
830         return 0;
831 }
832
833 void usage(void)
834 {
835         printf("Usage:\n");
836         printf("  eyefitest [OPTIONS]\n");
837         printf("  -a ESSID      add network (implies test unless --force)\n");
838         printf("  -t ESSID      test network\n");
839         printf("  -p KEY        set WPA key for add/test\n");
840         printf("  -r ESSID      remove network\n");
841         printf("  -s            scan for networks\n");
842         printf("  -c            list configured networks\n");
843         printf("  -b            reboot card\n");
844         printf("  -d level      set debugging level (default: 1)\n");
845         printf("  -k            print card unique key\n");
846         printf("  -l            dump card log\n");
847         printf("  -m            print card mac\n");
848         exit(4);
849 }
850
851 int main(int argc, char **argv)
852 {
853         if (argc == 1)
854                 usage();
855
856         debug_printf(3, "%s starting...\n", argv[0]);
857
858         //static int passed_wep = 0;
859         //static int passed_wpa = 0;
860         static int force = 0;
861         static struct option long_options[] = {
862                 //{"wep", 'x', &passed_wep, 1},
863                 //{"wpa", 'y', &passed_wpa, 1},
864                 {"force", 0, &force, 1},
865                 {"help", 'h', NULL, 1},
866         };
867
868         int option_index;
869         char c;
870         char *essid = NULL;
871         char *passwd = NULL;
872         char network_action = 0;
873         debug_printf(3, "about to parse arguments\n");
874         while ((c = getopt_long_only(argc, argv, "a:bcd:klmp:r:st:",
875                         &long_options[0], &option_index)) != -1) {
876                 debug_printf(3, "argument: '%c' %d optarg: '%s'\n", c, c, optarg);
877                 switch (c) {
878                 case 0:
879                         // was a long argument
880                         break;
881                 case 'a':
882                 case 't':
883                 case 'r':
884                         essid = optarg;
885                         network_action = c;
886                         break;
887                 case 'b':
888                         reboot_card();
889                         break;
890                 case 'c':
891                         print_configured_nets();
892                         break;
893                 case 'd':
894                         debug_level = atoi(optarg);
895                         break;
896                 case 'k':
897                         print_card_key();
898                         break;
899                 case 'l':
900                         get_log();
901                         break;
902                 case 'm':
903                         print_card_mac();
904                         break;
905                 case 'p':
906                         passwd = optarg;
907                         break;
908                 case 's':
909                         scan_print_nets();
910                         break;
911                 case 'h':
912                 default:
913                         usage();
914                         break;
915                 }
916         }
917         debug_printf(3, "after arguments essid: '%s' passwd: '%s'\n", essid, passwd);
918         if (network_action && essid) {
919                 int ret = 0;
920                 switch (network_action) {
921                 case 't':
922                         ret = try_connection_to(essid, passwd);
923                         break;
924                 case 'a':
925                         if (!force) {
926                                 ret = try_connection_to(essid, passwd);
927                         } else {
928                                 debug_printf(1, "forced: skipping network test\n");
929                         }
930                         if (ret) {
931                                 printf("Error connecting to network '%s', not adding.\n", essid);
932                                 printf("use --force to override\n");
933                                 break;
934                         }
935                         add_network(essid, passwd);
936                         break;
937                 case 'r':
938                         remove_network(essid);
939                         break;
940                 }
941         }
942         return 0;
943 }
944
945