1 /*
2  * A simple command-line exerciser for the library.
3  * Not really useful for anything but debugging.
4  * SPDX-License-Identifier: BSD-2-clause
5  */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <stdbool.h>
9 #include <string.h>
10 #include <errno.h>
11 #include <stdarg.h>
12 #include <ctype.h>
13 
14 #include "../gps.h"
15 #include "../libgps.h"
16 #include "../gpsdclient.h"
17 
18 #include <unistd.h>
19 #include <getopt.h>
20 #include <signal.h>
21 
onsig(int sig)22 static void onsig(int sig)
23 {
24     (void)fprintf(stderr, "libgps: died with signal %d\n", sig);
25     exit(EXIT_FAILURE);
26 }
27 
28 #ifdef SOCKET_EXPORT_ENABLE
29 /* must start zeroed, otherwise the unit test will try to chase garbage pointer fields. */
30 static struct gps_data_t gpsdata;
31 #endif
32 
main(int argc,char * argv[])33 int main(int argc, char *argv[])
34 {
35     struct gps_data_t collect;
36     struct fixsource_t source;
37     char buf[BUFSIZ];
38     int option;
39     bool batchmode = false;
40     bool forwardmode = false;
41     char *fmsg = NULL;
42 #ifdef CLIENTDEBUG_ENABLE
43     int debug = 0;
44 #endif
45 
46     (void)signal(SIGSEGV, onsig);
47 #ifdef SIGBUS
48     (void)signal(SIGBUS, onsig);
49 #endif
50 
51     while ((option = getopt(argc, argv, "bf:hsD:?")) != -1) {
52 	switch (option) {
53 	case 'b':
54 	    batchmode = true;
55 	    break;
56 	case 'f':
57 	    forwardmode = true;
58 	    fmsg = optarg;
59 	    break;
60 	case 's':
61 	    (void)
62 		printf("Sizes: fix=%zd gpsdata=%zd rtcm2=%zd rtcm3=%zd "
63                        "ais=%zd compass=%zd raw=%zd devices=%zd policy=%zd "
64                        "version=%zd, noise=%zd\n",
65 		 sizeof(struct gps_fix_t),
66 		 sizeof(struct gps_data_t), sizeof(struct rtcm2_t),
67 		 sizeof(struct rtcm3_t), sizeof(struct ais_t),
68 		 sizeof(struct attitude_t), sizeof(struct rawdata_t),
69 		 sizeof(collect.devices), sizeof(struct gps_policy_t),
70 		 sizeof(struct version_t), sizeof(struct gst_t));
71 	    exit(EXIT_SUCCESS);
72 #ifdef CLIENTDEBUG_ENABLE
73 	case 'D':
74 	    debug = atoi(optarg);
75 	    break;
76 #endif
77 	case '?':
78 	case 'h':
79 	default:
80 	    (void)fputs("usage: test_libgps [-b] [-f fwdmsg] [-D lvl] [-s] [server[:port:[device]]]\n", stderr);
81 	    exit(EXIT_FAILURE);
82 	}
83     }
84 
85     /* Grok the server, port, and device. */
86     if (optind < argc) {
87 	gpsd_source_spec(argv[optind], &source);
88     } else
89 	gpsd_source_spec(NULL, &source);
90 
91 #ifdef CLIENTDEBUG_ENABLE
92     gps_enable_debug(debug, stdout);
93 #endif
94     if (batchmode) {
95 #ifdef SOCKET_EXPORT_ENABLE
96 	while (fgets(buf, sizeof(buf), stdin) != NULL) {
97 	    if (buf[0] == '{' || isalpha( (int) buf[0])) {
98 		gps_unpack(buf, &gpsdata);
99 #ifdef LIBGPS_DEBUG
100 		libgps_dump_state(&gpsdata);
101 #endif
102 	    }
103 	}
104 #endif
105     } else if (gps_open(source.server, source.port, &collect) != 0) {
106 	(void)fprintf(stderr,
107 		      "test_libgps: no gpsd running or network error: %d, %s\n",
108 		      errno, gps_errstr(errno));
109 	exit(EXIT_FAILURE);
110     } else if (forwardmode) {
111 	if (gps_send(&collect, fmsg) == -1) {
112 	  (void)fprintf(stderr,
113 			"test_libgps: gps send error: %d, %s\n",
114 			errno, gps_errstr(errno));
115 	}
116 	if (gps_read(&collect, NULL, 0) == -1) {
117 	  (void)fprintf(stderr,
118 			"test_libgps: gps read error: %d, %s\n",
119 			errno, gps_errstr(errno));
120 	}
121 #ifdef SOCKET_EXPORT_ENABLE
122 #ifdef LIBGPS_DEBUG
123 	libgps_dump_state(&collect);
124 #endif
125 #endif
126 	(void)gps_close(&collect);
127     } else {
128 	int tty = isatty(0);
129 
130 	if (tty)
131 	    (void)fputs("This is the gpsd exerciser.\n", stdout);
132 	for (;;) {
133 	    if (tty)
134 		(void)fputs("> ", stdout);
135 	    if (fgets(buf, sizeof(buf), stdin) == NULL) {
136 		if (tty)
137 		    putchar('\n');
138 		break;
139 	    }
140 	    collect.set = 0;
141 	    (void)gps_send(&collect, buf);
142 	    (void)gps_read(&collect, NULL, 0);
143 #ifdef SOCKET_EXPORT_ENABLE
144 #ifdef LIBGPS_DEBUG
145 	    libgps_dump_state(&collect);
146 #endif
147 #endif
148 	}
149 	(void)gps_close(&collect);
150     }
151     return 0;
152 }
153 
154