CAMLprim value ocaml_sd_listen_fds(value connect_to) { CAMLparam1(connect_to); CAMLlocal1(sock_ret); int sock = -EBADR, n; n = sd_listen_fds(0); if (n <= 0) { sd_notifyf(0, "STATUS=Failed to get any active sockets: %s\n" "ERRNO=%i", strerror(errno), errno); caml_failwith("ocaml_sd_listen_fds() failed to get any sockets"); } else if (n != 2) { fprintf(stderr, SD_ERR "Expected 2 fds but given %d\n", n); sd_notifyf(0, "STATUS=Mismatch on number (2): %s\n" "ERRNO=%d", strerror(EBADR), EBADR); caml_failwith("ocaml_sd_listen_fds() mismatch"); } sock = oxen_verify_socket_socket(String_val(connect_to)); if (sock <= 0) { fprintf(stderr, "failed to verify sock %s\n", String_val(connect_to)); caml_failwith("ocaml_sd_listen_fds_init() invalid socket"); } sock_ret = Val_int(sock); CAMLreturn(sock_ret); }
int main(void) { sd_listen_fds(true); sd_notify_supported(); sd_notify(false, "XXX"); sd_notifyf(false, "foo=%s", "bar"); }
static void raw_pull_report_progress(RawPull *i, RawProgress p) { unsigned percent; assert(i); switch (p) { case RAW_DOWNLOADING: { unsigned remain = 80; percent = 0; if (i->settings_job) { percent += i->settings_job->progress_percent * 5 / 100; remain -= 5; } if (i->roothash_job) { percent += i->roothash_job->progress_percent * 5 / 100; remain -= 5; } if (i->checksum_job) { percent += i->checksum_job->progress_percent * 5 / 100; remain -= 5; } if (i->signature_job) { percent += i->signature_job->progress_percent * 5 / 100; remain -= 5; } if (i->raw_job) percent += i->raw_job->progress_percent * remain / 100; break; } case RAW_VERIFYING: percent = 80; break; case RAW_UNPACKING: percent = 85; break; case RAW_FINALIZING: percent = 90; break; case RAW_COPYING: percent = 95; break; default: assert_not_reached("Unknown progress state"); } sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent); log_debug("Combined progress %u%%", percent); }
_PUBLIC_ void become_daemon(bool do_fork, bool no_process_group, bool log_stdout) { pid_t newpid; if (do_fork) { newpid = fork(); if (newpid) { #if HAVE_SYSTEMD sd_notifyf(0, "READY=0\nSTATUS=Starting process...\nMAINPID=%lu", (unsigned long) newpid); #endif /* HAVE_SYSTEMD */ _exit(0); } } /* detach from the terminal */ #ifdef HAVE_SETSID if (!no_process_group) setsid(); #elif defined(TIOCNOTTY) if (!no_process_group) { int i = open("/dev/tty", O_RDWR, 0); if (i != -1) { ioctl(i, (int) TIOCNOTTY, (char *)0); close(i); } } #endif /* HAVE_SETSID */ /* Close fd's 0,1,2 as appropriate. Needed if started by rsh. */ /* stdin must be open if we do not fork, for monitoring for * close. stdout must be open if we are logging there, and we * never close stderr (but debug might dup it onto a log file) */ close_low_fds(do_fork, !log_stdout, false); }
void ServiceNotification::serviceDisabled(std::string message){ #if defined(TBS_DEVICE) LOG_STREAM_DEBUG << "ServiceNotification::serviceDisabled: " << message << LE; std::string msg = "READY=0\n" "STATUS=" + message + "\n" "MAINPID=%lu"; sd_notifyf(0,msg.c_str(), (unsigned long) getpid()); #endif }
_PUBLIC_ void daemon_status(const char *name, const char *msg) { if (name == NULL) { name = "Samba"; } #ifdef HAVE_SYSTEMD sd_notifyf(0, "\nSTATUS=%s: %s", name, msg); #endif DEBUG(0, ("STATUS=daemon '%s' : %s", name, msg)); }
_PUBLIC_ void daemon_ready(const char *daemon) { if (daemon == NULL) { daemon = "Samba"; } #ifdef HAVE_SYSTEMD sd_notifyf(0, "READY=1\nSTATUS=%s: ready to serve connections...", daemon); #endif DEBUG(0, ("STATUS=daemon '%s' finished starting up and ready to serve connections", daemon)); }
static void reportStatus (void) { const double up = tr_sessionGetRawSpeed_KBps (mySession, TR_UP); const double dn = tr_sessionGetRawSpeed_KBps (mySession, TR_DOWN); if (up>0 || dn>0) sd_notifyf (0, "STATUS=Uploading %.2f KBps, Downloading %.2f KBps.\n", up, dn); else sd_notify (0, "STATUS=Idle.\n"); }
static int oxen_verify_socket_socket(const char *connect_to) { if ((strcmp(XEN_RUN_STORED "/socket_ro", connect_to) != 0) && (strcmp(XEN_RUN_STORED "/socket", connect_to) != 0)) { sd_notifyf(0, "STATUS=unexpected socket: %s\n" "ERRNO=%i", connect_to, EBADR); return -EBADR; } return oxen_get_sd_fd(connect_to); }
_PUBLIC_ void exit_daemon(const char *msg, int error) { #ifdef HAVE_SYSTEMD if (msg == NULL) { msg = strerror(error); } sd_notifyf(0, "STATUS=daemon failed to start: %s\n" "ERRNO=%i", msg, error); #endif DEBUG(0, ("STATUS=daemon failed to start: %s, error code %d\n", msg, error)); exit(1); }
/* assume first argument after "fmt" is for DAEMON_NAME, that is really not of interest in our "nametag" function based on sd_notify (that very data point is provided implicitly) */ void sd_notify_wrapper(const char *fmt, ...) { /* assume that first %s in fmt is intended for DAEMON_NAME, i.e., for first argument following fmt in original set_proc_title invocation, which has already been dropped before it boils down here (using the wrapping macro trick); we now simply append the reset after that first %s (with whitespace stripped) to the "Running: " prefix */ int rv; char buffer[255]; char *fmt_iter; char *suffix = NULL; va_list ap; switch (local->type) { case ARBITRATOR: case GEOSTORE: break; default: return; /* not expected to be run as system service */ } fmt_iter = strchr(fmt, '%'); while (fmt_iter) { switch (*++fmt_iter) { case 's': suffix = fmt_iter; /* fall through */ default: fmt_iter = NULL; } } if (!suffix) { log_warn("%s:%d: invalid format: %s", __FILE__, __LINE__, fmt); return; } while (isspace(*++suffix)) /* noop */ ; va_start(ap, fmt); fmt_iter = va_arg(ap, char *); /* just shift by one */ assert(!strcmp(fmt_iter, DAEMON_NAME)); rv = vsnprintf(buffer, sizeof(buffer), suffix, ap); va_end(ap); rv = sd_notifyf(0, "READY=1\n" "STATUS=Running: %s", buffer); if (rv < 0) log_warn("%s:%d: sd_notifyf fail", __FILE__, __LINE__); }
static void dkr_pull_report_progress(DkrPull *i, DkrProgress p) { unsigned percent; assert(i); switch (p) { case DKR_SEARCHING: percent = 0; if (i->images_job) percent += i->images_job->progress_percent * 5 / 100; break; case DKR_RESOLVING: percent = 5; if (i->tags_job) percent += i->tags_job->progress_percent * 5 / 100; break; case DKR_METADATA: percent = 10; if (i->ancestry_job) percent += i->ancestry_job->progress_percent * 5 / 100; if (i->json_job) percent += i->json_job->progress_percent * 5 / 100; break; case DKR_DOWNLOADING: percent = 20; percent += 75 * i->current_ancestry / MAX(1U, i->n_ancestry); if (i->layer_job) percent += i->layer_job->progress_percent * 75 / MAX(1U, i->n_ancestry) / 100; break; case DKR_COPYING: percent = 95; break; default: assert_not_reached("Unknown progress state"); } sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent); log_debug("Combined progress %u%%", percent); }
static void tar_pull_report_progress(TarPull *i, TarProgress p) { unsigned percent; assert(i); switch (p) { case TAR_DOWNLOADING: { unsigned remain = 85; percent = 0; if (i->checksum_job) { percent += i->checksum_job->progress_percent * 5 / 100; remain -= 5; } if (i->signature_job) { percent += i->signature_job->progress_percent * 5 / 100; remain -= 5; } if (i->tar_job) percent += i->tar_job->progress_percent * remain / 100; break; } case TAR_VERIFYING: percent = 85; break; case TAR_FINALIZING: percent = 90; break; case TAR_COPYING: percent = 95; break; default: assert_not_reached("Unknown progress state"); } sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent); log_debug("Combined progress %u%%", percent); }
static void raw_export_report_progress(RawExport *e) { unsigned percent; assert(e); if (e->written_uncompressed >= (uint64_t) e->st.st_size) percent = 100; else percent = (unsigned) ((e->written_uncompressed * UINT64_C(100)) / (uint64_t) e->st.st_size); if (percent == e->last_percent) return; if (!ratelimit_below(&e->progress_rate_limit)) return; sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent); log_info("Exported %u%%.", percent); e->last_percent = percent; }
static void tar_export_report_progress(TarExport *e) { unsigned percent; assert(e); /* Do we have any quota info? If not, we don't know anything about the progress */ if (e->quota_referenced == (uint64_t) -1) return; if (e->written_uncompressed >= e->quota_referenced) percent = 100; else percent = (unsigned) ((e->written_uncompressed * UINT64_C(100)) / e->quota_referenced); if (percent == e->last_percent) return; if (!ratelimit_test(&e->progress_rate_limit)) return; sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent); log_info("Exported %u%%.", percent); e->last_percent = percent; }
static void raw_import_report_progress(RawImport *i) { unsigned percent; assert(i); /* We have no size information, unless the source is a regular file */ if (!S_ISREG(i->st.st_mode)) return; if (i->written_compressed >= (uint64_t) i->st.st_size) percent = 100; else percent = (unsigned) ((i->written_compressed * UINT64_C(100)) / (uint64_t) i->st.st_size); if (percent == i->last_percent) return; if (!ratelimit_below(&i->progress_rate_limit)) return; sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent); log_info("Imported %u%%.", percent); i->last_percent = percent; }
static void server_callback(AvahiServer *s, AvahiServerState state, void *userdata) { DaemonConfig *c = userdata; assert(s); assert(c); /* This function is possibly called before the global variable * avahi_server has been set, therefore we do it explicitly */ avahi_server = s; #ifdef HAVE_DBUS if (c->enable_dbus && state != AVAHI_SERVER_INVALID && state != AVAHI_SERVER_FAILURE) dbus_protocol_server_state_changed(state); #endif switch (state) { case AVAHI_SERVER_RUNNING: avahi_log_info("Server startup complete. Host name is %s. Local service cookie is %u.", avahi_server_get_host_name_fqdn(s), avahi_server_get_local_service_cookie(s)); sd_notifyf(0, "STATUS=Server startup complete. Host name is %s. Local service cookie is %u.", avahi_server_get_host_name_fqdn(s), avahi_server_get_local_service_cookie(s)); avahi_set_proc_title(argv0, "%s: running [%s]", argv0, avahi_server_get_host_name_fqdn(s)); static_service_add_to_server(); static_hosts_add_to_server(); remove_dns_server_entry_groups(); if (c->publish_resolv_conf && resolv_conf_name_servers && resolv_conf_name_servers[0]) resolv_conf_entry_group = add_dns_servers(s, resolv_conf_entry_group, resolv_conf_name_servers); if (c->publish_dns_servers && c->publish_dns_servers[0]) dns_servers_entry_group = add_dns_servers(s, dns_servers_entry_group, c->publish_dns_servers); simple_protocol_restart_queries(); break; case AVAHI_SERVER_COLLISION: { char *n; static_service_remove_from_server(); static_hosts_remove_from_server(); remove_dns_server_entry_groups(); n = avahi_alternative_host_name(avahi_server_get_host_name(s)); avahi_log_warn("Host name conflict, retrying with %s", n); sd_notifyf(0, "STATUS=Host name conflict, retrying with %s", n); avahi_set_proc_title(argv0, "%s: collision [%s]", argv0, n); avahi_server_set_host_name(s, n); avahi_free(n); break; } case AVAHI_SERVER_FAILURE: avahi_log_error("Server error: %s", avahi_strerror(avahi_server_errno(s))); sd_notifyf(0, "STATUS=Server error: %s", avahi_strerror(avahi_server_errno(s))); avahi_simple_poll_quit(simple_poll_api); break; case AVAHI_SERVER_REGISTERING: sd_notifyf(0, "STATUS=Registering host name %s", avahi_server_get_host_name_fqdn(s)); avahi_set_proc_title(argv0, "%s: registering [%s]", argv0, avahi_server_get_host_name_fqdn(s)); static_service_remove_from_server(); static_hosts_remove_from_server(); remove_dns_server_entry_groups(); break; case AVAHI_SERVER_INVALID: break; } }
int main(int argc, char *argv[]) { int r = 255; int wrote_pid_file = 0; avahi_set_log_function(log_function); init_rand_seed(); avahi_server_config_init(&config.server_config); config.command = DAEMON_RUN; config.daemonize = 0; config.config_file = NULL; #ifdef HAVE_DBUS config.enable_dbus = 1; config.fail_on_missing_dbus = 1; config.n_clients_max = 0; config.n_objects_per_client_max = 0; config.n_entries_per_entry_group_max = 0; #endif config.drop_root = 1; config.set_rlimits = 1; #ifdef ENABLE_CHROOT config.use_chroot = 1; #endif config.modify_proc_title = 1; config.disable_user_service_publishing = 0; config.publish_dns_servers = NULL; config.publish_resolv_conf = 0; config.use_syslog = 0; config.debug = 0; config.rlimit_as_set = 0; config.rlimit_core_set = 0; config.rlimit_data_set = 0; config.rlimit_fsize_set = 0; config.rlimit_nofile_set = 0; config.rlimit_stack_set = 0; #ifdef RLIMIT_NPROC config.rlimit_nproc_set = 0; #endif if ((argv0 = strrchr(argv[0], '/'))) argv0 = avahi_strdup(argv0 + 1); else argv0 = avahi_strdup(argv[0]); daemon_pid_file_ident = (const char *) argv0; daemon_log_ident = (char*) argv0; daemon_pid_file_proc = pid_file_proc; if (parse_command_line(&config, argc, argv) < 0) goto finish; if (config.modify_proc_title) avahi_init_proc_title(argc, argv); #ifdef ENABLE_CHROOT config.use_chroot = config.use_chroot && config.drop_root; #endif if (config.command == DAEMON_HELP) { help(stdout); r = 0; } else if (config.command == DAEMON_VERSION) { printf("%s "PACKAGE_VERSION"\n", argv0); r = 0; } else if (config.command == DAEMON_KILL) { if (daemon_pid_file_kill_wait(SIGTERM, 5) < 0) { avahi_log_warn("Failed to kill daemon: %s", strerror(errno)); goto finish; } r = 0; } else if (config.command == DAEMON_RELOAD) { if (daemon_pid_file_kill(SIGHUP) < 0) { avahi_log_warn("Failed to kill daemon: %s", strerror(errno)); goto finish; } r = 0; } else if (config.command == DAEMON_CHECK) r = (daemon_pid_file_is_running() >= 0) ? 0 : 1; else if (config.command == DAEMON_RUN) { pid_t pid; if (getuid() != 0 && config.drop_root) { avahi_log_error("This program is intended to be run as root."); goto finish; } if ((pid = daemon_pid_file_is_running()) >= 0) { avahi_log_error("Daemon already running on PID %u", pid); goto finish; } if (load_config_file(&config) < 0) goto finish; if (config.daemonize) { daemon_retval_init(); if ((pid = daemon_fork()) < 0) goto finish; else if (pid != 0) { int ret; /** Parent **/ if ((ret = daemon_retval_wait(20)) < 0) { avahi_log_error("Could not receive return value from daemon process."); goto finish; } r = ret; goto finish; } /* Child */ } if (config.use_syslog || config.daemonize) daemon_log_use = DAEMON_LOG_SYSLOG; if (sd_listen_fds(0) <= 0) if (daemon_close_all(-1) < 0) avahi_log_warn("Failed to close all remaining file descriptors: %s", strerror(errno)); daemon_reset_sigs(-1); daemon_unblock_sigs(-1); if (make_runtime_dir() < 0) goto finish; if (config.drop_root) { #ifdef ENABLE_CHROOT if (config.use_chroot) if (avahi_caps_reduce() < 0) goto finish; #endif if (drop_root() < 0) goto finish; #ifdef ENABLE_CHROOT if (config.use_chroot) if (avahi_caps_reduce2() < 0) goto finish; #endif } if (daemon_pid_file_create() < 0) { avahi_log_error("Failed to create PID file: %s", strerror(errno)); if (config.daemonize) daemon_retval_send(1); goto finish; } else wrote_pid_file = 1; if (config.set_rlimits) enforce_rlimits(); chdir("/"); #ifdef ENABLE_CHROOT if (config.drop_root && config.use_chroot) if (avahi_chroot_helper_start(argv0) < 0) { avahi_log_error("failed to start chroot() helper daemon."); goto finish; } #endif avahi_log_info("%s "PACKAGE_VERSION" starting up.", argv0); sd_notifyf(0, "STATUS=%s "PACKAGE_VERSION" starting up.", argv0); avahi_set_proc_title(argv0, "%s: starting up", argv0); if (run_server(&config) == 0) r = 0; avahi_log_info("%s "PACKAGE_VERSION" exiting.", argv0); sd_notifyf(0, "STATUS=%s "PACKAGE_VERSION" exiting.", argv0); } finish: if (config.daemonize) daemon_retval_done(); avahi_server_config_free(&config.server_config); avahi_free(config.config_file); avahi_strfreev(config.publish_dns_servers); avahi_strfreev(resolv_conf_name_servers); avahi_strfreev(resolv_conf_search_domains); if (wrote_pid_file) { #ifdef ENABLE_CHROOT avahi_chroot_helper_unlink(pid_file_proc()); #else daemon_pid_file_remove(); #endif } #ifdef ENABLE_CHROOT avahi_chroot_helper_shutdown(); #endif avahi_free(argv0); return r; }
bool XzeroDaemon::setup(std::istream *settings, const std::string& filename, int optimizationLevel) { TRACE("setup(%s)", filename.c_str()); runner_->setErrorHandler(std::bind(&wrap_log_error, this, "parser", std::placeholders::_1)); runner_->setOptimizationLevel(optimizationLevel); if (!runner_->open(filename, settings)) { sd_notifyf(0, "ERRNO=%d", errno); goto err; } if (!validateConfig()) goto err; // run setup TRACE("run 'setup'"); if (runner_->invoke(runner_->findHandler("setup"))) goto err; // grap the request handler TRACE("get pointer to 'main'"); { bool (*main)(void*); main = runner_->getPointerTo(runner_->findHandler("main")); if (!main) goto err; server_->requestHandler = main; } // {{{ setup server-tag { #if defined(HAVE_SYS_UTSNAME_H) { utsname utsname; if (uname(&utsname) == 0) { addComponent(std::string(utsname.sysname) + "/" + utsname.release); addComponent(utsname.machine); } } #endif #if defined(HAVE_BZLIB_H) { std::string zver("bzip2/"); zver += BZ2_bzlibVersion(); zver = zver.substr(0, zver.find(",")); addComponent(zver); } #endif #if defined(HAVE_ZLIB_H) { std::string zver("zlib/"); zver += zlib_version; addComponent(zver); } #endif Buffer tagbuf; tagbuf.push_back("x0/" VERSION); if (!components_.empty()) { tagbuf.push_back(" ("); for (int i = 0, e = components_.size(); i != e; ++i) { if (i) tagbuf.push_back(", "); tagbuf.push_back(components_[i]); } tagbuf.push_back(")"); } server_->tag = tagbuf.str(); } // }}} // {{{ run post-config hooks TRACE("setup: post_config"); for (auto i: plugins_) if (!i->post_config()) goto err; // }}} // {{{ run post-check hooks TRACE("setup: post_check"); for (auto i: plugins_) if (!i->post_check()) goto err; // }}} // {{{ check for available TCP listeners if (server_->listeners().empty()) { log(Severity::error, "No HTTP listeners defined"); goto err; } for (auto i: server_->listeners()) if (!i->isOpen()) goto err; // }}} // {{{ check for SO_REUSEPORT feature in TCP listeners if (server_->workers().size() == 1) { // fast-path scheduling for single-threaded mode server_->workers().front()->bind(server_->listeners().front()); } else { std::list<ServerSocket*> dups; for (auto listener: server_->listeners()) { if (listener->reusePort()) { for (auto worker: server_->workers()) { if (worker->id() > 0) { // clone listener for non-main worker listener = listener->clone(worker->loop()); dups.push_back(listener); } worker->bind(listener); } } } // FIXME: this is not yet well thought. // - how to handle configuration file reloads wrt SO_REUSEPORT? for (auto dup: dups) { server_->listeners().push_back(dup); } } // }}} // {{{ x0d: check for superfluous passed file descriptors (and close them) for (auto fd: ServerSocket::getInheritedSocketList()) { bool found = false; for (auto li: server_->listeners()) { if (fd == li->handle()) { found = true; break; } } if (!found) { log(Severity::debug, "Closing inherited superfluous listening socket %d.", fd); ::close(fd); } } // }}} // {{{ systemd: check for superfluous passed file descriptors if (int count = sd_listen_fds(0)) { int maxfd = SD_LISTEN_FDS_START + count; count = 0; for (int fd = SD_LISTEN_FDS_START; fd < maxfd; ++fd) { bool found = false; for (auto li: server_->listeners()) { if (fd == li->handle()) { found = true; break; } } if (!found) { ++count; } } if (count) { fprintf(stderr, "superfluous systemd file descriptors: %d\n", count); return false; } } // }}} // XXX post worker wakeup // we do an explicit wakeup of all workers here since there might be already // some (configure-time related) events pending, i.e. director's (fcgi) health checker // FIXME this is more a workaround than a fix. for (auto worker: server_->workers()) worker->wakeup(); TRACE("setup: done."); return true; err: return false; }
void run(EpmdVars *g) { struct EPMD_SOCKADDR_IN iserv_addr[MAX_LISTEN_SOCKETS]; int listensock[MAX_LISTEN_SOCKETS]; int num_sockets; int i; int opt; unsigned short sport = g->port; node_init(g); g->conn = conn_init(g); #ifdef HAVE_SYSTEMD_DAEMON if (g->is_systemd) { int n; dbg_printf(g,2,"try to obtain sockets from systemd"); n = sd_listen_fds(0); if (n < 0) { dbg_perror(g,"cannot obtain sockets from systemd"); epmd_cleanup_exit(g,1); } else if (n == 0) { dbg_tty_printf(g,0,"systemd provides no sockets"); epmd_cleanup_exit(g,1); } else if (n > MAX_LISTEN_SOCKETS) { dbg_tty_printf(g,0,"cannot listen on more than %d IP addresses", MAX_LISTEN_SOCKETS); epmd_cleanup_exit(g,1); } num_sockets = n; for (i = 0; i < num_sockets; i++) { g->listenfd[i] = listensock[i] = SD_LISTEN_FDS_START + i; } } else { #endif /* HAVE_SYSTEMD_DAEMON */ dbg_printf(g,2,"try to initiate listening port %d", g->port); if (g->addresses != NULL && /* String contains non-separator characters if: */ g->addresses[strspn(g->addresses," ,")] != '\000') { char *tmp; char *token; int loopback_ok = 0; if ((tmp = (char *)malloc(strlen(g->addresses) + 1)) == NULL) { dbg_perror(g,"cannot allocate memory"); epmd_cleanup_exit(g,1); } strcpy(tmp,g->addresses); for(token = strtok(tmp,", "), num_sockets = 0; token != NULL; token = strtok(NULL,", "), num_sockets++) { struct EPMD_IN_ADDR addr; #ifdef HAVE_INET_PTON int ret; if ((ret = inet_pton(FAMILY,token,&addr)) == -1) { dbg_perror(g,"cannot convert IP address to network format"); epmd_cleanup_exit(g,1); } else if (ret == 0) #elif !defined(EPMD6) if ((addr.EPMD_S_ADDR = inet_addr(token)) == INADDR_NONE) #endif { dbg_tty_printf(g,0,"cannot parse IP address \"%s\"",token); epmd_cleanup_exit(g,1); } if (IS_ADDR_LOOPBACK(addr)) loopback_ok = 1; if (num_sockets - loopback_ok == MAX_LISTEN_SOCKETS - 1) { dbg_tty_printf(g,0,"cannot listen on more than %d IP addresses", MAX_LISTEN_SOCKETS); epmd_cleanup_exit(g,1); } SET_ADDR(iserv_addr[num_sockets],addr.EPMD_S_ADDR,sport); } free(tmp); if (!loopback_ok) { SET_ADDR(iserv_addr[num_sockets],EPMD_ADDR_LOOPBACK,sport); num_sockets++; } } else { SET_ADDR(iserv_addr[0],EPMD_ADDR_ANY,sport); num_sockets = 1; } #ifdef HAVE_SYSTEMD_DAEMON } #endif /* HAVE_SYSTEMD_DAEMON */ #if !defined(__WIN32__) /* We ignore the SIGPIPE signal that is raised when we call write twice on a socket closed by the other end. */ signal(SIGPIPE, SIG_IGN); #endif /* * Initialize number of active file descriptors. * Stdin, stdout, and stderr are still open. */ g->active_conn = 3 + num_sockets; g->max_conn -= num_sockets; FD_ZERO(&g->orig_read_mask); g->select_fd_top = 0; #ifdef HAVE_SYSTEMD_DAEMON if (g->is_systemd) for (i = 0; i < num_sockets; i++) select_fd_set(g, listensock[i]); else { #endif /* HAVE_SYSTEMD_DAEMON */ for (i = 0; i < num_sockets; i++) { if ((listensock[i] = socket(FAMILY,SOCK_STREAM,0)) < 0) { dbg_perror(g,"error opening stream socket"); epmd_cleanup_exit(g,1); } g->listenfd[i] = listensock[i]; /* * Note that we must not enable the SO_REUSEADDR on Windows, * because addresses will be reused even if they are still in use. */ #if !defined(__WIN32__) opt = 1; if (setsockopt(listensock[i],SOL_SOCKET,SO_REUSEADDR,(char* ) &opt, sizeof(opt)) <0) { dbg_perror(g,"can't set sockopt"); epmd_cleanup_exit(g,1); } #endif /* In rare cases select returns because there is someone to accept but the request is withdrawn before the accept function is called. We set the listen socket to be non blocking to prevent us from being hanging in accept() waiting for the next request. */ #if (defined(__WIN32__) || defined(NO_FCNTL)) opt = 1; /* Gives warning in VxWorks */ if (ioctl(listensock[i], FIONBIO, &opt) != 0) #else opt = fcntl(listensock[i], F_GETFL, 0); if (fcntl(listensock[i], F_SETFL, opt | O_NONBLOCK) == -1) #endif /* __WIN32__ || VXWORKS */ dbg_perror(g,"failed to set non-blocking mode of listening socket %d", listensock[i]); if (bind(listensock[i], (struct sockaddr*) &iserv_addr[i], sizeof(iserv_addr[i])) < 0) { if (errno == EADDRINUSE) { dbg_tty_printf(g,1,"there is already a epmd running at port %d", g->port); epmd_cleanup_exit(g,0); } else { dbg_perror(g,"failed to bind socket"); epmd_cleanup_exit(g,1); } } if(listen(listensock[i], SOMAXCONN) < 0) { dbg_perror(g,"failed to listen on socket"); epmd_cleanup_exit(g,1); } select_fd_set(g, listensock[i]); } #ifdef HAVE_SYSTEMD_DAEMON } sd_notifyf(0, "READY=1\n" "STATUS=Processing port mapping requests...\n" "MAINPID=%lu", (unsigned long) getpid()); #endif /* HAVE_SYSTEMD_DAEMON */ dbg_tty_printf(g,2,"entering the main select() loop"); select_again: while(1) { fd_set read_mask = g->orig_read_mask; struct timeval timeout; int ret; /* If we are idle we time out now and then to enable the code below to close connections that are old and probably hanging. Make sure that select will return often enough. */ timeout.tv_sec = (g->packet_timeout < IDLE_TIMEOUT) ? 1 : IDLE_TIMEOUT; timeout.tv_usec = 0; if ((ret = select(g->select_fd_top, &read_mask, (fd_set *)0,(fd_set *)0,&timeout)) < 0) { dbg_perror(g,"error in select "); switch (errno) { case EAGAIN: case EINTR: break; default: epmd_cleanup_exit(g,1); } } else { time_t now; if (ret == 0) { FD_ZERO(&read_mask); } if (g->delay_accept) { /* Test of busy server */ sleep(g->delay_accept); } for (i = 0; i < num_sockets; i++) if (FD_ISSET(listensock[i],&read_mask)) { if (do_accept(g, listensock[i]) && g->active_conn < g->max_conn) { /* * The accept() succeeded, and we have at least one file * descriptor still free, which means that another accept() * could succeed. Go do do another select(), in case there * are more incoming connections waiting to be accepted. */ goto select_again; } } /* Check all open streams marked by select for data or a close. We also close all open sockets except ALIVE with no activity for a long period */ now = current_time(g); for (i = 0; i < g->max_conn; i++) { if (g->conn[i].open == EPMD_TRUE) { if (FD_ISSET(g->conn[i].fd,&read_mask)) do_read(g,&g->conn[i]); else if ((g->conn[i].keep == EPMD_FALSE) && ((g->conn[i].mod_time + g->packet_timeout) < now)) { dbg_tty_printf(g,1,"closing because timed out on receive"); epmd_conn_close(g,&g->conn[i]); } } } } } }
static int rename_service(sd_bus *a, sd_bus *b) { _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; _cleanup_free_ char *p = NULL, *name = NULL; const char *comm; char **cmdline; uid_t uid; pid_t pid; int r; assert(a); assert(b); r = sd_bus_get_owner_creds(b, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_AUGMENT, &creds); if (r < 0) return r; r = sd_bus_creds_get_euid(creds, &uid); if (r < 0) return r; r = sd_bus_creds_get_pid(creds, &pid); if (r < 0) return r; r = sd_bus_creds_get_cmdline(creds, &cmdline); if (r < 0) return r; r = sd_bus_creds_get_comm(creds, &comm); if (r < 0) return r; name = uid_to_name(uid); if (!name) return -ENOMEM; p = strv_join(cmdline, " "); if (!p) return -ENOMEM; /* The status string gets the full command line ... */ sd_notifyf(false, "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)", pid, p, uid, name); /* ... and the argv line only the short comm */ if (arg_command_line_buffer) { size_t m, w; m = strlen(arg_command_line_buffer); w = snprintf(arg_command_line_buffer, m, "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]", pid, comm, uid, name); if (m > w) memzero(arg_command_line_buffer + w, m - w); } log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s", pid, p, uid, name, a->unique_name); return 0; }
int main_loop() { struct hub_config configuration; struct acl_handle acl; struct hub_info* hub = 0; if (net_initialize() == -1) return -1; do { if (hub) { LOG_INFO("Reloading configuration files..."); LOG_DEBUG("Hub status: %d", (int) hub->status); /* Reinitialize logs */ hub_log_shutdown(); hub_log_initialize(arg_log, arg_log_syslog); hub_set_log_verbosity(arg_verbose); } if (read_config(arg_config, &configuration, !arg_have_config) == -1) return -1; if (acl_initialize(&configuration, &acl) == -1) return -1; /* * Don't restart networking when re-reading configuration. * This might not be possible either, since we might have * dropped our privileges to do so. */ if (!hub) { hub = hub_start_service(&configuration); if (!hub) { acl_shutdown(&acl); free_config(&configuration); net_destroy(); hub_log_shutdown(); return -1; } #if !defined(WIN32) setup_signal_handlers(hub); #ifdef SYSTEMD /* Notify the service manager that this daemon has * been successfully initalized and shall enter the * main loop. */ sd_notifyf(0, "READY=1\n" "MAINPID=%lu", (unsigned long) getpid()); #endif /* SYSTEMD */ #endif /* ! WIN32 */ } hub_set_variables(hub, &acl); hub_event_loop(hub); hub_free_variables(hub); acl_shutdown(&acl); free_config(&configuration); } while (hub->status == hub_status_restart); #if !defined(WIN32) shutdown_signal_handlers(hub); #endif if (hub) { hub_shutdown_service(hub); } net_destroy(); hub_log_shutdown(); return 0; }
int manager_connect(Manager *m) { int r; assert(m); manager_disconnect(m); m->event_retry = sd_event_source_unref(m->event_retry); if (!ratelimit_test(&m->ratelimit)) { log_debug("Slowing down attempts to contact servers."); r = sd_event_add_time(m->event, &m->event_retry, clock_boottime_or_monotonic(), now(clock_boottime_or_monotonic()) + RETRY_USEC, 0, manager_retry_connect, m); if (r < 0) { log_error("Failed to create retry timer: %s", strerror(-r)); return r; } return 0; } /* If we already are operating on some address, switch to the * next one. */ if (m->current_server_address && m->current_server_address->addresses_next) manager_set_server_address(m, m->current_server_address->addresses_next); else { struct addrinfo hints = { .ai_flags = AI_NUMERICSERV|AI_ADDRCONFIG, .ai_socktype = SOCK_DGRAM, }; /* Hmm, we are through all addresses, let's look for the next host instead */ if (m->current_server_name && m->current_server_name->names_next) manager_set_server_name(m, m->current_server_name->names_next); else { ServerName *f; /* Our current server name list is exhausted, * let's find the next one to iterate. First * we try the system list, then the link list. * After having processed the link list we * jump back to the system list. However, if * both lists are empty, we change to the * fallback list. */ if (!m->current_server_name || m->current_server_name->type == SERVER_LINK) { f = m->system_servers; if (!f) f = m->link_servers; } else { f = m->link_servers; if (!f) f = m->system_servers; } if (!f) f = m->fallback_servers; if (!f) { manager_set_server_name(m, NULL); log_debug("No server found."); return 0; } manager_set_server_name(m, f); } /* Tell the resolver to reread /etc/resolv.conf, in * case it changed. */ res_init(); /* Flush out any previously resolved addresses */ server_name_flush_addresses(m->current_server_name); log_debug("Resolving %s...", m->current_server_name->string); r = sd_resolve_getaddrinfo(m->resolve, &m->resolve_query, m->current_server_name->string, "123", &hints, manager_resolve_handler, m); if (r < 0) { log_error("Failed to create resolver: %s", strerror(-r)); return r; } return 1; } r = manager_begin(m); if (r < 0) return r; return 1; } void manager_disconnect(Manager *m) { assert(m); m->resolve_query = sd_resolve_query_unref(m->resolve_query); m->event_timer = sd_event_source_unref(m->event_timer); m->event_receive = sd_event_source_unref(m->event_receive); m->server_socket = safe_close(m->server_socket); m->event_clock_watch = sd_event_source_unref(m->event_clock_watch); m->clock_watch_fd = safe_close(m->clock_watch_fd); m->event_timeout = sd_event_source_unref(m->event_timeout); sd_notifyf(false, "STATUS=Idle."); }
ScreenToVnc::ScreenToVnc(QObject *parent) : QObject(parent) { IN; // TODO: make that configurable? exitWhenLastClientGone = false; isEmptyMouse = false; m_fbfd = -1; lastPointerEvent = QDateTime::currentMSecsSinceEpoch(); lastPointerMove = lastPointerEvent; // Unix Signal Handling set up if (::socketpair(AF_UNIX, SOCK_STREAM, 0, unixHupSignalFd)) qFatal("Couldn't create HUP socketpair"); if (::socketpair(AF_UNIX, SOCK_STREAM, 0, unixTermSignalFd)) qFatal("Couldn't create TERM socketpair"); hupSignalNotifier = new QSocketNotifier(unixHupSignalFd[1], QSocketNotifier::Read, this); connect(hupSignalNotifier, SIGNAL(activated(int)), this, SLOT(qtHubSignalHandler())); termSignalNotifier = new QSocketNotifier(unixTermSignalFd[1], QSocketNotifier::Read, this); connect(termSignalNotifier, SIGNAL(activated(int)), this, SLOT(qtTermSignalHandler())); // init the Framebuffer init_fb(); // setup vnc server // must run after init_rb, so m_scrinfo and m_xPadding is set! char *argv[0]; m_server = rfbGetScreen(0,argv,(m_scrinfo.xres + m_xPadding), m_scrinfo.yres, 8, 3, m_scrinfo.bits_per_pixel / 8); if(!m_server){ LOG() << "failed to create VNC server"; } m_server->desktopName = "Mer VNC"; m_server->frameBuffer=(char*)malloc((m_scrinfo.xres + m_xPadding)*m_scrinfo.yres*(m_scrinfo.bits_per_pixel / 8)); m_server->alwaysShared=(1==1); m_server->newClientHook = newclient; m_server->ptrAddEvent = mouseHandler; // check if launched by systemd with a ready socket (LISTEN_FDS env var) int sd_fds = sd_listen_fds(1); if (sd_fds){ for (int i = SD_LISTEN_FDS_START; i <= (SD_LISTEN_FDS_START + sd_fds - 1); i++){ if (sd_is_socket(i, AF_INET6, SOCK_STREAM, 1) || sd_is_socket(i, AF_INET, SOCK_STREAM, 1)){ LOG() << "using given socket at FD:" << i; m_server->autoPort = false; m_server->port = 0; m_server->ipv6port = 0; m_server->udpPort = 0; m_server->listenSock = i; FD_SET(m_server->listenSock, &(m_server->allFds)); m_server->maxFd = m_server->listenSock; exitWhenLastClientGone = true; } } } // init the cursors init_fingerPointers(); makeRichCursor(m_server); // Initialize the VNC server rfbInitServer(m_server); // init compare frame buffer m_compareFrameBuffer = (unsigned short int *)calloc((m_scrinfo.xres + m_xPadding) * m_scrinfo.yres, (m_scrinfo.bits_per_pixel / 8)); m_screenshotTimer = new QTimer(this); connect(m_screenshotTimer, SIGNAL(timeout()), this, SLOT(grapFrame())); m_processTimer = new QTimer(this); connect(m_processTimer, SIGNAL(timeout()), this, SLOT(rfbProcessTrigger())); // open the event device // TODO: not Hardcode? eventDev = open("/dev/input/event0", O_RDWR); if(eventDev < 0) { LOG() << "can't open /dev/input/event0"; return; } // start the process trigger timers m_processTimer->start(); m_screenshotTimer->start(300); // inform systemd that we started up sd_notifyf(0, "READY=1\n" "STATUS=Processing requests...\n" "MAINPID=%lu", (unsigned long) getpid()); OUT; }
int main(int argc, char *argv[]) { enum { FD_SOCKET, FD_WALL_TIMER, FD_NOLOGIN_TIMER, FD_SHUTDOWN_TIMER, _FD_MAX }; int r = EXIT_FAILURE, n_fds; int one = 1; struct shutdownd_command c; struct pollfd pollfd[_FD_MAX]; bool exec_shutdown = false, unlink_nologin = false, failed = false; unsigned i; if (getppid() != 1) { log_error("This program should be invoked by init only."); return EXIT_FAILURE; } if (argc > 1) { log_error("This program does not take arguments."); return EXIT_FAILURE; } log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); log_parse_environment(); log_open(); if ((n_fds = sd_listen_fds(true)) < 0) { log_error("Failed to read listening file descriptors from environment: %s", strerror(-r)); return EXIT_FAILURE; } if (n_fds != 1) { log_error("Need exactly one file descriptor."); return EXIT_FAILURE; } if (setsockopt(SD_LISTEN_FDS_START, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) { log_error("SO_PASSCRED failed: %m"); return EXIT_FAILURE; } zero(c); zero(pollfd); pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START; pollfd[FD_SOCKET].events = POLLIN; for (i = 0; i < _FD_MAX; i++) { if (i == FD_SOCKET) continue; pollfd[i].events = POLLIN; if ((pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) { log_error("timerfd_create(): %m"); failed = true; } } if (failed) goto finish; log_debug("systemd-shutdownd running as pid %lu", (unsigned long) getpid()); sd_notify(false, "READY=1\n" "STATUS=Processing requests..."); do { int k; usec_t n; if (poll(pollfd, _FD_MAX, -1) < 0) { if (errno == EAGAIN || errno == EINTR) continue; log_error("poll(): %m"); goto finish; } n = now(CLOCK_REALTIME); if (pollfd[FD_SOCKET].revents) { if ((k = read_packet(pollfd[FD_SOCKET].fd, &c)) < 0) goto finish; else if (k > 0 && c.elapse > 0) { struct itimerspec its; char date[FORMAT_TIMESTAMP_MAX]; if (c.warn_wall) { /* Send wall messages every so often */ zero(its); timespec_store(&its.it_value, when_wall(n, c.elapse)); if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) { log_error("timerfd_settime(): %m"); goto finish; } /* Warn immediately if less than 15 minutes are left */ if (n < c.elapse && n + 15*USEC_PER_MINUTE >= c.elapse) warn_wall(n, &c); } /* Disallow logins 5 minutes prior to shutdown */ zero(its); timespec_store(&its.it_value, when_nologin(c.elapse)); if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) { log_error("timerfd_settime(): %m"); goto finish; } /* Shutdown after the specified time is reached */ zero(its); timespec_store(&its.it_value, c.elapse); if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) { log_error("timerfd_settime(): %m"); goto finish; } sd_notifyf(false, "STATUS=Shutting down at %s...", format_timestamp(date, sizeof(date), c.elapse)); } } if (pollfd[FD_WALL_TIMER].revents) { struct itimerspec its; warn_wall(n, &c); flush_fd(pollfd[FD_WALL_TIMER].fd); /* Restart timer */ zero(its); timespec_store(&its.it_value, when_wall(n, c.elapse)); if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) { log_error("timerfd_settime(): %m"); goto finish; } } if (pollfd[FD_NOLOGIN_TIMER].revents) { int e; log_info("Creating /run/nologin, blocking further logins..."); if ((e = write_one_line_file("/run/nologin", "System is going down.")) < 0) log_error("Failed to create /run/nologin: %s", strerror(-e)); else unlink_nologin = true; flush_fd(pollfd[FD_NOLOGIN_TIMER].fd); } if (pollfd[FD_SHUTDOWN_TIMER].revents) { exec_shutdown = true; goto finish; } } while (c.elapse > 0); r = EXIT_SUCCESS; log_debug("systemd-shutdownd stopped as pid %lu", (unsigned long) getpid()); finish: for (i = 0; i < _FD_MAX; i++) if (pollfd[i].fd >= 0) close_nointr_nofail(pollfd[i].fd); if (unlink_nologin) unlink("/run/nologin"); if (exec_shutdown) { char sw[3]; sw[0] = '-'; sw[1] = c.mode; sw[2] = 0; execl(SYSTEMCTL_BINARY_PATH, "shutdown", sw, "now", (c.warn_wall && c.wall_message[0]) ? c.wall_message : (c.warn_wall ? NULL : "--no-wall"), NULL); log_error("Failed to execute /sbin/shutdown: %m"); } sd_notify(false, "STATUS=Exiting..."); return r; }
void notifyStatus(const QString &status) { sd_notifyf(0, "STATUS=%s", status.toLocal8Bit().constData()); }
bool XzeroDaemon::setup(std::unique_ptr<std::istream>&& settings, const std::string& filename, int optimizationLevel) { TRACE(1, "setup(%s)", filename.c_str()); FlowParser parser(this); parser.importHandler = std::bind(&XzeroDaemon::import, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); if (!parser.open(filename, std::move(settings))) { sd_notifyf(0, "ERRNO=%d", errno); fprintf(stderr, "Failed to open file: %s\n", filename.c_str()); return false; } unit_ = parser.parse(); if (!unit_) return false; if (dumpAST_) ASTPrinter::print(unit_.get()); std::unique_ptr<IRProgram> ir = IRGenerator::generate(unit_.get()); if (!ir) { fprintf(stderr, "IR generation failed. Aborting.\n"); return false; } { PassManager pm; // mandatory passes pm.registerPass(std::make_unique<UnusedBlockPass>()); // optional passes if (optimizationLevel >= 1) { pm.registerPass(std::make_unique<EmptyBlockElimination>()); pm.registerPass(std::make_unique<InstructionElimination>()); } pm.run(ir.get()); } if (dumpIR_) { ir->dump(); } program_ = TargetCodeGenerator().generate(ir.get()); ir.reset(); if (!program_) { fprintf(stderr, "Code generation failed. Aborting.\n"); return false; } if (!program_->link(this)) { fprintf(stderr, "Program linking failed. Aborting.\n"); return false; } if (!validateConfig()) { return false; } if (dumpTargetCode_) program_->dump(); // run setup TRACE(1, "run 'setup'"); if (program_->findHandler("setup")->run(nullptr)) // should not return true return false; // grap the request handler TRACE(1, "get pointer to 'main'"); { auto main = program_->findHandler("main"); server_->requestHandler = [=](x0::HttpRequest* r) { FlowVM::Runner* cx = static_cast<FlowVM::Runner*>(r->setCustomData(r, main->createRunner())); cx->setUserData(r); bool handled = cx->run(); if (!cx->isSuspended() && !handled) { r->finish(); } }; } // {{{ setup server-tag { #if defined(HAVE_SYS_UTSNAME_H) { utsname utsname; if (uname(&utsname) == 0) { addComponent(std::string(utsname.sysname) + "/" + utsname.release); addComponent(utsname.machine); } } #endif #if defined(HAVE_BZLIB_H) { std::string zver("bzip2/"); zver += BZ2_bzlibVersion(); zver = zver.substr(0, zver.find(",")); addComponent(zver); } #endif #if defined(HAVE_ZLIB_H) { std::string zver("zlib/"); zver += zlib_version; addComponent(zver); } #endif Buffer tagbuf; tagbuf.push_back("x0/" VERSION); if (!components_.empty()) { tagbuf.push_back(" ("); for (int i = 0, e = components_.size(); i != e; ++i) { if (i) tagbuf.push_back(", "); tagbuf.push_back(components_[i]); } tagbuf.push_back(")"); } server_->tag = tagbuf.str(); } // }}} // {{{ run post-config hooks TRACE(1, "setup: post_config"); for (auto i: plugins_) if (!i->post_config()) goto err; // }}} // {{{ run post-check hooks TRACE(1, "setup: post_check"); for (auto i: plugins_) if (!i->post_check()) goto err; // }}} // {{{ check for available TCP listeners if (server_->listeners().empty()) { log(Severity::error, "No HTTP listeners defined"); goto err; } for (auto i: server_->listeners()) if (!i->isOpen()) goto err; // }}} // {{{ check for SO_REUSEPORT feature in TCP listeners if (server_->workers().size() == 1) { // fast-path scheduling for single-threaded mode server_->workers().front()->bind(server_->listeners().front()); } else { std::list<ServerSocket*> dups; for (auto listener: server_->listeners()) { if (listener->reusePort()) { for (auto worker: server_->workers()) { if (worker->id() > 0) { // clone listener for non-main worker listener = listener->clone(worker->loop()); dups.push_back(listener); } worker->bind(listener); } } } // FIXME: this is not yet well thought. // - how to handle configuration file reloads wrt SO_REUSEPORT? for (auto dup: dups) { server_->listeners().push_back(dup); } } // }}} // {{{ x0d: check for superfluous passed file descriptors (and close them) for (auto fd: ServerSocket::getInheritedSocketList()) { bool found = false; for (auto li: server_->listeners()) { if (fd == li->handle()) { found = true; break; } } if (!found) { log(Severity::debug, "Closing inherited superfluous listening socket %d.", fd); ::close(fd); } } // }}} // {{{ systemd: check for superfluous passed file descriptors if (int count = sd_listen_fds(0)) { int maxfd = SD_LISTEN_FDS_START + count; count = 0; for (int fd = SD_LISTEN_FDS_START; fd < maxfd; ++fd) { bool found = false; for (auto li: server_->listeners()) { if (fd == li->handle()) { found = true; break; } } if (!found) { ++count; } } if (count) { fprintf(stderr, "superfluous systemd file descriptors: %d\n", count); return false; } } // }}} // XXX post worker wakeup // we do an explicit wakeup of all workers here since there might be already // some (configure-time related) events pending, i.e. director's (fcgi) health checker // FIXME this is more a workaround than a fix. for (auto worker: server_->workers()) worker->wakeup(); TRACE(1, "setup: done."); return true; err: return false; }
bool HomeApplication::run(const QString &shell) { // If a compositor is already running we cannot continue if (Compositor::instance()->isRunning()) { qCWarning(GREENISLAND_COMPOSITOR) << "Compositor already running, don't call run() more than once!"; return false; } // Set plugin GreenIsland::Compositor::s_fixedShell = shell; // Check whether XDG_RUNTIME_DIR is ok or not GreenIsland::verifyXdgRuntimeDir(); // If a socket is passed it means that we are nesting into // another compositor, let's do some checks if (!m_socket.isEmpty()) { // We need wayland QPA plugin if (!QGuiApplication::platformName().startsWith(QStringLiteral("wayland"))) { qCWarning(GREENISLAND_COMPOSITOR) << "By passing the \"--socket\" argument you are requesting to nest" << "this compositor into another, but you forgot to pass " << "also \"-platform wayland\"!"; #if HAVE_SYSTEMD if (m_notify) sd_notifyf(0, "STATUS=Nesting requested, but no wayland QPA"); #endif return false; } } // Screen configuration if (!m_fakeScreenFileName.isEmpty()) { // Need the native backend if (QGuiApplication::platformName().startsWith(QStringLiteral("wayland"))) { qCWarning(GREENISLAND_COMPOSITOR) << "Fake screen configuration is not allowed when Green Island" << "is nested into another compositor"; #if HAVE_SYSTEMD if (m_notify) sd_notifyf(0, "STATUS=Fake screen configuration not allowed when nested"); #endif return false; } } // Create the compositor Compositor *compositor = Compositor::instance(); if (!m_fakeScreenFileName.isEmpty()) compositor->setFakeScreenConfiguration(m_fakeScreenFileName); QObject::connect(compositor, &Compositor::screenConfigurationAcquired, [this] { #if HAVE_SYSTEMD // Notify systemd when the screen configuration is ready if (m_notify) { qCDebug(GREENISLAND_COMPOSITOR) << "Compositor ready, notify systemd on" << qgetenv("NOTIFY_SOCKET"); sd_notify(0, "READY=1"); } #endif }); compositor->run(); compositorLaunched(); return true; }
static int manager_receive_response(sd_event_source *source, int fd, uint32_t revents, void *userdata) { Manager *m = userdata; struct ntp_msg ntpmsg; struct iovec iov = { .iov_base = &ntpmsg, .iov_len = sizeof(ntpmsg), }; union { struct cmsghdr cmsghdr; uint8_t buf[CMSG_SPACE(sizeof(struct timeval))]; } control; union sockaddr_union server_addr; struct msghdr msghdr = { .msg_iov = &iov, .msg_iovlen = 1, .msg_control = &control, .msg_controllen = sizeof(control), .msg_name = &server_addr, .msg_namelen = sizeof(server_addr), }; struct cmsghdr *cmsg; struct timespec now_ts; struct timeval *recv_time; ssize_t len; double origin, receive, trans, dest; double delay, offset; bool spike; int leap_sec; int r; assert(source); assert(m); if (revents & (EPOLLHUP|EPOLLERR)) { log_warning("Server connection returned error."); return manager_connect(m); } len = recvmsg(fd, &msghdr, MSG_DONTWAIT); if (len < 0) { if (errno == EAGAIN) return 0; log_warning("Error receiving message. Disconnecting."); return manager_connect(m); } if (iov.iov_len < sizeof(struct ntp_msg)) { log_warning("Invalid response from server. Disconnecting."); return manager_connect(m); } if (!m->current_server_name || !m->current_server_address || !sockaddr_equal(&server_addr, &m->current_server_address->sockaddr)) { log_debug("Response from unknown server."); return 0; } recv_time = NULL; for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { if (cmsg->cmsg_level != SOL_SOCKET) continue; switch (cmsg->cmsg_type) { case SCM_TIMESTAMP: recv_time = (struct timeval *) CMSG_DATA(cmsg); break; } } if (!recv_time) { log_error("Invalid packet timestamp."); return -EINVAL; } if (!m->pending) { log_debug("Unexpected reply. Ignoring."); return 0; } /* check our "time cookie" (we just stored nanoseconds in the fraction field) */ if (be32toh(ntpmsg.origin_time.sec) != m->trans_time.tv_sec + OFFSET_1900_1970 || be32toh(ntpmsg.origin_time.frac) != m->trans_time.tv_nsec) { log_debug("Invalid reply; not our transmit time. Ignoring."); return 0; } m->event_timeout = sd_event_source_unref(m->event_timeout); if (be32toh(ntpmsg.recv_time.sec) < TIME_EPOCH + OFFSET_1900_1970 || be32toh(ntpmsg.trans_time.sec) < TIME_EPOCH + OFFSET_1900_1970) { log_debug("Invalid reply, returned times before epoch. Ignoring."); return manager_connect(m); } if (NTP_FIELD_LEAP(ntpmsg.field) == NTP_LEAP_NOTINSYNC) { log_debug("Server is not synchronized. Disconnecting."); return manager_connect(m); } if (!IN_SET(NTP_FIELD_VERSION(ntpmsg.field), 3, 4)) { log_debug("Response NTPv%d. Disconnecting.", NTP_FIELD_VERSION(ntpmsg.field)); return manager_connect(m); } if (NTP_FIELD_MODE(ntpmsg.field) != NTP_MODE_SERVER) { log_debug("Unsupported mode %d. Disconnecting.", NTP_FIELD_MODE(ntpmsg.field)); return manager_connect(m); } /* valid packet */ m->pending = false; m->retry_interval = 0; /* announce leap seconds */ if (NTP_FIELD_LEAP(ntpmsg.field) & NTP_LEAP_PLUSSEC) leap_sec = 1; else if (NTP_FIELD_LEAP(ntpmsg.field) & NTP_LEAP_MINUSSEC) leap_sec = -1; else leap_sec = 0; /* * "Timestamp Name ID When Generated * ------------------------------------------------------------ * Originate Timestamp T1 time request sent by client * Receive Timestamp T2 time request received by server * Transmit Timestamp T3 time reply sent by server * Destination Timestamp T4 time reply received by client * * The round-trip delay, d, and system clock offset, t, are defined as: * d = (T4 - T1) - (T3 - T2) t = ((T2 - T1) + (T3 - T4)) / 2" */ assert_se(clock_gettime(clock_boottime_or_monotonic(), &now_ts) >= 0); origin = tv_to_d(recv_time) - (ts_to_d(&now_ts) - ts_to_d(&m->trans_time_mon)) + OFFSET_1900_1970; receive = ntp_ts_to_d(&ntpmsg.recv_time); trans = ntp_ts_to_d(&ntpmsg.trans_time); dest = tv_to_d(recv_time) + OFFSET_1900_1970; offset = ((receive - origin) + (trans - dest)) / 2; delay = (dest - origin) - (trans - receive); spike = manager_sample_spike_detection(m, offset, delay); manager_adjust_poll(m, offset, spike); log_debug("NTP response:\n" " leap : %u\n" " version : %u\n" " mode : %u\n" " stratum : %u\n" " precision : %.6f sec (%d)\n" " reference : %.4s\n" " origin : %.3f\n" " receive : %.3f\n" " transmit : %.3f\n" " dest : %.3f\n" " offset : %+.3f sec\n" " delay : %+.3f sec\n" " packet count : %"PRIu64"\n" " jitter : %.3f%s\n" " poll interval: " USEC_FMT "\n", NTP_FIELD_LEAP(ntpmsg.field), NTP_FIELD_VERSION(ntpmsg.field), NTP_FIELD_MODE(ntpmsg.field), ntpmsg.stratum, exp2(ntpmsg.precision), ntpmsg.precision, ntpmsg.stratum == 1 ? ntpmsg.refid : "n/a", origin - OFFSET_1900_1970, receive - OFFSET_1900_1970, trans - OFFSET_1900_1970, dest - OFFSET_1900_1970, offset, delay, m->packet_count, m->samples_jitter, spike ? " spike" : "", m->poll_interval_usec / USEC_PER_SEC); if (!spike) { m->sync = true; r = manager_adjust_clock(m, offset, leap_sec); if (r < 0) log_error("Failed to call clock_adjtime(): %m"); } log_info("interval/delta/delay/jitter/drift " USEC_FMT "s/%+.3fs/%.3fs/%.3fs/%+ippm%s", m->poll_interval_usec / USEC_PER_SEC, offset, delay, m->samples_jitter, m->drift_ppm, spike ? " (ignored)" : ""); r = manager_arm_timer(m, m->poll_interval_usec); if (r < 0) { log_error("Failed to rearm timer: %s", strerror(-r)); return r; } return 0; } static int manager_listen_setup(Manager *m) { union sockaddr_union addr = {}; static const int tos = IPTOS_LOWDELAY; static const int on = 1; int r; assert(m); assert(m->server_socket < 0); assert(!m->event_receive); assert(m->current_server_address); addr.sa.sa_family = m->current_server_address->sockaddr.sa.sa_family; m->server_socket = socket(addr.sa.sa_family, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (m->server_socket < 0) return -errno; r = bind(m->server_socket, &addr.sa, m->current_server_address->socklen); if (r < 0) return -errno; r = setsockopt(m->server_socket, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)); if (r < 0) return -errno; setsockopt(m->server_socket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); return sd_event_add_io(m->event, &m->event_receive, m->server_socket, EPOLLIN, manager_receive_response, m); } static int manager_begin(Manager *m) { _cleanup_free_ char *pretty = NULL; int r; assert(m); assert_return(m->current_server_name, -EHOSTUNREACH); assert_return(m->current_server_address, -EHOSTUNREACH); m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC; server_address_pretty(m->current_server_address, &pretty); log_info("Using NTP server %s (%s).", strna(pretty), m->current_server_name->string); sd_notifyf(false, "STATUS=Using Time Server %s (%s).", strna(pretty), m->current_server_name->string); r = manager_listen_setup(m); if (r < 0) { log_warning("Failed to setup connection socket: %s", strerror(-r)); return r; } r = manager_clock_watch_setup(m); if (r < 0) return r; return manager_send_request(m); } void manager_set_server_name(Manager *m, ServerName *n) { assert(m); if (m->current_server_name == n) return; m->current_server_name = n; m->current_server_address = NULL; manager_disconnect(m); if (n) log_debug("Selected server %s.", n->string); }