The Assimilation Monitoring Project
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
misc.c
Go to the documentation of this file.
1 
25 #include <projectcommon.h>
26 #include <stdlib.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #ifdef HAVE_SYS_UTSNAME_H
31 # include <sys/utsname.h>
32 #endif
33 #include <errno.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #ifndef WIN32
39 #include <sys/time.h>
40 #include <sys/resource.h>
41 #endif
42 #include <signal.h>
43 #include <misc.h>
44 
45 void assimilation_logger(const gchar *log_domain, GLogLevelFlags log_level,
46  const gchar *message, gpointer user_data);
47 const char * assim_syslogid = "assim";
48 FSTATIC void catch_pid_signal(int signum);
49 
51 #ifdef HAVE_UNAME
52 char *
53 proj_get_sysname(void)
54 {
55  struct utsname un; // System name, etc.
56  uname(&un);
57  return g_strdup(un.nodename);
58 }
59 #else
60 # ifdef HAVE_GETCOMPUTERNAME
61 char *
62 proj_get_sysname(void)
63 {
64 // BOOL WINAPI GetComputerName(_Out_ LPTSTR lpBuffer, _Inout_ LPDWORD lpnSize);
65 
66  char sn[MAX_COMPUTERNAME_LENGTH + 1];
67  DWORD snsize = sizeof(sn);
68  BOOL ret;
69 
70  ret = GetComputerName((LPSTR) sn, &snsize);
71  if(ret) {
72  return g_strdup(sn);
73  }
74 
75  return g_strdup("GetComputerName failed");
76 }
77 # else
78 # error "Need some function to get our computer name!"
79 # endif
80 #endif
81 
82 #ifndef WIN32
83 
84 void
85 daemonize_me( gboolean stay_in_foreground,
86  const char* dirtorunin,
87  char* pidfile)
88 {
89  struct rlimit nofile_limits;
90  int nullperms[] = { O_RDONLY, O_WRONLY, O_WRONLY};
91  unsigned j;
92  getrlimit(RLIMIT_NOFILE, &nofile_limits);
93 
94  // g_warning("%s.%d: pid file is %s", __FUNCTION__, __LINE__, pidfile);
95  if (pidfile) {
96  if (are_we_already_running(pidfile, NULL) == PID_RUNNING) {
97  g_message("Already running.");
98  exit(0);
99  }
100  }
101 
102 #ifdef HAS_FORK
103  if (!stay_in_foreground) {
104  int k;
105  int childpid;
106 
107  (void)setsid();
108 
109 
110  for (k=0; k < 2; ++k) {
111  childpid = fork();
112  if (childpid < 0) {
113  g_error("Cannot fork [%s %d]", g_strerror(errno), errno);
114  exit(1);
115  }
116  if (childpid > 0) {
117  exit(0);
118  }
119  // Otherwise, we're the child.
120  // NOTE: probably can't drop a core in '/'
121  }
122  }
123 #endif
124  if (chdir(dirtorunin ? dirtorunin : "/" )) {
125  g_warning("%s.%d: Cannot change directory to [%s]", __FUNCTION__
126  , __LINE__, dirtorunin);
127  }
128  umask(027);
129  // Need to do this after forking and before closing our file descriptors
130  if (pidfile) {
131  if (are_we_already_running(pidfile, NULL) == PID_RUNNING) {
132  g_message("%s.%d: Already running.", __FUNCTION__, __LINE__);
133  exit(0);
134  }
135  // Exit if we can't create the requested pidfile
136  if (!create_pid_file(pidfile)) {
137  exit(1);
138  }
139  }
140  // Now make sure we don't have any funky file descriptors hanging around here...
141  if (!stay_in_foreground) {
142  int nullfd;
143  for (j=0; j < DIMOF(nullperms); ++j) {
144  close(j);
145  nullfd = open("/dev/null", nullperms[j]);
146 
147  if (nullfd < 0) {
148  g_error("%s.%d: Cannot open /dev/null(!)", __FUNCTION__, __LINE__);
149  exit(1);
150  }
151 
152  // Even more paranoia
153  if (nullfd != (int)j) {
154  if (dup2(nullfd, j) != (int)j) {
155  g_error("dup2(%d,%d) failed. World coming to end.", nullfd, j);
156  }
157  (void)close(nullfd);
158  }
159  }
160  }
161  // A bit paranoid - but not so much as you might think...
162  for (j=DIMOF(nullperms); j < nofile_limits.rlim_cur; ++j) {
163  close(j);
164  }
165 }
166 #else
167 void
168 daemonize_me( gboolean stay_in_foreground,
169  const char* dirtorunin,
170  const char* pidfile)
171 {
172  if (pidfile) {
173  if (are_we_already_running(pidfile, NULL) == PID_RUNNING) {
174  g_message("Already running.");
175  exit(0);
176  }
177  }
178  // Exit if we can't create the requested pidfile
179  if (!create_pid_file(pidfile)) {
180  exit(1);
181  }
182 }
183 #endif
184 
185 static gboolean syslog_opened = FALSE;
186 void
187 assimilation_openlog(const char* logname)
188 {
189 #ifndef WIN32
190  const int syslog_options = LOG_PID|LOG_NDELAY;
191  const int syslog_facility = LOG_DAEMON;
192 
193  if (!syslog_opened) {
194  g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION
195  , assimilation_logger, NULL);
196  }
197  assim_syslogid = strrchr(logname, '/');
198  if (assim_syslogid && assim_syslogid[1] != '\0') {
199  assim_syslogid += 1;
200  }else{
201  assim_syslogid = logname;
202  }
203  if (syslog_opened) {
204  closelog();
205  }
206  g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL);
207  openlog(assim_syslogid, syslog_options, syslog_facility);
208  syslog_opened = TRUE;
209 #endif
210 }
211 void
212 assimilation_logger(const gchar *log_domain,
213  GLogLevelFlags log_level,
214  const gchar *message,
215  gpointer ignored)
216 {
217 #ifdef WIN32
218 #define LOG_INFO 6
219 #define LOG_DEBUG 7
220 #define LOG_NOTICE 5
221 #define LOG_WARNING 4
222 #define LOG_ERR 3
223 #define LOG_CRIT 2
224 #define LOG_ALERT 1
225 #define LOG_EMERG 0
226 #endif
227  int syslogprio = LOG_INFO;
228  const char * prefix = "INFO:";
229 
230  (void)ignored;
231  if (!syslog_opened) {
233  }
234  if (log_level & G_LOG_LEVEL_DEBUG) {
235  syslogprio = LOG_DEBUG;
236  prefix = "DEBUG";
237  }
238  if (log_level & G_LOG_LEVEL_INFO) {
239  syslogprio = LOG_INFO;
240  prefix = "INFO";
241  }
242  if (log_level & G_LOG_LEVEL_MESSAGE) {
243  syslogprio = LOG_NOTICE;
244  prefix = "NOTICE";
245  }
246  if (log_level & G_LOG_LEVEL_WARNING) {
247  syslogprio = LOG_WARNING;
248  prefix = "WARN";
249  }
250  if (log_level & G_LOG_LEVEL_CRITICAL) {
251  syslogprio = LOG_ERR;
252  prefix = "ERROR";
253  }
254  if (log_level & G_LOG_LEVEL_ERROR) {
255  syslogprio = LOG_EMERG; // Or maybe LOG_CRIT ?
256  prefix = "EMERG";
257  }
258 #ifndef WIN32
259  syslog(syslogprio, "%s:%s %s", prefix
260  , log_domain == NULL ? "" : log_domain
261  , message);
262 #else
263  {
264  char msg[256];
265  g_snprintf(msg, sizeof(msg), "%s: %s:%s %s\n",assim_syslogid, prefix
266  , log_domain == NULL ? "" : log_domain
267  , message);
268  OutputDebugString((LPCSTR) msg);
269  }
270 #endif
271  fprintf(stderr, "%s: %s:%s %s\n", assim_syslogid, prefix
272  , log_domain == NULL ? "" : log_domain
273  , message);
274 }
275 
276 #ifdef WIN32
277 #define SEP '\\'
278 //@todo: these will be replaced when windows functionality cathes up
279 #define PROCSELFEXE "/"
280 #define PROCOTHEREXE "/"
281 #else
282 #define SEP '/'
283 #define PROCSELFEXE "/proc/self/exe"
284 #define PROCOTHEREXE "/proc/%d/exe"
285 #endif
286 #define MAXPIDLEN 16
287 #define MAXPATH 256
288 
289 static gboolean created_pid_file = FALSE;
290 
293 are_we_already_running( const char * pidfile
294 , int* pidarg)
295 {
296  char * pidcontents; // Contents of the pid file
297  int pid; // Pid from the pid file
298  char* ourexepath; // Pathname of our executable
299  char* ourexecmd; // command name of our executable
300  char* pidexepath; // Pathname of the 'pid' executable
301  char* pidexecmd; // command name the 'pid' executable
302 #ifdef WIN32
303  char w_ourexepath[MAXPATH];
304  int nSize = MAXPATH-1, ret;
305 #endif
306  char pidexename[sizeof(PROCOTHEREXE)+16]; // Name of /proc entry for 'pid'
307 
308  //g_debug("%s.%d: PID file path [%s]", __FUNCTION__, __LINE__, pidfile);
309  if (pidarg) {
310  *pidarg = 0;
311  }
312 
313  // Does the pid file exist?
314  if (!g_file_test(pidfile, G_FILE_TEST_IS_REGULAR)) {
315  //g_debug("%s.%d: PID file [%s] does not exist", __FUNCTION__, __LINE__, pidfile);
316  return PID_NOTRUNNING;
317  }
318  // Can we read it?
319  if (!g_file_get_contents(pidfile, &pidcontents, NULL, NULL)) {
320  //g_debug("%s.%d: PID file [%s] cannot be read", __FUNCTION__, __LINE__, pidfile);
321  return PID_NOTRUNNING;
322  }
323  // We assume it's passably well-formed...
324  pid = atoi(pidcontents);
325  g_free(pidcontents); pidcontents = NULL;
326  // Is it a legitimate pid value?
327  if (pid < 2) {
328  //g_debug("%s.%d: PID file [%s] contains pid %d", __FUNCTION__, __LINE__, pidfile, pid);
329  return PID_NOTRUNNING;
330  }
331  if (pidarg) {
332  *pidarg = pid;
333  }
334  // Is it still running?
335 #ifdef WIN32
336  if(TerminateProcess((void *)pid, 0) == 0)
337 #else
338  if (kill(pid, 0) < 0 && errno != EPERM)
339 #endif
340  {
341  //g_debug("%s.%d: PID %d is not running", __FUNCTION__, __LINE__, pid);
342  return PID_DEAD;
343  }
344  // Now let's see if it's "us" - our process
345  // That is, is it the same executable as we are?
346 
347  // So, what is the pathname of our executable?
348 #ifndef WIN32
349  ourexepath = g_file_read_link(PROCSELFEXE, NULL);
350 #else
351  ret = GetModuleFileName(NULL, w_ourexepath, nSize);
352  if(ret == 0) {
353  //g_debug("%s.%d: GetModuleFileName failed %d", __FUNCTION__, __LINE__, GetLastError());
354  return(PID_DEAD);
355  }
356  ourexepath = g_strdup(w_ourexepath);
357 #endif
358  if (NULL == ourexepath) {
359  return PID_RUNNING;
360  }
361  if (strrchr(ourexepath, SEP) != NULL) {
362  ourexecmd = strrchr(ourexepath, SEP)+1;
363  }else{
364  ourexecmd = ourexepath;
365  }
366  g_snprintf(pidexename, sizeof(pidexename), PROCOTHEREXE, pid);
367 
368  // What is the pathname of the executable that holds the pid lock?
369  pidexepath = g_file_read_link(pidexename, NULL);
370  if (pidexepath == NULL) {
371  g_free(ourexepath); ourexepath = NULL;
372  return PID_RUNNING;
373  }
374  if (strrchr(pidexepath, SEP) != NULL) {
375  pidexecmd = strrchr(pidexepath, SEP)+1;
376  }else{
377  pidexecmd = pidexepath;
378  }
379  // Is it the same executable as we are?
380  if (strcmp(ourexecmd, pidexecmd) == 0) {
381  //g_debug("%s.%d: Link %s is the same as %s", __FUNCTION__, __LINE__, ourexepath
382  //, pidexepath);
383  g_free(ourexepath); ourexepath = NULL;
384  g_free(pidexepath); pidexepath = NULL;
385  return PID_RUNNING;
386  }
387  //g_debug("%s.%d: Link %s is NOT the same as %s", __FUNCTION__, __LINE__, ourexecmd
388  //, pidexecmd);
389  g_free(ourexepath); ourexepath = NULL;
390  g_free(pidexepath); pidexepath = NULL;
391  return PID_NOTUS;
392 }
393 
395 gboolean
396 create_pid_file(const char * pidfile)
397 {
398  char pidbuf[16];
399  GError* errptr = NULL;
400  PidRunningStat pstat;
401 
402 #if _MSC_VER
403 WINIMPORT
404 __out
405 void *
406 __stdcall
407 GetCurrentProcess();
408 #define GETPID GetCurrentProcessId()
409 #else
410 #define GETPID getpid()
411 #endif
412  //g_debug("%s.%d: Creating pid file %s for pid %d", __FUNCTION__, __LINE__, pidfile, GETPID);
413  pstat = are_we_already_running(pidfile, NULL);
414  if (PID_RUNNING == pstat) {
415  return FALSE;
416  }
417  g_snprintf(pidbuf, sizeof(pidbuf), "%6d\n", GETPID);
418  if (pstat == PID_DEAD || pstat == PID_NOTUS) {
419  //g_debug("%s.%d: Unlinking dead pid file %s", __FUNCTION__, __LINE__, pidfile);
420  g_unlink(pidfile);
421  }
422 
423  if (g_file_set_contents(pidfile, pidbuf, strlen(pidbuf), &errptr)) {
424  //g_debug("%s.%d: Successfully set file %s to content [%s]"
425  //, __FUNCTION__, __LINE__, pidfile, pidbuf);
426 #ifndef WIN32
427  if (chmod(pidfile, 0644) < 0) {
428  g_warning("%s.%d: Could not chmod pid file %s to 0644", __FUNCTION__, __LINE__
429  , pidfile);
430  }
431 #endif
432  created_pid_file = TRUE;
433  return TRUE;
434  }
435  g_critical("%s.%d: Cannot create pid file [%s]. Reason: %s"
436  , __FUNCTION__, __LINE__, pidfile, errptr->message);
437  fprintf(stderr, "%s.%d: Cannot create pid file [%s]. Reason: %s\n"
438  , __FUNCTION__, __LINE__, pidfile, errptr->message);
439  return FALSE;
440 }
442 char *
444  char *p_pidfile;
445 #ifndef WIN32
446  p_pidfile = g_build_filename(STD_PID_DIR, procname, NULL);
447 #else
448  const char * const *dirs = g_get_system_config_dirs();
449  p_pidfile = g_build_filename(dirs[0], procname, NULL);
450 #endif
451  //g_debug("%s.%d: pidfile = %s", __FUNCTION__, __LINE__, p_pidfile);
452  return(p_pidfile);
453 }
455 void
456 remove_pid_file(const char * pidfile)
457 {
458  if (created_pid_file) {
459  g_unlink(pidfile);
460  }
461 }
462 
464 int
465 kill_pid_service(const char * pidfile, int signal)
466 {
467  int service_pid = 0;
468  PidRunningStat pidstat;
469 
470  pidstat = are_we_already_running(pidfile, &service_pid);
471  if (pidstat == PID_RUNNING) {
472 #ifndef WIN32
473  return kill((pid_t)service_pid, signal);
474 #else
475  if(TerminateProcess((HANDLE) service_pid, signal) != 0) {
476  g_unlink(pidfile);
477  return(-1);
478  }
479 #endif
480  }
481  g_unlink(pidfile); // No harm in removing it...
482  return 0;
483 }
484 
485 static const char * saved_pidfile = NULL;
487 void
488 rmpid_and_exit_on_signal(const char * pidfile, int signal_in)
489 {
490 #ifndef WIN32
491  struct sigaction sigact;
492 #endif
493 
494  if (pidfile != NULL) {
495  saved_pidfile = pidfile;
496  }
497 #ifndef WIN32
498  memset(&sigact, 0, sizeof(sigact));
499  sigact.sa_handler = catch_pid_signal;
500  sigaction(signal_in, &sigact, NULL);
501 #else
502  signal(signal_in, catch_pid_signal);
503 #endif
504 }
505 FSTATIC void
506 catch_pid_signal(int unused_signum)
507 {
508  (void)unused_signum;
509  g_unlink(saved_pidfile);
510  exit(0);
511 }
512 
514 guint
516 {
517  // These exit codes from the Linux Standard Base
518  // http://refspecs.linuxbase.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
519  switch (stat) {
520  case PID_NOTRUNNING:
521  return 3; // LSB: program is not running`
522 
523  case PID_DEAD: /*FALLTHROUGH*/
524  case PID_NOTUS: // This could be an excessively anal retentive check...
525  return 1; // LSB: program is dead and /var/run/pid exists
526 
527  case PID_RUNNING:
528  return 0; // LSB: program is running
529 
530  default: /*FALLTHROUGH*/
531  break;
532  }
533  return 4; // LSB: program or service status is unknown
534 }
535 
537 WINEXPORT gchar **
538 assim_merge_environ(const gchar * const* env
539 , ConfigContext* update)
540 {
541  int j;
542  int initenvcount;
543  int updatecount = 0;
544  gchar** result;
545  int resultelem = 0;
546  gchar** newenv = NULL;
547 
548  if (NULL == env) {
549  // The result of g_get_environ() has to be freed later...
550  // Store malloced copy in 'newenv' so that 'env' parameter can be const...
551  newenv = g_get_environ();
552  env = (const gchar* const*) newenv;
553  }
554 
555  for (initenvcount = 0; env[initenvcount]; ++initenvcount) {
556  ; /* Nothing - just count */
557  }
558  if (update) {
559  updatecount = update->keycount(update);
560  }
561 
562  // This is the worst case for the size needed...
563  result = (gchar**) g_malloc((updatecount+initenvcount+1)* sizeof(gchar*));
564 
565  if (update) {
566  GSList* updatekeys = NULL;
567  GSList* thiskeylist;
568 
569 
570  updatekeys = update->keys(update);
571 
572  // Put all our update keys in first...
573  for (thiskeylist = updatekeys; thiskeylist; thiskeylist=thiskeylist->next) {
574  char * thiskey = (char *)thiskeylist->data;
575  enum ConfigValType vtype= update->gettype(update, thiskey);
576  GString * gsvalue = g_string_new("");
577 
578  g_string_printf(gsvalue, "%s=", thiskey);
579 
580  switch (vtype) {
581  case CFG_BOOL:
582  // Do we want true/false -- or 1/0 ??
583  g_string_append(gsvalue, update->getbool(update, thiskey) ? "true" : "false");
584  break;
585 
586  case CFG_INT64:
587  g_string_append_printf(gsvalue, FMT_64BIT"d", update->getint(update,thiskey));
588  break;
589 
590  case CFG_STRING:
591  g_string_append(gsvalue, update->getstring(update, thiskey));
592  break;
593  case CFG_NETADDR: {
594  NetAddr* addr = update->getaddr(update,thiskey);
595  char * s = addr->baseclass.toString(&addr->baseclass);
596  g_string_append(gsvalue, s);
597  g_free(s);
598  // No need to unref 'addr' - it's not a copy
599  break;
600  }
601  default:
602  g_string_free(gsvalue, TRUE);
603  gsvalue = NULL;
604  g_free(thiskey);
605  thiskeylist->data = thiskey = NULL;
606  continue;
607  }
608  result[resultelem] = g_string_free(gsvalue, FALSE);
609  gsvalue = NULL;
610  ++resultelem;
611  // The keys in the key list are NOT copies. Don't free them!!
612  // g_free(thiskey);
613  thiskeylist->data = thiskey = NULL;
614  }
615  // Done with 'updatekeys'
616  g_slist_free(updatekeys);
617  updatekeys = NULL;
618 
619  }
620 
621  // Now, add all the env vars not overridden by 'update'
622  for (j = 0; env[j]; ++j) {
623  char * envname;
624  char * eqpos;
625  eqpos = strchr(env[j], '=');
626  if (NULL == eqpos || eqpos == env[j]) {
627  continue;
628  }
629  envname = g_strndup(env[j], eqpos - env[j]);
630  // Make sure it isn't overridden before including it...
631  if (NULL == update || (update->gettype(update, envname) == CFG_EEXIST)) {
632  result[resultelem] = g_strdup(env[j]);
633  ++resultelem;
634  }
635  g_free(envname);
636  }
637  result[resultelem] = NULL;
638 
639  if (newenv) {
640  g_strfreev(newenv);
641  }
642  newenv = NULL;
643  env = NULL;
644  return result;
645 }
646 
648 WINEXPORT void
649 assim_free_environ(gchar ** env)
650 {
651  g_strfreev(env);
652 }