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