Exemple #1
0
/*@-mustfreefresh -mustfreeonly -branchstate -globstate@*/
int main(int argc, char **argv)
{
    int ch;
    bool daemonize = false;
    unsigned int flags = WATCH_ENABLE;
    struct exportmethod_t *method = NULL;

    progname = argv[0];

    if (export_default() == NULL) {
	(void)fprintf(stderr, "%s: no export methods.\n", progname);
	exit(1);
    }

    logfile = stdout;
    while ((ch = getopt(argc, argv, "dD:e:f:hi:lm:V")) != -1) {
	switch (ch) {
	case 'd':
	    openlog(basename(progname), LOG_PID | LOG_PERROR, LOG_DAEMON);
	    daemonize = true;
	    break;
#ifdef CLIENTDEBUG_ENABLE
	case 'D':
	    debug = atoi(optarg);
	    gps_enable_debug(debug, logfile);
	    break;
#endif /* CLIENTDEBUG_ENABLE */
	case 'e':
	    method = export_lookup(optarg);
	    if (method == NULL) {
		(void)fprintf(stderr,
			      "%s: %s is not a known export method.\n",
			      progname, optarg);
		exit(1);
	    }
	    break;
       case 'f':       /* Output file name. */
            {
                char    fname[PATH_MAX];
                time_t  t;
                size_t  s;

                t = time(NULL);
                s = strftime(fname, sizeof(fname), optarg, localtime(&t));
                if (s == 0) {
                        syslog(LOG_ERR,
                            "Bad template \"%s\", logging to stdout.", optarg);
                        break;
                }
                logfile = fopen(fname, "w");
                if (logfile == NULL)
                        syslog(LOG_ERR,
                            "Failed to open %s: %s, logging to stdout.",
                            fname, strerror(errno));
                break;
            }
	case 'i':		/* set polling interfal */
	    timeout = (time_t) atoi(optarg);
	    if (timeout < 1)
		timeout = 1;
	    if (timeout >= 3600)
		fprintf(stderr,
			"WARNING: track timeout is an hour or more!\n");
	    break;
	case 'l':
	    export_list(stderr);
	    exit(0);
        case 'm':
	    minmove = (double )atoi(optarg);
	    break;
	case 'V':
	    (void)fprintf(stderr, "%s revision " REVISION "\n", progname);
	    exit(0);
	default:
	    usage();
	    /* NOTREACHED */
	}
    }

    if (daemonize && logfile == stdout) {
	syslog(LOG_ERR, "Daemon mode with no valid logfile name - exiting.");
	exit(1);
    }

    if (method != NULL)
	if (method->magic != NULL) {
	    source.server = (char *)method->magic;
	    source.port = NULL;
	}

    if (optind < argc) {
	gpsd_source_spec(argv[optind], &source);
    } else
	gpsd_source_spec(NULL, &source);
#if 0
    (void)fprintf(logfile,"<!-- server: %s port: %s  device: %s -->\n",
		 source.server, source.port, source.device);
#endif

    /* catch all interesting signals */
    (void)signal(SIGTERM, quit_handler);
    (void)signal(SIGQUIT, quit_handler);
    (void)signal(SIGINT, quit_handler);

    /*@-unrecog@*/
    /* might be time to daemonize */
    if (daemonize) {
	/* not SuS/POSIX portable, but we have our own fallback version */
	if (daemon(0, 0) != 0)
	    (void) fprintf(stderr,"demonization failed: %s\n", strerror(errno));
    }
    /*@+unrecog@*/

    //syslog (LOG_INFO, "---------- STARTED ----------");

    if (gps_open(source.server, source.port, &gpsdata) != 0) {
	(void)fprintf(stderr,
		      "%s: no gpsd running or network error: %d, %s\n",
		      progname, errno, gps_errstr(errno));
	exit(1);
    }

    if (source.device != NULL)
	flags |= WATCH_DEVICE;
    (void)gps_stream(&gpsdata, flags, source.device);

    print_gpx_header();
    (int)gps_mainloop(&gpsdata, 5000000, conditionally_log_fix);
    print_gpx_footer();
    (void)gps_close(&gpsdata);

    exit(0);
}
Exemple #2
0
int main(int argc, char *argv[])
{
    struct gps_data_t collect;
    struct fixsource_t source;
    char buf[BUFSIZ];
    int option;
    bool batchmode = false;
    bool forwardmode = false;
    char *fmsg = NULL;
#ifdef CLIENTDEBUG_ENABLE
    int debug = 0;
#endif

    (void)signal(SIGSEGV, onsig);
    (void)signal(SIGBUS, onsig);

    while ((option = getopt(argc, argv, "bf:hsD:?")) != -1) {
	switch (option) {
	case 'b':
	    batchmode = true;
	    break;
	case 'f':
	    forwardmode = true;
	    fmsg = optarg;
	    break;
	case 's':
	    (void)
		printf
		("Sizes: fix=%zd gpsdata=%zd rtcm2=%zd rtcm3=%zd ais=%zd compass=%zd raw=%zd devices=%zd policy=%zd version=%zd, noise=%zd\n",
		 sizeof(struct gps_fix_t),
		 sizeof(struct gps_data_t), sizeof(struct rtcm2_t),
		 sizeof(struct rtcm3_t), sizeof(struct ais_t),
		 sizeof(struct attitude_t), sizeof(struct rawdata_t),
		 sizeof(collect.devices), sizeof(struct policy_t),
		 sizeof(struct version_t), sizeof(struct gst_t));
	    exit(EXIT_SUCCESS);
#ifdef CLIENTDEBUG_ENABLE
	case 'D':
	    debug = atoi(optarg);
	    break;
#endif
	case '?':
	case 'h':
	default:
	    (void)fputs("usage: test_libgps [-b] [-f fwdmsg] [-D lvl] [-s] [server[:port:[device]]]\n", stderr);
	    exit(EXIT_FAILURE);
	}
    }

    /* Grok the server, port, and device. */
    if (optind < argc) {
	gpsd_source_spec(argv[optind], &source);
    } else
	gpsd_source_spec(NULL, &source);

#ifdef CLIENTDEBUG_ENABLE
    gps_enable_debug(debug, stdout);
#endif
    if (batchmode) {
#ifdef SOCKET_EXPORT_ENABLE
	while (fgets(buf, sizeof(buf), stdin) != NULL) {
	    if (buf[0] == '{' || isalpha(buf[0])) {
		gps_unpack(buf, &gpsdata);
		libgps_dump_state(&gpsdata);
	    }
	}
#endif
    } else if (gps_open(source.server, source.port, &collect) != 0) {
	(void)fprintf(stderr,
		      "test_libgps: no gpsd running or network error: %d, %s\n",
		      errno, gps_errstr(errno));
	exit(EXIT_FAILURE);
    } else if (forwardmode) {
	(void)gps_send(&collect, fmsg);
	(void)gps_read(&collect);
#ifdef SOCKET_EXPORT_ENABLE
	libgps_dump_state(&collect);
#endif
	(void)gps_close(&collect);
    } else {
	int tty = isatty(0);

	if (tty)
	    (void)fputs("This is the gpsd exerciser.\n", stdout);
	for (;;) {
	    if (tty)
		(void)fputs("> ", stdout);
	    if (fgets(buf, sizeof(buf), stdin) == NULL) {
		if (tty)
		    putchar('\n');
		break;
	    }
	    collect.set = 0;
	    (void)gps_send(&collect, buf);
	    (void)gps_read(&collect);
#ifdef SOCKET_EXPORT_ENABLE
	    libgps_dump_state(&collect);
#endif
	}
	(void)gps_close(&collect);
    }

    return 0;
}
Exemple #3
0
/*@-mustfreefresh -globstate@*/
int main(int argc, char **argv)
{
    int ch;
    bool daemonize = false;
    struct method_t *mp, *method = NULL;

    progname = argv[0];

    logfile = stdout;
    while ((ch = getopt(argc, argv, "dD:e:f:hi:lm:V")) != -1) {
	switch (ch) {
	case 'd':
	    openlog(basename(progname), LOG_PID | LOG_PERROR, LOG_DAEMON);
	    daemonize = true;
	    break;
#ifdef CLIENTDEBUG_ENABLE
	case 'D':
	    debug = atoi(optarg);
	    gps_enable_debug(debug, logfile);
	    break;
#endif /* CLIENTDEBUG_ENABLE */
	case 'e':
	    for (mp = methods;
		 mp < methods + NITEMS(methods);
		 mp++)
		if (strcmp(mp->name, optarg) == 0)
		    method = mp;
	    if (method == NULL) {
		(void)fprintf(stderr,
			      "%s: %s is not a known export method.\n",
			      progname, optarg);
		exit(1);
	    }
	    break;
       case 'f':       /* Output file name. */
            {
                char    fname[PATH_MAX];
                time_t  t;
                size_t  s;

                t = time(NULL);
                s = strftime(fname, sizeof(fname), optarg, localtime(&t));
                if (s == 0) {
                        syslog(LOG_ERR,
                            "Bad template \"%s\", logging to stdout.", optarg);
                        break;
                }
                logfile = fopen(fname, "w");
                if (logfile == NULL)
                        syslog(LOG_ERR,
                            "Failed to open %s: %s, logging to stdout.",
                            fname, strerror(errno));
                break;
            }
	case 'i':		/* set polling interfal */
	    timeout = (time_t) atoi(optarg);
	    if (timeout < 1)
		timeout = 1;
	    if (timeout >= 3600)
		fprintf(stderr,
			"WARNING: track timeout is an hour or more!\n");
	    break;
	case 'l':
	    for (method = methods;
		 method < methods + NITEMS(methods);
		 method++)
		(void)printf("%s: %s\n", method->name, method->description);
	    exit(0);
        case 'm':
	    minmove = (double )atoi(optarg);
	    break;
	case 'V':
	    (void)fprintf(stderr, "gpxlogger revision " REVISION "\n");
	    exit(0);
	default:
	    usage();
	    /* NOTREACHED */
	}
    }

    if (daemonize && logfile == stdout) {
	syslog(LOG_ERR, "Daemon mode with no valid logfile name - exiting.");
	exit(1);
    }

    if (optind < argc) {
	gpsd_source_spec(argv[optind], &source);
    } else
	gpsd_source_spec(NULL, &source);
#if 0
    (void)fprintf(logfile,"<!-- server: %s port: %s  device: %s -->\n",
		 source.server, source.port, source.device);
#endif

    /* initializes the some gpsdata data structure */
    gpsdata.status = STATUS_NO_FIX;
    gpsdata.satellites_used = 0;
    gps_clear_fix(&(gpsdata.fix));
    gps_clear_dop(&(gpsdata.dop));

    /* catch all interesting signals */
    (void)signal(SIGTERM, quit_handler);
    (void)signal(SIGQUIT, quit_handler);
    (void)signal(SIGINT, quit_handler);

    /*@-unrecog@*/
    /* might be time to daemonize */
    if (daemonize) {
	/* not SuS/POSIX portable, but we have our own fallback version */
	if (daemon(0, 0) != 0)
	    (void) fprintf(stderr,"demonization failed: %s\n", strerror(errno));
    }
    /*@+unrecog@*/

    //syslog (LOG_INFO, "---------- STARTED ----------");

    if (method != NULL) {
	exit((*method->method)());
    } else if (NITEMS(methods)) {
	exit((methods[0].method)());
    } else {
	(void)fprintf(stderr, "%s: no export methods.\n", progname);
	exit(1);
    }
}
Exemple #4
0
void gpsmm::enable_debug(int level, FILE *fp)
{
#ifdef CLIENTDEBUG_ENABLE
    gps_enable_debug(level, fp);
#endif /* CLIENTDEBUG_ENABLE */
}
int main(int argc, char **argv)
{
    int option, status;
    char *device = NULL, *devtype = NULL; 
    char *speed = NULL, *control = NULL, *rate = NULL;
    bool to_binary = false, to_nmea = false, reset = false; 
    bool lowlevel=false, echo=false;
    struct gps_data_t gpsdata;
    const struct gps_type_t *forcetype = NULL;
    const struct gps_type_t **dp;
    unsigned int timeout = 4;
#ifdef ALLOW_CONTROLSEND
    char cooked[BUFSIZ];
    ssize_t cooklen = 0;
#endif /* ALLOW_RECONFIGURE */

#define USAGE	"usage: gpsctl [-l] [-b | -n | -r] [-D n] [-s speed] [-c rate] [-T timeout] [-V] [-t devtype] [-x control] [-e] <device>\n"
    while ((option = getopt(argc, argv, "bec:fhlnrs:t:x:D:T:V")) != -1) {
	switch (option) {
	case 'b':		/* switch to vendor binary mode */
	    to_binary = true;
	    break;
	case 'c':
#ifdef ALLOW_RECONFIGURE
	    rate = optarg;
#else
	    gpsd_report(LOG_ERROR, "cycle-change capability has been conditioned out.\n");
#endif /* ALLOW_RECONFIGURE */
	    break;
	case 'x':		/* ship specified control string */
#ifdef ALLOW_CONTROLSEND
	    control = optarg;
	    lowlevel = true;
	    if ((cooklen = hex_escapes(cooked, control)) <= 0) {
		gpsd_report(LOG_ERROR, 
			    "invalid escape string (error %d)\n", (int)cooklen);
		exit(1);
	    }
#else
	    gpsd_report(LOG_ERROR, "control_send capability has been conditioned out.\n");	    
#endif /* ALLOW_CONTROLSEND */
	    break;
	case 'e':		/* echo specified control string with wrapper */
	    lowlevel = true;
	    echo = true;
	    break;
	case 'f':		/* force direct access to the device */
	    lowlevel = true;
	    break;
        case 'l':		/* list known device types */
	    for (dp = gpsd_drivers; *dp; dp++) {
#ifdef ALLOW_RECONFIGURE
		if ((*dp)->mode_switcher != NULL)
		    (void)fputs("-[bn]\t", stdout);
		else
		    (void)fputc('\t', stdout);
		if ((*dp)->speed_switcher != NULL)
		    (void)fputs("-s\t", stdout);
		else
		    (void)fputc('\t', stdout);
		if ((*dp)->rate_switcher != NULL)
		    (void)fputs("-c\t", stdout);
		else
		    (void)fputc('\t', stdout);
#endif /* ALLOW_RECONFIGURE */
#ifdef ALLOW_CONTROLSEND
		if ((*dp)->control_send != NULL)
		    (void)fputs("-x\t", stdout);
		else
		    (void)fputc('\t', stdout);
#endif /* ALLOW_CONTROLSEND */
		(void)puts((*dp)->type_name);
	    }
	    exit(0);
	case 'n':		/* switch to NMEA mode */
#ifdef ALLOW_RECONFIGURE
	    to_nmea = true;
#else
	    gpsd_report(LOG_ERROR, "speed-change capability has been conditioned out.\n");
#endif /* ALLOW_RECONFIGURE */
	    break;
	case 'r':		/* force-switch to default mode */
#ifdef ALLOW_RECONFIGURE
	    reset = true;
	    lowlevel = false;	/* so we'll abort if the daemon is running */
#else
	    gpsd_report(LOG_ERROR, "reset capability has been conditioned out.\n");
#endif /* ALLOW_RECONFIGURE */
	    break;
	case 's':		/* change output baud rate */
#ifdef ALLOW_RECONFIGURE
	    speed = optarg;
#else
	    gpsd_report(LOG_ERROR, "speed-change capability has been conditioned out.\n");
#endif /* ALLOW_RECONFIGURE */
	    break;
	case 't':		/* force the device type */
	    devtype = optarg;
	    break;
	case 'T':		/* set the timeout on packet recognition */
	    timeout = (unsigned)atoi(optarg);
	    break;
	case 'D':		/* set debugging level */
	    debuglevel = atoi(optarg);
	    gpsd_hexdump_level = debuglevel;
#ifdef CLIENTDEBUG_ENABLE
	    gps_enable_debug(debuglevel, stderr);
#endif /* CLIENTDEBUG_ENABLE */
	    break;
	case 'V':
	    (void)fprintf(stderr, "gpsctl: version %s (revision %s)\n",
			  VERSION, REVISION);
	    break;
	case 'h':
	default:
	    fprintf(stderr, USAGE);
	    break;
	}
    }

    if (optind < argc)
	device = argv[optind];

    if (devtype != NULL) {
	int matchcount = 0;
	for (dp = gpsd_drivers; *dp; dp++) {
	    if (strstr((*dp)->type_name, devtype) != NULL) {
		forcetype = *dp;
		matchcount++;
	    }
	}
	if (matchcount == 0)
	    gpsd_report(LOG_ERROR, "no driver type name matches '%s'.\n", devtype);
	else if (matchcount == 1) {
	    assert(forcetype != NULL);
	    gpsd_report(LOG_PROG, "%s driver selected.\n", forcetype->type_name);
	} else {
	    forcetype = NULL;
	    gpsd_report(LOG_ERROR, "%d driver type names match '%s'.\n",
			matchcount, devtype);
	}
    }    

    if ((int)to_nmea + (int)to_binary + (int)reset > 1) {
	gpsd_report(LOG_ERROR, "make up your mind, would you?\n");
	exit(0);
    }

    (void) signal(SIGINT, onsig);
    (void) signal(SIGTERM, onsig);
    (void) signal(SIGQUIT, onsig);

    /*@-nullpass@*/ /* someday, add null annotation to the gpsopen_r() params */
    if (!lowlevel) {
	/* Try to open the stream to gpsd. */
	if (gps_open_r(NULL, NULL, &gpsdata) != 0) {
	    gpsd_report(LOG_ERROR, "no gpsd running or network error: %s.\n", 
			netlib_errstr(errno));
	    lowlevel = true;
	}
    }
    /*@-nullpass@*/

    /* ^ someday, add out annotation to the gpspoll() param  and remove */
    if (!lowlevel) {
	/* OK, there's a daemon instance running.  Do things the easy way */
	struct devconfig_t *devlistp;
	(void)gps_read(&gpsdata);
	if ((gpsdata.set & DEVICELIST_SET) != 0) {
	    gpsd_report(LOG_ERROR, "no VERSION response received; update your gpsd.\n"); 
	    (void)gps_close(&gpsdata);
	    exit(1);
	}
	(void)gps_query(&gpsdata, "?DEVICES;\n");
	if ((gpsdata.set & DEVICELIST_SET) == 0) {
	    gpsd_report(LOG_ERROR, "no DEVICES response received.\n"); 
	    (void)gps_close(&gpsdata);
	    exit(1);
	}

	if (gpsdata.devices.ndevices == 0) {
	    gpsd_report(LOG_ERROR, "no devices connected.\n"); 
	    (void)gps_close(&gpsdata);
	    exit(1);
	} else if (gpsdata.devices.ndevices > 1 && device == NULL) {
	    gpsd_report(LOG_ERROR, 
			"multiple devices and no device specified.\n");
	    (void)gps_close(&gpsdata);
	    exit(1);
	}
	gpsd_report(LOG_PROG,"%d device(s) found.\n",gpsdata.devices.ndevices);

	if (gpsdata.devices.ndevices == 1) {
	    devlistp = &gpsdata.devices.list[0];
	    device = devlistp->path;
	} else {
	    int i;
	    assert(device != NULL);
	    for (i = 0; i < gpsdata.devices.ndevices; i++)
		if (strcmp(device, gpsdata.devices.list[i].path) == 0)
		    goto foundit;
	    gpsd_report(LOG_ERROR, "specified device not found.\n");
	    (void)gps_close(&gpsdata);
	    exit(1);
	foundit:
	    devlistp = &gpsdata.devices.list[i];
	}

	/* if no control operation was specified, just ID the device */
	if (speed==NULL && rate == NULL && !to_nmea && !to_binary && !reset) {
	    gpsd_report(LOG_SHOUT, "%s identified as %s at %d\n",
			devlistp->path, devlistp->driver, devlistp->baudrate);
	    exit(0);
	}

	status = 0;
#ifdef ALLOW_RECONFIGURE
	if (reset)
	{
	    gpsd_report(LOG_PROG, "cannot reset with gpsd running.\n");
	    exit(0);
	}

	/*@-boolops@*/
	if (to_nmea) {
	    (void)gps_query(&gpsdata, "?DEVICE={\"path\":\"%s\",\"native\":0}\r\n", device); 
	    if ((gpsdata.set & ERROR_SET) || (gpsdata.dev.driver_mode != MODE_NMEA)) {
		gpsd_report(LOG_ERROR, "%s mode change to NMEA failed\n", gpsdata.dev.path);
		status = 1;
	    } else
		gpsd_report(LOG_PROG, "%s mode change succeeded\n", gpsdata.dev.path);
	}
	else if (to_binary) {
	    (void)gps_query(&gpsdata, "?DEVICE={\"path\":\"%s\",\"native\":1}\r\n", device);
	    if ((gpsdata.set & ERROR_SET) || (gpsdata.dev.driver_mode != MODE_BINARY)) {
		gpsd_report(LOG_ERROR, "%s mode change to native mode failed\n", gpsdata.dev.path);
		status = 1;
	    } else
		gpsd_report(LOG_PROG, "%s mode change succeeded\n", gpsdata.dev.path);
	}
	/*@+boolops@*/
	if (speed != NULL) {
	    char parity = 'N';
	    char stopbits = '1';
	    if (strchr(speed, ':') == NULL)
		(void)gps_query(&gpsdata,
				"?DEVICE={\"path\":\"%s\",\"bps\":%s}\r\n", 
				device, speed);
	    else {
		char *modespec = strchr(speed, ':');
		/*@ +charint @*/
		status = 0;
		if (modespec!=NULL) {
		    *modespec = '\0';
		    if (strchr("78", *++modespec) == NULL) {
			gpsd_report(LOG_ERROR, "No support for that word lengths.\n");
			status = 1;
		    }
		    parity = *++modespec;
		    if (strchr("NOE", parity) == NULL) {
			gpsd_report(LOG_ERROR, "What parity is '%c'?\n", parity);
			status = 1;
		    }
		    stopbits = *++modespec;
		    if (strchr("12", stopbits) == NULL) {
			gpsd_report(LOG_ERROR, "Stop bits must be 1 or 2.\n");
			status = 1;
		    }
		}
		if (status == 0)
		    (void)gps_query(&gpsdata, 
				    "?DEVICE={\"path\":\"%s\",\"bps\":%s,\"parity\":\"%c\",\"stopbits\":%c}\r\n", 
				    device, speed, parity, stopbits);
	    }
	    if (atoi(speed) != (int)gpsdata.dev.baudrate) {
		gpsd_report(LOG_ERROR, "%s driver won't support %s%c%c\n", 
			    gpsdata.dev.path,
			    speed, parity, stopbits);
		status = 1;
	    } else
		gpsd_report(LOG_PROG, "%s change to %s%c%c succeeded\n", 
			    gpsdata.dev.path,
			    speed, parity, stopbits);
	}
	if (rate != NULL) {
	    (void)gps_query(&gpsdata, 
			    "?DEVICE={\"path\":\"%s\",\"cycle\":%s}\n", 
			    device, rate);
	}
#endif /* ALLOW_RECONFIGURE */
	(void)gps_close(&gpsdata);
	exit(status);
#ifdef ALLOW_RECONFIGURE
    } else if (reset) {
	/* hard reset will go through lower-level operations */
	const int speeds[] = {2400, 4800, 9600, 19200, 38400, 57600, 115200};
	static struct gps_context_t	context;	/* start it zeroed */
	static struct gps_device_t	session;	/* zero this too */
	int i;

	if (device == NULL || forcetype == NULL) {
		gpsd_report(LOG_ERROR, "device and type must be specified for the reset operation.\n");
		exit(1);
	    }

	/*@ -mustfreeonly -immediatetrans @*/
	session.context = &context;
	gpsd_tty_init(&session);
	(void)strlcpy(session.gpsdata.dev.path, device, sizeof(session.gpsdata.dev.path));
	session.device_type = forcetype;
	(void)gpsd_open(&session);
	(void)gpsd_set_raw(&session);
	(void)session.device_type->speed_switcher(&session, 4800, 'N', 1);
	(void)tcdrain(session.gpsdata.gps_fd);
	for(i = 0; i < (int)(sizeof(speeds) / sizeof(speeds[0])); i++) {
	    (void)gpsd_set_speed(&session, speeds[i], 'N', 1);
	    (void)session.device_type->speed_switcher(&session, 4800, 'N', 1);
	    (void)tcdrain(session.gpsdata.gps_fd);
	}
	gpsd_set_speed(&session, 4800, 'N', 1);
	for (i = 0; i < 3; i++)
	    if (session.device_type->mode_switcher)
		session.device_type->mode_switcher(&session, MODE_NMEA);
	gpsd_wrap(&session);
	exit(0);
	/*@ +mustfreeonly +immediatetrans @*/
#endif /* ALLOW_RECONFIGURE */
    } else {
	/* access to the daemon failed, use the low-level facilities */
	static struct gps_context_t	context;	/* start it zeroed */
	static struct gps_device_t	session;	/* zero this too */
	/*@ -mustfreeonly -immediatetrans @*/
	session.context = &context;	/* in case gps_init isn't called */

	if (echo)
	    context.readonly = true;

	(void) alarm(timeout);
	(void) signal(SIGALRM, onsig);
	/*
	 * Unless the user has forced a type and only wants to see the
	 * string (not send it) we now need to try to open the device
	 * and find out what is actually there.
	 */
	if (!(forcetype != NULL && echo)) {
	    int seq;

	    if (device == NULL) {
		gpsd_report(LOG_ERROR, "device must be specified for low-level access.\n");
		exit(1);
	    }
	    gpsd_init(&session, &context, device);
	    gpsd_report(LOG_PROG, "initialization passed.\n");
	    if (gpsd_activate(&session) == -1) {
		gpsd_report(LOG_ERROR,
			      "activation of device %s failed, errno=%d\n",
			      device, errno);
		exit(2);
	    }
	    /* hunt for packet type and serial parameters */
	    for (seq = 0; session.device_type == NULL; seq++) {
		if (get_packet(&session) == ERROR_SET) {
		    gpsd_report(LOG_ERROR,
				"autodetection failed.\n");
		    exit(2);
		} else {
		    gpsd_report(LOG_IO,
				"autodetection after %d reads.\n", seq);
		    (void) alarm(0);
		    break;
		}
	    }
	    gpsd_report(LOG_PROG, "%s looks like a %s at %d.\n",
			device, gpsd_id(&session), session.gpsdata.dev.baudrate);

	    if (forcetype!=NULL && strcmp("Generic NMEA", session.device_type->type_name) !=0 && strcmp(forcetype->type_name, session.device_type->type_name)!=0) {
		gpsd_report(LOG_ERROR, "'%s' doesn't match non-generic type '%s' of selected device.\n", forcetype->type_name, session.device_type->type_name);
	    }

	    /* 
	     * If we've identified this as an NMEA device, we have to eat
	     * packets for a while to see if one of our probes elicits an
	     * ID response telling us that it's really a SiRF or
	     * something.  If so, the libgpsd(3) layer will automatically
	     * redispatch to the correct driver type.
	     */
	    if (strcmp(session.device_type->type_name, "Generic NMEA") == 0) {
		int dummy;
		for (dummy = 0; dummy < REDIRECT_SNIFF; dummy++) {
		    if ((get_packet(&session) & DEVICEID_SET)!=0)
			break;
		}
	    }
	    gpsd_report(LOG_SHOUT, "%s identified as a %s at %d.\n",
			device, gpsd_id(&session), session.gpsdata.dev.baudrate);
	}

	/* if no control operation was specified, we're done */
	if (speed==NULL && !to_nmea && !to_binary && control==NULL)
	    exit(0);

	/* maybe user wants to see the packet rather than send it */
	if (echo)
	    session.gpsdata.gps_fd = fileno(stdout);

	/* control op specified; maybe we forced the type */
	if (forcetype != NULL)
	    (void)gpsd_switch_driver(&session, forcetype->type_name);

	/* now perform the actual control function */
	status = 0;
#ifdef ALLOW_RECONFIGURE
	/*@ -nullderef @*/
	if (to_nmea || to_binary) {
	    if (session.device_type->mode_switcher == NULL) {
		gpsd_report(LOG_SHOUT, 
			      "%s devices have no mode switch.\n",
			      session.device_type->type_name);
		status = 1;
	    } else {
		int target_mode = to_nmea ? MODE_NMEA : MODE_BINARY;
		int target_type = to_nmea ? NMEA_PACKET : session.device_type->packet_type;

		gpsd_report(LOG_SHOUT, 
			      "switching to mode %s.\n",
			    to_nmea ? "NMEA" : "BINARY");
		session.device_type->mode_switcher(&session, target_mode);


		/* 
		 * Hunt for packet type again (mode might have
		 * changed).  We've found by experiment that you can't
		 * close the connection to the device after a mode
		 * change but before you see a packet of the right
		 * type come back from it - otherwise you can hit a
		 * timing window where the mode-change control message
		 * gets ignored or flushed.
		 */
		if (!echo) {
		    /* suppresses probing for subtypes */
		    context.readonly = true;
		    (void)sleep(1);
		    (void) alarm(timeout);
		    for (;;) {
			if (get_packet(&session) == ERROR_SET) {
			    continue;
			} else if (session.packet.type == target_type) {
			    (void)alarm(0);
			    break;
			}
		    }
		    context.readonly = false;
		}
		/*@ -nullpass @*/
		gpsd_report(LOG_SHOUT, "after mode change, %s looks like a %s at %d.\n",
			    device, gpsd_id(&session), session.gpsdata.dev.baudrate);
		/*@ +nullpass @*/
	    }
	}
	if (speed) {
	    char parity = echo ? 'N': session.gpsdata.dev.parity;
	    int stopbits = echo ? 1 : session.gpsdata.dev.stopbits;
	    char *modespec;

	    modespec = strchr(speed, ':');
	    /*@ +charint @*/
	    status = 0;
	    if (modespec!=NULL) {
		*modespec = '\0';
		if (strchr("78", *++modespec) == NULL) {
		    gpsd_report(LOG_ERROR, "No support for that word lengths.\n");
		    status = 1;
		}
		parity = *++modespec;
		if (strchr("NOE", parity) == NULL) {
		    gpsd_report(LOG_ERROR, "What parity is '%c'?\n", parity);
		    status = 1;
		}
		stopbits = *++modespec;
		if (strchr("12", parity) == NULL) {
		    gpsd_report(LOG_ERROR, "Stop bits must be 1 or 2.\n");
		    status = 1;
		}
		stopbits = (int)(stopbits-'0');
	    }
	    if (status == 0) {
		if (session.device_type->speed_switcher == NULL) {
		    gpsd_report(LOG_ERROR, 
				"%s devices have no speed switch.\n",
				session.device_type->type_name);
		    status = 1;
		}
		else if (session.device_type->speed_switcher(&session, 
							     (speed_t)atoi(speed),
							     parity, 
							     stopbits)) {
		    /*
		     * See the 'deep black magic' comment in
		     * gpsd.c:set_serial() Probably not needed here,
		     * but it can't hurt.
		     */
		    (void)tcdrain(session.gpsdata.gps_fd);
		    (void)usleep(50000);
		    gpsd_report(LOG_PROG, "%s change to %s%c%d succeeded\n", 
			    session.gpsdata.dev.path,
			    speed, parity, stopbits);
		} else {
		    gpsd_report(LOG_ERROR, "%s driver won't support %s%c%d.\n",
				session.gpsdata.dev.path,
				speed, parity, stopbits);
		    status = 1;
		}
	    }
	}
	if (rate) {
	    bool write_enable = context.readonly;
	    context.readonly = false;
	    if (session.device_type->rate_switcher == NULL) {
		gpsd_report(LOG_ERROR, 
			      "%s devices have no rate switcher.\n",
			      session.device_type->type_name);
		status = 1;
	    } else {
		double rate_dbl = strtod(rate, NULL);

		if (!session.device_type->rate_switcher(&session, rate_dbl)) {
		    gpsd_report(LOG_ERROR, "rate switch failed.\n");
		    status = 1;
		}
	    }
	    context.readonly = write_enable;
	}
#endif /* ALLOW_RECONFIGURE */
#ifdef ALLOW_CONTROLSEND
	/*@ -compdef @*/
	if (control) {
	    bool write_enable = context.readonly;
	    context.readonly = false;
	    if (session.device_type->control_send == NULL) {
		gpsd_report(LOG_ERROR, 
			      "%s devices have no control sender.\n",
			      session.device_type->type_name);
		status = 1;
	    } else {
		if (session.device_type->control_send(&session, 
						      cooked, 
						      (size_t)cooklen) == -1) {
		    gpsd_report(LOG_ERROR, "control transmission failed.\n");
		    status = 1;
		}
	    }
	    context.readonly = write_enable;
	}
	/*@ +compdef @*/
#endif /* ALLOW_CONTROLSEND */

	if (forcetype == NULL || !echo) {
	    /*
	     * Give the device time to settle before closing it.  Alas, this is
	     * voodoo programming; we don't know it will have any effect, but
	     * GPSes are notoriously prone to timing-dependent errors.
	     */
	    (void)usleep(300000);

	    gpsd_wrap(&session);
	}
	exit(status);
	/*@ +nullderef @*/
	/*@ +mustfreeonly +immediatetrans @*/
    }
}
Exemple #6
0
int main(int argc, char **argv)
{
    char buf[4096];
    bool timestamp = false;
    char *format = "%F %T";
    char tmstr[200];
    bool daemonize = false;
    bool binary = false;
    bool sleepy = false;
    bool new_line = true;
    bool raw = false;
    bool watch = false;
    bool profile = false;
    int option_u = 0;                   // option to show uSeconds
    long count = -1;
    int option;
    unsigned int vflag = 0, l = 0;
    FILE *fp;
    unsigned int flags;
    fd_set fds;

    struct fixsource_t source;
    char *serialport = NULL;
    char *outfile = NULL;

    flags = WATCH_ENABLE;
    while ((option = getopt(argc, argv, "?dD:lhrRwStT:vVn:s:o:pPu2")) != -1) {
	switch (option) {
	case 'D':
	    debug = atoi(optarg);
#ifdef CLIENTDEBUG_ENABLE
	    gps_enable_debug(debug, stderr);
#endif /* CLIENTDEBUG_ENABLE */
	    break;
	case 'n':
	    count = strtol(optarg, 0, 0);
	    break;
	case 'r':
	    raw = true;
	    /*
	     * Yes, -r invokes NMEA mode rather than proper raw mode.
	     * This emulates the behavior under the old protocol.
	     */
	    flags |= WATCH_NMEA;
	    break;
	case 'R':
	    flags |= WATCH_RAW;
	    binary = true;
	    break;
	case 'd':
	    daemonize = true;
	    break;
	case 'l':
	    sleepy = true;
	    break;
	case 't':
	    timestamp = true;
	    break;
	case 'T':
	    timestamp = true;
	    format = optarg;
	    break;
	case 'u':
	    timestamp = true;
	    option_u++;
	    break;
	case 'v':
	    vflag++;
	    break;
	case 'w':
	    flags |= WATCH_JSON;
	    watch = true;
	    break;
	case 'S':
	    flags |= WATCH_SCALED;
	    break;
	case 'p':
	    profile = true;
	    break;
	case 'P':
	    flags |= WATCH_PPS;
	    break;
	case 'V':
	    (void)fprintf(stderr, "%s: %s (revision %s)\n",
			  argv[0], VERSION, REVISION);
	    exit(EXIT_SUCCESS);
	case 's':
	    serialport = optarg;
	    break;
	case 'o':
	    outfile = optarg;
	    break;
	case '2':
	    flags |= WATCH_SPLIT24;
	    break;
	case '?':
	case 'h':
	default:
	    usage();
	    exit(EXIT_FAILURE);
	}
    }

    /* Grok the server, port, and device. */
    if (optind < argc) {
	gpsd_source_spec(argv[optind], &source);
    } else
	gpsd_source_spec(NULL, &source);

    if (serialport != NULL && !raw) {
	(void)fprintf(stderr, "gpspipe: use of '-s' requires '-r'.\n");
	exit(EXIT_FAILURE);
    }

    if (outfile == NULL && daemonize) {
	(void)fprintf(stderr, "gpspipe: use of '-d' requires '-o'.\n");
	exit(EXIT_FAILURE);
    }

    if (!raw && !watch && !binary) {
	(void)fprintf(stderr,
		      "gpspipe: one of '-R', '-r', or '-w' is required.\n");
	exit(EXIT_FAILURE);
    }

    /* Daemonize if the user requested it. */
    if (daemonize)
	if (daemon(0, 0) != 0)
	    (void)fprintf(stderr,
			  "gpspipe: demonization failed: %s\n",
			  strerror(errno));

    /* Sleep for ten seconds if the user requested it. */
    if (sleepy)
	(void)sleep(10);

    /* Open the output file if the user requested it.  If the user
     * requested '-R', we use the 'b' flag in fopen() to "do the right
     * thing" in non-linux/unix OSes. */
    if (outfile == NULL) {
	fp = stdout;
    } else {
	if (binary)
	    fp = fopen(outfile, "wb");
	else
	    fp = fopen(outfile, "w");

	if (fp == NULL) {
	    (void)fprintf(stderr,
			  "gpspipe: unable to open output file:  %s\n",
			  outfile);
	    exit(EXIT_FAILURE);
	}
    }

    /* Open the serial port and set it up. */
    if (serialport)
	open_serial(serialport);

    if (gps_open(source.server, source.port, &gpsdata) != 0) {
	(void)fprintf(stderr,
		      "gpspipe: could not connect to gpsd %s:%s, %s(%d)\n",
		      source.server, source.port, gps_errstr(errno), errno);
	exit(EXIT_FAILURE);
    }

    if (profile)
	flags |= WATCH_TIMING;
    if (source.device != NULL)
	flags |= WATCH_DEVICE;
    (void)gps_stream(&gpsdata, flags, source.device);

    if ((isatty(STDERR_FILENO) == 0) || daemonize)
	vflag = 0;

    for (;;) {
	int r = 0;
	struct timeval tv;

	tv.tv_sec = 0;
	tv.tv_usec = 100000;
	FD_ZERO(&fds);
	FD_SET(gpsdata.gps_fd, &fds);
	errno = 0;
	r = select(gpsdata.gps_fd+1, &fds, NULL, NULL, &tv);
	if (r == -1 && errno != EINTR) {
	    (void)fprintf(stderr, "gpspipe: select error %s(%d)\n",
			  strerror(errno), errno);
	    exit(EXIT_FAILURE);
	} else if (r == 0)
		continue;

	if (vflag)
	    spinner(vflag, l++);

	/* reading directly from the socket avoids decode overhead */
	errno = 0;
	r = (int)read(gpsdata.gps_fd, buf, sizeof(buf));
	if (r > 0) {
	    int i = 0;
	    int j = 0;
	    for (i = 0; i < r; i++) {
		char c = buf[i];
		if (j < (int)(sizeof(serbuf) - 1)) {
		    serbuf[j++] = buf[i];
		}
		if (new_line && timestamp) {
		    char tmstr_u[20];            // time with "usec" resolution
		    struct timespec now;
		    struct tm *tmp_now;

		    (void)clock_gettime(CLOCK_REALTIME, &now);
		    tmp_now = localtime((time_t *)&(now.tv_sec));
		    (void)strftime(tmstr, sizeof(tmstr), format, tmp_now);
		    new_line = 0;

		    switch( option_u ) {
		    case 2:
			(void)snprintf(tmstr_u, sizeof(tmstr_u),
				       " %ld.%06ld",
				       (long)now.tv_sec,
				       (long)now.tv_nsec/1000);
			break;
		    case 1:
			(void)snprintf(tmstr_u, sizeof(tmstr_u),
				       ".%06ld", (long)now.tv_nsec/1000);
			break;
		    default:
			*tmstr_u = '\0';
			break;
		    }

		    if (fprintf(fp, "%.24s%s: ", tmstr, tmstr_u) <= 0) {
			(void)fprintf(stderr,
				      "gpspipe: write error, %s(%d)\n",
				      strerror(errno), errno);
			exit(EXIT_FAILURE);
		    }
		}
		if (fputc(c, fp) == EOF) {
		    fprintf(stderr, "gpspipe: write error, %s(%d)\n",
			    strerror(errno), errno);
		    exit(EXIT_FAILURE);
		}

		if (c == '\n') {
		    if (serialport != NULL) {
			if (write(fd_out, serbuf, (size_t) j) == -1) {
			    fprintf(stderr,
				    "gpspipe: serial port write error, %s(%d)\n",
				    strerror(errno), errno);
			    exit(EXIT_FAILURE);
			}
			j = 0;
		    }

		    new_line = true;
		    /* flush after every good line */
		    if (fflush(fp)) {
			(void)fprintf(stderr,
				      "gpspipe: fflush error, %s(%d)\n",
				      strerror(errno), errno);
			exit(EXIT_FAILURE);
		    }
		    if (count > 0) {
			if (0 >= --count) {
			    /* completed count */
			    exit(EXIT_SUCCESS);
			}
		    }
		}
	    }
	} else {
	    if (r == -1) {
		if (errno == EAGAIN)
		    continue;
		else
		    (void)fprintf(stderr, "gpspipe: read error %s(%d)\n",
			      strerror(errno), errno);
		exit(EXIT_FAILURE);
	    } else {
		exit(EXIT_SUCCESS);
	    }
	}
    }

#ifdef __UNUSED__
    if (serialport != NULL) {
	/* Restore the old serial port settings. */
	if (tcsetattr(fd_out, TCSANOW, &oldtio) != 0) {
	    (void)fprintf(stderr, "gpsipe: error restoring serial port settings\n");
	    exit(EXIT_FAILURE);
	}
    }
#endif /* __UNUSED__ */

    exit(EXIT_SUCCESS);
}
Exemple #7
0
int main(int argc, char *argv[])
{
    struct gps_data_t collect;
    char buf[BUFSIZ];
    int option;
    bool batchmode = false;
    int debug = 0;

    (void)signal(SIGSEGV, onsig);
    (void)signal(SIGBUS, onsig);

    while ((option = getopt(argc, argv, "bhsD:?")) != -1) {
	switch (option) {
	case 'b':
	    batchmode = true;
	    break;
	case 's':
	    (void)
		printf
		("Sizes: fix=%zd gpsdata=%zd rtcm2=%zd rtcm3=%zd ais=%zd compass=%zd raw=%zd devices=%zd policy=%zd version=%zd, noise=%zd\n",
		 sizeof(struct gps_fix_t),
		 sizeof(struct gps_data_t), sizeof(struct rtcm2_t),
		 sizeof(struct rtcm3_t), sizeof(struct ais_t),
		 sizeof(struct attitude_t), sizeof(struct rawdata_t),
		 sizeof(collect.devices), sizeof(struct policy_t),
		 sizeof(struct version_t), sizeof(struct gst_t));
	    exit(EXIT_SUCCESS);
	case 'D':
	    debug = atoi(optarg);
	    break;
	case '?':
	case 'h':
	default:
	    (void)fputs("usage: test_libgps [-b] [-D lvl] [-s]\n", stderr);
	    exit(EXIT_FAILURE);
	}
    }

    gps_enable_debug(debug, stdout);
    if (batchmode) {
	while (fgets(buf, sizeof(buf), stdin) != NULL) {
	    if (buf[0] == '{' || isalpha(buf[0])) {
		gps_unpack(buf, &gpsdata);
		libgps_dump_state(&gpsdata);
	    }
	}
    } else if (gps_open(NULL, 0, &collect) <= 0) {
	(void)fputs("Daemon is not running.\n", stdout);
	exit(EXIT_FAILURE);
    } else if (optind < argc) {
	(void)strlcpy(buf, argv[optind], BUFSIZ);
	(void)strlcat(buf, "\n", BUFSIZ);
	(void)gps_send(&collect, buf);
	(void)gps_read(&collect);
	libgps_dump_state(&collect);
	(void)gps_close(&collect);
    } else {
	int tty = isatty(0);

	if (tty)
	    (void)fputs("This is the gpsd exerciser.\n", stdout);
	for (;;) {
	    if (tty)
		(void)fputs("> ", stdout);
	    if (fgets(buf, sizeof(buf), stdin) == NULL) {
		if (tty)
		    putchar('\n');
		break;
	    }
	    collect.set = 0;
	    (void)gps_send(&collect, buf);
	    (void)gps_read(&collect);
	    libgps_dump_state(&collect);
	}
	(void)gps_close(&collect);
    }

    return 0;
}
Exemple #8
0
int main(int argc, char *argv[])
{
    int option;
    unsigned int flags = WATCH_ENABLE;

    /*@ -observertrans @*/
    switch (gpsd_units()) {
    case imperial:
	altfactor = METERS_TO_FEET;
	altunits = "ft";
	speedfactor = MPS_TO_MPH;
	speedunits = "mph";
	break;
    case nautical:
	altfactor = METERS_TO_FEET;
	altunits = "ft";
	speedfactor = MPS_TO_KNOTS;
	speedunits = "knots";
	break;
    case metric:
	altfactor = 1;
	altunits = "m";
	speedfactor = MPS_TO_KPH;
	speedunits = "kph";
	break;
    default:
	/* leave the default alone */
	break;
    }
    /*@ +observertrans @*/

    /* Process the options.  Print help if requested. */
    while ((option = getopt(argc, argv, "hVl:smu:D:")) != -1) {
	switch (option) {
#ifdef CLIENTDEBUG_ENABLE
	case 'D':
	    debug = atoi(optarg);
	    gps_enable_debug(debug, stderr);
	    break;
#endif /* CLIENTDEBUG_ENABLE */
	case 'm':
	    magnetic_flag = true;
	    break;
	case 's':
	    silent_flag = true;
	    break;
	case 'u':
	    /*@ -observertrans @*/
	    switch (optarg[0]) {
	    case 'i':
		altfactor = METERS_TO_FEET;
		altunits = "ft";
		speedfactor = MPS_TO_MPH;
		speedunits = "mph";
		continue;
	    case 'n':
		altfactor = METERS_TO_FEET;
		altunits = "ft";
		speedfactor = MPS_TO_KNOTS;
		speedunits = "knots";
		continue;
	    case 'm':
		altfactor = 1;
		altunits = "m";
		speedfactor = MPS_TO_KPH;
		speedunits = "kph";
		continue;
	    default:
		(void)fprintf(stderr, "Unknown -u argument: %s\n", optarg);
	    }
	    break;
	    /*@ +observertrans @*/
	case 'V':
	    (void)fprintf(stderr, "cgps: %s (revision %s)\n",
			  VERSION, REVISION);
	    exit(EXIT_SUCCESS);
	case 'l':
	    switch (optarg[0]) {
	    case 'd':
		deg_type = deg_dd;
		continue;
	    case 'm':
		deg_type = deg_ddmm;
		continue;
	    case 's':
		deg_type = deg_ddmmss;
		continue;
	    default:
		(void)fprintf(stderr, "Unknown -l argument: %s\n", optarg);
		/*@ -casebreak @*/
	    }
	    break;
	case 'h':
	default:
	    usage(argv[0]);
	    break;
	}
    }

    /* Grok the server, port, and device. */
    if (optind < argc) {
	gpsd_source_spec(argv[optind], &source);
    } else
	gpsd_source_spec(NULL, &source);

    /* Open the stream to gpsd. */
    if (gps_open(source.server, source.port, &gpsdata) != 0) {
	(void)fprintf(stderr,
		      "cgps: no gpsd running or network error: %d, %s\n",
		      errno, gps_errstr(errno));
	exit(EXIT_FAILURE);
    }

    /* note: we're assuming BSD-style reliable signals here */
    (void)signal(SIGINT, die);
    (void)signal(SIGHUP, die);
    (void)signal(SIGWINCH, resize);

    windowsetup();

    status_timer = time(NULL);

    if (source.device != NULL)
	flags |= WATCH_DEVICE;
    (void)gps_stream(&gpsdata, flags, source.device);

    /* heart of the client */
    for (;;) {
	int c;

	if (!gps_waiting(&gpsdata, 5000000)) {
	    die(GPS_TIMEOUT);
	} else {
	    errno = 0;
	    if (gps_read(&gpsdata) == -1) {
		fprintf(stderr, "cgps: socket error 4\n");
		die(errno == 0 ? GPS_GONE : GPS_ERROR);
	    } else {
		/* Here's where updates go now that things are established. */
#ifdef TRUENORTH
		if (compass_flag)
		    update_compass_panel(&gpsdata);
		else
#endif /* TRUENORTH */
		    update_gps_panel(&gpsdata);
	    }
	}

	/* Check for user input. */
	c = wgetch(datawin);

	switch (c) {
	    /* Quit */
	case 'q':
	    die(CGPS_QUIT);
	    break;

	    /* Toggle spewage of raw gpsd data. */
	case 's':
	    silent_flag = !silent_flag;
	    break;

	    /* Clear the spewage area. */
	case 'c':
	    (void)werase(messages);
	    break;

	default:
	    break;
	}
    }
}
Exemple #9
0
static bool gps_query(/*@out@*/struct gps_data_t *gpsdata,
		       gps_mask_t expect,
		       const int timeout,
		       const char *fmt, ... )
/* ship a command and wait on an expected response type */
{
    static fd_set rfds;
    char buf[BUFSIZ];
    va_list ap;
    time_t starttime;
#ifdef COMPAT_SELECT
    struct timeval tv;
#else
    struct timespec tv;
    sigset_t oldset, blockset;

    (void)sigemptyset(&blockset);
    (void)sigaddset(&blockset, SIGHUP);
    (void)sigaddset(&blockset, SIGINT);
    (void)sigaddset(&blockset, SIGTERM);
    (void)sigaddset(&blockset, SIGQUIT);
    (void)sigprocmask(SIG_BLOCK, &blockset, &oldset);
#endif /* COMPAT_SELECT */

    va_start(ap, fmt);
    (void)vsnprintf(buf, sizeof(buf)-2, fmt, ap);
    va_end(ap);
    if (buf[strlen(buf)-1] != '\n')
	(void)strlcat(buf, "\n", BUFSIZ);
    /*@-usedef@*/
    if (write(gpsdata->gps_fd, buf, strlen(buf)) <= 0) {
	gpsd_report(&context.errout, LOG_ERROR, "gps_query(), write failed\n");
	return false;
    }
    /*@+usedef@*/
    gpsd_report(&context.errout, LOG_PROG, "gps_query(), wrote, %s\n", buf);

    FD_ZERO(&rfds);
    starttime = time(NULL);
    for (;;) {
	FD_CLR(gpsdata->gps_fd, &rfds);

	gpsd_report(&context.errout, LOG_PROG, "waiting...\n");

	/*@ -usedef -type -nullpass -compdef @*/
	tv.tv_sec = 2;
#ifdef COMPAT_SELECT
	tv.tv_usec = 0;
	if (select(gpsdata->gps_fd + 1, &rfds, NULL, NULL, &tv) == -1) {
#else
	tv.tv_nsec = 0;
	if (pselect(gpsdata->gps_fd + 1, &rfds, NULL, NULL, &tv, &oldset) == -1) {
#endif
	    if (errno == EINTR || !FD_ISSET(gpsdata->gps_fd, &rfds))
		continue;
	    gpsd_report(&context.errout, LOG_ERROR, "select %s\n", strerror(errno));
	    exit(EXIT_FAILURE);
	}
	/*@ +usedef +type +nullpass +compdef @*/

	gpsd_report(&context.errout, LOG_PROG, "reading...\n");

	(void)gps_read(gpsdata);
	if (ERROR_SET & gpsdata->set) {
	    gpsd_report(&context.errout, LOG_ERROR, "error '%s'\n", gpsdata->error);
	    return false;
	}

	/*@ +ignorequals @*/
	if ((expect == NON_ERROR) || (expect & gpsdata->set) != 0)
	    return true;
	else if (timeout > 0 && (time(NULL) - starttime > timeout)) {
	    gpsd_report(&context.errout, LOG_ERROR,
			"timed out after %d seconds\n",
			timeout);
	    return false;
	}
	/*@ -ignorequals @*/
    }

    return false;
}

static void onsig(int sig)
{
    if (sig == SIGALRM) {
	gpsd_report(&context.errout, LOG_ERROR, "packet recognition timed out.\n");
	exit(EXIT_FAILURE);
    } else {
	gpsd_report(&context.errout, LOG_ERROR, "killed by signal %d\n", sig);
	exit(EXIT_SUCCESS);
    }
}

static char /*@observer@*/ *gpsd_id( /*@in@ */ struct gps_device_t *session)
/* full ID of the device for reports, including subtype */
{
    static char buf[128];
    if ((session == NULL) || (session->device_type == NULL) ||
	(session->device_type->type_name == NULL))
	return "unknown,";
    (void)strlcpy(buf, session->device_type->type_name, sizeof(buf));
    if (session->subtype[0] != '\0') {
	(void)strlcat(buf, " ", sizeof(buf));
	(void)strlcat(buf, session->subtype, sizeof(buf));
    }
    return (buf);
}

static void ctlhook(struct gps_device_t *device UNUSED, gps_mask_t changed UNUSED)
/* recognize when we've achieved sync */
{
    static int packet_counter = 0;

    /*
     * If it's NMEA, go back around enough times for the type probes to
     * reveal any secret identity (like SiRF or UBX) the chip might have.
     * If it's not, getting more packets might fetch subtype information.
     */
    if (packet_counter++ >= REDIRECT_SNIFF)
    {
	hunting = false;
	(void) alarm(0);
    }
}

int main(int argc, char **argv)
{
    int option, status;
    char *device = NULL, *devtype = NULL;
    char *speed = NULL, *control = NULL, *rate = NULL;
    bool to_binary = false, to_nmea = false, reset = false;
    bool lowlevel=false, echo=false;
    struct gps_data_t gpsdata;
    const struct gps_type_t *forcetype = NULL;
    const struct gps_type_t **dp;
#ifdef CONTROLSEND_ENABLE
    char cooked[BUFSIZ];
    ssize_t cooklen = 0;
#endif /* RECONFIGURE_ENABLE */

    context.errout.label = "gpsctl";

#define USAGE	"usage: gpsctl [-l] [-b | -n | -r] [-D n] [-s speed] [-c rate] [-T timeout] [-V] [-t devtype] [-x control] [-e] <device>\n"
    while ((option = getopt(argc, argv, "bec:fhlnrs:t:x:D:T:V")) != -1) {
	switch (option) {
	case 'b':		/* switch to vendor binary mode */
	    to_binary = true;
	    break;
	case 'c':
#ifdef RECONFIGURE_ENABLE
	    rate = optarg;
#else
	    gpsd_report(&context.errout, LOG_ERROR,
			"cycle-change capability has been conditioned out.\n");
#endif /* RECONFIGURE_ENABLE */
	    break;
	case 'x':		/* ship specified control string */
#ifdef CONTROLSEND_ENABLE
	    control = optarg;
	    lowlevel = true;
	    if ((cooklen = hex_escapes(cooked, control)) <= 0) {
		gpsd_report(&context.errout, LOG_ERROR,
			    "invalid escape string (error %d)\n", (int)cooklen);
		exit(EXIT_FAILURE);
	    }
#else
	    gpsd_report(&context.errout, LOG_ERROR,
			"control_send capability has been conditioned out.\n");
#endif /* CONTROLSEND_ENABLE */
	    break;
	case 'e':		/* echo specified control string with wrapper */
	    lowlevel = true;
	    echo = true;
	    break;
	case 'f':		/* force direct access to the device */
	    lowlevel = true;
	    break;
        case 'l':		/* list known device types */
	    for (dp = gpsd_drivers; *dp; dp++) {
#ifdef RECONFIGURE_ENABLE
		if ((*dp)->mode_switcher != NULL)
		    (void)fputs("-[bn]\t", stdout);
		else
		    (void)fputc('\t', stdout);
		if ((*dp)->speed_switcher != NULL)
		    (void)fputs("-s\t", stdout);
		else
		    (void)fputc('\t', stdout);
		if ((*dp)->rate_switcher != NULL)
		    (void)fputs("-c\t", stdout);
		else
		    (void)fputc('\t', stdout);
#endif /* RECONFIGURE_ENABLE */
#ifdef CONTROLSEND_ENABLE
		if ((*dp)->control_send != NULL)
		    (void)fputs("-x\t", stdout);
		else
		    (void)fputc('\t', stdout);
#endif /* CONTROLSEND_ENABLE */
		(void)puts((*dp)->type_name);
	    }
	    exit(EXIT_SUCCESS);
	case 'n':		/* switch to NMEA mode */
#ifdef RECONFIGURE_ENABLE
	    to_nmea = true;
#else
	    gpsd_report(&context.errout, LOG_ERROR,
			"speed-change capability has been conditioned out.\n");
#endif /* RECONFIGURE_ENABLE */
	    break;
	case 'r':		/* force-switch to default mode */
#ifdef RECONFIGURE_ENABLE
	    reset = true;
	    lowlevel = false;	/* so we'll abort if the daemon is running */
#else
	    gpsd_report(&context.errout, LOG_ERROR,
			"reset capability has been conditioned out.\n");
#endif /* RECONFIGURE_ENABLE */
	    break;
	case 's':		/* change output baud rate */
#ifdef RECONFIGURE_ENABLE
	    speed = optarg;
#else
	    gpsd_report(&context.errout, LOG_ERROR,
			"speed-change capability has been conditioned out.\n");
#endif /* RECONFIGURE_ENABLE */
	    break;
	case 't':		/* force the device type */
	    devtype = optarg;
	    break;
	case 'T':		/* set the timeout on packet recognition */
	    timeout = (unsigned)atoi(optarg);
	    explicit_timeout = true;
	    break;
	case 'D':		/* set debugging level */
	    debuglevel = atoi(optarg);
#ifdef CLIENTDEBUG_ENABLE
	    gps_enable_debug(debuglevel, stderr);
#endif /* CLIENTDEBUG_ENABLE */
	    break;
	case 'V':
	    (void)fprintf(stderr, "version %s (revision %s)\n",
			  VERSION, REVISION);
	    exit(EXIT_SUCCESS);
	case 'h':
	default:
	    fprintf(stderr, USAGE);
	    break;
	}
    }

    if (optind < argc)
	device = argv[optind];

    if (devtype != NULL) {
	int matchcount = 0;
	for (dp = gpsd_drivers; *dp; dp++) {
	    if (strstr((*dp)->type_name, devtype) != NULL) {
		forcetype = *dp;
		matchcount++;
	    }
	}
	if (matchcount == 0)
	    gpsd_report(&context.errout, LOG_ERROR,
			"no driver type name matches '%s'.\n", devtype);
	else if (matchcount == 1) {
	    assert(forcetype != NULL);
	    gpsd_report(&context.errout, LOG_PROG,
			"%s driver selected.\n", forcetype->type_name);
	} else {
	    forcetype = NULL;
	    gpsd_report(&context.errout, LOG_ERROR,
			"%d driver type names match '%s'.\n",
			matchcount, devtype);
	}
    }

    if (((int)to_nmea + (int)to_binary + (int)reset) > 1) {
	gpsd_report(&context.errout, LOG_ERROR, "make up your mind, would you?\n");
	exit(EXIT_SUCCESS);
    }

    (void) signal(SIGINT, onsig);
    (void) signal(SIGTERM, onsig);
    (void) signal(SIGQUIT, onsig);

    /*@-nullpass@*/ /* someday, add null annotation to the gpsopen() params */
    if (!lowlevel) {
	/* Try to open the stream to gpsd. */
	if (gps_open(NULL, NULL, &gpsdata) != 0) {
	    gpsd_report(&context.errout, LOG_ERROR,
			"no gpsd running or network error: %s.\n",
			gps_errstr(errno));
	    lowlevel = true;
	}
    }
    /*@-nullpass@*/

    if (!lowlevel) {
	int i, devcount;

	if (!explicit_timeout)
	    timeout = HIGH_LEVEL_TIMEOUT;

	/* what devices have we available? */
	if (!gps_query(&gpsdata, DEVICELIST_SET, (int)timeout, "?DEVICES;\n")) {
	    gpsd_report(&context.errout, LOG_ERROR, "no DEVICES response received.\n");
	    (void)gps_close(&gpsdata);
	    exit(EXIT_FAILURE);
	}
	if (gpsdata.devices.ndevices == 0) {
	    gpsd_report(&context.errout, LOG_ERROR, "no devices connected.\n");
	    (void)gps_close(&gpsdata);
	    exit(EXIT_FAILURE);
	} else if (gpsdata.devices.ndevices > 1 && device == NULL) {
	    gpsd_report(&context.errout, LOG_ERROR,
			"multiple devices and no device specified.\n");
	    (void)gps_close(&gpsdata);
	    exit(EXIT_FAILURE);
	}
	gpsd_report(&context.errout, LOG_PROG,
		    "%d device(s) found.\n",gpsdata.devices.ndevices);

	/* try to mine the devicelist return for the data we want */
	if (gpsdata.devices.ndevices == 1 && device == NULL) {
	    device = gpsdata.dev.path;
	    i = 0;
	} else {
	    assert(device != NULL);
	    for (i = 0; i < gpsdata.devices.ndevices; i++)
		if (strcmp(device, gpsdata.devices.list[i].path) == 0) {
		    goto devicelist_entry_matches;
		}
	    gpsd_report(&context.errout, LOG_ERROR,
			"specified device not found in device list.\n");
	    (void)gps_close(&gpsdata);
	    exit(EXIT_FAILURE);
	devicelist_entry_matches:;
	}
	(void)memcpy(&gpsdata.dev,
		     &gpsdata.devices.list[i],
		     sizeof(struct devconfig_t));
	devcount = gpsdata.devices.ndevices;

	/* if the device has not identified, watch it until it does so */
	if (gpsdata.dev.driver[0] == '\0') {
	    if (gps_stream(&gpsdata, WATCH_ENABLE|WATCH_JSON, NULL) == -1) {
		gpsd_report(&context.errout, LOG_ERROR, "stream set failed.\n");
		(void)gps_close(&gpsdata);
		exit(EXIT_FAILURE);
	    }

	    while (devcount > 0) {
		errno = 0;
		if (gps_read(&gpsdata) == -1) {
		    gpsd_report(&context.errout, LOG_ERROR, "data read failed.\n");
		    (void)gps_close(&gpsdata);
		    exit(EXIT_FAILURE);
		}

		if (gpsdata.set & DEVICE_SET) {
		    --devcount;
		    assert(gpsdata.dev.path[0]!='\0' && gpsdata.dev.driver[0]!='\0');
		    if (strcmp(gpsdata.dev.path, device) == 0) {
			goto matching_device_seen;
		    }
		}
	    }
	    gpsd_report(&context.errout, LOG_ERROR, "data read failed.\n");
	    (void)gps_close(&gpsdata);
	    exit(EXIT_FAILURE);
	matching_device_seen:;
	}

	/* sanity check */
	if (gpsdata.dev.driver[0] == '\0') {
	    gpsd_report(&context.errout, LOG_SHOUT, "%s can't be identified.\n",
			gpsdata.dev.path);
	    (void)gps_close(&gpsdata);
	    exit(EXIT_SUCCESS);
	}

	/* if no control operation was specified, just ID the device */
	if (speed==NULL && rate == NULL && !to_nmea && !to_binary && !reset) {
	    (void)printf("%s identified as a %s", 
			 gpsdata.dev.path, gpsdata.dev.driver);
	    if (gpsdata.dev.subtype[0] != '\0') {
		(void)fputc(' ', stdout);
		(void)fputs(gpsdata.dev.subtype, stdout);
	    }
	    if (gpsdata.dev.baudrate > 0)
		(void)printf(" at %u baud", gpsdata.dev.baudrate);
	    (void)fputc('.', stdout);
	    (void)fputc('\n', stdout);
	}

	status = 0;
#ifdef RECONFIGURE_ENABLE
	if (reset)
	{
	    gpsd_report(&context.errout, LOG_PROG,
			"cannot reset with gpsd running.\n");
	    exit(EXIT_SUCCESS);
	}

	/*@-boolops@*/
	/*
	 * We used to wait on DEVICE_SET here.  That doesn't work
	 * anymore because when the demon generates its response it
	 * sets the mode bit in the response from the current packet
	 * type, which may not have changed (probably will not have
	 * changed) even though the command to switch modes has been
	 * sent and will shortly take effect.
	 */
	if (to_nmea) {
	    if (!gps_query(&gpsdata, NON_ERROR, (int)timeout, 
			   "?DEVICE={\"path\":\"%s\",\"native\":0}\r\n",
			   device)) {
		gpsd_report(&context.errout, LOG_ERROR,
			    "%s mode change to NMEA failed\n",
			    gpsdata.dev.path);
		status = 1;
	    } else
		gpsd_report(&context.errout, LOG_PROG,
			    "%s mode change succeeded\n", gpsdata.dev.path);
	}
	else if (to_binary) {
	    if (!gps_query(&gpsdata, NON_ERROR, (int)timeout,
			   "?DEVICE={\"path\":\"%s\",\"native\":1}\r\n",
			   device)) {
		gpsd_report(&context.errout, LOG_ERROR,
			    "%s mode change to native mode failed\n",
			    gpsdata.dev.path);
		status = 1;
	    } else
		gpsd_report(&context.errout, LOG_PROG,
			    "%s mode change succeeded\n",
			    gpsdata.dev.path);
	}
	/*@+boolops@*/
	if (speed != NULL) {
	    char parity = 'N';
	    char stopbits = '1';
	    if (strchr(speed, ':') == NULL)
		(void)gps_query(&gpsdata,
				DEVICE_SET, (int)timeout,
				 "?DEVICE={\"path\":\"%s\",\"bps\":%s}\r\n",
				 device, speed);
	    else {
		char *modespec = strchr(speed, ':');
		/*@ +charint @*/
		status = 0;
		if (modespec!=NULL) {
		    *modespec = '\0';
		    if (strchr("78", *++modespec) == NULL) {
			gpsd_report(&context.errout, LOG_ERROR,
				    "No support for that word length.\n");
			status = 1;
		    }
		    parity = *++modespec;
		    if (strchr("NOE", parity) == NULL) {
			gpsd_report(&context.errout, LOG_ERROR,
				    "What parity is '%c'?\n", parity);
			status = 1;
		    }
		    stopbits = *++modespec;
		    if (strchr("12", stopbits) == NULL) {
			gpsd_report(&context.errout, LOG_ERROR,
				    "Stop bits must be 1 or 2.\n");
			status = 1;
		    }
		}
		if (status == 0)
		    (void)gps_query(&gpsdata,
				    DEVICE_SET, (int)timeout,
				     "?DEVICE={\"path\":\"%s\",\"bps\":%s,\"parity\":\"%c\",\"stopbits\":%c}\r\n",
				     device, speed, parity, stopbits);
	    }
	    if (atoi(speed) != (int)gpsdata.dev.baudrate) {
		gpsd_report(&context.errout, LOG_ERROR,
			    "%s driver won't support %s%c%c\n",
			    gpsdata.dev.path,
			    speed, parity, stopbits);
		status = 1;
	    } else
		gpsd_report(&context.errout, LOG_PROG,
			    "%s change to %s%c%c succeeded\n",
			    gpsdata.dev.path,
			    speed, parity, stopbits);
	}
	if (rate != NULL) {
	    (void)gps_query(&gpsdata,
			    DEVICE_SET, (int)timeout,
			    "?DEVICE={\"path\":\"%s\",\"cycle\":%s}\n",
			    device, rate);
	}
#endif /* RECONFIGURE_ENABLE */
	(void)gps_close(&gpsdata);
	exit(status);
#ifdef RECONFIGURE_ENABLE
    } else if (reset) {
	/* hard reset will go through lower-level operations */
	const int speeds[] = {2400, 4800, 9600, 19200, 38400, 57600, 115200};
	static struct gps_device_t	session;	/* zero this too */
	int i;

	if (device == NULL || forcetype == NULL) {
		gpsd_report(&context.errout, LOG_ERROR,
			    "device and type must be specified for the reset operation.\n");
		exit(EXIT_FAILURE);
	    }

	/*@ -mustfreeonly -immediatetrans @*/
	gps_context_init(&context, "gpsctl");
	context.errout.debug = debuglevel;
	session.context = &context;
	gpsd_tty_init(&session);
	(void)strlcpy(session.gpsdata.dev.path, device, sizeof(session.gpsdata.dev.path));
	session.device_type = forcetype;
	(void)gpsd_open(&session);
	(void)gpsd_set_raw(&session);
	(void)session.device_type->speed_switcher(&session, 4800, 'N', 1);
	(void)tcdrain(session.gpsdata.gps_fd);
	for(i = 0; i < (int)(sizeof(speeds) / sizeof(speeds[0])); i++) {
	    (void)gpsd_set_speed(&session, speeds[i], 'N', 1);
	    (void)session.device_type->speed_switcher(&session, 4800, 'N', 1);
	    (void)tcdrain(session.gpsdata.gps_fd);
	}
	gpsd_set_speed(&session, 4800, 'N', 1);
	for (i = 0; i < 3; i++)
	    if (session.device_type->mode_switcher)
		session.device_type->mode_switcher(&session, MODE_NMEA);
	gpsd_wrap(&session);
	exit(EXIT_SUCCESS);
	/*@ +mustfreeonly +immediatetrans @*/
#endif /* RECONFIGURE_ENABLE */
    } else {
	/* access to the daemon failed, use the low-level facilities */
	static struct gps_device_t	session;	/* zero this too */
	fd_set all_fds;
	fd_set rfds;

	/*
	 * Unless the user explicitly requested it, always run to end of 
	 * hunt rather than timing out. Otherwise we can easily get messages
	 * that spuriously look like failure at high baud rates. 
	 */

	/*@ -mustfreeonly -immediatetrans @*/
	gps_context_init(&context, "gpsctl");
	context.errout.debug = debuglevel;
	session.context = &context;	/* in case gps_init isn't called */

	if (echo)
	    context.readonly = true;

	if (timeout > 0) {
	    (void) alarm(timeout);
	    (void) signal(SIGALRM, onsig);
	}
	/*
	 * Unless the user has forced a type and only wants to see the
	 * string (not send it) we now need to try to open the device
	 * and find out what is actually there.
	 */
	if (!(forcetype != NULL && echo)) {
	    int maxfd = 0;
	    if (device == NULL) {
		gpsd_report(&context.errout, LOG_ERROR,
			    "device must be specified for low-level access.\n");
		exit(EXIT_FAILURE);
	    }

	    gpsd_init(&session, &context, device);
	    if (gpsd_activate(&session, O_PROBEONLY) < 0) {
		gpsd_report(&context.errout, LOG_ERROR,
			    "initial GPS device %s open failed\n",
			    device);
		exit(EXIT_FAILURE);
	    }
	    gpsd_report(&context.errout, LOG_INF, 
			"device %s activated\n", session.gpsdata.dev.path);
	    /*@i1@*/FD_SET(session.gpsdata.gps_fd, &all_fds);
	    if (session.gpsdata.gps_fd > maxfd)
		 maxfd = session.gpsdata.gps_fd;

	    /* initialize the GPS context's time fields */
	    gpsd_time_init(&context, time(NULL));

	    /*@-compdef@*/
	    /* grab packets until we time out, get sync, or fail sync */
	    for (hunting = true; hunting; )
	    {
		fd_set efds;
		switch(gpsd_await_data(&rfds, &efds, maxfd, &all_fds, &context.errout))
		{
		case AWAIT_GOT_INPUT:
		    break;
		case AWAIT_NOT_READY:
		    /* no recovery from bad fd is possible */
		    if (FD_ISSET(session.gpsdata.gps_fd, &efds))
			exit(EXIT_FAILURE);
		    continue;
		case AWAIT_FAILED:
		    exit(EXIT_FAILURE);
		}

		switch(gpsd_multipoll(FD_ISSET(session.gpsdata.gps_fd, &rfds),
					       &session, ctlhook, 0))
		{
		case DEVICE_READY:
		    FD_SET(session.gpsdata.gps_fd, &all_fds);
		    break;
		case DEVICE_UNREADY:
		    FD_CLR(session.gpsdata.gps_fd, &all_fds);
		    break;
		case DEVICE_ERROR:
		    /* this is where a failure to sync lands */
		    gpsd_report(&context.errout, LOG_WARN,
				"device error, bailing out.\n");
		    exit(EXIT_FAILURE);
		case DEVICE_EOF:
		    gpsd_report(&context.errout, LOG_WARN,
				"device signed off, bailing out.\n");
		    exit(EXIT_SUCCESS);
		default:
		    break;
		}
	    }
	    /*@+compdef@*/

	    gpsd_report(&context.errout, LOG_PROG,
			"%s looks like a %s at %d.\n",
			device, gpsd_id(&session),
			session.gpsdata.dev.baudrate);

	    if (forcetype!=NULL && strcmp("NMEA0183", session.device_type->type_name) !=0 && strcmp(forcetype->type_name, session.device_type->type_name)!=0) {
		gpsd_report(&context.errout, LOG_ERROR,
			    "'%s' doesn't match non-generic type '%s' of selected device.\n",
			    forcetype->type_name,
			    session.device_type->type_name);
	    }
	}

	(void)printf("%s identified as a %s at %u baud.\n",
                       device, gpsd_id(&session),
                       session.gpsdata.dev.baudrate);

	/* if no control operation was specified, we're done */
	if (speed==NULL && !to_nmea && !to_binary && control==NULL)
	    exit(EXIT_SUCCESS);

	/* maybe user wants to see the packet rather than send it */
	if (echo)
	    session.gpsdata.gps_fd = fileno(stdout);

	/* control op specified; maybe we forced the type */
	if (forcetype != NULL)
	    (void)gpsd_switch_driver(&session, forcetype->type_name);

	/* now perform the actual control function */
	status = 0;
#ifdef RECONFIGURE_ENABLE
	/*@ -nullderef @*/
	if (to_nmea || to_binary) {
	    bool write_enable = context.readonly;
	    context.readonly = false;
	    if (session.device_type->mode_switcher == NULL) {
		gpsd_report(&context.errout, LOG_SHOUT,
			      "%s devices have no mode switch.\n",
			      session.device_type->type_name);
		status = 1;
	    } else {
		int target_mode = to_nmea ? MODE_NMEA : MODE_BINARY;

		gpsd_report(&context.errout, LOG_SHOUT,
			    "switching to mode %s.\n",
			    to_nmea ? "NMEA" : "BINARY");
		session.device_type->mode_switcher(&session, target_mode);
		settle(&session);
	    }
	    context.readonly = write_enable;
	}
	if (speed) {
	    char parity = echo ? 'N': session.gpsdata.dev.parity;
	    int stopbits = echo ? 1 : session.gpsdata.dev.stopbits;
	    char *modespec;

	    modespec = strchr(speed, ':');
	    /*@ +charint @*/
	    status = 0;
	    if (modespec!=NULL) {
		*modespec = '\0';
		if (strchr("78", *++modespec) == NULL) {
		    gpsd_report(&context.errout, LOG_ERROR,
				"No support for that word lengths.\n");
		    status = 1;
		}
		parity = *++modespec;
		if (strchr("NOE", parity) == NULL) {
		    gpsd_report(&context.errout, LOG_ERROR,
				"What parity is '%c'?\n", parity);
		    status = 1;
		}
		stopbits = *++modespec;
		if (strchr("12", parity) == NULL) {
		    gpsd_report(&context.errout, LOG_ERROR,
				"Stop bits must be 1 or 2.\n");
		    status = 1;
		}
		stopbits = (int)(stopbits-'0');
	    }
	    if (status == 0) {
		if (session.device_type->speed_switcher == NULL) {
		    gpsd_report(&context.errout, LOG_ERROR,
				"%s devices have no speed switch.\n",
				session.device_type->type_name);
		    status = 1;
		}
		else if (session.device_type->speed_switcher(&session,
							     (speed_t)atoi(speed),
							     parity,
							     stopbits)) {
		    settle(&session);
		    gpsd_report(&context.errout, LOG_PROG,
				"%s change to %s%c%d succeeded\n",
				session.gpsdata.dev.path,
				speed, parity, stopbits);
		} else {
		    gpsd_report(&context.errout, LOG_ERROR,
				"%s driver won't support %s%c%d.\n",
				session.gpsdata.dev.path,
				speed, parity, stopbits);
		    status = 1;
		}
	    }
	}
	if (rate) {
	    bool write_enable = context.readonly;
	    context.readonly = false;
	    if (session.device_type->rate_switcher == NULL) {
		gpsd_report(&context.errout, LOG_ERROR,
			      "%s devices have no rate switcher.\n",
			      session.device_type->type_name);
		status = 1;
	    } else {
		double rate_dbl = strtod(rate, NULL);

		if (!session.device_type->rate_switcher(&session, rate_dbl)) {
		    gpsd_report(&context.errout, LOG_ERROR, "rate switch failed.\n");
		    status = 1;
		}
		settle(&session);
	    }
	    context.readonly = write_enable;
	}
#endif /* RECONFIGURE_ENABLE */
#ifdef CONTROLSEND_ENABLE
	/*@ -compdef @*/
	if (control) {
	    bool write_enable = context.readonly;
	    context.readonly = false;
	    if (session.device_type->control_send == NULL) {
		gpsd_report(&context.errout, LOG_ERROR,
			      "%s devices have no control sender.\n",
			      session.device_type->type_name);
		status = 1;
	    } else {
		if (session.device_type->control_send(&session,
						      cooked,
						      (size_t)cooklen) == -1) {
		    gpsd_report(&context.errout, LOG_ERROR,
				"control transmission failed.\n");
		    status = 1;
		}
		settle(&session);
	    }
	    context.readonly = write_enable;
	}
	/*@ +compdef @*/
#endif /* CONTROLSEND_ENABLE */

	exit(status);
	/*@ +nullderef @*/
	/*@ +mustfreeonly +immediatetrans @*/
    }
}
Exemple #10
0
int main(int argc, char **argv)
{
    int ch;
    bool daemonize = false;
    unsigned int flags = WATCH_ENABLE;
    struct exportmethod_t *method = NULL;

    progname = argv[0];

    method = export_default();
    if (method == NULL) {
	(void)fprintf(stderr, "%s: no export methods.\n", progname);
	exit(EXIT_FAILURE);
    }

    logfile = stdout;
    while ((ch = getopt(argc, argv, "dD:e:f:hi:lm:V")) != -1) {
	switch (ch) {
	case 'd':
	    openlog(basename(progname), LOG_PID | LOG_PERROR, LOG_DAEMON);
	    daemonize = true;
	    break;
#ifdef CLIENTDEBUG_ENABLE
	case 'D':
	    debug = atoi(optarg);
	    gps_enable_debug(debug, logfile);
	    break;
#endif /* CLIENTDEBUG_ENABLE */
	case 'e':
	    method = export_lookup(optarg);
	    if (method == NULL) {
		(void)fprintf(stderr,
			      "%s: %s is not a known export method.\n",
			      progname, optarg);
		exit(EXIT_FAILURE);
	    }
	    break;
       case 'f':       /* Output file name. */
            {
                char   *fname = NULL;
                time_t  t;
                size_t  s = 0;
                size_t fnamesize = strlen(optarg);

                t = time(NULL);
                while (s == 0) {
		    char *newfname = realloc(fname, fnamesize);
		    if (newfname == NULL) {
			syslog(LOG_ERR, "realloc failed.");
			goto bailout;
		    } else {
			fnamesize += 1024;
			fname = newfname;
		    }
		    s = strftime(fname, fnamesize-1, optarg, localtime(&t));
                }
                fname[s] = '\0';;
                logfile = fopen(fname, "w");
                if (logfile == NULL)
		    syslog(LOG_ERR,
			   "Failed to open %s: %s, logging to stdout.",
			   fname, strerror(errno));
	    bailout:
                free(fname);
                break;
            }
	case 'i':		/* set polling interfal */
	    timeout = (time_t) atoi(optarg);
	    if (timeout < 1)
		timeout = 1;
	    if (timeout >= 3600)
		fprintf(stderr,
			"WARNING: track timeout is an hour or more!\n");
	    break;
	case 'l':
	    export_list(stderr);
	    exit(EXIT_SUCCESS);
        case 'm':
	    minmove = (double )atoi(optarg);
	    break;
	case 'V':
	    (void)fprintf(stderr, "%s: version %s (revision %s)\n",
			  progname, VERSION, REVISION);
	    exit(EXIT_SUCCESS);
	default:
	    usage();
	    /* NOTREACHED */
	}
    }

    if (daemonize && logfile == stdout) {
	syslog(LOG_ERR, "Daemon mode with no valid logfile name - exiting.");
	exit(EXIT_FAILURE);
    }

    if (method->magic != NULL) {
	source.server = (char *)method->magic;
	source.port = NULL;
	source.device = NULL;
    } else {
	source.server = (char *)"localhost";
	source.port = (char *)DEFAULT_GPSD_PORT;
	source.device = NULL;
    }

    if (optind < argc) {
	/* in this case, switch to the method "socket" always */
	gpsd_source_spec(argv[optind], &source);
    }
#if 0
    (void)fprintf(logfile,"<!-- server: %s port: %s  device: %s -->\n",
		 source.server, source.port, source.device);
#endif

    /* catch all interesting signals */
    (void)signal(SIGTERM, quit_handler);
    (void)signal(SIGQUIT, quit_handler);
    (void)signal(SIGINT, quit_handler);

    /* might be time to daemonize */
    if (daemonize) {
	/* not SuS/POSIX portable, but we have our own fallback version */
	if (daemon(0, 0) != 0)
	    (void) fprintf(stderr,"demonization failed: %s\n", strerror(errno));
    }

    //syslog (LOG_INFO, "---------- STARTED ----------");

    if (gps_open(source.server, source.port, &gpsdata) != 0) {
	(void)fprintf(stderr,
		      "%s: no gpsd running or network error: %d, %s\n",
		      progname, errno, gps_errstr(errno));
	exit(EXIT_FAILURE);
    }

    if (source.device != NULL)
	flags |= WATCH_DEVICE;
    (void)gps_stream(&gpsdata, flags, source.device);

    print_gpx_header();
    (void)gps_mainloop(&gpsdata, 5000000, conditionally_log_fix);
    print_gpx_footer();
    (void)gps_close(&gpsdata);

    exit(EXIT_SUCCESS);
}