/** internal functions implementation starts here **/ int ev_irc_connect(void* dummy1, void* dummy2) { int cr; stdlog(L_INFO, "Connecting to IRC server %s:%i", RemoteServer, RemotePort); cr = irc_FullConnect(RemoteServer, RemotePort, ServerPass, 0); if(cr < 0) { errlog("Could not connect to IRC server: %s", irc_GetLastMsg()); exit(1); } stdlog(L_INFO, "Netjoin complete, %.1d Kbs received", irc_InByteCount()/1024); /* not sure if this fork should be on the irc module for now lets leave it like this to make sure we only fork after the connection is fully established */ if( nofork == 0 ) { fork_process(); write_pidfile(); } irc_LoopWhileConnected(); errlog("Disconnected:%s\n", irc_GetLastMsg()); /* stdlog(L_INFO, "PTlink IRC Services Terminated"); */ return 0; }
void start(const char *cmd, monitor_t *monitor) { exec: { pid = fork(); int status; switch (pid) { case -1: perror("fork()"); exit(1); case 0: log("sh -c \"%s\"", cmd); execl("/bin/bash", "bash", "-c", cmd, 0); perror("execl()"); exit(1); default: log("pid %d", pid); // write pidfile if (monitor->pidfile) { log("write pid to %s", monitor->pidfile); write_pidfile(monitor->pidfile, pid); } // wait for exit waitpid(pid, &status, 0); // signalled if (WIFSIGNALED(status)) { log("signal(%s)", strsignal(WTERMSIG(status))); log("sleep(%d)", monitor->sleepsec); sleep(monitor->sleepsec); goto error; } // check status if (WEXITSTATUS(status)) { log("exit(%d)", WEXITSTATUS(status)); log("sleep(%d)", monitor->sleepsec); sleep(monitor->sleepsec); goto error; } // alerts error: { if (monitor->on_error) { log("on error \"%s\"", monitor->on_error); int status = system(monitor->on_error); if (status) { log("exit(%d)", status); log("shutting down"); exit(status); } } goto exec; } } } }
int daemonize() { pid_t pid = fork(); if (pid < 0) { exit(EXIT_FAILURE); } if (pid > 0) { exit(EXIT_SUCCESS); } if (write_pidfile() != 0) { return -1; } int ret = setsid(); if (ret == -1) { XLOG_ERR("failed to set session id: %s", strerror(errno)); unlink(PIDFILE); return -1; } for (int fd = getdtablesize(); fd >= 0; --fd) { close(fd); } chdir("/"); int fd = open("/dev/null", O_RDWR); dup(fd); dup(fd); return 0; }
static void client_background(void) { bb_daemonize(0); logmode &= ~LOGMODE_STDIO; /* rewrite pidfile, as our pid is different now */ write_pidfile(client_config.pidfile); }
void daemonize(const char *pidfile) { pid_t pid, sid; /* Return if already a daemon */ if (getppid() == 1) return; /* Fork off the parent process */ pid = fork(); if (pid < 0) { PERROR("fork", errno); exit(EXIT_FAILURE); } /* If we got a good PID, then we can exit the parent process. */ if (pid > 0) { exit(EXIT_SUCCESS); } /* At this point we are executing as the child process */ write_pidfile(pidfile); /* Change the file mode mask */ umask(0); /* Create a new SID for the child process */ sid = setsid(); if (sid < 0) { PERROR("setsid", errno); exit(EXIT_FAILURE); } /* Change the current working directory. This prevents the current directory from being locked; hence not being able to remove it. */ if ((chdir("/")) < 0) { PERROR("chdir", errno); exit(EXIT_FAILURE); } /* Redirect standard files to /dev/null */ if (freopen( "/dev/null", "r", stdin) == NULL) { PERROR("freopen: stdin", errno); } if (freopen( "/dev/null", "w", stdout) == NULL) { PERROR("freopen: stdout", errno); } if (freopen( "/dev/null", "w", stderr) == NULL) { PERROR("freopen: stderr", errno); } }
int main(int argc, char *argv[]) { char *password; int port = DEFAULT_LISTEN_PORT; parameters_t pars; struct sched_param sched_par; openlog("tcpconsole", LOG_CONS|LOG_NDELAY|LOG_NOWAIT|LOG_PID, LOG_DAEMON); if (getuid()) error_exit("This program must be invoked with root-rights."); password = read_password("/etc/tcpconsole.pw"); if (signal(SIGTERM, SIG_IGN) == SIG_ERR) error_exit("signal(SIGTERM) failed"); if (signal(SIGHUP, SIG_IGN) == SIG_ERR) error_exit("signal(SIGHUP) failed"); pars.sysrq_fd = open_file("/proc/sysrq-trigger", O_WRONLY); pars.vcsa0_fd = open_file("/dev/vcsa", O_RDONLY); if (setpriority(PRIO_PROCESS, 0, -10) == -1) error_exit("Setpriority failed"); if (nice(-20) == -1) error_exit("Failed to set nice-value to -20"); if (mlockall(MCL_CURRENT) == -1 || mlockall(MCL_FUTURE) == -1) error_exit("Failed to lock program in core"); memset(&sched_par, 0x00, sizeof(sched_par)); sched_par.sched_priority = sched_get_priority_max(SCHED_RR); if (sched_setscheduler(0, SCHED_RR, &sched_par) == -1) error_exit("Failed to set scheduler properties for this process"); syslog(LOG_INFO, "tcpconsole started"); write_pidfile("/var/run/tcpconsole.pid"); if ((pars.dmesg_buffer_size = klogctl(10, NULL, 0)) == -1) error_exit("klogctl(10) failed"); pars.dmesg_buffer = (char *)malloc(pars.dmesg_buffer_size + 1); if (!pars.dmesg_buffer) error_exit("malloc failure"); listen_on_socket(port, &pars, password); return 1; }
int main(int argc, char **argv) { struct Config *config = NULL; const char *config_file = "/etc/sniproxy.conf"; int background_flag = 1; pid_t pid; int opt; while ((opt = getopt(argc, argv, "fc:")) != -1) { switch (opt) { case 'c': config_file = optarg; break; case 'f': /* foreground */ background_flag = 0; break; default: usage(); exit(EXIT_FAILURE); } } config = init_config(config_file); if (config == NULL) { fprintf(stderr, "Unable to load %s\n", config_file); return 1; } init_server(config); if (background_flag) { pid = daemonize(config->user ? config->user : DEFAULT_USERNAME); if (pid != 0 && config->pidfile != NULL) { /* parent */ write_pidfile(config->pidfile, pid); free_config(config); return 0; } } run_server(); free_config(config); return 0; }
/* Become a SysV daemon */ int become_daemon(void) { int fd; long maxfd, i; switch (fork()) { case -1: return -1; /* error */ case 0: break; /* child process created */ default: exit(EXIT_FAILURE); /* parent receives child's PID */ } /* Detach from any terminal and create an independent session. */ if (setsid() == -1) return -1; /* Ensure that the daemon can never re-acquire a terminal again. */ switch (fork()) { case -1: return -1; case 0: break; default: exit(EXIT_FAILURE); } /* Reset file mode creation mask. */ umask(0); /* Change current directory to root directory (/) */ if (chdir("/") == -1) return -1; /* Find maximum open file descriptors */ maxfd = sysconf(_SC_OPEN_MAX); if (maxfd == -1) maxfd = MAX_OPEN; /* Close all open file descriptors */ for (i = 0; i < maxfd; i++) close(i); /* Connect /dev/null to stdin, stdout, stderr */ close(STDIN_FILENO); fd = open("/dev/null", O_RDWR); if (fd != STDIN_FILENO) return -1; if (dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO) return -1; if (dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) return -1; /* Write PID file in /var/run/ */ if (write_pidfile() == -1) return -1; return 0; }
int main(int argc, char **argv){ monitor_t monitor; monitor.pidfile = NULL; monitor.mon_pidfile = NULL; monitor.on_error = NULL; monitor.logfile = "mon.log"; monitor.daemon = 0; monitor.sleepsec = 1; command_t program; program.data = &monitor; command_init(&program, "mon", VERSION); command_option(&program, "-l", "--log <path>", "specify logfile [mon.log]", on_log); command_option(&program, "-s", "--sleep <sec>", "sleep seconds before re-executing [1]", on_sleep); command_option(&program, "-S", "--status", "check status of --pidfile", on_status); command_option(&program, "-p", "--pidfile <path>", "write pid to <path>", on_pidfile); command_option(&program, "-m", "--mon-pidfile <path>", "write mon(1) pid to <path>", on_mon_pidfile); command_option(&program, "-P", "--prefix <str>", "add a log prefix", on_prefix); command_option(&program, "-d", "--daemonize", "daemonize the program", on_daemonize); command_option(&program, "-e", "--on-error <cmd>", "execute <cmd> on errors", on_error); command_parse(&program, argc, argv); // command required if (!program.argc) error("<cmd> required"); const char *cmd = program.argv[0]; // signals signal(SIGTERM, graceful_exit); signal(SIGQUIT, graceful_exit); // daemonize if (monitor.daemon) { daemonize(); redirect_stdio_to(monitor.logfile); } // write mon pidfile if (monitor.mon_pidfile) { log("write mon pid to %s", monitor.mon_pidfile); write_pidfile(monitor.mon_pidfile, getpid()); } start(cmd, &monitor); return 0; }
int main(void) { const pid_t pid = getpid(); write_pidfile(pid); wait_for_peer_invocation(); static const char dir[] = "attach-p-cmd.test cmd"; int rc = chdir(dir); printf("%-5d chdir(\"%s\") = %s\n" "%-5d +++ exited with 0 +++\n", pid, dir, sprintrc(rc), pid); return 0; }
/// <summary>Our raspicomm daemon specific work gets done.</summary> void do_work(void) { /* setup the syslog for logging */ init_syslog(); /* read the settings from the settings file */ Settings settings; int ret; if ((ret = load_settings(&settings)) < 0) { //syslog(LOG_ERR, "loading settings failed (%i)", ret); exit(EXIT_FAILURE); } if (settings.log) { syslog(LOG_INFO, "starting..."); syslog(LOG_INFO, "using %s: port '%i' and pidfile '%s' and log=%i", ret == 0 ? "default configuration" : "configurationfile", settings.port, settings.pidfile, settings.log); } /* write the pidfile */ if ( write_pidfile(settings.pidfile) != 0) if (settings.log) syslog(LOG_ERR, "writing PIDFILE '%s' failed", settings.pidfile); /* use the settings to initialize the raspicomm */ if (daemon_init_raspicomm(&settings) != SUCCESS) exit(EXIT_FAILURE); /* init the pipe */ if (init_pipe() != 0) if (settings.log) syslog(LOG_ERR, "init_pipe failed"); /* block and work */ enter_main_loop(&settings); /* tear down raspicomm */ daemon_shutdown(); }
/* Detach from current terminal, write pidfile, kill parent */ bool detach(void) { setup_signals(); /* First check if we can open a fresh new pidfile */ #ifndef HAVE_MINGW if(!write_pidfile()) return false; /* If we succeeded in doing that, detach */ closelogger(); #endif if(do_detach) { #ifndef HAVE_MINGW if(daemon(0, 0)) { fprintf(stderr, "Couldn't detach from terminal: %s", strerror(errno)); return false; } /* Now UPDATE the pid in the pidfile, because we changed it... */ if(!write_pid(pidfilename)) { fprintf(stderr, "Could not write pid file %s: %s\n", pidfilename, strerror(errno)); return false; } #else if(!statushandle) exit(install_service()); #endif } openlogger(identname, use_logfile?LOGMODE_FILE:(do_detach?LOGMODE_SYSLOG:LOGMODE_STDERR)); logger(LOG_NOTICE, "tincd %s (%s %s) starting, debug level %d", VERSION, __DATE__, __TIME__, debug_level); xalloc_fail_func = memory_full; return true; }
static void client_background(void) { #ifdef __uClinux__ bb_error_msg("cannot background in uclinux (yet)"); /* ... mainly because udhcpc calls client_background() * in _the _middle _of _udhcpc _run_, not at the start! * If that will be properly disabled for NOMMU, client_background() * will work on NOMMU too */ #else // chdir(/) is problematic. Imagine that e.g. pidfile name is RELATIVE! what will unlink do then, eh? bb_daemonize(DAEMON_CHDIR_ROOT); /* rewrite pidfile, as our pid is different now */ if (client_config.pidfile) write_pidfile(client_config.pidfile); logmode &= ~LOGMODE_STDIO; #endif client_config.foreground = 1; /* Do not fork again. */ client_config.background_if_no_lease = 0; }
bool daemonize(const char* pid_path) { /* Double fork. */ pid_t ret; ret = fork(); if (ret == -1) { err(EXIT_FAILURE, "fork()"); } else if (ret > 0) { waitpid(ret, NULL, 0); return false; } ret = fork(); if (ret == -1) { err(EXIT_FAILURE, "fork()"); } else if (ret > 0) { exit(EXIT_SUCCESS); } /* Write PID. */ if (!write_pidfile(pid_path)) err(EXIT_FAILURE, "%s", pid_path); /* Change directory. */ if (chdir("/") == -1) warn("%s", "/"); /* Create new session ID. */ if (setsid() == -1) warn("setsid()"); /* Close standard streams. */ if (int fd = open("/dev/null", O_RDWR) > 0) for (int i = 0; i < 3; ++i) dup2(fd, i); return true; }
int main (int argc, char **argv) { int c; char *config_dir = DEFAULT_CONFIG_DIR; char *seafile_dir = NULL; char *central_config_dir = NULL; char *logfile = NULL; const char *debug_str = NULL; int daemon_mode = 1; int is_master = 0; CcnetClient *client; char *ccnet_debug_level_str = "info"; char *seafile_debug_level_str = "debug"; int cloud_mode = 0; #ifdef WIN32 argv = get_argv_utf8 (&argc); #endif while ((c = getopt_long (argc, argv, short_options, long_options, NULL)) != EOF) { switch (c) { case 'h': exit (1); break; case 'v': exit (1); break; case 'c': config_dir = optarg; break; case 'd': seafile_dir = g_strdup(optarg); break; case 'F': central_config_dir = g_strdup(optarg); break; case 'f': daemon_mode = 0; break; case 'l': logfile = g_strdup(optarg); break; case 'D': debug_str = optarg; break; case 'g': ccnet_debug_level_str = optarg; break; case 'G': seafile_debug_level_str = optarg; break; case 'm': is_master = 1; break; case 'P': pidfile = optarg; break; case 'C': cloud_mode = 1; break; default: usage (); exit (1); } } argc -= optind; argv += optind; #ifndef WIN32 if (daemon_mode) { #ifndef __APPLE__ daemon (1, 0); #else /* __APPLE */ /* daemon is deprecated under APPLE * use fork() instead * */ switch (fork ()) { case -1: seaf_warning ("Failed to daemonize"); exit (-1); break; case 0: /* all good*/ break; default: /* kill origin process */ exit (0); } #endif /* __APPLE */ } #endif /* !WIN32 */ cdc_init (); #if !GLIB_CHECK_VERSION(2, 35, 0) g_type_init(); #endif #if !GLIB_CHECK_VERSION(2,32,0) g_thread_init (NULL); #endif if (!debug_str) debug_str = g_getenv("SEAFILE_DEBUG"); seafile_debug_set_flags_string (debug_str); if (seafile_dir == NULL) seafile_dir = g_build_filename (config_dir, "seafile", NULL); if (logfile == NULL) logfile = g_build_filename (seafile_dir, "seafile.log", NULL); if (seafile_log_init (logfile, ccnet_debug_level_str, seafile_debug_level_str) < 0) { seaf_warning ("Failed to init log.\n"); exit (1); } client = ccnet_init (central_config_dir, config_dir); if (!client) exit (1); register_processors (client); start_rpc_service (client, cloud_mode); create_sync_rpc_clients (central_config_dir, config_dir); create_async_rpc_clients (client); seaf = seafile_session_new (central_config_dir, seafile_dir, client); if (!seaf) { seaf_warning ("Failed to create seafile session.\n"); exit (1); } seaf->is_master = is_master; seaf->ccnetrpc_client = ccnetrpc_client; seaf->async_ccnetrpc_client = async_ccnetrpc_client; seaf->ccnetrpc_client_t = ccnetrpc_client_t; seaf->async_ccnetrpc_client_t = async_ccnetrpc_client_t; seaf->client_pool = ccnet_client_pool_new (central_config_dir, config_dir); seaf->cloud_mode = cloud_mode; load_history_config (); g_free (seafile_dir); g_free (logfile); set_signal_handlers (seaf); /* init seaf */ if (seafile_session_init (seaf) < 0) exit (1); if (seafile_session_start (seaf) < 0) exit (1); if (pidfile) { if (write_pidfile (pidfile) < 0) { ccnet_message ("Failed to write pidfile\n"); return -1; } } atexit (on_seaf_server_exit); /* Create a system default repo to contain the tutorial file. */ schedule_create_system_default_repo (seaf); ccnet_main (client); return 0; }
int main(int argc, char *argv[]) { struct sockaddr_in me; #ifdef ENABLE_IPV6 struct sockaddr_in6 me6; #endif /* ENABLE_IPV6 */ curl_socket_t sock = CURL_SOCKET_BAD; curl_socket_t msgsock = CURL_SOCKET_BAD; int wrotepidfile = 0; int flag; unsigned short port = DEFAULT_PORT; char *pidname= (char *)".rtsp.pid"; struct httprequest req; int rc; int error; int arg=1; long pid; while(argc>arg) { if(!strcmp("--version", argv[arg])) { printf("rtspd IPv4%s" "\n" , #ifdef ENABLE_IPV6 "/IPv6" #else "" #endif ); return 0; } else if(!strcmp("--pidfile", argv[arg])) { arg++; if(argc>arg) pidname = argv[arg++]; } else if(!strcmp("--logfile", argv[arg])) { arg++; if(argc>arg) serverlogfile = argv[arg++]; } else if(!strcmp("--ipv4", argv[arg])) { #ifdef ENABLE_IPV6 ipv_inuse = "IPv4"; use_ipv6 = FALSE; #endif arg++; } else if(!strcmp("--ipv6", argv[arg])) { #ifdef ENABLE_IPV6 ipv_inuse = "IPv6"; use_ipv6 = TRUE; #endif arg++; } else if(!strcmp("--port", argv[arg])) { arg++; if(argc>arg) { char *endptr; long lnum = -1; lnum = strtol(argv[arg], &endptr, 10); if((endptr != argv[arg] + strlen(argv[arg])) || (lnum < 1025L) || (lnum > 65535L)) { fprintf(stderr, "rtspd: invalid --port argument (%s)\n", argv[arg]); return 0; } port = (unsigned short)(lnum & 0xFFFFL); arg++; } } else if(!strcmp("--srcdir", argv[arg])) { arg++; if(argc>arg) { path = argv[arg]; arg++; } } else { puts("Usage: rtspd [option]\n" " --version\n" " --logfile [file]\n" " --pidfile [file]\n" " --ipv4\n" " --ipv6\n" " --port [port]\n" " --srcdir [path]"); return 0; } } #ifdef WIN32 win32_init(); atexit(win32_cleanup); #endif install_signal_handlers(); pid = (long)getpid(); #ifdef ENABLE_IPV6 if(!use_ipv6) #endif sock = socket(AF_INET, SOCK_STREAM, 0); #ifdef ENABLE_IPV6 else sock = socket(AF_INET6, SOCK_STREAM, 0); #endif if(CURL_SOCKET_BAD == sock) { error = SOCKERRNO; logmsg("Error creating socket: (%d) %s", error, strerror(error)); goto server_cleanup; } flag = 1; if (0 != setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&flag, sizeof(flag))) { error = SOCKERRNO; logmsg("setsockopt(SO_REUSEADDR) failed with error: (%d) %s", error, strerror(error)); goto server_cleanup; } #ifdef ENABLE_IPV6 if(!use_ipv6) { #endif memset(&me, 0, sizeof(me)); me.sin_family = AF_INET; me.sin_addr.s_addr = INADDR_ANY; me.sin_port = htons(port); rc = bind(sock, (struct sockaddr *) &me, sizeof(me)); #ifdef ENABLE_IPV6 } else { memset(&me6, 0, sizeof(me6)); me6.sin6_family = AF_INET6; me6.sin6_addr = in6addr_any; me6.sin6_port = htons(port); rc = bind(sock, (struct sockaddr *) &me6, sizeof(me6)); } #endif /* ENABLE_IPV6 */ if(0 != rc) { error = SOCKERRNO; logmsg("Error binding socket on port %hu: (%d) %s", port, error, strerror(error)); goto server_cleanup; } logmsg("Running %s version on port %d", ipv_inuse, (int)port); /* start accepting connections */ rc = listen(sock, 5); if(0 != rc) { error = SOCKERRNO; logmsg("listen() failed with error: (%d) %s", error, strerror(error)); goto server_cleanup; } /* ** As soon as this server writes its pid file the test harness will ** attempt to connect to this server and initiate its verification. */ wrotepidfile = write_pidfile(pidname); if(!wrotepidfile) goto server_cleanup; for (;;) { msgsock = accept(sock, NULL, NULL); if(got_exit_signal) break; if (CURL_SOCKET_BAD == msgsock) { error = SOCKERRNO; logmsg("MAJOR ERROR: accept() failed with error: (%d) %s", error, strerror(error)); break; } /* ** As soon as this server acepts a connection from the test harness it ** must set the server logs advisor read lock to indicate that server ** logs should not be read until this lock is removed by this server. */ set_advisor_read_lock(SERVERLOGS_LOCK); serverlogslocked = 1; logmsg("====> Client connect"); #ifdef TCP_NODELAY /* * Disable the Nagle algorithm to make it easier to send out a large * response in many small segments to torture the clients more. */ flag = 1; if (setsockopt(msgsock, IPPROTO_TCP, TCP_NODELAY, (void *)&flag, sizeof(flag)) == -1) { logmsg("====> TCP_NODELAY failed"); } #endif /* initialization of httprequest struct is done in get_request(), but due to pipelining treatment the pipelining struct field must be initialized previously to FALSE every time a new connection arrives. */ req.pipelining = FALSE; do { if(got_exit_signal) break; if(get_request(msgsock, &req)) /* non-zero means error, break out of loop */ break; if(prevbounce) { /* bounce treatment requested */ if((req.testno == prevtestno) && (req.partno == prevpartno)) { req.partno++; logmsg("BOUNCE part number to %ld", req.partno); } else { prevbounce = FALSE; prevtestno = -1; prevpartno = -1; } } send_doc(msgsock, &req); if(got_exit_signal) break; if((req.testno < 0) && (req.testno != DOCNUMBER_CONNECT)) { logmsg("special request received, no persistency"); break; } if(!req.open) { logmsg("instructed to close connection after server-reply"); break; } if(req.open) logmsg("=> persistant connection request ended, awaits new request"); /* if we got a CONNECT, loop and get another request as well! */ } while(req.open || (req.testno == DOCNUMBER_CONNECT)); if(got_exit_signal) break; logmsg("====> Client disconnect"); sclose(msgsock); msgsock = CURL_SOCKET_BAD; if(serverlogslocked) { serverlogslocked = 0; clear_advisor_read_lock(SERVERLOGS_LOCK); } if (req.testno == DOCNUMBER_QUIT) break; } server_cleanup: if((msgsock != sock) && (msgsock != CURL_SOCKET_BAD)) sclose(msgsock); if(sock != CURL_SOCKET_BAD) sclose(sock); if(got_exit_signal) logmsg("signalled to die"); if(wrotepidfile) unlink(pidname); if(serverlogslocked) { serverlogslocked = 0; clear_advisor_read_lock(SERVERLOGS_LOCK); } restore_signal_handlers(); if(got_exit_signal) { logmsg("========> %s rtspd (port: %d pid: %ld) exits with signal (%d)", ipv_inuse, (int)port, pid, exit_signal); /* * To properly set the return status of the process we * must raise the same signal SIGINT or SIGTERM that we * caught and let the old handler take care of it. */ raise(exit_signal); } logmsg("========> rtspd quits"); return 0; }
int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) { unsigned opt; char *signame; char *startas; char *chuid; #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY // char *retry_arg = NULL; // int retries = -1; char *opt_N; #endif INIT_G(); opt = GETOPT32(argv, "^" "KSbqtma:n:s:u:c:x:p:" IF_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:") /* -K or -S is required; they are mutually exclusive */ /* -p is required if -m is given */ /* -xpun (at least one) is required if -K is given */ /* -xa (at least one) is required if -S is given */ /* -q turns off -v */ "\0" "K:S:K--S:S--K:m?p:K?xpun:S?xa" IF_FEATURE_START_STOP_DAEMON_FANCY("q-v"), LONGOPTS &startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile IF_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N) /* We accept and ignore -R <param> / --retry <param> */ IF_FEATURE_START_STOP_DAEMON_FANCY(,NULL) ); if (opt & OPT_s) { signal_nr = get_signum(signame); if (signal_nr < 0) bb_show_usage(); } if (!(opt & OPT_a)) startas = execname; if (!execname) /* in case -a is given and -x is not */ execname = startas; if (execname) { G.execname_sizeof = strlen(execname) + 1; G.execname_cmpbuf = xmalloc(G.execname_sizeof + 1); } // IF_FEATURE_START_STOP_DAEMON_FANCY( // if (retry_arg) // retries = xatoi_positive(retry_arg); // ) //argc -= optind; argv += optind; if (userspec) { user_id = bb_strtou(userspec, NULL, 10); if (errno) user_id = xuname2uid(userspec); } /* Both start and stop need to know current processes */ do_procinit(); if (opt & CTX_STOP) { int i = do_stop(); return (opt & OPT_OKNODO) ? 0 : (i <= 0); } if (G.found_procs) { if (!QUIET) printf("%s is already running\n%u\n", execname, (unsigned)G.found_procs->pid); return !(opt & OPT_OKNODO); } #ifdef OLDER_VERSION_OF_X if (execname) xstat(execname, &G.execstat); #endif *--argv = startas; if (opt & OPT_BACKGROUND) { #if BB_MMU bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS + DAEMON_DOUBLE_FORK); /* DAEMON_DEVNULL_STDIO is superfluous - * it's always done by bb_daemonize() */ #else /* Daemons usually call bb_daemonize_or_rexec(), but SSD can do * without: SSD is not itself a daemon, it _execs_ a daemon. * The usual NOMMU problem of "child can't run indefinitely, * it must exec" does not bite us: we exec anyway. */ pid_t pid = xvfork(); if (pid != 0) { /* parent */ /* why _exit? the child may have changed the stack, * so "return 0" may do bad things */ _exit(EXIT_SUCCESS); } /* Child */ setsid(); /* detach from controlling tty */ /* Redirect stdio to /dev/null, close extra FDs */ bb_daemon_helper(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS); #endif } if (opt & OPT_MAKEPID) { /* User wants _us_ to make the pidfile */ write_pidfile(pidfile); } if (opt & OPT_c) { struct bb_uidgid_t ugid; parse_chown_usergroup_or_die(&ugid, chuid); if (ugid.uid != (uid_t) -1L) { struct passwd *pw = xgetpwuid(ugid.uid); if (ugid.gid != (gid_t) -1L) pw->pw_gid = ugid.gid; /* initgroups, setgid, setuid: */ change_identity(pw); } else if (ugid.gid != (gid_t) -1L) { xsetgid(ugid.gid); setgroups(1, &ugid.gid); } } #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY if (opt & OPT_NICELEVEL) { /* Set process priority */ int prio = getpriority(PRIO_PROCESS, 0) + xatoi_range(opt_N, INT_MIN/2, INT_MAX/2); if (setpriority(PRIO_PROCESS, 0, prio) < 0) { bb_perror_msg_and_die("setpriority(%d)", prio); } } #endif execvp(startas, argv); bb_perror_msg_and_die("can't execute '%s'", startas); }
int crond_main(int argc UNUSED_PARAM, char **argv) { time_t t2; unsigned rescan; unsigned sleep_time; unsigned opts; INIT_G(); /* "-b after -f is ignored", and so on for every pair a-b */ opt_complementary = "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l") /* -l and -d have numeric param */ ":l+" IF_FEATURE_CROND_D(":d+"); opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"), &G.log_level, &G.log_filename, &G.crontab_dir_name IF_FEATURE_CROND_D(,&G.log_level)); /* both -d N and -l N set the same variable: G.log_level */ if (!(opts & OPT_f)) { /* close stdin, stdout, stderr. * close unused descriptors - don't need them. */ bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); } if (!(opts & OPT_d) && G.log_filename == NULL) { /* logging to syslog */ openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON); logmode = LOGMODE_SYSLOG; } //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ reopen_logfile_to_stderr(); xchdir(G.crontab_dir_name); log8("crond (busybox "BB_VER") started, log level %d", G.log_level); rescan_crontab_dir(); write_pidfile(CONFIG_PID_FILE_PATH "/crond.pid"); /* Main loop */ t2 = time(NULL); rescan = 60; sleep_time = 60; for (;;) { struct stat sbuf; time_t t1; long dt; /* Synchronize to 1 minute, minimum 1 second */ t1 = t2; sleep(sleep_time - (time(NULL) % sleep_time)); t2 = time(NULL); dt = (long)t2 - (long)t1; reopen_logfile_to_stderr(); /* * The file 'cron.update' is checked to determine new cron * jobs. The directory is rescanned once an hour to deal * with any screwups. * * Check for time jump. Disparities over an hour either way * result in resynchronization. A negative disparity * less than an hour causes us to effectively sleep until we * match the original time (i.e. no re-execution of jobs that * have just been run). A positive disparity less than * an hour causes intermediate jobs to be run, but only once * in the worst case. * * When running jobs, the inequality used is greater but not * equal to t1, and less then or equal to t2. */ if (stat(G.crontab_dir_name, &sbuf) != 0) sbuf.st_mtime = 0; /* force update (once) if dir was deleted */ if (G.crontab_dir_mtime != sbuf.st_mtime) { G.crontab_dir_mtime = sbuf.st_mtime; rescan = 1; } if (--rescan == 0) { rescan = 60; rescan_crontab_dir(); } process_cron_update_file(); log5("wakeup dt=%ld", dt); if (dt < -60 * 60 || dt > 60 * 60) { bb_error_msg("time disparity of %ld minutes detected", dt / 60); /* and we do not run any jobs in this case */ } else if (dt > 0) { /* Usual case: time advances forward, as expected */ flag_starting_jobs(t1, t2); start_jobs(); sleep_time = 60; if (check_completions() > 0) { /* some jobs are still running */ sleep_time = 10; } } /* else: time jumped back, do not run any jobs */ } /* for (;;) */ return 0; /* not reached */ }
int main(int argc, char **argv) { const char *config_file = "/etc/sniproxy.conf"; int background_flag = 1; int max_nofiles = 65536; int opt; while ((opt = getopt(argc, argv, "fc:n:V")) != -1) { switch (opt) { case 'c': config_file = optarg; break; case 'f': /* foreground */ background_flag = 0; break; case 'n': max_nofiles = atoi(optarg); break; case 'V': printf("sniproxy %s\n", sniproxy_version); #ifdef HAVE_LIBUDNS printf("compiled with udns support\n"); #endif return EXIT_SUCCESS; default: usage(); return EXIT_FAILURE; } } config = init_config(config_file, EV_DEFAULT); if (config == NULL) { fprintf(stderr, "Unable to load %s\n", config_file); usage(); return EXIT_FAILURE; } /* ignore SIGPIPE, or it will kill us */ signal(SIGPIPE, SIG_IGN); if (background_flag) { if (config->pidfile != NULL) remove(config->pidfile); daemonize(); if (config->pidfile != NULL) write_pidfile(config->pidfile, getpid()); } start_binder(); set_limits(max_nofiles); init_listeners(&config->listeners, &config->tables, EV_DEFAULT); /* Drop permissions only when we can */ drop_perms(config->user ? config->user : default_username); ev_signal_init(&sighup_watcher, signal_cb, SIGHUP); ev_signal_init(&sigusr1_watcher, signal_cb, SIGUSR1); ev_signal_init(&sigusr2_watcher, signal_cb, SIGUSR2); ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_start(EV_DEFAULT, &sighup_watcher); ev_signal_start(EV_DEFAULT, &sigusr1_watcher); ev_signal_start(EV_DEFAULT, &sigusr2_watcher); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); resolv_init(EV_DEFAULT, config->resolver.nameservers, config->resolver.search, config->resolver.mode); init_connections(); ev_run(EV_DEFAULT, 0); free_connections(EV_DEFAULT); resolv_shutdown(EV_DEFAULT); free_config(config, EV_DEFAULT); stop_binder(); return 0; }
int eooqd_main(int argc, char *argv[]) { int r; char *pid_file_name, *instance_id_str; char *check; struct event *checkQueueEvent, *rePostEvent; struct timeval tv; struct rlimit limit; atlas_id= NULL; instance_id_str= NULL; pid_file_name= NULL; queue_id= ""; (void)getopt32(argv, "A:i:P:q:", &atlas_id, &instance_id_str, &pid_file_name, &queue_id); if (argc != optind+1) { bb_show_usage(); return 1; } instance_id= 0; if (instance_id_str) { instance_id= strtoul(instance_id_str, &check, 0); if (check[0] != '\0') { report("unable to parse instance id '%s'", instance_id_str); return 1; } } if(pid_file_name) { write_pidfile(pid_file_name); } state = xzalloc(sizeof(*state)); state->atlas_id= atlas_id; state->queue_file= argv[optind]; state->max_busy= 10; state->slots= xzalloc(sizeof(*state->slots) * state->max_busy); if (strlen(state->queue_file) + strlen(SUFFIX) + 1 > sizeof(state->curr_qfile)) { report("filename too long ('%s')", state->queue_file); return 1; } strlcpy(state->curr_qfile, state->queue_file, sizeof(state->curr_qfile)); strlcat(state->curr_qfile, SUFFIX, sizeof(state->curr_qfile)); signal(SIGQUIT, SIG_DFL); limit.rlim_cur= RLIM_INFINITY; limit.rlim_max= RLIM_INFINITY; setrlimit(RLIMIT_CORE, &limit); /* Create libevent event base */ EventBase= event_base_new(); if (!EventBase) { crondlog(DIE9 "event_base_new failed"); /* exits */ } DnsBase= evdns_base_new(EventBase, 1 /*initialize*/); if (!DnsBase) { event_base_free(EventBase); crondlog(DIE9 "evdns_base_new failed"); /* exits */ } checkQueueEvent= event_new(EventBase, -1, EV_TIMEOUT|EV_PERSIST, checkQueue, NULL); if (!checkQueueEvent) crondlog(DIE9 "event_new failed"); /* exits */ tv.tv_sec= 1; tv.tv_usec= 0; event_add(checkQueueEvent, &tv); rePostEvent= event_new(EventBase, -1, EV_TIMEOUT|EV_PERSIST, re_post, NULL); if (!rePostEvent) crondlog(DIE9 "event_new failed"); /* exits */ tv.tv_sec= 60; tv.tv_usec= 0; event_add(rePostEvent, &tv); r= event_base_loop(EventBase, 0); if (r != 0) crondlog(LVL9 "event_base_loop failed"); return 0; }
int cr_service(bool daemon_mode) { int server_fd = -1; int child_pid; struct sockaddr_un client_addr; socklen_t client_addr_len; { struct sockaddr_un server_addr; socklen_t server_addr_len; server_fd = socket(AF_LOCAL, SOCK_SEQPACKET, 0); if (server_fd == -1) { pr_perror("Can't initialize service socket"); goto err; } memset(&server_addr, 0, sizeof(server_addr)); memset(&client_addr, 0, sizeof(client_addr)); server_addr.sun_family = AF_LOCAL; if (opts.addr == NULL) { pr_warn("Binding to local dir address!\n"); opts.addr = CR_DEFAULT_SERVICE_ADDRESS; } strcpy(server_addr.sun_path, opts.addr); server_addr_len = strlen(server_addr.sun_path) + sizeof(server_addr.sun_family); client_addr_len = sizeof(client_addr); unlink(server_addr.sun_path); if (bind(server_fd, (struct sockaddr *) &server_addr, server_addr_len) == -1) { pr_perror("Can't bind"); goto err; } pr_info("The service socket is bound to %s\n", server_addr.sun_path); /* change service socket permissions, so anyone can connect to it */ if (chmod(server_addr.sun_path, 0666)) { pr_perror("Can't change permissions of the service socket"); goto err; } if (listen(server_fd, 16) == -1) { pr_perror("Can't listen for socket connections"); goto err; } } if (daemon_mode) { if (daemon(1, 0) == -1) { pr_perror("Can't run service server in the background"); goto err; } } if (opts.pidfile) { if (write_pidfile(getpid()) == -1) { pr_perror("Can't write pidfile"); goto err; } } if (setup_sigchld_handler()) goto err; while (1) { int sk; pr_info("Waiting for connection...\n"); sk = accept(server_fd, &client_addr, &client_addr_len); if (sk == -1) { pr_perror("Can't accept connection"); goto err; } pr_info("Connected.\n"); child_pid = fork(); if (child_pid == 0) { int ret; if (restore_sigchld_handler()) exit(1); close(server_fd); init_opts(); ret = cr_service_work(sk); close(sk); exit(ret != 0); } if (child_pid < 0) pr_perror("Can't fork a child"); close(sk); } err: close_safe(&server_fd); return 1; }
int main(int argc, char **argv) { char *dst = NULL, *src = NULL; struct sigaction sa; int mode = NONE; int opt; while ((opt=getopt_long(argc, argv, main_sopts, main_lopts, NULL)) != -1) { switch(opt) { case 'l': mode = SHOW; detach = 0; break; case 's': mode = LISTEN; break; case 'c': mode = CONNECT; dst = strdup(optarg); break; case 'Q': mode = CONNECT; if (optarg) search_duration = atoi(optarg); break; case 'k': mode = KILL; detach = 0; dst = strdup(optarg); break; case 'K': mode = KILL; detach = 0; break; case 'i': src = strdup(optarg); break; case 'r': bnep_str2svc(optarg, &role); break; case 'd': bnep_str2svc(optarg, &service); break; case 'D': use_sdp = 0; break; case 'E': encrypt = 1; break; case 'S': secure = 1; break; case 'M': master = 1; break; case 'e': strcpy(netdev, optarg); break; case 'n': detach = 0; break; case 'p': if (optarg) persist = atoi(optarg); else persist = 5; break; case 'C': if (optarg) use_cache = atoi(optarg); else use_cache = 2; break; case 'P': pidfile = strdup(optarg); break; case 'z': cleanup = 1; break; case 'h': default: printf(main_help); exit(0); } } argc -= optind; argv += optind; optind = 0; if (bnep_init()) return -1; /* Check non daemon modes first */ switch (mode) { case SHOW: do_show(); return 0; case KILL: do_kill(dst); return 0; case NONE: printf(main_help); return 0; } /* Initialize signals */ memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = SIG_IGN; sigaction(SIGCHLD, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); sa.sa_handler = sig_hup; sigaction(SIGHUP, &sa, NULL); sa.sa_handler = sig_term; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); if (detach) { if (fork()) exit(0); /* Direct stdin,stdout,stderr to '/dev/null' */ { int fd = open("/dev/null", O_RDWR); dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); close(fd); } setsid(); chdir("/"); } openlog("pand", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON); syslog(LOG_INFO, "Bluetooth PAN daemon version %s", VERSION); if (src) { src_dev = hci_devid(src); if (src_dev < 0 || hci_devba(src_dev, &src_addr) < 0) { syslog(LOG_ERR, "Invalid source. %s(%d)", strerror(errno), errno); return -1; } } if (pidfile && write_pidfile()) return -1; if (dst) { /* Disable cache invalidation */ use_cache = 0; strncpy(cache.dst, dst, sizeof(cache.dst) - 1); str2ba(dst, &cache.bdaddr); cache.valid = 1; free(dst); } switch (mode) { case CONNECT: do_connect(); break; case LISTEN: do_listen(); break; } if (pidfile) unlink(pidfile); return 0; }
int main(int argc, char **argv) { g_start_sec = cf_get_seconds(); // Initialize cf_thread wrapper. cf_thread_init(); // Initialize memory allocation. cf_alloc_init(); // Initialize fault management framework. cf_fault_init(); // Setup signal handlers. as_signal_setup(); // Initialize TLS library. tls_check_init(); int opt; int opt_i; const char *config_file = DEFAULT_CONFIG_FILE; bool run_in_foreground = false; bool new_style_daemon = false; bool cold_start_cmd = false; uint32_t instance = 0; // Parse command line options. while ((opt = getopt_long(argc, argv, "", CMD_OPTS, &opt_i)) != -1) { switch (opt) { case 'h': // printf() since we want stdout and don't want cf_fault's prefix. printf("%s\n", HELP); return 0; case 'v': // printf() since we want stdout and don't want cf_fault's prefix. printf("%s build %s\n", aerospike_build_type, aerospike_build_id); return 0; case 'f': config_file = cf_strdup(optarg); break; case 'F': // As a "new-style" daemon(*), asd runs in the foreground and // ignores the following configuration items: // - user ('user') // - group ('group') // - PID file ('pidfile') // // If ignoring configuration items, or if the 'console' sink is not // specified, warnings will appear in stderr. // // (*) http://0pointer.de/public/systemd-man/daemon.html#New-Style%20Daemons run_in_foreground = true; new_style_daemon = true; break; case 'd': run_in_foreground = true; break; case 'c': cold_start_cmd = true; break; case 'n': instance = (uint32_t)strtol(optarg, NULL, 0); break; default: // fprintf() since we don't want cf_fault's prefix. fprintf(stderr, "%s\n", USAGE); return 1; } } // Set all fields in the global runtime configuration instance. This parses // the configuration file, and creates as_namespace objects. (Return value // is a shortcut pointer to the global runtime configuration instance.) as_config *c = as_config_init(config_file); // Detect NUMA topology and, if requested, prepare for CPU and NUMA pinning. cf_topo_config(c->auto_pin, (cf_topo_numa_node_index)instance, &c->service.bind); // Perform privilege separation as necessary. If configured user & group // don't have root privileges, all resources created or reopened past this // point must be set up so that they are accessible without root privileges. // If not, the process will self-terminate with (hopefully!) a log message // indicating which resource is not set up properly. cf_process_privsep(c->uid, c->gid); // // All resources such as files, devices, and shared memory must be created // or reopened below this line! (The configuration file is the only thing // that must be opened above, in order to parse the user & group.) //========================================================================== // A "new-style" daemon expects console logging to be configured. (If not, // log messages won't be seen via the standard path.) if (new_style_daemon) { if (! cf_fault_console_is_held()) { cf_warning(AS_AS, "in new-style daemon mode, console logging is not configured"); } } // Activate log sinks. Up to this point, 'cf_' log output goes to stderr, // filtered according to NO_SINKS_LIMIT in fault.c. After this point, 'cf_' // log output will appear in all log file sinks specified in configuration, // with specified filtering. If console sink is specified in configuration, // 'cf_' log output will continue going to stderr, but filtering will switch // from NO_SINKS_LIMIT to that specified in console sink configuration. if (0 != cf_fault_sink_activate_all_held()) { // Specifics of failure are logged in cf_fault_sink_activate_all_held(). cf_crash_nostack(AS_AS, "can't open log sink(s)"); } // Daemonize asd if specified. After daemonization, output to stderr will no // longer appear in terminal. Instead, check /tmp/aerospike-console.<pid> // for console output. if (! run_in_foreground && c->run_as_daemon) { // Don't close any open files when daemonizing. At this point only log // sink files are open - instruct cf_process_daemonize() to ignore them. int open_fds[CF_FAULT_SINKS_MAX]; int num_open_fds = cf_fault_sink_get_fd_list(open_fds); cf_process_daemonize(open_fds, num_open_fds); } // Log which build this is - should be the first line in the log file. cf_info(AS_AS, "<><><><><><><><><><> %s build %s <><><><><><><><><><>", aerospike_build_type, aerospike_build_id); // Includes echoing the configuration file to log. as_config_post_process(c, config_file); xdr_config_post_process(); // If we allocated a non-default config file name, free it. if (config_file != DEFAULT_CONFIG_FILE) { cf_free((void*)config_file); } // Write the pid file, if specified. if (! new_style_daemon) { write_pidfile(c->pidfile); } else { if (c->pidfile) { cf_warning(AS_AS, "will not write PID file in new-style daemon mode"); } } // Check that required directories are set up properly. validate_directory(c->work_directory, "work"); validate_directory(c->mod_lua.user_path, "Lua user"); validate_smd_directory(); // Initialize subsystems. At this point we're allocating local resources, // starting worker threads, etc. (But no communication with other server // nodes or clients yet.) as_json_init(); // Jansson JSON API used by System Metadata as_index_tree_gc_init(); // thread to purge dropped index trees as_sindex_thr_init(); // defrag secondary index (ok during population) as_nsup_init(); // load previous evict-void-time(s) // Initialize namespaces. Each namespace decides here whether it will do a // warm or cold start. Index arenas, partition structures and index tree // structures are initialized. Secondary index system metadata is restored. as_namespaces_init(cold_start_cmd, instance); // Initialize the storage system. For warm and cool restarts, this includes // fully resuming persisted indexes - this may take a few minutes. as_storage_init(); // Migrate memory to correct NUMA node (includes resumed index arenas). cf_topo_migrate_memory(); // Drop capabilities that we kept only for initialization. cf_process_drop_startup_caps(); // Activate the storage system. For cold starts and cool restarts, this // includes full drive scans - this may take several hours. The defrag // subsystem starts operating at the end of this call. as_storage_load(); // Populate all secondary indexes. This may block for a long time. as_sindex_boot_populateall(); cf_info(AS_AS, "initializing services..."); cf_dns_init(); // DNS resolver as_netio_init(); // query responses as_security_init(); // security features as_tsvc_init(); // all transaction handling as_hb_init(); // inter-node heartbeat as_skew_monitor_init(); // clock skew monitor as_fabric_init(); // inter-node communications as_exchange_init(); // initialize the cluster exchange subsystem as_clustering_init(); // clustering-v5 start as_info_init(); // info transaction handling as_migrate_init(); // move data between nodes as_proxy_init(); // do work on behalf of others as_rw_init(); // read & write service as_query_init(); // query transaction handling as_udf_init(); // user-defined functions as_scan_init(); // scan a namespace or set as_batch_init(); // batch transaction handling as_xdr_init(); // cross data-center replication as_mon_init(); // monitor // Wait for enough available storage. We've been defragging all along, but // here we wait until it's enough. This may block for a long time. as_storage_wait_for_defrag(); // Start subsystems. At this point we may begin communicating with other // cluster nodes, and ultimately with clients. as_smd_start(); // enables receiving cluster state change events as_health_start(); // starts before fabric and hb to capture them as_fabric_start(); // may send & receive fabric messages as_xdr_start(); // XDR should start before it joins other nodes as_hb_start(); // start inter-node heartbeat as_exchange_start(); // start the cluster exchange subsystem as_clustering_start(); // clustering-v5 start as_nsup_start(); // may send evict-void-time(s) to other nodes as_service_start(); // server will now receive client transactions as_info_port_start(); // server will now receive info transactions as_ticker_start(); // only after everything else is started // Relevant for enterprise edition only. as_storage_start_tomb_raider(); // Log a service-ready message. cf_info(AS_AS, "service ready: soon there will be cake!"); //-------------------------------------------- // Startup is done. This thread will now wait // quietly for a shutdown signal. // // Stop this thread from finishing. Intentionally deadlocking on a mutex is // a remarkably efficient way to do this. pthread_mutex_lock(&g_main_deadlock); g_startup_complete = true; pthread_mutex_lock(&g_main_deadlock); // When the service is running, you are here (deadlocked) - the signals that // stop the service (yes, these signals always occur in this thread) will // unlock the mutex, allowing us to continue. g_shutdown_started = true; pthread_mutex_unlock(&g_main_deadlock); pthread_mutex_destroy(&g_main_deadlock); //-------------------------------------------- // Received a shutdown signal. // as_storage_shutdown(instance); as_xdr_shutdown(); cf_info(AS_AS, "finished clean shutdown - exiting"); // If shutdown was totally clean (all threads joined) we could just return, // but for now we exit to make sure all threads die. #ifdef DOPROFILE exit(0); // exit(0) so profile build actually dumps gmon.out #else _exit(0); #endif return 0; }
/* * main * */ int main (int argc, char *argv[]) { GOptionContext *opt_ctx = NULL; gboolean become_daemon = FALSE; gboolean g_fatal_warnings = FALSE; char *pidfile = NULL, *state_file = NULL, *dhcp = NULL; char *config = NULL, *plugins = NULL, *conf_plugins = NULL; char *log_level = NULL, *log_domains = NULL; char **dns = NULL; gboolean success; BMPolicy *policy = NULL; BMDBusManager *dbus_mgr = NULL; GError *error = NULL; gboolean wrote_pidfile = FALSE; char *cfg_log_level = NULL, *cfg_log_domains = NULL; GOptionEntry options[] = { { "no-daemon", 0, 0, G_OPTION_ARG_NONE, &become_daemon, "Don't become a daemon", NULL }, { "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings, "Make all warnings fatal", NULL }, { "pid-file", 0, 0, G_OPTION_ARG_FILENAME, &pidfile, "Specify the location of a PID file", "filename" }, { "state-file", 0, 0, G_OPTION_ARG_FILENAME, &state_file, "State file location", "/path/to/state.file" }, { "config", 0, 0, G_OPTION_ARG_FILENAME, &config, "Config file location", "/path/to/config.file" }, { "plugins", 0, 0, G_OPTION_ARG_STRING, &plugins, "List of plugins separated by ','", "plugin1,plugin2" }, { "log-level", 0, 0, G_OPTION_ARG_STRING, &log_level, "Log level: one of [ERR, WARN, INFO, DEBUG]", "INFO" }, { "log-domains", 0, 0, G_OPTION_ARG_STRING, &log_domains, "Log domains separated by ',': any combination of [NONE,HW,BT,USER_SET,SYS_SET,SUSPEND,CORE,DEVICE]", "HW" }, {NULL} }; if (getuid () != 0) { fprintf (stderr, "You must be root to run BarcodeManager!\n"); exit (1); } if (!g_module_supported ()) { fprintf (stderr, "GModules are not supported on your platform!\n"); exit (1); } bindtextdomain (GETTEXT_PACKAGE, BMLOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); /* Parse options */ opt_ctx = g_option_context_new (""); g_option_context_set_translation_domain (opt_ctx, "UTF-8"); g_option_context_set_ignore_unknown_options (opt_ctx, FALSE); g_option_context_set_help_enabled (opt_ctx, TRUE); g_option_context_add_main_entries (opt_ctx, options, NULL); g_option_context_set_summary (opt_ctx, "BarcodeManager monitors all barcode scanners automatically."); success = g_option_context_parse (opt_ctx, &argc, &argv, NULL); g_option_context_free (opt_ctx); if (!success) { fprintf (stderr, _("Invalid option. Please use --help to see a list of valid options.\n")); exit (1); } /* Make GIO ignore the remote VFS service; otherwise it tries to use the * session bus to contact the remote service, and NM shouldn't ever be * talking on the session bus. See rh #588745 */ setenv ("GIO_USE_VFS", "local", 1); pidfile = pidfile ? pidfile : g_strdup (BM_DEFAULT_PID_FILE); state_file = state_file ? state_file : g_strdup (BM_DEFAULT_SYSTEM_STATE_FILE); /* check pid file */ if (check_pidfile (pidfile)) exit (1); /* Parse the config file */ if (config) { if (!parse_config_file (config, &conf_plugins, &dhcp, &dns, &cfg_log_level, &cfg_log_domains, &error)) { fprintf (stderr, "Config file %s invalid: (%d) %s\n", config, error ? error->code : -1, (error && error->message) ? error->message : "unknown"); exit (1); } } else { gboolean parsed = FALSE; /* Even though we prefer BarcodeManager.conf, we need to check the * old bm-system-settings.conf first to preserve compat with older * setups. In package managed systems dropping a BarcodeManager.conf * onto the system would make NM use it instead of bm-system-settings.conf, * changing behavior during an upgrade. We don't want that. */ /* Try deprecated bm-system-settings.conf first */ if (g_file_test (BM_OLD_SYSTEM_CONF_FILE, G_FILE_TEST_EXISTS)) { config = g_strdup (BM_OLD_SYSTEM_CONF_FILE); parsed = parse_config_file (config, &conf_plugins, &dhcp, &dns, &cfg_log_level, &cfg_log_domains, &error); if (!parsed) { fprintf (stderr, "Default config file %s invalid: (%d) %s\n", config, error ? error->code : -1, (error && error->message) ? error->message : "unknown"); g_free (config); config = NULL; g_clear_error (&error); } } /* Try the preferred BarcodeManager.conf last */ if (!parsed && g_file_test (BM_DEFAULT_SYSTEM_CONF_FILE, G_FILE_TEST_EXISTS)) { config = g_strdup (BM_DEFAULT_SYSTEM_CONF_FILE); parsed = parse_config_file (config, &conf_plugins, &dhcp, &dns, &cfg_log_level, &cfg_log_domains, &error); if (!parsed) { fprintf (stderr, "Default config file %s invalid: (%d) %s\n", config, error ? error->code : -1, (error && error->message) ? error->message : "unknown"); g_free (config); config = NULL; g_clear_error (&error); } } } /* Logging setup */ if (!bm_logging_setup (log_level ? log_level : cfg_log_level, log_domains ? log_domains : cfg_log_domains, &error)) { fprintf (stderr, _("%s. Please use --help to see a list of valid options.\n"), error->message); exit (1); } /* Plugins specified with '--plugins' override those of config file */ plugins = plugins ? plugins : g_strdup (conf_plugins); g_free (conf_plugins); /* Parse the state file */ if (!parse_state_file (state_file, &error)) { fprintf (stderr, "State file %s parsing failed: (%d) %s\n", state_file, error ? error->code : -1, (error && error->message) ? error->message : "unknown"); /* Not a hard failure */ } g_clear_error (&error); /* Tricky: become_daemon is FALSE by default, so unless it's TRUE because * of a CLI option, it'll become TRUE after this */ become_daemon = !become_daemon; if (become_daemon) { if (daemon (0, 0) < 0) { int saved_errno; saved_errno = errno; fprintf (stderr, "Could not daemonize: %s [error %u]\n", g_strerror (saved_errno), saved_errno); exit (1); } if (write_pidfile (pidfile)) wrote_pidfile = TRUE; } if (g_fatal_warnings) { GLogLevelFlags fatal_mask; fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK); fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL; g_log_set_always_fatal (fatal_mask); } /* * Set the umask to 0022, which results in 0666 & ~0022 = 0644. * Otherwise, if root (or an su'ing user) has a wacky umask, we could * write out an unreadable resolv.conf. */ umask (022); g_type_init (); if (!g_thread_supported ()) g_thread_init (NULL); dbus_g_thread_init (); #ifndef HAVE_DBUS_GLIB_DISABLE_LEGACY_PROP_ACCESS #error HAVE_DBUS_GLIB_DISABLE_LEGACY_PROP_ACCESS not defined #endif #if HAVE_DBUS_GLIB_DISABLE_LEGACY_PROP_ACCESS /* Ensure that non-exported properties don't leak out, and that the * introspection 'access' permissions are respected. */ dbus_glib_global_set_disable_legacy_property_access (); #endif setup_signals (); bm_logging_start (become_daemon); bm_log_info (LOGD_CORE, "BarcodeManager (version " BM_DIST_VERSION ") is starting..."); success = FALSE; if (config) bm_log_info (LOGD_CORE, "Read config file %s", config); main_loop = g_main_loop_new (NULL, FALSE); /* Initialize our DBus service & connection */ dbus_mgr = bm_dbus_manager_get (); manager = bm_manager_get (config, plugins, state_file, &error); if (manager == NULL) { bm_log_err (LOGD_CORE, "failed to initialize the barcode manager: %s", error && error->message ? error->message : "(unknown)"); goto done; } policy = bm_policy_new (manager); if (policy == NULL) { bm_log_err (LOGD_CORE, "failed to initialize the policy."); goto done; } /* Start our DBus service */ if (!bm_dbus_manager_start_service (dbus_mgr)) { bm_log_err (LOGD_CORE, "failed to start the dbus service."); goto done; } bm_manager_start (manager); success = TRUE; /* Told to quit before getting to the mainloop by the signal handler */ if (quit_early == TRUE) goto done; g_main_loop_run (main_loop); done: if (policy) bm_policy_destroy (policy); if (manager) g_object_unref (manager); bm_logging_shutdown (); if (pidfile && wrote_pidfile) unlink (pidfile); /* Free options */ g_free (pidfile); g_free (state_file); g_free (config); g_free (plugins); g_free (dhcp); g_strfreev (dns); g_free (log_level); g_free (log_domains); g_free (cfg_log_level); g_free (cfg_log_domains); bm_log_info (LOGD_CORE, "exiting (%s)", success ? "success" : "error"); exit (success ? 0 : 1); }
int32_t main(int argc, char *argv[]) { int32_t opt; uint32_t n; char *cfgfile = NULL; struct stat sb; struct bitcoind *b, *sigfrom; struct psj *psj; struct sigaction act; struct config *cfg; cfg = malloc(sizeof(*cfg)); if (cfg == NULL) { APPLOG(LOG_CRIT, "cfg malloc failed"); exit(255); } while ((opt = getopt(argc, argv, "hs:c:")) != -1) { switch(opt) { case 'c': cfgfile = optarg; break; case 's': cfg->force_pid = atoi(optarg); break; default: case 'h': usage(); } } APPLOG(LOG_NOTICE, "psj_sigmon v0.5 starting up"); /* config file parsing */ if (parse_cfg(cfgfile ? cfgfile : "config.cfg", cfg)) { APPLOG(LOG_CRIT, "parse_cfg error"); exit(255); } if (cfg->bitcoind_used == 0) { APPLOG(LOG_CRIT, "no bitcoind defined, exiting"); exit(EXIT_SUCCESS); } if (cfg->psj_used == 0) { APPLOG(LOG_CRIT, "no psj defined, exiting"); exit(EXIT_SUCCESS); } if (cfg->pidfile) { if (write_pidfile(cfg->pidfile) != 0) { APPLOG(LOG_CRIT, "write_pidfile failed"); exit(255); } } if (cfg->daemon) { APPLOG(LOG_NOTICE, "daemonising, you will hear no more from me"); if (daemon(false, false) == -1) { APPLOG(LOG_CRIT, "except daemonising failed.. dying"); exit(255); } cfg->daemon_done = true; } /* install signal handlers */ act.sa_flags = SA_SIGINFO; act.sa_sigaction = &sig_handler; sigaction(SIGUSR1, &act, NULL); sigaction(SIGINT, &act, NULL); sigaction(SIGTERM, &act, NULL); while(1) { select(0, NULL, NULL, NULL, NULL); APPLOG(LOG_INFO, "got signal %d, from pid %d", sig, pid); /* handle INT and TERM */ if (sig == SIGINT || sig == SIGTERM) /* break out of loop and exit gracefully */ break; /* ignore non-USR1 */ if (sig != SIGUSR1) continue; if (cfg->force_pid) { pid = cfg->force_pid; APPLOG(LOG_DEBUG, "forcing sending-pid to %d", pid); } sigfrom = NULL; for(n = 0 ; n < cfg->bitcoind_used ; n++) { /* check if pid == this bitcoind's pid */ b = cfg->bitcoind_list[n]; if (stat(b->pidfile, &sb) == -1) { APPLOG(LOG_WARNING, "%s on stat of %s", strerror(errno), b->pidfile); continue; } if (sb.st_mtime > b->pidfile_mtime) { /* refresh what we think the pid is of this * bitcoind */ b->pid = read_pidfile(b->pidfile); b->pidfile_mtime = sb.st_mtime; APPLOG(LOG_DEBUG, "%s changed: new pid is %u", b->pidfile, b->pid); } if (b->pid == pid) { APPLOG(LOG_DEBUG, "signal matches %s (%s)", b->pidfile, b->name); sigfrom = b; break; } } if (sigfrom == NULL) { APPLOG(LOG_WARNING, "signal not from a recognised pid"); continue; } /* tell each psj about b->name */ for(n = 0 ; n < cfg->psj_used ; n++) { psj = cfg->psj_list[n]; APPLOG(LOG_INFO, "notifying %s of signal", psj->hostport); poke_psj(cfg,psj, b); } } APPLOG(LOG_INFO, "shutting down, removing pidfile"); unlink(cfg->pidfile); /* we're lazy, the kernel will clean up our memory, sorry valgrind :p */ return EXIT_SUCCESS; }
int main(int argc, char *argv[]) { srvr_sockaddr_union_t me; curl_socket_t sock = CURL_SOCKET_BAD; curl_socket_t msgsock = CURL_SOCKET_BAD; int wrotepidfile = 0; char *pidname= (char *)".sockfilt.pid"; bool juggle_again; int rc; int error; int arg=1; enum sockmode mode = PASSIVE_LISTEN; /* default */ const char *addr = NULL; while(argc>arg) { if(!strcmp("--version", argv[arg])) { printf("sockfilt IPv4%s\n", #ifdef ENABLE_IPV6 "/IPv6" #else "" #endif ); return 0; } else if(!strcmp("--verbose", argv[arg])) { verbose = TRUE; arg++; } else if(!strcmp("--pidfile", argv[arg])) { arg++; if(argc>arg) pidname = argv[arg++]; } else if(!strcmp("--logfile", argv[arg])) { arg++; if(argc>arg) serverlogfile = argv[arg++]; } else if(!strcmp("--ipv6", argv[arg])) { #ifdef ENABLE_IPV6 ipv_inuse = "IPv6"; use_ipv6 = TRUE; #endif arg++; } else if(!strcmp("--ipv4", argv[arg])) { /* for completeness, we support this option as well */ #ifdef ENABLE_IPV6 ipv_inuse = "IPv4"; use_ipv6 = FALSE; #endif arg++; } else if(!strcmp("--bindonly", argv[arg])) { bind_only = TRUE; arg++; } else if(!strcmp("--port", argv[arg])) { arg++; if(argc>arg) { char *endptr; unsigned long ulnum = strtoul(argv[arg], &endptr, 10); if((endptr != argv[arg] + strlen(argv[arg])) || ((ulnum != 0UL) && ((ulnum < 1025UL) || (ulnum > 65535UL)))) { fprintf(stderr, "sockfilt: invalid --port argument (%s)\n", argv[arg]); return 0; } port = curlx_ultous(ulnum); arg++; } } else if(!strcmp("--connect", argv[arg])) { /* Asked to actively connect to the specified local port instead of doing a passive server-style listening. */ arg++; if(argc>arg) { char *endptr; unsigned long ulnum = strtoul(argv[arg], &endptr, 10); if((endptr != argv[arg] + strlen(argv[arg])) || (ulnum < 1025UL) || (ulnum > 65535UL)) { fprintf(stderr, "sockfilt: invalid --connect argument (%s)\n", argv[arg]); return 0; } connectport = curlx_ultous(ulnum); arg++; } } else if(!strcmp("--addr", argv[arg])) { /* Set an IP address to use with --connect; otherwise use localhost */ arg++; if(argc>arg) { addr = argv[arg]; arg++; } } else { puts("Usage: sockfilt [option]\n" " --version\n" " --verbose\n" " --logfile [file]\n" " --pidfile [file]\n" " --ipv4\n" " --ipv6\n" " --bindonly\n" " --port [port]\n" " --connect [port]\n" " --addr [address]"); return 0; } } #ifdef WIN32 win32_init(); atexit(win32_cleanup); setmode(fileno(stdin), O_BINARY); setmode(fileno(stdout), O_BINARY); setmode(fileno(stderr), O_BINARY); #endif install_signal_handlers(); #ifdef ENABLE_IPV6 if(!use_ipv6) #endif sock = socket(AF_INET, SOCK_STREAM, 0); #ifdef ENABLE_IPV6 else sock = socket(AF_INET6, SOCK_STREAM, 0); #endif if(CURL_SOCKET_BAD == sock) { error = SOCKERRNO; logmsg("Error creating socket: (%d) %s", error, strerror(error)); write_stdout("FAIL\n", 5); goto sockfilt_cleanup; } if(connectport) { /* Active mode, we should connect to the given port number */ mode = ACTIVE; #ifdef ENABLE_IPV6 if(!use_ipv6) { #endif memset(&me.sa4, 0, sizeof(me.sa4)); me.sa4.sin_family = AF_INET; me.sa4.sin_port = htons(connectport); me.sa4.sin_addr.s_addr = INADDR_ANY; if (!addr) addr = "127.0.0.1"; Curl_inet_pton(AF_INET, addr, &me.sa4.sin_addr); rc = connect(sock, &me.sa, sizeof(me.sa4)); #ifdef ENABLE_IPV6 } else { memset(&me.sa6, 0, sizeof(me.sa6)); me.sa6.sin6_family = AF_INET6; me.sa6.sin6_port = htons(connectport); if (!addr) addr = "::1"; Curl_inet_pton(AF_INET6, addr, &me.sa6.sin6_addr); rc = connect(sock, &me.sa, sizeof(me.sa6)); } #endif /* ENABLE_IPV6 */ if(rc) { error = SOCKERRNO; logmsg("Error connecting to port %hu: (%d) %s", connectport, error, strerror(error)); write_stdout("FAIL\n", 5); goto sockfilt_cleanup; } logmsg("====> Client connect"); msgsock = sock; /* use this as stream */ } else { /* passive daemon style */ sock = sockdaemon(sock, &port); if(CURL_SOCKET_BAD == sock) { write_stdout("FAIL\n", 5); goto sockfilt_cleanup; } msgsock = CURL_SOCKET_BAD; /* no stream socket yet */ } logmsg("Running %s version", ipv_inuse); if(connectport) logmsg("Connected to port %hu", connectport); else if(bind_only) logmsg("Bound without listening on port %hu", port); else logmsg("Listening on port %hu", port); wrotepidfile = write_pidfile(pidname); if(!wrotepidfile) { write_stdout("FAIL\n", 5); goto sockfilt_cleanup; } do { juggle_again = juggle(&msgsock, sock, &mode); } while(juggle_again); sockfilt_cleanup: if((msgsock != sock) && (msgsock != CURL_SOCKET_BAD)) sclose(msgsock); if(sock != CURL_SOCKET_BAD) sclose(sock); if(wrotepidfile) unlink(pidname); restore_signal_handlers(); if(got_exit_signal) { logmsg("============> sockfilt exits with signal (%d)", exit_signal); /* * To properly set the return status of the process we * must raise the same signal SIGINT or SIGTERM that we * caught and let the old handler take care of it. */ raise(exit_signal); } logmsg("============> sockfilt quits"); return 0; }
int main(int argc, char *argv[]) { pid_t pid; int pm_fd; struct sigaction act; sigset_t sigmask; int c; char errmsg[PATH_MAX + 64]; int pid_fd; prog = argv[0]; if (geteuid() != 0) { (void) fprintf(stderr, "%s: Must be root\n", prog); exit(EXIT_FAILURE); } if ((pid_fd = open_pidfile(prog)) == -1) exit(EXIT_FAILURE); /* * Process options */ broadcast = 1; while ((c = getopt(argc, argv, "n")) != EOF) { switch (c) { case 'n': broadcast = 0; break; case '?': (void) fprintf(stderr, "Usage: %s [-n]\n", prog); exit(EXIT_FAILURE); } } pm_fd = open(PM, O_RDWR); if (pm_fd == -1) { (void) sprintf(errmsg, "%s: %s", prog, PM); perror(errmsg); exit(EXIT_FAILURE); } (void) close(pm_fd); /* * Initialize mutex lock used to insure only one command to * run at a time. */ if (mutex_init(&poweroff_mutex, USYNC_THREAD, NULL) != 0) { (void) fprintf(stderr, "%s: Unable to initialize mutex lock\n", prog); exit(EXIT_FAILURE); } if ((info = (pwr_info_t *)malloc(sizeof (pwr_info_t))) == NULL) { (void) sprintf(errmsg, "%s: malloc", prog); perror(errmsg); exit(EXIT_FAILURE); } /* * Daemon is set to go... */ if ((pid = fork()) < 0) exit(EXIT_FAILURE); else if (pid != 0) exit(EXIT_SUCCESS); pid = getpid(); openlog(prog, 0, LOG_DAEMON); if (write_pidfile(pid_fd, pid) == -1) /* logs errors on failure */ exit(EXIT_FAILURE); (void) close(pid_fd); /* * Close all the parent's file descriptors (Bug 1225843). */ closefrom(0); (void) setsid(); (void) chdir("/"); (void) umask(0); #ifdef DEBUG /* * Connect stdout to the console. */ if (dup2(open("/dev/console", O_WRONLY|O_NOCTTY), 1) == -1) { logerror("Unable to connect to the console."); } #endif info->pd_flags = PD_AC; info->pd_idle_time = -1; info->pd_start_time = 0; info->pd_finish_time = 0; /* * Allow SIGQUIT, SIGINT and SIGTERM signals to terminate us * any time */ act.sa_handler = kill_handler; (void) sigemptyset(&act.sa_mask); act.sa_flags = 0; (void) sigaction(SIGQUIT, &act, NULL); (void) sigaction(SIGINT, &act, NULL); (void) sigaction(SIGTERM, &act, NULL); (void) sigfillset(&sigmask); (void) sigdelset(&sigmask, SIGQUIT); (void) sigdelset(&sigmask, SIGINT); (void) sigdelset(&sigmask, SIGTERM); (void) thr_sigsetmask(SIG_SETMASK, &sigmask, NULL); /* * If "power_button" device node can be opened, create a new * thread to monitor the power button. */ if ((pb_fd = open(PB, O_RDONLY)) != -1) { if (thr_create(NULL, NULL, (void *(*)(void *))power_button_monitor, NULL, THR_DAEMON, NULL) != 0) { logerror("Unable to monitor system's power button."); } } #ifdef sparc do_attach(); #endif /* * Create a new thread to monitor system activity and suspend * system if idle. */ if (thr_create(NULL, NULL, (void *(*)(void *))system_activity_monitor, NULL, THR_DAEMON, NULL) != 0) { logerror("Unable to create thread to monitor system activity."); } /* * Block until we receive an explicit terminate signal */ (void) sigsuspend(&sigmask); return (1); }
int zcip_main(int argc UNUSED_PARAM, char **argv) { int state; char *r_opt; unsigned opts; // ugly trick, but I want these zeroed in one go struct { const struct in_addr null_ip; const struct ether_addr null_addr; struct in_addr ip; struct ifreq ifr; int timeout_ms; /* must be signed */ unsigned conflicts; unsigned nprobes; unsigned nclaims; int ready; } L; #define null_ip (L.null_ip ) #define null_addr (L.null_addr ) #define ip (L.ip ) #define ifr (L.ifr ) #define timeout_ms (L.timeout_ms) #define conflicts (L.conflicts ) #define nprobes (L.nprobes ) #define nclaims (L.nclaims ) #define ready (L.ready ) memset(&L, 0, sizeof(L)); INIT_G(); #define FOREGROUND (opts & 1) #define QUIT (opts & 2) // parse commandline: prog [options] ifname script // exactly 2 args; -v accumulates and implies -f opt_complementary = "=2:vv:vf"; opts = getopt32(argv, "fqr:p:v", &r_opt, &pidfile, &verbose); #if !BB_MMU // on NOMMU reexec early (or else we will rerun things twice) if (!FOREGROUND) bb_daemonize_or_rexec(0 /*was: DAEMON_CHDIR_ROOT*/, argv); #endif // open an ARP socket // (need to do it before openlog to prevent openlog from taking // fd 3 (sock_fd==3)) xmove_fd(xsocket(AF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)), sock_fd); if (!FOREGROUND) { // do it before all bb_xx_msg calls openlog(applet_name, 0, LOG_DAEMON); logmode |= LOGMODE_SYSLOG; } if (opts & 4) { // -r n.n.n.n if (inet_aton(r_opt, &ip) == 0 || (ntohl(ip.s_addr) & IN_CLASSB_NET) != LINKLOCAL_ADDR ) { bb_error_msg_and_die("invalid link address"); } } argv += optind - 1; /* Now: argv[0]:junk argv[1]:intf argv[2]:script argv[3]:NULL */ /* We need to make space for script argument: */ argv[0] = argv[1]; argv[1] = argv[2]; /* Now: argv[0]:intf argv[1]:script argv[2]:junk argv[3]:NULL */ #define argv_intf (argv[0]) xsetenv("interface", argv_intf); // initialize the interface (modprobe, ifup, etc) if (run(argv, "init", NULL)) return EXIT_FAILURE; // initialize saddr // saddr is: { u16 sa_family; u8 sa_data[14]; } //memset(&saddr, 0, sizeof(saddr)); //TODO: are we leaving sa_family == 0 (AF_UNSPEC)?! safe_strncpy(saddr.sa_data, argv_intf, sizeof(saddr.sa_data)); // bind to the interface's ARP socket xbind(sock_fd, &saddr, sizeof(saddr)); // get the interface's ethernet address //memset(&ifr, 0, sizeof(ifr)); strncpy_IFNAMSIZ(ifr.ifr_name, argv_intf); xioctl(sock_fd, SIOCGIFHWADDR, &ifr); memcpy(ð_addr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN); // start with some stable ip address, either a function of // the hardware address or else the last address we used. // we are taking low-order four bytes, as top-order ones // aren't random enough. // NOTE: the sequence of addresses we try changes only // depending on when we detect conflicts. { uint32_t t; move_from_unaligned32(t, ((char *)ð_addr + 2)); srand(t); } if (ip.s_addr == 0) ip.s_addr = pick(); // FIXME cases to handle: // - zcip already running! // - link already has local address... just defend/update // daemonize now; don't delay system startup if (!FOREGROUND) { #if BB_MMU bb_daemonize(0 /*was: DAEMON_CHDIR_ROOT*/); #endif if (verbose) bb_info_msg("start, interface %s", argv_intf); } write_pidfile(pidfile); bb_signals(BB_FATAL_SIGS, cleanup); // run the dynamic address negotiation protocol, // restarting after address conflicts: // - start with some address we want to try // - short random delay // - arp probes to see if another host uses it // - arp announcements that we're claiming it // - use it // - defend it, within limits // exit if: // - address is successfully obtained and -q was given: // run "<script> config", then exit with exitcode 0 // - poll error (when does this happen?) // - read error (when does this happen?) // - sendto error (in arp()) (when does this happen?) // - revents & POLLERR (link down). run "<script> deconfig" first state = PROBE; while (1) { struct pollfd fds[1]; unsigned deadline_us; struct arp_packet p; int source_ip_conflict; int target_ip_conflict; fds[0].fd = sock_fd; fds[0].events = POLLIN; fds[0].revents = 0; // poll, being ready to adjust current timeout if (!timeout_ms) { timeout_ms = random_delay_ms(PROBE_WAIT); // FIXME setsockopt(sock_fd, SO_ATTACH_FILTER, ...) to // make the kernel filter out all packets except // ones we'd care about. } // set deadline_us to the point in time when we timeout deadline_us = MONOTONIC_US() + timeout_ms * 1000; VDBG("...wait %d %s nprobes=%u, nclaims=%u\n", timeout_ms, argv_intf, nprobes, nclaims); switch (safe_poll(fds, 1, timeout_ms)) { default: //bb_perror_msg("poll"); - done in safe_poll cleanup(EXIT_FAILURE); // timeout case 0: VDBG("state = %d\n", state); switch (state) { case PROBE: // timeouts in the PROBE state mean no conflicting ARP packets // have been received, so we can progress through the states if (nprobes < PROBE_NUM) { nprobes++; VDBG("probe/%u %s@%s\n", nprobes, argv_intf, inet_ntoa(ip)); arp(/* ARPOP_REQUEST, */ /* ð_addr, */ null_ip, &null_addr, ip); timeout_ms = PROBE_MIN * 1000; timeout_ms += random_delay_ms(PROBE_MAX - PROBE_MIN); } else { // Switch to announce state. state = ANNOUNCE; nclaims = 0; VDBG("announce/%u %s@%s\n", nclaims, argv_intf, inet_ntoa(ip)); arp(/* ARPOP_REQUEST, */ /* ð_addr, */ ip, ð_addr, ip); timeout_ms = ANNOUNCE_INTERVAL * 1000; } break; case RATE_LIMIT_PROBE: // timeouts in the RATE_LIMIT_PROBE state mean no conflicting ARP packets // have been received, so we can move immediately to the announce state state = ANNOUNCE; nclaims = 0; VDBG("announce/%u %s@%s\n", nclaims, argv_intf, inet_ntoa(ip)); arp(/* ARPOP_REQUEST, */ /* ð_addr, */ ip, ð_addr, ip); timeout_ms = ANNOUNCE_INTERVAL * 1000; break; case ANNOUNCE: // timeouts in the ANNOUNCE state mean no conflicting ARP packets // have been received, so we can progress through the states if (nclaims < ANNOUNCE_NUM) { nclaims++; VDBG("announce/%u %s@%s\n", nclaims, argv_intf, inet_ntoa(ip)); arp(/* ARPOP_REQUEST, */ /* ð_addr, */ ip, ð_addr, ip); timeout_ms = ANNOUNCE_INTERVAL * 1000; } else { // Switch to monitor state. state = MONITOR; // link is ok to use earlier // FIXME update filters run(argv, "config", &ip); ready = 1; conflicts = 0; timeout_ms = -1; // Never timeout in the monitor state. // NOTE: all other exit paths // should deconfig ... if (QUIT) cleanup(EXIT_SUCCESS); } break; case DEFEND: // We won! No ARP replies, so just go back to monitor. state = MONITOR; timeout_ms = -1; conflicts = 0; break; default: // Invalid, should never happen. Restart the whole protocol. state = PROBE; ip.s_addr = pick(); timeout_ms = 0; nprobes = 0; nclaims = 0; break; } // switch (state) break; // case 0 (timeout) // packets arriving, or link went down case 1: // We need to adjust the timeout in case we didn't receive // a conflicting packet. if (timeout_ms > 0) { unsigned diff = deadline_us - MONOTONIC_US(); if ((int)(diff) < 0) { // Current time is greater than the expected timeout time. // Should never happen. VDBG("missed an expected timeout\n"); timeout_ms = 0; } else { VDBG("adjusting timeout\n"); timeout_ms = (diff / 1000) | 1; /* never 0 */ } } if ((fds[0].revents & POLLIN) == 0) { if (fds[0].revents & POLLERR) { // FIXME: links routinely go down; // this shouldn't necessarily exit. bb_error_msg("iface %s is down", argv_intf); if (ready) { run(argv, "deconfig", &ip); } cleanup(EXIT_FAILURE); } continue; } // read ARP packet if (safe_read(sock_fd, &p, sizeof(p)) < 0) { bb_perror_msg(bb_msg_read_error); cleanup(EXIT_FAILURE); } if (p.eth.ether_type != htons(ETHERTYPE_ARP)) continue; #ifdef DEBUG { struct ether_addr *sha = (struct ether_addr *) p.arp.arp_sha; struct ether_addr *tha = (struct ether_addr *) p.arp.arp_tha; struct in_addr *spa = (struct in_addr *) p.arp.arp_spa; struct in_addr *tpa = (struct in_addr *) p.arp.arp_tpa; VDBG("%s recv arp type=%d, op=%d,\n", argv_intf, ntohs(p.eth.ether_type), ntohs(p.arp.arp_op)); VDBG("\tsource=%s %s\n", ether_ntoa(sha), inet_ntoa(*spa)); VDBG("\ttarget=%s %s\n", ether_ntoa(tha), inet_ntoa(*tpa)); } #endif if (p.arp.arp_op != htons(ARPOP_REQUEST) && p.arp.arp_op != htons(ARPOP_REPLY)) continue; source_ip_conflict = 0; target_ip_conflict = 0; if (memcmp(p.arp.arp_spa, &ip.s_addr, sizeof(struct in_addr)) == 0 && memcmp(&p.arp.arp_sha, ð_addr, ETH_ALEN) != 0 ) { source_ip_conflict = 1; } if (p.arp.arp_op == htons(ARPOP_REQUEST) && memcmp(p.arp.arp_tpa, &ip.s_addr, sizeof(struct in_addr)) == 0 && memcmp(&p.arp.arp_tha, ð_addr, ETH_ALEN) != 0 ) { target_ip_conflict = 1; } VDBG("state = %d, source ip conflict = %d, target ip conflict = %d\n", state, source_ip_conflict, target_ip_conflict); switch (state) { case PROBE: case ANNOUNCE: // When probing or announcing, check for source IP conflicts // and other hosts doing ARP probes (target IP conflicts). if (source_ip_conflict || target_ip_conflict) { conflicts++; if (conflicts >= MAX_CONFLICTS) { VDBG("%s ratelimit\n", argv_intf); timeout_ms = RATE_LIMIT_INTERVAL * 1000; state = RATE_LIMIT_PROBE; } // restart the whole protocol ip.s_addr = pick(); timeout_ms = 0; nprobes = 0; nclaims = 0; } break; case MONITOR: // If a conflict, we try to defend with a single ARP probe. if (source_ip_conflict) { VDBG("monitor conflict -- defending\n"); state = DEFEND; timeout_ms = DEFEND_INTERVAL * 1000; arp(/* ARPOP_REQUEST, */ /* ð_addr, */ ip, ð_addr, ip); } break; case DEFEND: // Well, we tried. Start over (on conflict). if (source_ip_conflict) { state = PROBE; VDBG("defend conflict -- starting over\n"); ready = 0; run(argv, "deconfig", &ip); // restart the whole protocol ip.s_addr = pick(); timeout_ms = 0; nprobes = 0; nclaims = 0; } break; default: // Invalid, should never happen. Restart the whole protocol. VDBG("invalid state -- starting over\n"); state = PROBE; ip.s_addr = pick(); timeout_ms = 0; nprobes = 0; nclaims = 0; break; } // switch state break; // case 1 (packets arriving) } // switch poll } // while (1) #undef argv_intf }
void ns_create(int argc, char **argv) { pid_t pid; int ret, status; struct ns_exec_args args; int flags; char *pidf; args.argc = argc; args.argv = argv; ret = socketpair(AF_UNIX, SOCK_SEQPACKET, 0, args.status_pipe); if (ret) { fprintf(stderr, "Pipe() failed %m\n"); exit(1); } flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWNET | CLONE_NEWIPC | SIGCHLD; if (getenv("ZDTM_USERNS")) flags |= CLONE_NEWUSER; pid = clone(ns_exec, args.stack_ptr, flags, &args); if (pid < 0) { fprintf(stderr, "clone() failed: %m\n"); exit(1); } close(args.status_pipe[1]); if (flags & CLONE_NEWUSER) { char pname[PATH_MAX]; int fd; snprintf(pname, sizeof(pname), "/proc/%d/uid_map", pid); fd = open(pname, O_WRONLY); if (fd < 0) { fprintf(stderr, "open(%s): %m\n", pname); exit(1); } if (write(fd, UID_MAP, sizeof(UID_MAP)) < 0) { fprintf(stderr, "write(" UID_MAP "): %m\n"); exit(1); } close(fd); snprintf(pname, sizeof(pname), "/proc/%d/gid_map", pid); fd = open(pname, O_WRONLY); if (fd < 0) { fprintf(stderr, "open(%s): %m\n", pname); exit(1); } if (write(fd, GID_MAP, sizeof(GID_MAP)) < 0) { fprintf(stderr, "write(" GID_MAP "): %m\n"); exit(1); } close(fd); } shutdown(args.status_pipe[0], SHUT_WR); pidf = pidfile; pidfile = malloc(strlen(pidfile) + 13); sprintf(pidfile, "%s%s", pidf, INPROGRESS); if (write_pidfile(pid)) { fprintf(stderr, "Preparations fail\n"); exit(1); } status = 1; ret = read(args.status_pipe[0], &status, sizeof(status)); if (ret != sizeof(status) || status) { fprintf(stderr, "The test failed (%d, %d)\n", ret, status); exit(1); } ret = read(args.status_pipe[0], &status, sizeof(status)); if (ret != 0) { fprintf(stderr, "Unexpected message from test\n"); exit(1); } unlink(pidfile); pidfile = pidf; if (write_pidfile(pid)) exit(1); exit(0); }
void Anope::Init(int ac, char **av) { /* Set file creation mask and group ID. */ #if defined(DEFUMASK) && HAVE_UMASK umask(DEFUMASK); #endif /* Parse command line arguments */ ParseCommandLineArguments(ac, av); if (GetCommandLineArgument("version", 'v')) { Log(LOG_TERMINAL) << "Anope-" << Anope::Version() << " -- " << Anope::VersionBuildString(); throw CoreException(); } if (GetCommandLineArgument("help", 'h')) { Log(LOG_TERMINAL) << "Anope-" << Anope::Version() << " -- " << Anope::VersionBuildString(); Log(LOG_TERMINAL) << "Anope IRC Services (http://www.anope.org)"; Log(LOG_TERMINAL) << "Usage ./" << Anope::ServicesBin << " [options] ..."; Log(LOG_TERMINAL) << "-c, --config=filename.conf"; Log(LOG_TERMINAL) << " --confdir=conf file direcory"; Log(LOG_TERMINAL) << " --dbdir=database directory"; Log(LOG_TERMINAL) << "-d, --debug[=level]"; Log(LOG_TERMINAL) << "-h, --help"; Log(LOG_TERMINAL) << " --localedir=locale directory"; Log(LOG_TERMINAL) << " --logdir=logs directory"; Log(LOG_TERMINAL) << " --modulesdir=modules directory"; Log(LOG_TERMINAL) << "-e, --noexpire"; Log(LOG_TERMINAL) << "-n, --nofork"; Log(LOG_TERMINAL) << " --nothird"; Log(LOG_TERMINAL) << " --protocoldebug"; Log(LOG_TERMINAL) << "-r, --readonly"; Log(LOG_TERMINAL) << "-s, --support"; Log(LOG_TERMINAL) << "-v, --version"; Log(LOG_TERMINAL) << ""; Log(LOG_TERMINAL) << "Further support is available from http://www.anope.org"; Log(LOG_TERMINAL) << "Or visit us on IRC at irc.anope.org #anope"; throw CoreException(); } if (GetCommandLineArgument("nofork", 'n')) Anope::NoFork = true; if (GetCommandLineArgument("support", 's')) { Anope::NoFork = Anope::NoThird = true; ++Anope::Debug; } if (GetCommandLineArgument("readonly", 'r')) Anope::ReadOnly = true; if (GetCommandLineArgument("nothird")) Anope::NoThird = true; if (GetCommandLineArgument("noexpire", 'e')) Anope::NoExpire = true; if (GetCommandLineArgument("protocoldebug")) Anope::ProtocolDebug = true; Anope::string arg; if (GetCommandLineArgument("debug", 'd', arg)) { if (!arg.empty()) { int level = arg.is_number_only() ? convertTo<int>(arg) : -1; if (level > 0) Anope::Debug = level; else throw CoreException("Invalid option given to --debug"); } else ++Anope::Debug; } if (GetCommandLineArgument("config", 'c', arg)) { if (arg.empty()) throw CoreException("The --config option requires a file name"); ServicesConf = Configuration::File(arg, false); } if (GetCommandLineArgument("confdir", 0, arg)) { if (arg.empty()) throw CoreException("The --confdir option requires a path"); Anope::ConfigDir = arg; } if (GetCommandLineArgument("dbdir", 0, arg)) { if (arg.empty()) throw CoreException("The --dbdir option requires a path"); Anope::DataDir = arg; } if (GetCommandLineArgument("localedir", 0, arg)) { if (arg.empty()) throw CoreException("The --localedir option requires a path"); Anope::LocaleDir = arg; } if (GetCommandLineArgument("modulesdir", 0, arg)) { if (arg.empty()) throw CoreException("The --modulesdir option requires a path"); Anope::ModuleDir = arg; } if (GetCommandLineArgument("logdir", 0, arg)) { if (arg.empty()) throw CoreException("The --logdir option requires a path"); Anope::LogDir = arg; } /* Chdir to Services data directory. */ if (chdir(Anope::ServicesDir.c_str()) < 0) { throw CoreException("Unable to chdir to " + Anope::ServicesDir + ": " + Anope::LastError()); } Log(LOG_TERMINAL) << "Anope " << Anope::Version() << ", " << Anope::VersionBuildString(); #ifdef _WIN32 if (!SupportedWindowsVersion()) throw CoreException(GetWindowsVersion() + " is not a supported version of Windows"); #else /* If we're root, issue a warning now */ if (!getuid() && !getgid()) { /* If we are configured to setuid later, don't issue a warning */ Configuration::Block *options = Config->GetBlock("options"); if (options->Get<Anope::string>("user").empty()) { std::cerr << "WARNING: You are currently running Anope as the root superuser. Anope does not" << std::endl; std::cerr << " require root privileges to run, and it is discouraged that you run Anope" << std::endl; std::cerr << " as the root superuser." << std::endl; sleep(3); } } #endif #ifdef _WIN32 Log(LOG_TERMINAL) << "Using configuration file " << Anope::ConfigDir << "\\" << ServicesConf.GetName(); #else Log(LOG_TERMINAL) << "Using configuration file " << Anope::ConfigDir << "/" << ServicesConf.GetName(); /* Fork to background */ if (!Anope::NoFork) { /* Install these before fork() - it is possible for the child to * connect and kill() the parent before it is able to install the * handler. */ struct sigaction sa, old_sigusr2, old_sigchld; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sa.sa_handler = parent_signal_handler; sigaction(SIGUSR2, &sa, &old_sigusr2); sigaction(SIGCHLD, &sa, &old_sigchld); int i = fork(); if (i > 0) { sigset_t mask; sigemptyset(&mask); sigsuspend(&mask); exit(Anope::ReturnValue); } else if (i == -1) { Log() << "Error, unable to fork: " << Anope::LastError(); Anope::NoFork = true; } /* Child doesn't need these */ sigaction(SIGUSR2, &old_sigusr2, NULL); sigaction(SIGCHLD, &old_sigchld, NULL); } #endif /* Initialize the socket engine. Note that some engines can not survive a fork(), so this must be here. */ SocketEngine::Init(); ServiceManager::Init(); EventManager::Init(); new BotInfoType(); new XLineType(nullptr); new OperBlockType(); /* Read configuration file; exit if there are problems. */ try { Config = new Configuration::Conf(); } catch (const ConfigException &ex) { Log(LOG_TERMINAL) << ex.GetReason(); Log(LOG_TERMINAL) << "*** Support resources: Read through the anope.conf self-contained"; Log(LOG_TERMINAL) << "*** documentation. Read the documentation files found in the 'docs'"; Log(LOG_TERMINAL) << "*** folder. Visit our portal located at http://www.anope.org/. Join"; Log(LOG_TERMINAL) << "*** our support channel on /server irc.anope.org channel #anope."; throw CoreException("Configuration file failed to validate"); } /* Create me */ Configuration::Block *block = Config->GetBlock("serverinfo"); Me = new Server(NULL, block->Get<Anope::string>("name"), 0, block->Get<Anope::string>("description"), block->Get<Anope::string>("id")); for (std::pair<Anope::string, User *> p : UserListByNick) { User *u = p.second; if (u->type != UserType::BOT) continue; ServiceBot *bi = anope_dynamic_static_cast<ServiceBot *>(u); bi->server = Me; ++Me->users; } /* Announce ourselves to the logfile. */ Log() << "Anope " << Anope::Version() << " starting up" << (Anope::Debug || Anope::ReadOnly ? " (options:" : "") << (Anope::Debug ? " debug" : "") << (Anope::ReadOnly ? " readonly" : "") << (Anope::Debug || Anope::ReadOnly ? ")" : ""); InitSignals(); /* Initialize multi-language support */ Language::InitLanguages(); /* Initialize random number generator */ block = Config->GetBlock("options"); srand(block->Get<unsigned>("seed") ^ time(NULL)); ModeManager::Apply(nullptr); /* load modules */ Log() << "Loading modules..."; for (int i = 0; i < Config->CountBlock("module"); ++i) ModuleManager::LoadModule(Config->GetBlock("module", i)->Get<Anope::string>("name"), NULL); #ifndef _WIN32 /* We won't background later, so we should setuid now */ if (Anope::NoFork) setuidgid(); #endif Module *protocol = ModuleManager::FindFirstOf(PROTOCOL); if (protocol == NULL) throw CoreException("You must load a protocol module!"); /* Write our PID to the PID file. */ write_pidfile(); Log() << "Using IRCd protocol " << protocol->name; /* Auto assign sid if applicable */ if (IRCD->RequiresID) { Anope::string sid = IRCD->SID_Retrieve(); if (Me->GetSID() == Me->GetName()) Me->SetSID(sid); for (std::pair<Anope::string, User *> p : UserListByNick) { User *u = p.second; if (u->type != UserType::BOT) continue; ServiceBot *bi = anope_dynamic_static_cast<ServiceBot *>(u); bi->GenerateUID(); } } /* Load up databases */ Log() << "Loading databases..."; EventReturn MOD_RESULT = EventManager::Get()->Dispatch(&Event::LoadDatabase::OnLoadDatabase);; static_cast<void>(MOD_RESULT); Log() << "Databases loaded"; for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end; ++it) it->second->Sync(); }