gpsdctl.c 3.9 KB

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