symon.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /* $Id: symon.c,v 1.41 2005/03/20 16:17:22 dijkstra Exp $ */
  2. /*
  3. * Copyright (c) 2001-2005 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 <sys/time.h>
  33. #include <errno.h>
  34. #include <fcntl.h>
  35. #include <limits.h>
  36. #include <pwd.h>
  37. #include <signal.h>
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include <sysexits.h>
  42. #include <syslog.h>
  43. #include <time.h>
  44. #include <unistd.h>
  45. #include "conf.h"
  46. #include "data.h"
  47. #include "error.h"
  48. #include "net.h"
  49. #include "readconf.h"
  50. #include "symon.h"
  51. #include "symonnet.h"
  52. #include "xmalloc.h"
  53. __BEGIN_DECLS
  54. void alarmhandler(int);
  55. void drop_priviledges();
  56. void exithandler(int);
  57. void huphandler(int);
  58. void set_stream_use(struct muxlist *);
  59. __END_DECLS
  60. int flag_unsecure = 0;
  61. int flag_hup = 0;
  62. int symon_interval = SYMON_DEFAULT_INTERVAL;
  63. /* map stream types to inits and getters */
  64. struct funcmap streamfunc[] = {
  65. {MT_IO1, 0, NULL, init_io, gets_io, get_io},
  66. {MT_CPU, 0, NULL, init_cpu, gets_cpu, get_cpu},
  67. {MT_MEM, 0, NULL, init_mem, NULL, get_mem},
  68. {MT_IF, 0, NULL, init_if, gets_if, get_if},
  69. {MT_PF, 0, privinit_pf, init_pf, NULL, get_pf},
  70. {MT_DEBUG, 0, NULL, init_debug, NULL, get_debug},
  71. {MT_PROC, 0, NULL, init_proc, gets_proc, get_proc},
  72. {MT_MBUF, 0, NULL, init_mbuf, NULL, get_mbuf},
  73. {MT_SENSOR, 0, privinit_sensor, init_sensor, NULL, get_sensor},
  74. {MT_IO2, 0, NULL, init_io, gets_io, get_io},
  75. {MT_PFQ, 0, privinit_pfq, init_pfq, gets_pfq, get_pfq},
  76. {MT_EOT, 0, NULL, NULL, NULL}
  77. };
  78. void
  79. set_stream_use(struct muxlist *mul)
  80. {
  81. struct mux *mux;
  82. struct stream *stream;
  83. int i;
  84. for (i = 0; i < MT_EOT; i++)
  85. streamfunc[i].used = 0;
  86. SLIST_FOREACH(mux, mul, muxes) {
  87. SLIST_FOREACH(stream, &mux->sl, streams)
  88. streamfunc[stream->type].used = 1;
  89. }
  90. }
  91. void
  92. drop_priviledges(int unsecure)
  93. {
  94. struct passwd *pw;
  95. if (unsecure) {
  96. if (setegid(getgid()) || setgid(getgid()) ||
  97. seteuid(getuid()) || setuid(getuid()))
  98. fatal("can't drop priviledges: %.200s", strerror(errno));
  99. } else {
  100. if ((pw = getpwnam(SYMON_USER)) == NULL)
  101. fatal("could not get user information for user '%.200s': %.200s",
  102. SYMON_USER, strerror(errno));
  103. if (chroot(pw->pw_dir) < 0)
  104. fatal("chroot failed: %.200s", strerror(errno));
  105. if (chdir("/") < 0)
  106. fatal("chdir / failed: %.200s", strerror(errno));
  107. if (setgroups(1, &pw->pw_gid))
  108. fatal("can't setgroups: %.200s", strerror(errno));
  109. if (setgid(pw->pw_gid))
  110. fatal("can't set group id: %.200s", strerror(errno));
  111. if (setegid(pw->pw_gid))
  112. fatal("can't set effective group id: %.200s", strerror(errno));
  113. if (setuid(pw->pw_uid))
  114. fatal("can't set user id: %.200s", strerror(errno));
  115. if (seteuid(pw->pw_uid))
  116. fatal("can't set effective user id: %.200s", strerror(errno));
  117. }
  118. }
  119. /* alarmhandler that gets called every symon_interval */
  120. void
  121. alarmhandler(int s)
  122. {
  123. /* EMPTY */
  124. }
  125. void
  126. exithandler(int s)
  127. {
  128. info("received signal %d - quitting", s);
  129. exit(1);
  130. }
  131. void
  132. huphandler(int s)
  133. {
  134. info("hup received");
  135. flag_hup = 1;
  136. }
  137. /*
  138. * Symon is a system measurement utility.
  139. *
  140. * The main goals symon hopes to accomplish are:
  141. * - to take fine grained measurements of system parameters
  142. * - with minimal performance impact
  143. * - in a secure way.
  144. *
  145. * Measurements are processed by a second program called symux. symon and symux
  146. * communicate via udp.
  147. */
  148. int
  149. main(int argc, char *argv[])
  150. {
  151. struct muxlist mul, newmul;
  152. struct itimerval alarminterval;
  153. struct stream *stream;
  154. struct mux *mux;
  155. time_t now, last_update;
  156. FILE *pidfile;
  157. char *cfgpath;
  158. int ch;
  159. int i;
  160. SLIST_INIT(&mul);
  161. /* reset flags */
  162. flag_debug = 0;
  163. flag_daemon = 0;
  164. flag_unsecure = 0;
  165. cfgpath = SYMON_CONFIG_FILE;
  166. while ((ch = getopt(argc, argv, "dvuf:")) != -1) {
  167. switch (ch) {
  168. case 'd':
  169. flag_debug = 1;
  170. break;
  171. case 'f':
  172. cfgpath = xstrdup(optarg);
  173. break;
  174. case 'u':
  175. flag_unsecure = 1;
  176. break;
  177. case 'v':
  178. info("symon version %s", SYMON_VERSION);
  179. default:
  180. info("usage: %s [-d] [-u] [-v] [-f cfgfile]", __progname);
  181. exit(EX_USAGE);
  182. }
  183. }
  184. if (!read_config_file(&mul, cfgpath))
  185. fatal("configuration file contained errors - aborting");
  186. set_stream_use(&mul);
  187. /* open resources that might not be available after priviledge drop */
  188. for (i = 0; i < MT_EOT; i++)
  189. if (streamfunc[i].used && (streamfunc[i].privinit != NULL))
  190. (streamfunc[i].privinit) ();
  191. if ((pidfile = fopen(SYMON_PID_FILE, "w")) == NULL)
  192. warning("could not open \"%.200s\", %.200s", SYMON_PID_FILE,
  193. strerror(errno));
  194. drop_priviledges(flag_unsecure);
  195. if (flag_debug != 1) {
  196. if (daemon(0, 0) != 0)
  197. fatal("daemonize failed: %.200s", strerror(errno));
  198. flag_daemon = 1;
  199. if (pidfile) {
  200. fprintf(pidfile, "%u\n", (u_int) getpid());
  201. fclose(pidfile);
  202. }
  203. }
  204. info("symon version %s", SYMON_VERSION);
  205. if (flag_debug == 1)
  206. info("program id=%d", (u_int) getpid());
  207. /* setup signal handlers */
  208. signal(SIGALRM, alarmhandler);
  209. signal(SIGHUP, huphandler);
  210. signal(SIGINT, exithandler);
  211. signal(SIGQUIT, exithandler);
  212. signal(SIGTERM, exithandler);
  213. /* prepare crc32 */
  214. init_crc32();
  215. /* init modules */
  216. SLIST_FOREACH(mux, &mul, muxes) {
  217. connect2mux(mux);
  218. SLIST_FOREACH(stream, &mux->sl, streams) {
  219. (streamfunc[stream->type].init) (stream->args);
  220. }
  221. }
  222. set_stream_use(&mul);
  223. /* setup alarm */
  224. timerclear(&alarminterval.it_interval);
  225. timerclear(&alarminterval.it_value);
  226. alarminterval.it_interval.tv_sec =
  227. alarminterval.it_value.tv_sec = symon_interval;
  228. if (setitimer(ITIMER_REAL, &alarminterval, NULL) != 0) {
  229. fatal("alarm setup failed: %.200s", strerror(errno));
  230. }
  231. last_update = time(NULL);
  232. for (;;) { /* FOREVER */
  233. sleep(symon_interval); /* alarm will interrupt sleep */
  234. now = time(NULL);
  235. if (flag_hup == 1) {
  236. flag_hup = 0;
  237. SLIST_INIT(&newmul);
  238. if (flag_unsecure) {
  239. if (!read_config_file(&newmul, cfgpath)) {
  240. info("new configuration contains errors; keeping old configuration");
  241. free_muxlist(&newmul);
  242. } else {
  243. free_muxlist(&mul);
  244. mul = newmul;
  245. info("read configuration file '%.200s' successfully", cfgpath);
  246. /* init modules */
  247. SLIST_FOREACH(mux, &mul, muxes) {
  248. connect2mux(mux);
  249. SLIST_FOREACH(stream, &mux->sl, streams) {
  250. (streamfunc[stream->type].init) (stream->args);
  251. }
  252. }
  253. set_stream_use(&mul);
  254. }
  255. } else {
  256. info("configuration unreachable because of privsep; keeping old configuration");
  257. }
  258. } else {
  259. /* check timing to catch ntp drifts */
  260. if (now < (last_update + symon_interval)) {
  261. if (now < (last_update + symon_interval + symon_interval)) {
  262. debug("last update is very long ago - assuming that system time changed");
  263. last_update = now;
  264. } else {
  265. debug("did not sleep %d seconds - skipping a measurement", symon_interval);
  266. continue;
  267. }
  268. } else {
  269. last_update = now;
  270. }
  271. /* populate for modules that get all their measurements in one go */
  272. for (i = 0; i < MT_EOT; i++)
  273. if (streamfunc[i].used && (streamfunc[i].gets != NULL))
  274. (streamfunc[i].gets) ();
  275. SLIST_FOREACH(mux, &mul, muxes) {
  276. prepare_packet(mux);
  277. SLIST_FOREACH(stream, &mux->sl, streams)
  278. stream_in_packet(stream, mux);
  279. finish_packet(mux);
  280. send_packet(mux);
  281. }
  282. }
  283. }
  284. return (EX_SOFTWARE); /* NOTREACHED */
  285. }