symon.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. /* $Id: symon.c,v 1.34 2004/02/26 22:48:08 dijkstra Exp $ */
  2. /*
  3. * Copyright (c) 2001-2004 Willem Dijkstra
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * - Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * - Redistributions in binary form must reproduce the above
  13. * copyright notice, this list of conditions and the following
  14. * disclaimer in the documentation and/or other materials provided
  15. * with the distribution.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  25. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  27. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28. * POSSIBILITY OF SUCH DAMAGE.
  29. *
  30. */
  31. #include <sys/param.h>
  32. #include <errno.h>
  33. #include <fcntl.h>
  34. #include <limits.h>
  35. #include <pwd.h>
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <string.h>
  39. #include <sysexits.h>
  40. #include <syslog.h>
  41. #include <unistd.h>
  42. #include "data.h"
  43. #include "error.h"
  44. #include "symon.h"
  45. #include "symonnet.h"
  46. #include "net.h"
  47. #include "readconf.h"
  48. #include "xmalloc.h"
  49. __BEGIN_DECLS
  50. void alarmhandler(int);
  51. void drop_priviledges();
  52. void exithandler(int);
  53. void huphandler(int);
  54. void set_stream_use(struct muxlist *);
  55. __END_DECLS
  56. int flag_unsecure = 0;
  57. int flag_hup = 0;
  58. int symon_interval = SYMON_DEFAULT_INTERVAL;
  59. /* map stream types to inits and getters */
  60. struct funcmap streamfunc[] = {
  61. {MT_IO1, 0, NULL, init_io, gets_io, get_io},
  62. {MT_CPU, 0, NULL, init_cpu, NULL, get_cpu},
  63. {MT_MEM, 0, NULL, init_mem, NULL, get_mem},
  64. {MT_IF, 0, NULL, init_if, NULL, get_if},
  65. {MT_PF, 0, privinit_pf, init_pf, NULL, get_pf},
  66. {MT_DEBUG, 0, NULL, init_debug, NULL, get_debug},
  67. {MT_PROC, 0, NULL, init_proc, gets_proc, get_proc},
  68. {MT_MBUF, 0, NULL, init_mbuf, NULL, get_mbuf},
  69. {MT_SENSOR, 0, NULL, init_sensor, NULL, get_sensor},
  70. {MT_IO2, 0, NULL, init_io, gets_io, get_io},
  71. {MT_EOT, 0, NULL, NULL, NULL}
  72. };
  73. void
  74. set_stream_use(struct muxlist *mul)
  75. {
  76. struct mux *mux;
  77. struct stream *stream;
  78. int i;
  79. for (i = 0; i < MT_EOT; i++)
  80. streamfunc[i].used = 0;
  81. SLIST_FOREACH(mux, mul, muxes) {
  82. SLIST_FOREACH(stream, &mux->sl, streams)
  83. streamfunc[stream->type].used = 1;
  84. }
  85. }
  86. void
  87. drop_priviledges(int unsecure)
  88. {
  89. struct passwd *pw;
  90. if (unsecure) {
  91. if (setegid(getgid()) || setgid(getgid()) ||
  92. seteuid(getuid()) || setuid(getuid()))
  93. fatal("can't drop priviledges: %.200s", strerror(errno));
  94. } else {
  95. if ((pw = getpwnam(SYMON_USER)) == NULL)
  96. fatal("could not get user information for user '%.200s': %.200s",
  97. SYMON_USER, strerror(errno));
  98. if (chroot(pw->pw_dir) < 0)
  99. fatal("chroot failed: %.200s", strerror(errno));
  100. if (chdir("/") < 0)
  101. fatal("chdir / failed: %.200s", strerror(errno));
  102. if (setgroups(1, &pw->pw_gid) ||
  103. setegid(pw->pw_gid) || setgid(pw->pw_gid) ||
  104. seteuid(pw->pw_uid) || setuid(pw->pw_uid))
  105. fatal("can't drop privileges: %.200s", strerror(errno));
  106. }
  107. }
  108. /* alarmhandler that gets called every symon_interval */
  109. void
  110. alarmhandler(int s)
  111. {
  112. /* EMPTY */
  113. }
  114. void
  115. exithandler(int s)
  116. {
  117. info("received signal %d - quitting", s);
  118. exit(1);
  119. }
  120. void
  121. huphandler(int s)
  122. {
  123. info("hup received");
  124. flag_hup = 1;
  125. }
  126. /*
  127. * Symon is a system measurement utility.
  128. *
  129. * The main goals symon hopes to accomplish are:
  130. * - to take fine grained measurements of system parameters
  131. * - with minimal performance impact
  132. * - in a secure way.
  133. *
  134. * Measurements are processed by a second program called symux. symon and symux
  135. * communicate via udp.
  136. */
  137. int
  138. main(int argc, char *argv[])
  139. {
  140. struct muxlist mul, newmul;
  141. struct itimerval alarminterval;
  142. struct stream *stream;
  143. struct mux *mux;
  144. FILE *pidfile;
  145. char *cfgpath;
  146. int ch;
  147. int i;
  148. SLIST_INIT(&mul);
  149. /* reset flags */
  150. flag_debug = 0;
  151. flag_daemon = 0;
  152. flag_unsecure = 0;
  153. cfgpath = SYMON_CONFIG_FILE;
  154. while ((ch = getopt(argc, argv, "dvuf:")) != -1) {
  155. switch (ch) {
  156. case 'd':
  157. flag_debug = 1;
  158. break;
  159. case 'f':
  160. cfgpath = xstrdup(optarg);
  161. break;
  162. case 'u':
  163. flag_unsecure = 1;
  164. break;
  165. case 'v':
  166. info("symon version %s", SYMON_VERSION);
  167. default:
  168. info("usage: %s [-d] [-u] [-v] [-f cfgfile]", __progname);
  169. exit(EX_USAGE);
  170. }
  171. }
  172. if (!read_config_file(&mul, cfgpath))
  173. fatal("configuration file contained errors - aborting");
  174. set_stream_use(&mul);
  175. /* open resources that might not be available after priviledge drop */
  176. for (i = 0; i < MT_EOT; i++)
  177. if (streamfunc[i].used && (streamfunc[i].privinit != NULL))
  178. (streamfunc[i].privinit) ();
  179. if ((pidfile = fopen(SYMON_PID_FILE, "w")) == NULL)
  180. warning("could not open \"%.200s\", %.200s", SYMON_PID_FILE,
  181. strerror(errno));
  182. drop_priviledges(flag_unsecure);
  183. if (flag_debug != 1) {
  184. if (daemon(0, 0) != 0)
  185. fatal("daemonize failed: %.200s", strerror(errno));
  186. flag_daemon = 1;
  187. if (pidfile) {
  188. fprintf(pidfile, "%u\n", (u_int) getpid());
  189. fclose(pidfile);
  190. }
  191. }
  192. info("symon version %s", SYMON_VERSION);
  193. if (flag_debug == 1)
  194. info("program id=%d", (u_int) getpid());
  195. /* setup signal handlers */
  196. signal(SIGALRM, alarmhandler);
  197. signal(SIGHUP, huphandler);
  198. signal(SIGINT, exithandler);
  199. signal(SIGQUIT, exithandler);
  200. signal(SIGTERM, exithandler);
  201. /* prepare crc32 */
  202. init_crc32();
  203. /* init modules */
  204. SLIST_FOREACH(mux, &mul, muxes) {
  205. connect2mux(mux);
  206. SLIST_FOREACH(stream, &mux->sl, streams) {
  207. (streamfunc[stream->type].init) (stream->args);
  208. }
  209. }
  210. set_stream_use(&mul);
  211. /* setup alarm */
  212. timerclear(&alarminterval.it_interval);
  213. timerclear(&alarminterval.it_value);
  214. alarminterval.it_interval.tv_sec =
  215. alarminterval.it_value.tv_sec = symon_interval;
  216. if (setitimer(ITIMER_REAL, &alarminterval, NULL) != 0) {
  217. fatal("alarm setup failed: %.200s", strerror(errno));
  218. }
  219. for (;;) { /* FOREVER */
  220. sleep(symon_interval); /* alarm will interrupt sleep */
  221. if (flag_hup == 1) {
  222. flag_hup = 0;
  223. SLIST_INIT(&newmul);
  224. if (flag_unsecure) {
  225. if (!read_config_file(&newmul, cfgpath)) {
  226. info("new configuration contains errors; keeping old configuration");
  227. free_muxlist(&newmul);
  228. } else {
  229. free_muxlist(&mul);
  230. mul = newmul;
  231. info("read configuration file '%.200s' successfully", cfgpath);
  232. /* init modules */
  233. SLIST_FOREACH(mux, &mul, muxes) {
  234. connect2mux(mux);
  235. SLIST_FOREACH(stream, &mux->sl, streams) {
  236. (streamfunc[stream->type].init) (stream->args);
  237. }
  238. }
  239. set_stream_use(&mul);
  240. }
  241. } else {
  242. info("configuration unreachable because of privsep; keeping old configuration");
  243. }
  244. } else {
  245. /* populate for modules that get all their measurements in one go */
  246. for (i = 0; i < MT_EOT; i++)
  247. if (streamfunc[i].used && (streamfunc[i].gets != NULL))
  248. (streamfunc[i].gets) ();
  249. SLIST_FOREACH(mux, &mul, muxes) {
  250. prepare_packet(mux);
  251. SLIST_FOREACH(stream, &mux->sl, streams)
  252. stream_in_packet(stream, mux);
  253. finish_packet(mux);
  254. send_packet(mux);
  255. }
  256. }
  257. }
  258. return (EX_SOFTWARE); /* NOTREACHED */
  259. }