1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
/* gpsdctl.c -- communicate with the control socket of a gpsd instance
*
* This file is Copyright (c) 2010 by the GPSD project
* BSD terms apply: see the file COPYING in the distribution root for details.
*
*/
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#ifndef S_SPLINT_S
#include <unistd.h>
#endif /* S_SPLINT_S */
#include <syslog.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#ifndef S_SPLINT_S
#include <sys/socket.h>
#endif /* S_SPLINT_S */
#include "gpsd.h"
#define DEFAULT_GPSD_TEST_SOCKET "/tmp/gpsd.sock"
static char *control_socket = DEFAULT_GPSD_SOCKET;
static char *gpsd_options = "";
static int gpsd_control(char *action, char *argument)
/* pass a command to gpsd; start the daemon if not already running */
{
int connect = -1;
char buf[512];
int status;
(void)syslog(LOG_ERR, "gpsd_control(action=%s, arg=%s)", action, argument);
if (access(control_socket, F_OK) == 0 &&
(connect = netlib_localsocket(control_socket, SOCK_STREAM)) >= 0)
syslog(LOG_INFO, "reached a running gpsd");
else if (strcmp(action, "add") == 0) {
(void)snprintf(buf, sizeof(buf),
"gpsd %s -F %s", gpsd_options, control_socket);
(void)syslog(LOG_NOTICE, "launching %s", buf);
if (system(buf) != 0) {
(void)syslog(LOG_ERR, "launch of gpsd failed");
return -1;
}
if (access(control_socket, F_OK) == 0)
connect = netlib_localsocket(control_socket, SOCK_STREAM);
}
if (connect < 0) {
syslog(LOG_ERR, "can't reach gpsd");
return -1;
}
/*
* We've got a live connection to the gpsd control socket. No
* need to parse the response, because gpsd will lock on to the
* device if it's really a GPS and ignore it if it's not.
*
* The only other place in the code that knows about the format of
* the add and remove commands is the handle_control() function in
* gpsd.c. Be careful about keeping them in sync, or hotplugging
* will have mysterious failures.
*/
/*@ -sefparams @*/
if (strcmp(action, "add") == 0) {
/*
* Force the group-read & group-write bits on, so gpsd will still be
* able to use this device after dropping root privileges.
*/
struct stat sb;
/* coverity[toctou] */
if (stat(argument, &sb) != 1)
(void)chmod(argument, sb.st_mode | S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
(void)snprintf(buf, sizeof(buf), "+%s\r\n", argument);
status = (int)write(connect, buf, strlen(buf));
ignore_return(read(connect, buf, 12));
} else if (strcmp(action, "remove") == 0) {
(void)snprintf(buf, sizeof(buf), "-%s\r\n", argument);
status = (int)write(connect, buf, strlen(buf));
ignore_return(read(connect, buf, 12));
} else {
(void)syslog(LOG_ERR, "unknown action \"%s\"", action);
status = -1;
}
/*@ +sefparams @*/
(void)close(connect);
//syslog(LOG_DEBUG, "gpsd_control ends");
return status;
}
int main(int argc, char *argv[])
{
openlog("gpsdctl", 0, LOG_DAEMON);
if (argc != 3) {
(void)syslog(LOG_ERR, "requires action and argument (%d)", argc);
exit(EXIT_FAILURE);
} else {
/*@-observertrans@*/
char *sockenv = getenv("GPSD_SOCKET");
char *optenv = getenv("GPSD_OPTIONS");
if (sockenv != NULL)
control_socket = sockenv;
else if (geteuid() != 0)
control_socket = DEFAULT_GPSD_TEST_SOCKET;
if (optenv != NULL)
gpsd_options = optenv;
/* coverity[string_size] */
if (gpsd_control(argv[1], argv[2]) < 0)
exit(EXIT_FAILURE);
else
exit(EXIT_SUCCESS);
/*@+observertrans@*/
}
}
|