uvd.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. * daemon for version information of embedded systems
  3. *
  4. * Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19. *
  20. */
  21. #include <arpa/inet.h>
  22. #include <errno.h>
  23. #include <fcntl.h>
  24. #include <getopt.h>
  25. #include <netinet/in.h>
  26. #include <signal.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <sys/socket.h>
  31. #include <sys/stat.h>
  32. #include <sys/types.h>
  33. #include <time.h>
  34. #include <unistd.h>
  35. #define VERSION "0.1"
  36. #define LOGFILE "/tmp/uvd.log"
  37. #define LOCKFILE "/tmp/uvd.lock"
  38. #define BUFSIZE 1024
  39. #define VERFILE "/etc/adkversion"
  40. void version() {
  41. fprintf(stdout, "uvd version %s", VERSION);
  42. exit(EXIT_SUCCESS);
  43. }
  44. static const char *log_date(void) {
  45. static char buf[18];
  46. time_t t = time(NULL);
  47. strftime(buf, 18, "%b %d %H:%M:%S", localtime(&t));
  48. return buf;
  49. }
  50. void die(const char *msg) {
  51. fprintf(stderr, "%s\n", msg);
  52. exit(EXIT_FAILURE);
  53. }
  54. void die_log(FILE *lf, const char *msg) {
  55. fprintf(lf, "%s: %s\n", log_date(), msg);
  56. exit(EXIT_FAILURE);
  57. }
  58. void log_msg(FILE *lf, const char *msg) {
  59. fprintf(lf, "%s: %s\n", log_date(), msg);
  60. fflush(lf);
  61. }
  62. void signal_handler(int sig) {
  63. switch(sig) {
  64. case SIGHUP:
  65. break;
  66. case SIGTERM:
  67. case SIGINT:
  68. case SIGQUIT:
  69. unlink(LOCKFILE);
  70. exit(EXIT_SUCCESS);
  71. break;
  72. default:
  73. break;
  74. }
  75. }
  76. void usage(int argc, char *argv[]) {
  77. if (argc >=1) {
  78. fprintf(stdout, "Usage: %s [ --help | --debug | --version ]\n", argv[0]);
  79. fprintf(stdout, " Options:\n");
  80. fprintf(stdout, " --debug | -d start in debug mode, don't fork\n");
  81. fprintf(stdout, " --version | -v show version\n");
  82. fprintf(stdout, " --help | -h show help\n");
  83. fprintf(stdout, "\n");
  84. }
  85. exit(EXIT_SUCCESS);
  86. }
  87. int main(int argc, char **argv) {
  88. pid_t pid, sid;
  89. int lfd, c, ss, n, res;
  90. FILE *lf = NULL;
  91. int vf;
  92. struct sigaction sigact;
  93. int daemonize = 1;
  94. int optval = 1;
  95. char buf[BUFSIZE];
  96. struct sockaddr_in server = { 0 };
  97. struct sockaddr_in clientaddr; /* client addr */
  98. socklen_t clientlen;
  99. /* options descriptor */
  100. static struct option longopts[] = {
  101. { "debug", no_argument, 0, 'd' },
  102. { "help", no_argument, 0, 'h' },
  103. { "version", no_argument, 0, 'v' },
  104. { NULL, 0, NULL, 0 }
  105. };
  106. while((c = getopt_long(argc, argv, "dhv", longopts, NULL)) != -1) {
  107. switch(c) {
  108. case 'h':
  109. usage(argc, argv);
  110. break;
  111. case 'v':
  112. version();
  113. break;
  114. case 'd':
  115. daemonize = 0;
  116. break;
  117. default:
  118. usage(argc, argv);
  119. }
  120. }
  121. if (daemonize) {
  122. /* Fork off the parent process */
  123. pid = fork();
  124. if (pid < 0)
  125. die("Can't fork process");
  126. /* If we got a pid, we exit the parent process */
  127. if (pid > 0)
  128. exit(EXIT_SUCCESS);
  129. /* Change the file mode mask */
  130. umask(0);
  131. }
  132. /* Open a logfile */
  133. lf = fopen(LOGFILE, "a");
  134. if (lf == NULL)
  135. die("Can't open logfile");
  136. if (daemonize) {
  137. /* Create a new session for child process */
  138. if ((sid = setsid()) < 0)
  139. die_log(lf, "Can't create a new session for child process");
  140. /* Change the current working directory */
  141. if ((chdir("/")) < 0)
  142. die_log(lf, "Can't change working directory to /");
  143. }
  144. /* check if daemon already running */
  145. if ((lfd = open(LOCKFILE, O_RDWR | O_CREAT, 0640) < 0))
  146. die("Can't open or create lock file");
  147. if (lockf(lfd, F_TLOCK, 0) == -1)
  148. die("uvd already running!");
  149. if (daemonize) {
  150. /* Close out the standard file descriptors */
  151. close(STDIN_FILENO);
  152. close(STDOUT_FILENO);
  153. close(STDERR_FILENO);
  154. }
  155. /* Handle some signals */
  156. sigact.sa_handler = signal_handler;
  157. sigact.sa_flags = 0;
  158. sigaction(SIGHUP, &sigact, NULL);
  159. sigaction(SIGTERM, &sigact, NULL);
  160. sigaction(SIGINT, &sigact, NULL);
  161. sigaction(SIGQUIT, &sigact, NULL);
  162. log_msg(lf, "uvd started successfully");
  163. /* create network socket */
  164. if ((ss = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
  165. die("can not create socket");
  166. server.sin_addr.s_addr=htonl(INADDR_ANY);
  167. server.sin_family = AF_INET;
  168. server.sin_port = htons(4242);
  169. if (setsockopt (ss, SOL_SOCKET, SO_BROADCAST, (caddr_t) &optval, sizeof (optval)) < 0)
  170. die("can not set socket option");
  171. if (setsockopt (ss, SOL_SOCKET, SO_REUSEADDR, (caddr_t) &optval, sizeof (optval)) < 0)
  172. die("can not set socket option");
  173. if (bind(ss, (struct sockaddr *) &server, sizeof(server)) < 0)
  174. die("can not bind socket");
  175. /* loop forever */
  176. while(1) {
  177. clientlen = sizeof(clientaddr);
  178. n = recvfrom(ss, buf, BUFSIZE , 0, (struct sockaddr *)&clientaddr, &clientlen);
  179. if (n < 0)
  180. die_log(lf, "error reading from client");
  181. buf[n] = 0;
  182. res = strncmp(buf, "version", n);
  183. if (res > 0) {
  184. log_msg(lf, "been asked for version information");
  185. if ((vf = open(VERFILE, O_RDONLY)) < 0)
  186. die_log(lf, "unable to open version file");
  187. ssize_t num;
  188. do {
  189. num = read(vf, &buf, sizeof(buf));
  190. buf[num] = '\0';
  191. if (sendto(ss, buf, num, 0, (struct sockaddr *) &clientaddr, sizeof(clientaddr)) < 0)
  192. die_log(lf, "can not send data");
  193. } while (num > 0);
  194. close(vf);
  195. }
  196. }
  197. close(ss);
  198. return(0);
  199. }