/****************************************************************************** * * * Function: zbx_child_fork * * * * Purpose: fork from master process and set SIGCHLD handler * * * * Return value: same as system fork() function * * * * Author: Rudolfs Kreicbergs * * * * Comments: use this function only for forks from the main process * * * ******************************************************************************/ int zbx_child_fork() { pid_t pid; pid = zbx_fork(); /* ignore SIGCHLD to avoid problems with exiting scripts in zbx_execute() and other cases */ if (0 == pid) signal(SIGCHLD, SIG_DFL); return pid; }
/****************************************************************************** * * * Function: zbx_popen * * * * Purpose: this function opens a process by creating a pipe, forking, * * and invoking the shell * * * * Parameters: pid - [OUT] child process PID * * command - [IN] a pointer to a null-terminated string * * containing a shell command line * * * * Return value: on success, reading file descriptor is returned. On error, * * -1 is returned, and errno is set appropriately * * * * Author: Alexander Vladishev * * * ******************************************************************************/ static int zbx_popen(pid_t *pid, const char *command) { const char *__function_name = "zbx_popen"; int fd[2]; zabbix_log(LOG_LEVEL_DEBUG, "In %s() command:'%s'", __function_name, command); if (-1 == pipe(fd)) return -1; if (-1 == (*pid = zbx_fork())) { close(fd[0]); close(fd[1]); return -1; } if (0 != *pid) /* parent process */ { close(fd[1]); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __function_name, fd[0]); return fd[0]; } /* child process */ close(fd[0]); dup2(fd[1], STDOUT_FILENO); dup2(fd[1], STDERR_FILENO); close(fd[1]); /* set the child as the process group leader, otherwise orphans may be left after timeout */ if (-1 == setpgid(0, 0)) { zabbix_log(LOG_LEVEL_ERR, "%s(): failed to create a process group: %s", __function_name, zbx_strerror(errno)); exit(EXIT_SUCCESS); } zabbix_log(LOG_LEVEL_DEBUG, "%s(): executing script", __function_name); execl("/bin/sh", "sh", "-c", command, NULL); /* execl() returns only when an error occurs */ zabbix_log(LOG_LEVEL_WARNING, "execl() failed for [%s]: %s", command, zbx_strerror(errno)); exit(EXIT_SUCCESS); }
/****************************************************************************** * * * Function: zbx_popen * * * * Purpose: this function opens a process by creating a pipe, forking, * * and invoking the shell * * * * Parameters: pid - [OUT] child process PID * * command - [IN] a pointer to a null-terminated string * * containing a shell command line * * * * Return value: on success, reading file descriptor is returned. On error, * * -1 is returned, and errno is set appropriately * * * * Author: Alexander Vladishev * * * * Comments: * * * ******************************************************************************/ static int zbx_popen(pid_t *pid, const char *command) { const char *__function_name = "zbx_popen"; int fd[2]; zabbix_log(LOG_LEVEL_DEBUG, "In %s() command:'%s'", __function_name, command); if (-1 == pipe(fd)) return -1; if (-1 == (*pid = zbx_fork())) { close(fd[0]); close(fd[1]); return -1; } if (*pid > 0) /* parent process */ { close(fd[1]); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __function_name, fd[0]); return fd[0]; } /* child process */ close(fd[0]); dup2(fd[1], STDOUT_FILENO); close(fd[1]); zabbix_log(LOG_LEVEL_DEBUG, "%s() executing script", __function_name); execl("/bin/sh", "sh", "-c", command, NULL); zabbix_log(LOG_LEVEL_DEBUG, "%s() cannot execute script [%s]: %s", __function_name, command, strerror(errno)); exit(FAIL); }
/****************************************************************************** * * * Function: execute_action * * * * Purpose: execute an action depending on mediatype * * * * Parameters: alert - alert details * * mediatype - media details * * * * Return value: SUCCESS - action executed sucessfully * * FAIL - otherwise, error will contain error message * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ int execute_action(DB_ALERT *alert,DB_MEDIATYPE *mediatype, char *error, int max_error_len) { int res=FAIL; int pid; char full_path[MAX_STRING_LEN]; char env_alertid[128],env_actionid[128],env_clock[128],env_mediatypeid[128], env_status[128]; char *zbxenv[] = { (char *)&env_alertid, (char *)&env_actionid, (char *)&env_clock, (char *)&env_mediatypeid, (char *)&env_status, (char *)0 }; zabbix_log( LOG_LEVEL_DEBUG, "In execute_action(%s)", mediatype->smtp_server); if(mediatype->type==MEDIA_TYPE_EMAIL) { alarm(40); res = send_email(mediatype->smtp_server,mediatype->smtp_helo,mediatype->smtp_email,alert->sendto,alert->subject, alert->message, error, max_error_len); alarm(0); } #if defined (HAVE_JABBER) else if(mediatype->type==MEDIA_TYPE_JABBER) { /* Jabber uses its own timeouts */ res = send_jabber(mediatype->username, mediatype->passwd, alert->sendto, alert->subject, alert->message, error, max_error_len); } #endif /* HAVE_JABBER */ else if(mediatype->type==MEDIA_TYPE_SMS) { /* SMS uses its own timeouts */ res = send_sms(mediatype->gsm_modem,alert->sendto,alert->message, error, max_error_len); } else if(mediatype->type==MEDIA_TYPE_EXEC) { /* if(-1 == execl(CONFIG_ALERT_SCRIPTS_PATH,mediatype->exec_path,alert->sendto,alert->subject,alert->message))*/ zabbix_log( LOG_LEVEL_DEBUG, "Before execl([%s],[%s])", CONFIG_ALERT_SCRIPTS_PATH, mediatype->exec_path); /* if(-1 == execl("/home/zabbix/bin/lmt.sh","lmt.sh",alert->sendto,alert->subject,alert->message,(char *)0))*/ pid = zbx_fork(); if(0 != pid) { waitpid(pid,NULL,0); } else { strscpy(full_path,CONFIG_ALERT_SCRIPTS_PATH); zbx_strlcat(full_path,"/",MAX_STRING_LEN); zbx_strlcat(full_path,mediatype->exec_path,MAX_STRING_LEN); ltrim_spaces(full_path); zabbix_log( LOG_LEVEL_DEBUG, "Before executing [%s]", full_path); zbx_snprintf(env_alertid,127,"ZABBIX_ALERT_ID=%d", alert->alertid); zbx_snprintf(env_actionid,127,"ZABBIX_ACTION_ID=%d", alert->actionid); zbx_snprintf(env_clock,127,"ZABBIX_ALERT_TIME=%d", alert->clock); zbx_snprintf(env_mediatypeid,127,"ZABBIX_ALERT_MEDIATYPEID=%d", alert->mediatypeid); zbx_snprintf(env_status,127,"ZABBIX_ALERT_STATUS=%d", alert->status); /* if(-1 == execl(full_path,mediatype->exec_path,alert->sendto,alert->subject,alert->message,(char *)0))*/ if(-1 == execle(full_path,mediatype->exec_path,alert->sendto,alert->subject,alert->message,(char *)0, zbxenv)) { zabbix_log( LOG_LEVEL_ERR, "Error executing [%s] [%s]", full_path, strerror(errno)); zabbix_syslog("Error executing [%s] [%s]", full_path, strerror(errno)); zbx_snprintf(error,max_error_len,"Error executing [%s] [%s]", full_path, strerror(errno)); res = FAIL; } else { res = SUCCEED; } /* In normal case the program will never reach this point */ zabbix_log( LOG_LEVEL_DEBUG, "After execl()"); exit(0); } res = SUCCEED; } else { zabbix_log( LOG_LEVEL_ERR, "Unsupported media type [%d] for alert ID [%d]", mediatype->type, alert->alertid); zabbix_syslog("Unsupported media type [%d] for alert ID [%d]", mediatype->type, alert->alertid); zbx_snprintf(error,max_error_len,"Unsupported media type [%d]", mediatype->type); res=FAIL; } zabbix_log( LOG_LEVEL_DEBUG, "End execute_action()"); return res; }
/****************************************************************************** * * * Function: daemon_start * * * * Purpose: init process as daemon * * * * Parameters: allow_root - allow root permission for application * * user - user on the system to which to drop the * * privileges * * * * Author: Alexei Vladishev * * * * Comments: it doesn't allow running under 'root' if allow_root is zero * * * ******************************************************************************/ int daemon_start(int allow_root, const char *user) { pid_t pid; struct passwd *pwd; if (0 == allow_root && 0 == getuid()) /* running as root? */ { if (NULL == user) user = "******"; pwd = getpwnam(user); if (NULL == pwd) { zbx_error("user %s does not exist", user); zbx_error("cannot run as root!"); exit(EXIT_FAILURE); } if (0 == pwd->pw_uid) { zbx_error("User=%s contradicts AllowRoot=0", user); zbx_error("cannot run as root!"); exit(EXIT_FAILURE); } if (-1 == setgid(pwd->pw_gid)) { zbx_error("cannot setgid to %s: %s", user, zbx_strerror(errno)); exit(EXIT_FAILURE); } #ifdef HAVE_FUNCTION_INITGROUPS if (-1 == initgroups(user, pwd->pw_gid)) { zbx_error("cannot initgroups to %s: %s", user, zbx_strerror(errno)); exit(EXIT_FAILURE); } #endif if (-1 == setuid(pwd->pw_uid)) { zbx_error("cannot setuid to %s: %s", user, zbx_strerror(errno)); exit(EXIT_FAILURE); } #ifdef HAVE_FUNCTION_SETEUID if (-1 == setegid(pwd->pw_gid) || -1 == seteuid(pwd->pw_uid)) { zbx_error("cannot setegid or seteuid to %s: %s", user, zbx_strerror(errno)); exit(EXIT_FAILURE); } #endif } if (0 != (pid = zbx_fork())) exit(EXIT_SUCCESS); setsid(); signal(SIGHUP, SIG_IGN); if (0 != (pid = zbx_fork())) exit(EXIT_SUCCESS); if (-1 == chdir("/")) /* this is to eliminate warning: ignoring return value of chdir */ assert(0); umask(0002); redirect_std(CONFIG_LOG_FILE); if (FAIL == create_pid_file(CONFIG_PID_FILE)) exit(EXIT_FAILURE); atexit(daemon_stop); parent_pid = (int)getpid(); zbx_set_common_signal_handlers(); set_daemon_signal_handlers(); /* Set SIGCHLD now to avoid race conditions when a child process is created before */ /* sigaction() is called. To avoid problems when scripts exit in zbx_execute() and */ /* other cases, SIGCHLD is set to SIG_DFL in zbx_child_fork(). */ zbx_set_child_signal_handler(); return MAIN_ZABBIX_ENTRY(); }
/****************************************************************************** * * * Function: execute_action * * * * Purpose: execute an action depending on mediatype * * * * Parameters: alert - alert details * * mediatype - media details * * * * Return value: SUCCESS - action executed sucessfully * * FAIL - otherwise, error will contain error message * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ int execute_action(DB_ALERT *alert, DB_MEDIATYPE *mediatype, char *error, int max_error_len) { const char *__function_name = "execute_action"; int pid, res = FAIL; char full_path[MAX_STRING_LEN]; zabbix_log(LOG_LEVEL_DEBUG, "In %s(): alertid [" ZBX_FS_UI64 "] mediatype [%d]", __function_name, alert->alertid, mediatype->type); if (MEDIA_TYPE_EMAIL == mediatype->type) { alarm(40); res = send_email(mediatype->smtp_server, mediatype->smtp_helo, mediatype->smtp_email, alert->sendto, alert->subject, alert->message, error, max_error_len); alarm(0); } #if defined(HAVE_JABBER) else if (MEDIA_TYPE_JABBER == mediatype->type) { /* Jabber uses its own timeouts */ res = send_jabber(mediatype->username, mediatype->passwd, alert->sendto, alert->subject, alert->message, error, max_error_len); } #endif else if (MEDIA_TYPE_SMS == mediatype->type) { /* SMS uses its own timeouts */ res = send_sms(mediatype->gsm_modem, alert->sendto, alert->message, error, max_error_len); } else if (MEDIA_TYPE_EZ_TEXTING == mediatype->type) { /* Ez Texting uses its own timeouts */ res = send_ez_texting(mediatype->username, mediatype->passwd, alert->sendto, alert->message, mediatype->exec_path, error, max_error_len); } else if (MEDIA_TYPE_EXEC == mediatype->type) { pid = zbx_fork(); if (0 != pid) { waitpid(pid, NULL, 0); res = SUCCEED; } else { zbx_snprintf(full_path, sizeof(full_path), "%s/%s", CONFIG_ALERT_SCRIPTS_PATH, mediatype->exec_path); zabbix_log(LOG_LEVEL_DEBUG, "Before executing [%s]", full_path); if (-1 == execl(full_path, mediatype->exec_path, alert->sendto, alert->subject, alert->message, (char *)NULL)) { zabbix_log(LOG_LEVEL_ERR, "Error executing [%s] [%s]", full_path, strerror(errno)); zabbix_syslog("Error executing [%s] [%s]", full_path, strerror(errno)); exit(FAIL); } else THIS_SHOULD_NEVER_HAPPEN; } } else { zabbix_log(LOG_LEVEL_ERR, "Unsupported media type [%d] for alert ID [" ZBX_FS_UI64 "]", mediatype->type, alert->alertid); zabbix_syslog("Unsupported media type [%d] for alert ID [" ZBX_FS_UI64 "]", mediatype->type, alert->alertid); zbx_snprintf(error, max_error_len, "Unsupported media type [%d]", mediatype->type); res = FAIL; } zabbix_log(LOG_LEVEL_DEBUG, "End of %s(): %d", __function_name, zbx_result_string(res)); return res; }
int RUN_COMMAND(const char *cmd, const char *param, unsigned flags, AGENT_RESULT *result) { #define MAX_FLAG_LEN 10 char command[MAX_STRING_LEN]; char flag[MAX_FLAG_LEN]; #if defined (_WINDOWS) STARTUPINFO si; PROCESS_INFORMATION pi; char full_command[MAX_STRING_LEN]; #else /* not _WINDOWS */ pid_t pid; #endif assert(result); init_result(result); if (CONFIG_ENABLE_REMOTE_COMMANDS != 1) { SET_MSG_RESULT(result, strdup("ZBX_NOTSUPPORTED")); return SYSINFO_RET_FAIL; } if (num_param(param) > 2) return SYSINFO_RET_FAIL; if (0 != get_param(param, 1, command, sizeof(command))) return SYSINFO_RET_FAIL; if (*command == '\0') return SYSINFO_RET_FAIL; zabbix_log(LOG_LEVEL_DEBUG, "Run command '%s'", command); if (0 != get_param(param, 2, flag, sizeof(flag))) *flag = '\0'; if (*flag == '\0') zbx_snprintf(flag, sizeof(flag), "wait"); if (0 == strcmp(flag, "wait")) return EXECUTE_STR(cmd,command,flags,result); else if(0 != strcmp(flag,"nowait")) return SYSINFO_RET_FAIL; #if defined(_WINDOWS) zbx_snprintf(full_command, sizeof(full_command), "cmd /C \"%s\"", command); GetStartupInfo(&si); zabbix_log(LOG_LEVEL_DEBUG, "Execute command '%s'",full_command); if(!CreateProcess( NULL, /* No module name (use command line) */ full_command,/* Name of app to launch */ NULL, /* Default process security attributes */ NULL, /* Default thread security attributes */ FALSE, /* Don't inherit handles from the parent */ 0, /* Normal priority */ NULL, /* Use the same environment as the parent */ NULL, /* Launch in the current directory */ &si, /* Startup Information */ &pi)) /* Process information stored upon return */ { return SYSINFO_RET_FAIL; } #else /* not _WINDOWS */ pid = zbx_fork(); /* run new thread 1 */ switch(pid) { case -1: zabbix_log(LOG_LEVEL_WARNING, "fork failed for command '%s'",command); return SYSINFO_RET_FAIL; case 0: pid = zbx_fork(); /* run new tread 2 to replace by command */ switch(pid) { case -1: zabbix_log(LOG_LEVEL_WARNING, "fork2 failed for '%s'",command); return SYSINFO_RET_FAIL; case 0: /* * DON'T REMOVE SLEEP * sleep needed to return server result as "1" * then we can run "execl" * otherwise command print result into socket with STDOUT id */ sleep(3); /**/ /* replace thread 2 by the execution of command */ if(execl("/bin/sh", "sh", "-c", command, (char *)0)) { zabbix_log(LOG_LEVEL_WARNING, "execl failed for command '%s'",command); } /* In normal case the program will never reach this point */ exit(0); default: waitpid(pid, NULL, WNOHANG); /* NO WAIT can be used for thread 2 closing */ exit(0); /* close thread 1 and transmit thread 2 to system (solve zombie state) */ break; } default: waitpid(pid, NULL, 0); /* wait thread 1 closing */ break; } #endif /* _WINDOWS */ SET_UI64_RESULT(result, 1); return SYSINFO_RET_OK; }
/****************************************************************************** * * * Function: zbx_execute_nowait * * * * Purpose: this function executes a script in the background and * * suppresses the std output * * * * Parameters: command - [IN] command for execution * * * * Author: Rudolfs Kreicbergs * * * ******************************************************************************/ int zbx_execute_nowait(const char *command) { #ifdef _WINDOWS const char *__function_name = "zbx_execute_nowait"; char *full_command; STARTUPINFO si; PROCESS_INFORMATION pi; wchar_t *wcommand; full_command = zbx_dsprintf(NULL, "cmd /C \"%s\"", command); wcommand = zbx_utf8_to_unicode(full_command); /* fill in process startup info structure */ memset(&si, 0, sizeof(si)); si.cb = sizeof(si); GetStartupInfo(&si); zabbix_log(LOG_LEVEL_DEBUG, "%s(): executing [%s]", __function_name, full_command); if (0 == CreateProcess( NULL, /* no module name (use command line) */ wcommand, /* name of app to launch */ NULL, /* default process security attributes */ NULL, /* default thread security attributes */ FALSE, /* do not inherit handles from the parent */ 0, /* normal priority */ NULL, /* use the same environment as the parent */ NULL, /* launch in the current directory */ &si, /* startup information */ &pi)) /* process information stored upon return */ { zabbix_log(LOG_LEVEL_WARNING, "failed to create process for [%s]: %s", full_command, strerror_from_system(GetLastError())); return FAIL; } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); zbx_free(wcommand); zbx_free(full_command); return SUCCEED; #else /* not _WINDOWS */ pid_t pid; /* use a double fork for running the command in background */ if (-1 == (pid = zbx_fork())) { zabbix_log(LOG_LEVEL_WARNING, "first fork() failed for executing [%s]: %s", command, zbx_strerror(errno)); return FAIL; } else if (0 != pid) { waitpid(pid, NULL, 0); return SUCCEED; } /* This is the child process. Now create a grand child process which */ /* will be replaced by execl() with the actual command to be executed. */ pid = zbx_fork(); switch (pid) { case -1: zabbix_log(LOG_LEVEL_WARNING, "second fork() failed for executing [%s]: %s", command, zbx_strerror(errno)); break; case 0: /* this is the grand child process */ /* suppress the output of the executed script, otherwise */ /* the output might get written to a logfile or elsewhere */ redirect_std(NULL); /* replace the process with actual command to be executed */ execl("/bin/sh", "sh", "-c", command, NULL); /* execl() returns only when an error occurs */ zabbix_log(LOG_LEVEL_WARNING, "execl() failed for [%s]: %s", command, zbx_strerror(errno)); break; default: /* this is the child process, exit to complete the double fork */ waitpid(pid, NULL, WNOHANG); break; } /* always exit, parent has already returned */ exit(EXIT_SUCCESS); #endif }
/****************************************************************************** * * * Function: zbx_popen * * * * Purpose: this function opens a process by creating a pipe, forking, * * and invoking the shell * * * * Parameters: pid - [OUT] child process PID * * command - [IN] a pointer to a null-terminated string * * containing a shell command line * * * * Return value: on success, reading file descriptor is returned. On error, * * -1 is returned, and errno is set appropriately * * * * Author: Alexander Vladishev * * * ******************************************************************************/ static int zbx_popen(pid_t *pid, const char *command) { int fd[2], stdout_orig, stderr_orig; zabbix_log(LOG_LEVEL_DEBUG, "In %s() command:'%s'", __func__, command); if (-1 == pipe(fd)) return -1; if (-1 == (*pid = zbx_fork())) { close(fd[0]); close(fd[1]); return -1; } if (0 != *pid) /* parent process */ { close(fd[1]); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __func__, fd[0]); return fd[0]; } /* child process */ close(fd[0]); /* set the child as the process group leader, otherwise orphans may be left after timeout */ if (-1 == setpgid(0, 0)) { zabbix_log(LOG_LEVEL_ERR, "%s(): failed to create a process group: %s", __func__, zbx_strerror(errno)); exit(EXIT_FAILURE); } zabbix_log(LOG_LEVEL_DEBUG, "%s(): executing script", __func__); /* preserve stdout and stderr to restore them in case execl() fails */ stdout_orig = dup(STDOUT_FILENO); stderr_orig = dup(STDERR_FILENO); fcntl(stdout_orig, F_SETFD, FD_CLOEXEC); fcntl(stderr_orig, F_SETFD, FD_CLOEXEC); /* redirect output right before script execution after all logging is done */ dup2(fd[1], STDOUT_FILENO); dup2(fd[1], STDERR_FILENO); close(fd[1]); execl("/bin/sh", "sh", "-c", command, NULL); /* restore original stdout and stderr, because we don't want our output to be confused with script's output */ dup2(stdout_orig, STDOUT_FILENO); dup2(stderr_orig, STDERR_FILENO); close(stdout_orig); close(stderr_orig); /* this message may end up in stdout or stderr, that's why we needed to save and restore them */ zabbix_log(LOG_LEVEL_WARNING, "execl() failed for [%s]: %s", command, zbx_strerror(errno)); /* execl() returns only when an error occurs, let parent process know about it */ exit(EXIT_FAILURE); }
int MAIN_ZABBIX_ENTRY(void) { int i; pid_t pid; zbx_sock_t listen_sock; int server_num = 0; if(CONFIG_LOG_FILE == NULL) { zabbix_open_log(LOG_TYPE_SYSLOG,CONFIG_LOG_LEVEL,NULL); } else { zabbix_open_log(LOG_TYPE_FILE,CONFIG_LOG_LEVEL,CONFIG_LOG_FILE); } #ifdef HAVE_SNMP # define SNMP_FEATURE_STATUS "YES" #else # define SNMP_FEATURE_STATUS " NO" #endif #ifdef HAVE_LIBCURL # define LIBCURL_FEATURE_STATUS "YES" #else # define LIBCURL_FEATURE_STATUS " NO" #endif #ifdef HAVE_ODBC # define ODBC_FEATURE_STATUS "YES" #else # define ODBC_FEATURE_STATUS " NO" #endif #ifdef HAVE_IPV6 # define IPV6_FEATURE_STATUS "YES" #else # define IPV6_FEATURE_STATUS " NO" #endif zabbix_log( LOG_LEVEL_WARNING, "Starting zabbix_proxy. ZABBIX %s (revision %s).", ZABBIX_VERSION, ZABBIX_REVISION); zabbix_log( LOG_LEVEL_WARNING, "**** Enabled features ****"); zabbix_log( LOG_LEVEL_WARNING, "SNMP monitoring: " SNMP_FEATURE_STATUS ); zabbix_log( LOG_LEVEL_WARNING, "WEB monitoring: " LIBCURL_FEATURE_STATUS ); zabbix_log( LOG_LEVEL_WARNING, "ODBC: " ODBC_FEATURE_STATUS ); zabbix_log( LOG_LEVEL_WARNING, "IPv6 support: " IPV6_FEATURE_STATUS ); zabbix_log( LOG_LEVEL_WARNING, "**************************"); #ifdef HAVE_SQLITE3 if(ZBX_MUTEX_ERROR == php_sem_get(&sqlite_access, CONFIG_DBNAME)) { zbx_error("Unable to create mutex for sqlite"); exit(FAIL); } #endif /* HAVE_SQLITE3 */ DBinit(); init_database_cache(ZBX_PROCESS_PROXY); threads = calloc(1 + CONFIG_CONFSYNCER_FORKS + CONFIG_DATASENDER_FORKS + CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS + CONFIG_HOUSEKEEPER_FORKS + CONFIG_UNREACHABLE_POLLER_FORKS + CONFIG_HTTPPOLLER_FORKS + CONFIG_DISCOVERER_FORKS + CONFIG_DBSYNCER_FORKS + CONFIG_IPMIPOLLER_FORKS, sizeof(pid_t)); if (CONFIG_TRAPPERD_FORKS > 0) { if (FAIL == zbx_tcp_listen(&listen_sock, CONFIG_LISTEN_IP, (unsigned short)CONFIG_LISTEN_PORT)) { zabbix_log(LOG_LEVEL_CRIT, "Listener failed with error: %s.", zbx_tcp_strerror()); exit(1); } } for ( i = 1; i <= CONFIG_CONFSYNCER_FORKS + CONFIG_DATASENDER_FORKS + CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS + CONFIG_HOUSEKEEPER_FORKS + CONFIG_UNREACHABLE_POLLER_FORKS + CONFIG_HTTPPOLLER_FORKS + CONFIG_DISCOVERER_FORKS + CONFIG_DBSYNCER_FORKS + CONFIG_IPMIPOLLER_FORKS; i++) { if ((pid = zbx_fork()) == 0) { server_num = i; break; } else threads[i] = pid; } /* Main process */ if (server_num == 0) { init_main_process(); zabbix_log(LOG_LEVEL_WARNING, "server #%d started [Heartbeat sender]", server_num); main_heart_loop(); for (;;) zbx_sleep(3600); } if (server_num <= CONFIG_CONFSYNCER_FORKS) { zabbix_log(LOG_LEVEL_WARNING, "server #%d started [Configuration syncer]", server_num); main_proxyconfig_loop(server_num); } else if (server_num <= CONFIG_CONFSYNCER_FORKS + CONFIG_DATASENDER_FORKS) { zabbix_log(LOG_LEVEL_WARNING, "server #%d started [Datasender]", server_num); main_datasender_loop(); } else if (server_num <= CONFIG_CONFSYNCER_FORKS + CONFIG_DATASENDER_FORKS + CONFIG_POLLER_FORKS) { #ifdef HAVE_SNMP init_snmp("zabbix_server"); #endif /* HAVE_SNMP */ zabbix_log(LOG_LEVEL_WARNING, "server #%d started [Poller. SNMP:"SNMP_FEATURE_STATUS"]", server_num); main_poller_loop(ZBX_PROCESS_PROXY, ZBX_POLLER_TYPE_NORMAL, server_num - (CONFIG_CONFSYNCER_FORKS + CONFIG_DATASENDER_FORKS)); } else if (server_num <= CONFIG_CONFSYNCER_FORKS + CONFIG_DATASENDER_FORKS + CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS) { zabbix_log(LOG_LEVEL_WARNING, "server #%d started [Trapper]", server_num); child_trapper_main(ZBX_PROCESS_PROXY, &listen_sock); } else if(server_num <= CONFIG_CONFSYNCER_FORKS + CONFIG_DATASENDER_FORKS + CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS) { zabbix_log(LOG_LEVEL_WARNING, "server #%d started [ICMP pinger]", server_num); main_pinger_loop(ZBX_PROCESS_PROXY, server_num - (CONFIG_CONFSYNCER_FORKS + CONFIG_DATASENDER_FORKS + CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS)); } else if(server_num <= CONFIG_CONFSYNCER_FORKS + CONFIG_DATASENDER_FORKS + CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS + CONFIG_HOUSEKEEPER_FORKS) { zabbix_log(LOG_LEVEL_WARNING, "server #%d started [Housekeeper]", server_num); main_housekeeper_loop(); } else if(server_num <= CONFIG_CONFSYNCER_FORKS + CONFIG_DATASENDER_FORKS + CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS + CONFIG_HOUSEKEEPER_FORKS + CONFIG_UNREACHABLE_POLLER_FORKS) { #ifdef HAVE_SNMP init_snmp("zabbix_server"); #endif /* HAVE_SNMP */ zabbix_log(LOG_LEVEL_WARNING, "server #%d started [Poller for unreachable hosts. SNMP:"SNMP_FEATURE_STATUS"]", server_num); main_poller_loop(ZBX_PROCESS_PROXY, ZBX_POLLER_TYPE_UNREACHABLE, server_num - (CONFIG_CONFSYNCER_FORKS + CONFIG_DATASENDER_FORKS + CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS + CONFIG_HOUSEKEEPER_FORKS)); } else if (server_num <= CONFIG_CONFSYNCER_FORKS + CONFIG_DATASENDER_FORKS + CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS + CONFIG_HOUSEKEEPER_FORKS + CONFIG_UNREACHABLE_POLLER_FORKS + CONFIG_HTTPPOLLER_FORKS) { zabbix_log(LOG_LEVEL_WARNING, "server #%d started [HTTP Poller]", server_num); main_httppoller_loop(ZBX_PROCESS_PROXY, server_num - (CONFIG_CONFSYNCER_FORKS + CONFIG_DATASENDER_FORKS + CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS + CONFIG_HOUSEKEEPER_FORKS + CONFIG_UNREACHABLE_POLLER_FORKS)); } else if (server_num <= CONFIG_CONFSYNCER_FORKS + CONFIG_DATASENDER_FORKS + CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS + CONFIG_HOUSEKEEPER_FORKS + CONFIG_UNREACHABLE_POLLER_FORKS + CONFIG_HTTPPOLLER_FORKS + CONFIG_DISCOVERER_FORKS) { #ifdef HAVE_SNMP init_snmp("zabbix_server"); #endif /* HAVE_SNMP */ zabbix_log(LOG_LEVEL_WARNING, "server #%d started [Discoverer. SNMP:"SNMP_FEATURE_STATUS"]", server_num); main_discoverer_loop(ZBX_PROCESS_PROXY, server_num - (CONFIG_CONFSYNCER_FORKS + CONFIG_DATASENDER_FORKS + CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS + CONFIG_HOUSEKEEPER_FORKS + CONFIG_UNREACHABLE_POLLER_FORKS + CONFIG_HTTPPOLLER_FORKS)); } else if (server_num <= CONFIG_CONFSYNCER_FORKS + CONFIG_DATASENDER_FORKS + CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS + CONFIG_HOUSEKEEPER_FORKS + CONFIG_UNREACHABLE_POLLER_FORKS + CONFIG_HTTPPOLLER_FORKS + CONFIG_DISCOVERER_FORKS + CONFIG_DBSYNCER_FORKS) { zabbix_log(LOG_LEVEL_WARNING, "server #%d started [DB Syncer]", server_num); main_dbsyncer_loop(); } else if (server_num <= CONFIG_CONFSYNCER_FORKS + CONFIG_DATASENDER_FORKS + CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS + CONFIG_HOUSEKEEPER_FORKS + CONFIG_UNREACHABLE_POLLER_FORKS + CONFIG_HTTPPOLLER_FORKS + CONFIG_DISCOVERER_FORKS + CONFIG_DBSYNCER_FORKS + CONFIG_IPMIPOLLER_FORKS) { zabbix_log(LOG_LEVEL_WARNING, "server #%d started [IPMI Poller]", server_num); main_poller_loop(ZBX_PROCESS_PROXY, ZBX_POLLER_TYPE_IPMI, server_num - (CONFIG_CONFSYNCER_FORKS + CONFIG_DATASENDER_FORKS + CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS + CONFIG_HOUSEKEEPER_FORKS + CONFIG_UNREACHABLE_POLLER_FORKS + CONFIG_HTTPPOLLER_FORKS + CONFIG_DISCOVERER_FORKS + CONFIG_DBSYNCER_FORKS)); } return SUCCEED; }
int daemon_start(int allow_root, const char* user) { pid_t pid; struct passwd *pwd; struct sigaction phan; /* running as root ?*/ if((0 == allow_root) && (0 == getuid() || 0 == getgid())) { pwd = getpwnam(user); if (NULL == pwd) { zbx_error("User %s does not exist.", user); zbx_error("Cannot run as root !"); exit(FAIL); } if(setgid(pwd->pw_gid) ==-1) { zbx_error("Cannot setgid to %s [%s].", user, strerror(errno)); exit(FAIL); } #ifdef HAVE_FUNCTION_INITGROUPS if(initgroups(user, pwd->pw_gid) == -1) { zbx_error("Cannot initgroups to %s [%s].", user, strerror(errno)); exit(FAIL); } #endif /* HAVE_FUNCTION_INITGROUPS */ if(setuid(pwd->pw_uid) == -1) { zbx_error("Cannot setuid to %s [%s].", user, strerror(errno)); exit(FAIL); } #ifdef HAVE_FUNCTION_SETEUID if( (setegid(pwd->pw_gid) ==-1) || (seteuid(pwd->pw_uid) == -1) ) { zbx_error("Cannot setegid or seteuid to zabbix [%s].", strerror(errno)); exit(FAIL); } #endif /* HAVE_FUNCTION_SETEUID */ } if( (pid = zbx_fork()) != 0 ) { exit( 0 ); } setsid(); signal( SIGHUP, SIG_IGN ); if( (pid = zbx_fork()) !=0 ) { exit( 0 ); } /* This is to eliminate warning: ignoring return value of chdir */ if(-1 == chdir("/")) { assert(0); } umask(0002); redirect_std(CONFIG_LOG_FILE); #ifdef HAVE_SYS_RESOURCE_SETPRIORITY if(setpriority(PRIO_PROCESS,0,5)!=0) { zbx_error("Unable to set process priority to 5. Leaving default."); } #endif /* HAVE_SYS_RESOURCE_SETPRIORITY */ /*------------------------------------------------*/ if( FAIL == create_pid_file(APP_PID_FILE)) { exit(FAIL); } phan.sa_handler = child_signal_handler; sigemptyset(&phan.sa_mask); phan.sa_flags = 0; sigaction(SIGINT, &phan, NULL); sigaction(SIGQUIT, &phan, NULL); sigaction(SIGTERM, &phan, NULL); sigaction(SIGPIPE, &phan, NULL); zbx_setproctitle("main process"); return MAIN_ZABBIX_ENTRY(); }
/****************************************************************************** * * * Function: daemon_start * * * * Purpose: init process as daemon * * * * Parameters: allow_root - allow root permission for application * * * * Author: Alexei Vladishev * * * * Comments: it doesn't allow running under 'root' if allow_root is zero * * * ******************************************************************************/ int daemon_start(int allow_root) { pid_t pid; struct passwd *pwd; struct sigaction phan; char user[7] = "zabbix"; /* running as root ? */ if (0 == allow_root && (0 == getuid() || 0 == getgid())) { pwd = getpwnam(user); if (NULL == pwd) { zbx_error("user %s does not exist", user); zbx_error("Cannot run as root!"); exit(FAIL); } if (-1 == setgid(pwd->pw_gid)) { zbx_error("cannot setgid to %s: %s", user, zbx_strerror(errno)); exit(FAIL); } #ifdef HAVE_FUNCTION_INITGROUPS if (-1 == initgroups(user, pwd->pw_gid)) { zbx_error("cannot initgroups to %s: %s", user, zbx_strerror(errno)); exit(FAIL); } #endif if (-1 == setuid(pwd->pw_uid)) { zbx_error("cannot setuid to %s: %s", user, zbx_strerror(errno)); exit(FAIL); } #ifdef HAVE_FUNCTION_SETEUID if (-1 == setegid(pwd->pw_gid) || -1 == seteuid(pwd->pw_uid)) { zbx_error("cannot setegid or seteuid to %s: %s", user, zbx_strerror(errno)); exit(FAIL); } #endif } if (0 != (pid = zbx_fork())) exit(0); setsid(); signal(SIGHUP, SIG_IGN); if (0 != (pid = zbx_fork())) exit(0); /* this is to eliminate warning: ignoring return value of chdir */ if (-1 == chdir("/")) assert(0); umask(0002); redirect_std(CONFIG_LOG_FILE); #ifdef HAVE_SYS_RESOURCE_SETPRIORITY if (0 != setpriority(PRIO_PROCESS, 0, 5)) zbx_error("Unable to set process priority to 5. Leaving default."); #endif /*------------------------------------------------*/ if (FAIL == create_pid_file(CONFIG_PID_FILE)) exit(FAIL); parent_pid = (int)getpid(); phan.sa_sigaction = child_signal_handler; sigemptyset(&phan.sa_mask); phan.sa_flags = SA_SIGINFO; sigaction(SIGINT, &phan, NULL); sigaction(SIGQUIT, &phan, NULL); sigaction(SIGTERM, &phan, NULL); sigaction(SIGPIPE, &phan, NULL); sigaction(SIGILL, &phan, NULL); sigaction(SIGFPE, &phan, NULL); sigaction(SIGSEGV, &phan, NULL); sigaction(SIGBUS, &phan, NULL); sigaction(SIGALRM, &phan, NULL); sigaction(SIGUSR1, &phan, NULL); /* Set SIGCHLD now to avoid race conditions when a child process is created before */ /* sigaction() is called. To avoid problems when scripts exit in zbx_execute() and */ /* other cases, SIGCHLD is set to SIG_IGN in zbx_child_fork(). */ phan.sa_sigaction = parent_signal_handler; sigaction(SIGCHLD, &phan, NULL); zbx_setproctitle("main process"); return MAIN_ZABBIX_ENTRY(); }