/* Create a new PID file for the current process. */ int pa_pid_file_create(const char *procname) { int fd = -1; int ret = -1; char t[20]; pid_t pid; size_t l; char *fn; #ifdef OS_IS_WIN32 HANDLE process; #endif if (!(fn = pa_runtime_path("pid"))) goto fail; if ((fd = open_pid_file(fn, O_CREAT|O_RDWR)) < 0) goto fail; if ((pid = read_pid(fn, fd)) == (pid_t) -1) pa_log_warn("Corrupt PID file, overwriting."); else if (pid > 0) { int ours = 1; #ifdef OS_IS_WIN32 if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, false, pid)) != NULL) { CloseHandle(process); #else if (kill(pid, 0) >= 0 || errno != ESRCH) { #endif if (procname) if ((ours = proc_name_ours(pid, procname)) < 0) { pa_log_warn("Could not check to see if pid %lu is a pulseaudio process. " "Assuming it is and the daemon is already running.", (unsigned long) pid); goto fail; } if (ours) { pa_log("Daemon already running."); ret = 1; goto fail; } } pa_log_warn("Stale PID file, overwriting."); } /* Overwrite the current PID file */ if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) -1 || ftruncate(fd, (off_t) 0) < 0) { pa_log("Failed to truncate PID file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } pa_snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid()); l = strlen(t); if (pa_loop_write(fd, t, l, NULL) != (ssize_t) l) { pa_log("Failed to write PID file."); goto fail; } ret = 0; fail: if (fd >= 0) { pa_lock_fd(fd, 0); if (pa_close(fd) < 0) { pa_log("Failed to close PID file '%s': %s", fn, pa_cstrerror(errno)); ret = -1; } } pa_xfree(fn); return ret; } /* Remove the PID file, if it is ours */ int pa_pid_file_remove(void) { int fd = -1; char *fn; int ret = -1; pid_t pid; if (!(fn = pa_runtime_path("pid"))) goto fail; if ((fd = open_pid_file(fn, O_RDWR)) < 0) { pa_log_warn("Failed to open PID file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } if ((pid = read_pid(fn, fd)) == (pid_t) -1) goto fail; if (pid != getpid()) { pa_log("PID file '%s' not mine!", fn); goto fail; } if (ftruncate(fd, (off_t) 0) < 0) { pa_log_warn("Failed to truncate PID file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } #ifdef OS_IS_WIN32 pa_lock_fd(fd, 0); pa_close(fd); fd = -1; #endif if (unlink(fn) < 0) { pa_log_warn("Failed to remove PID file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } ret = 0; fail: if (fd >= 0) { pa_lock_fd(fd, 0); if (pa_close(fd) < 0) { pa_log_warn("Failed to close PID file '%s': %s", fn, pa_cstrerror(errno)); ret = -1; } } pa_xfree(fn); return ret; }
int main(int argc, char **argv) { options_t options; int doversion = 0; int dohelp = 0; int userclasses = 0; int opt; int option_index = 0; char prefix[IF_NAMESIZE + 3]; pid_t pid; int debug = 0; int i; int pidfd = -1; const struct option longopts[] = { {"arp", no_argument, NULL, 'a'}, {"script", required_argument, NULL, 'c'}, {"debug", no_argument, NULL, 'd'}, {"hostname", optional_argument, NULL, 'h'}, {"classid", optional_argument, NULL, 'i'}, {"release", no_argument, NULL, 'k'}, {"leasetime", required_argument, NULL, 'l'}, {"metric", required_argument, NULL, 'm'}, {"renew", no_argument, NULL, 'n'}, {"persistent", no_argument, NULL, 'p'}, {"inform", optional_argument, NULL, 's'}, {"request", optional_argument, NULL, 'r'}, {"timeout", required_argument, NULL, 't'}, {"userclass", required_argument, NULL, 'u'}, {"lastlease", no_argument, NULL, 'E'}, {"fqdn", required_argument, NULL, 'F'}, {"nogateway", no_argument, NULL, 'G'}, {"sethostname", no_argument, NULL, 'H'}, {"clientid", optional_argument, NULL, 'I'}, {"noipv4ll", no_argument, NULL, 'L'}, {"nomtu", no_argument, NULL, 'M'}, {"nontp", no_argument, NULL, 'N'}, {"nodns", no_argument, NULL, 'R'}, {"test", no_argument, NULL, 'T'}, {"nonis", no_argument, NULL, 'Y'}, {"help", no_argument, &dohelp, 1}, {"version", no_argument, &doversion, 1}, {NULL, 0, NULL, 0} }; /* Close any un-needed fd's */ for (i = getdtablesize() - 1; i >= 3; --i) close (i); openlog (PACKAGE, LOG_PID, LOG_LOCAL0); memset (&options, 0, sizeof (options_t)); options.script = (char *) DEFAULT_SCRIPT; snprintf (options.classid, CLASS_ID_MAX_LEN, "%s %s", PACKAGE, VERSION); options.classid_len = strlen (options.classid); options.doarp = true; options.dodns = true; options.domtu = true; options.donis = true; options.dontp = true; options.dogateway = true; options.daemonise = true; options.doinform = false; options.doipv4ll = true; options.timeout = DEFAULT_TIMEOUT; gethostname (options.hostname, sizeof (options.hostname)); if (strcmp (options.hostname, "(none)") == 0 || strcmp (options.hostname, "localhost") == 0) memset (options.hostname, 0, sizeof (options.hostname)); /* Don't set any optional arguments here so we retain POSIX * compatibility with getopt */ while ((opt = getopt_long(argc, argv, "c:dh:i:kl:m:npr:s:t:u:AEF:GHI:LMNRTY", longopts, &option_index)) != -1) { switch (opt) { case 0: if (longopts[option_index].flag) break; logger (LOG_ERR, "option `%s' should set a flag", longopts[option_index].name); exit (EXIT_FAILURE); break; case 'c': options.script = optarg; break; case 'd': debug++; switch (debug) { case 1: setloglevel (LOG_DEBUG); break; case 2: options.daemonise = false; break; } break; case 'h': if (! optarg) memset (options.hostname, 0, sizeof (options.hostname)); else if (strlen (optarg) > MAXHOSTNAMELEN) { logger (LOG_ERR, "`%s' too long for HostName string, max is %d", optarg, MAXHOSTNAMELEN); exit (EXIT_FAILURE); } else strlcpy (options.hostname, optarg, sizeof (options.hostname)); break; case 'i': if (! optarg) { memset (options.classid, 0, sizeof (options.classid)); options.classid_len = 0; } else if (strlen (optarg) > CLASS_ID_MAX_LEN) { logger (LOG_ERR, "`%s' too long for ClassID string, max is %d", optarg, CLASS_ID_MAX_LEN); exit (EXIT_FAILURE); } else options.classid_len = strlcpy (options.classid, optarg, sizeof (options.classid)); break; case 'k': options.signal = SIGHUP; break; case 'l': STRINGINT (optarg, options.leasetime); if (options.leasetime <= 0) { logger (LOG_ERR, "leasetime must be a positive value"); exit (EXIT_FAILURE); } break; case 'm': STRINGINT (optarg, options.metric); break; case 'n': options.signal = SIGALRM; break; case 'p': options.persistent = true; break; case 's': options.doinform = true; if (! optarg || strlen (optarg) == 0) { options.request_address.s_addr = 0; break; } else { char *slash = strchr (optarg, '/'); if (slash) { int cidr; /* nullify the slash, so the -r option can read the * address */ *slash++ = '\0'; if (sscanf (slash, "%d", &cidr) != 1) { logger (LOG_ERR, "`%s' is not a valid CIDR", slash); exit (EXIT_FAILURE); } options.request_netmask = inet_cidrtoaddr (cidr); } /* fall through */ } case 'r': if (! options.doinform) options.dorequest = true; if (strlen (optarg) > 0 && ! inet_aton (optarg, &options.request_address)) { logger (LOG_ERR, "`%s' is not a valid IP address", optarg); exit (EXIT_FAILURE); } break; case 't': STRINGINT (optarg, options.timeout); if (options.timeout < 0) { logger (LOG_ERR, "timeout must be a positive value"); exit (EXIT_FAILURE); } break; case 'u': { int offset = 0; for (i = 0; i < userclasses; i++) offset += (int) options.userclass[offset] + 1; if (offset + 1 + strlen (optarg) > USERCLASS_MAX_LEN) { logger (LOG_ERR, "userclass overrun, max is %d", USERCLASS_MAX_LEN); exit (EXIT_FAILURE); } userclasses++; memcpy (options.userclass + offset + 1 , optarg, strlen (optarg)); options.userclass[offset] = strlen (optarg); options.userclass_len += (strlen (optarg)) + 1; } break; case 'A': #ifndef ENABLE_ARP logger (LOG_ERR, "arp support not compiled into dhcpcd"); exit (EXIT_FAILURE); #endif options.doarp = false; break; case 'E': #ifndef ENABLE_INFO logger (LOG_ERR, "info support not compiled into dhcpcd"); exit (EXIT_FAILURE); #endif options.dolastlease = true; break; case 'F': if (strncmp (optarg, "none", strlen (optarg)) == 0) options.fqdn = FQDN_NONE; else if (strncmp (optarg, "ptr", strlen (optarg)) == 0) options.fqdn = FQDN_PTR; else if (strncmp (optarg, "both", strlen (optarg)) == 0) options.fqdn = FQDN_BOTH; else { logger (LOG_ERR, "invalid value `%s' for FQDN", optarg); exit (EXIT_FAILURE); } break; case 'G': options.dogateway = false; break; case 'H': options.dohostname++; break; case 'I': if (optarg) { if (strlen (optarg) > CLIENT_ID_MAX_LEN) { logger (LOG_ERR, "`%s' is too long for ClientID, max is %d", optarg, CLIENT_ID_MAX_LEN); exit (EXIT_FAILURE); } options.clientid_len = strlcpy (options.clientid, optarg, sizeof (options.clientid)); /* empty string disabled duid */ if (options.clientid_len == 0) options.clientid_len = -1; } else { memset (options.clientid, 0, sizeof (options.clientid)); options.clientid_len = -1; } break; case 'L': options.doipv4ll = false; break; case 'M': options.domtu = false; break; case 'N': options.dontp = false; break; case 'R': options.dodns = false; break; case 'T': #ifndef ENABLE_INFO logger (LOG_ERR, "info support not compiled into dhcpcd"); exit (EXIT_FAILURE); #endif options.test = true; options.persistent = true; break; case 'Y': options.donis = false; break; case '?': usage (); exit (EXIT_FAILURE); default: usage (); exit (EXIT_FAILURE); } } if (doversion) printf (""PACKAGE" "VERSION"\n"); if (dohelp) usage (); if (optind < argc) { if (strlen (argv[optind]) > IF_NAMESIZE) { logger (LOG_ERR, "`%s' is too long for an interface name (max=%d)", argv[optind], IF_NAMESIZE); exit (EXIT_FAILURE); } strlcpy (options.interface, argv[optind], sizeof (options.interface)); } else { /* If only version was requested then exit now */ if (doversion || dohelp) exit (EXIT_SUCCESS); logger (LOG_ERR, "no interface specified"); exit (EXIT_FAILURE); } if (strchr (options.hostname, '.')) { if (options.fqdn == FQDN_DISABLE) options.fqdn = FQDN_BOTH; } else options.fqdn = FQDN_DISABLE; if (options.request_address.s_addr == 0 && options.doinform) { if ((options.request_address.s_addr = get_address (options.interface)) != 0) options.keep_address = true; } if (geteuid ()) { logger (LOG_ERR, "you need to be root to run "PACKAGE); exit (EXIT_FAILURE); } snprintf (prefix, IF_NAMESIZE, "%s: ", options.interface); setlogprefix (prefix); snprintf (options.pidfile, sizeof (options.pidfile), PIDFILE, options.interface); chdir ("/"); umask (022); if (mkdir (CONFIGDIR, S_IRUSR |S_IWUSR |S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) && errno != EEXIST ) { logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", CONFIGDIR, strerror (errno)); exit (EXIT_FAILURE); } if (mkdir (ETCDIR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) && errno != EEXIST ) { logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", ETCDIR, strerror (errno)); exit (EXIT_FAILURE); } if (options.test) { if (options.dorequest || options.doinform) { logger (LOG_ERR, "cannot test with --inform or --request"); exit (EXIT_FAILURE); } if (options.dolastlease) { logger (LOG_ERR, "cannot test with --lastlease"); exit (EXIT_FAILURE); } if (options.signal != 0) { logger (LOG_ERR, "cannot test with --release or --renew"); exit (EXIT_FAILURE); } } if (options.signal != 0 ) { int killed = -1; pid = read_pid (options.pidfile); if (pid != 0) logger (LOG_INFO, "sending signal %d to pid %d", options.signal, pid); if (! pid || (killed = kill (pid, options.signal))) logger (options.signal == SIGALRM ? LOG_INFO : LOG_ERR, ""PACKAGE" not running"); if (pid != 0 && (options.signal != SIGALRM || killed != 0)) unlink (options.pidfile); if (killed == 0) exit (EXIT_SUCCESS); if (options.signal != SIGALRM) exit (EXIT_FAILURE); } if (! options.test) { if ((pid = read_pid (options.pidfile)) > 0 && kill (pid, 0) == 0) { logger (LOG_ERR, ""PACKAGE" already running on pid %d (%s)", pid, options.pidfile); exit (EXIT_FAILURE); } pidfd = open (options.pidfile, O_WRONLY | O_CREAT | O_NONBLOCK, 0660); if (pidfd == -1) { logger (LOG_ERR, "open `%s': %s", options.pidfile, strerror (errno)); exit (EXIT_FAILURE); } /* Lock the file so that only one instance of dhcpcd runs on an interface */ if (flock (pidfd, LOCK_EX | LOCK_NB) == -1) { logger (LOG_ERR, "flock `%s': %s", options.pidfile, strerror (errno)); exit (EXIT_FAILURE); } /* dhcpcd.sh should not interhit this fd */ if ((i = fcntl (pidfd, F_GETFD, 0)) == -1 || fcntl (pidfd, F_SETFD, i | FD_CLOEXEC) == -1) logger (LOG_ERR, "fcntl: %s", strerror (errno)); logger (LOG_INFO, PACKAGE " " VERSION " starting"); } /* Seed random */ srandomdev (); if (dhcp_run (&options, &pidfd)) { if (pidfd > -1) close (pidfd); unlink (options.pidfile); exit (EXIT_FAILURE); } exit (EXIT_SUCCESS); }
static ReadStatus read_data (DBusBabysitter *sitter, int fd) { int what; int got; DBusError error = DBUS_ERROR_INIT; ReadStatus r; r = read_ints (fd, &what, 1, &got, &error); switch (r) { case READ_STATUS_ERROR: _dbus_warn ("Failed to read data from fd %d: %s\n", fd, error.message); dbus_error_free (&error); return r; case READ_STATUS_EOF: return r; case READ_STATUS_OK: break; } if (got == 1) { switch (what) { case CHILD_EXITED: case CHILD_FORK_FAILED: case CHILD_EXEC_FAILED: { int arg; r = read_ints (fd, &arg, 1, &got, &error); switch (r) { case READ_STATUS_ERROR: _dbus_warn ("Failed to read arg from fd %d: %s\n", fd, error.message); dbus_error_free (&error); return r; case READ_STATUS_EOF: return r; case READ_STATUS_OK: break; } if (got == 1) { if (what == CHILD_EXITED) { sitter->have_child_status = TRUE; sitter->status = arg; sitter->errnum = 0; _dbus_verbose ("recorded child status exited = %d signaled = %d exitstatus = %d termsig = %d\n", WIFEXITED (sitter->status), WIFSIGNALED (sitter->status), WEXITSTATUS (sitter->status), WTERMSIG (sitter->status)); } else if (what == CHILD_FORK_FAILED) { sitter->have_fork_errnum = TRUE; sitter->errnum = arg; _dbus_verbose ("recorded fork errnum %d\n", sitter->errnum); } else if (what == CHILD_EXEC_FAILED) { sitter->have_exec_errnum = TRUE; sitter->errnum = arg; _dbus_verbose ("recorded exec errnum %d\n", sitter->errnum); } } } break; case CHILD_PID: { pid_t pid = -1; r = read_pid (fd, &pid, &error); switch (r) { case READ_STATUS_ERROR: _dbus_warn ("Failed to read PID from fd %d: %s\n", fd, error.message); dbus_error_free (&error); return r; case READ_STATUS_EOF: return r; case READ_STATUS_OK: break; } sitter->grandchild_pid = pid; _dbus_verbose ("recorded grandchild pid %d\n", sitter->grandchild_pid); } break; default: _dbus_warn ("Unknown message received from babysitter process\n"); break; } } return r; }
int ifplugd_main(int argc UNUSED_PARAM, char **argv) { int iface_status; int delay_time; const char *iface_status_str; struct pollfd netlink_pollfd[1]; unsigned opts; const char *api_mode_found; #if ENABLE_FEATURE_PIDFILE char *pidfile_name; pid_t pid_from_pidfile; #endif INIT_G(); opts = getopt32(argv, OPTION_STR, &G.iface, &G.script_name, &G.poll_time, &G.delay_up, &G.delay_down, &G.api_mode, &G.extra_arg); G.poll_time *= 1000; applet_name = xasprintf("ifplugd(%s)", G.iface); #if ENABLE_FEATURE_PIDFILE pidfile_name = xasprintf(CONFIG_PID_FILE_PATH "/ifplugd.%s.pid", G.iface); pid_from_pidfile = read_pid(pidfile_name); if (opts & FLAG_KILL) { if (pid_from_pidfile > 0) /* Upstream tool use SIGINT for -k */ kill(pid_from_pidfile, SIGINT); return EXIT_SUCCESS; } if (pid_from_pidfile > 0 && kill(pid_from_pidfile, 0) == 0) bb_error_msg_and_die("daemon already running"); #endif api_mode_found = strchr(api_modes, G.api_mode[0]); if (!api_mode_found) bb_error_msg_and_die("unknown API mode '%s'", G.api_mode); G.api_method_num = api_mode_found - api_modes; if (!(opts & FLAG_NO_DAEMON)) bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), ioctl_fd); if (opts & FLAG_MONITOR) { struct sockaddr_nl addr; int fd = xsocket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); memset(&addr, 0, sizeof(addr)); addr.nl_family = AF_NETLINK; addr.nl_groups = RTMGRP_LINK; addr.nl_pid = getpid(); xbind(fd, (struct sockaddr*)&addr, sizeof(addr)); xmove_fd(fd, netlink_fd); } write_pidfile(pidfile_name); /* this can't be moved before socket creation */ if (!(opts & FLAG_NO_SYSLOG)) { openlog(applet_name, 0, LOG_DAEMON); logmode |= LOGMODE_SYSLOG; } bb_signals(0 | (1 << SIGINT ) | (1 << SIGTERM) | (1 << SIGQUIT) | (1 << SIGHUP ) /* why we ignore it? */ /* | (1 << SIGCHLD) - run_script does not use it anymore */ , record_signo); bb_error_msg("started: %s", bb_banner); if (opts & FLAG_MONITOR) { struct ifreq ifrequest; set_ifreq_to_ifname(&ifrequest); G.iface_exists = (network_ioctl(SIOCGIFINDEX, &ifrequest, NULL) == 0); } if (G.iface_exists) maybe_up_new_iface(); iface_status = detect_link(); if (iface_status == IFSTATUS_ERR) goto exiting; iface_status_str = strstatus(iface_status); if (opts & FLAG_MONITOR) { bb_error_msg("interface %s", G.iface_exists ? "exists" : "doesn't exist, waiting"); } /* else we assume it always exists, but don't mislead user * by potentially lying that it really exists */ if (G.iface_exists) { bb_error_msg("link is %s", iface_status_str); } if ((!(opts & FLAG_NO_STARTUP) && iface_status == IFSTATUS_UP ) || (opts & FLAG_INITIAL_DOWN) ) { if (run_script(iface_status_str) != 0) goto exiting; } /* Main loop */ netlink_pollfd[0].fd = netlink_fd; netlink_pollfd[0].events = POLLIN; delay_time = 0; while (1) { int iface_status_old; switch (bb_got_signal) { case SIGINT: case SIGTERM: bb_got_signal = 0; goto cleanup; case SIGQUIT: bb_got_signal = 0; goto exiting; default: bb_got_signal = 0; /* do not clear bb_got_signal if already 0, this can lose signals */ case 0: break; } if (poll(netlink_pollfd, (opts & FLAG_MONITOR) ? 1 : 0, G.poll_time ) < 0 ) { if (errno == EINTR) continue; bb_perror_msg("poll"); goto exiting; } if ((opts & FLAG_MONITOR) && (netlink_pollfd[0].revents & POLLIN) ) { int iface_exists_old; iface_exists_old = G.iface_exists; G.iface_exists = check_existence_through_netlink(); if (G.iface_exists < 0) /* error */ goto exiting; if (iface_exists_old != G.iface_exists) { bb_error_msg("interface %sappeared", G.iface_exists ? "" : "dis"); if (G.iface_exists) maybe_up_new_iface(); } } /* note: if !G.iface_exists, returns DOWN */ iface_status_old = iface_status; iface_status = detect_link(); if (iface_status == IFSTATUS_ERR) { if (!(opts & FLAG_MONITOR)) goto exiting; iface_status = IFSTATUS_DOWN; } iface_status_str = strstatus(iface_status); if (iface_status_old != iface_status) { bb_error_msg("link is %s", iface_status_str); if (delay_time) { /* link restored its old status before * we ran script. don't run the script: */ delay_time = 0; } else { delay_time = monotonic_sec(); if (iface_status == IFSTATUS_UP) delay_time += G.delay_up; if (iface_status == IFSTATUS_DOWN) delay_time += G.delay_down; #if 0 /* if you are back in 1970... */ if (delay_time == 0) { sleep(1); delay_time = 1; } #endif } } if (delay_time && (int)(monotonic_sec() - delay_time) >= 0) { if (run_script(iface_status_str) != 0) goto exiting; delay_time = 0; } } /* while (1) */ cleanup: if (!(opts & FLAG_NO_SHUTDOWN) && (iface_status == IFSTATUS_UP || (iface_status == IFSTATUS_DOWN && delay_time) ) ) { setenv(IFPLUGD_ENV_PREVIOUS, strstatus(iface_status), 1); setenv(IFPLUGD_ENV_CURRENT, strstatus(-1), 1); run_script("down\0up"); /* reusing string */ } exiting: remove_pidfile(pidfile_name); bb_error_msg_and_die("exiting"); }
int main(int argc, char **argv) { options_t *options; int userclasses = 0; int opt; int option_index = 0; char *prefix; pid_t pid; int debug = 0; int i; int pidfd = -1; int sig = 0; /* Close any un-needed fd's */ for (i = getdtablesize() - 1; i >= 3; --i) close (i); openlog (PACKAGE, LOG_PID, LOG_LOCAL0); options = xmalloc (sizeof (options_t)); memset (options, 0, sizeof (options_t)); options->script = (char *) DEFAULT_SCRIPT; snprintf (options->classid, CLASS_ID_MAX_LEN, "%s %s", PACKAGE, VERSION); options->classid_len = strlen (options->classid); options->doarp = true; options->dodns = true; options->domtu = true; options->donis = true; options->dontp = true; options->dogateway = true; options->daemonise = true; options->doinform = false; options->doipv4ll = true; options->timeout = DEFAULT_TIMEOUT; gethostname (options->hostname, sizeof (options->hostname)); if (strcmp (options->hostname, "(none)") == 0 || strcmp (options->hostname, "localhost") == 0) memset (options->hostname, 0, sizeof (options->hostname)); /* Don't set any optional arguments here so we retain POSIX * compatibility with getopt */ while ((opt = getopt_long(argc, argv, EXTRA_OPTS "c:dh:i:kl:m:npr:s:t:u:xAEF:GHI:LMNRTY", longopts, &option_index)) != -1) { switch (opt) { case 0: if (longopts[option_index].flag) break; logger (LOG_ERR, "option `%s' should set a flag", longopts[option_index].name); exit (EXIT_FAILURE); break; case 'c': options->script = optarg; break; case 'd': debug++; switch (debug) { case 1: setloglevel (LOG_DEBUG); break; case 2: options->daemonise = false; break; } break; #ifdef THERE_IS_NO_FORK case 'f': options->daemonised = true; close_fds (); break; case 'g': dhcpcd_skiproutes = xstrdup (optarg); break; #endif case 'h': if (! optarg) memset (options->hostname, 0, sizeof (options->hostname)); else if (strlen (optarg) > MAXHOSTNAMELEN) { logger (LOG_ERR, "`%s' too long for HostName string, max is %d", optarg, MAXHOSTNAMELEN); exit (EXIT_FAILURE); } else strlcpy (options->hostname, optarg, sizeof (options->hostname)); break; case 'i': if (! optarg) { memset (options->classid, 0, sizeof (options->classid)); options->classid_len = 0; } else if (strlen (optarg) > CLASS_ID_MAX_LEN) { logger (LOG_ERR, "`%s' too long for ClassID string, max is %d", optarg, CLASS_ID_MAX_LEN); exit (EXIT_FAILURE); } else options->classid_len = strlcpy (options->classid, optarg, sizeof (options->classid)); break; case 'k': sig = SIGHUP; break; case 'l': STRINGINT (optarg, options->leasetime); if (options->leasetime <= 0) { logger (LOG_ERR, "leasetime must be a positive value"); exit (EXIT_FAILURE); } break; case 'm': STRINGINT (optarg, options->metric); break; case 'n': sig = SIGALRM; break; case 'p': options->persistent = true; break; case 's': options->doinform = true; options->doarp = false; if (! optarg || strlen (optarg) == 0) { options->request_address.s_addr = 0; break; } else { char *slash = strchr (optarg, '/'); if (slash) { int cidr; /* nullify the slash, so the -r option can read the * address */ *slash++ = '\0'; if (sscanf (slash, "%d", &cidr) != 1 || inet_cidrtoaddr (cidr, &options->request_netmask) != 0) { logger (LOG_ERR, "`%s' is not a valid CIDR", slash); exit (EXIT_FAILURE); } } /* fall through */ } case 'r': if (! options->doinform) options->dorequest = true; if (strlen (optarg) > 0 && ! inet_aton (optarg, &options->request_address)) { logger (LOG_ERR, "`%s' is not a valid IP address", optarg); exit (EXIT_FAILURE); } break; case 't': STRINGINT (optarg, options->timeout); if (options->timeout < 0) { logger (LOG_ERR, "timeout must be a positive value"); exit (EXIT_FAILURE); } break; case 'u': { int offset = 0; for (i = 0; i < userclasses; i++) offset += (int) options->userclass[offset] + 1; if (offset + 1 + strlen (optarg) > USERCLASS_MAX_LEN) { logger (LOG_ERR, "userclass overrun, max is %d", USERCLASS_MAX_LEN); exit (EXIT_FAILURE); } userclasses++; memcpy (options->userclass + offset + 1 , optarg, strlen (optarg)); options->userclass[offset] = strlen (optarg); options->userclass_len += (strlen (optarg)) + 1; } break; case 'x': sig = SIGTERM; break; case 'A': #ifndef ENABLE_ARP logger (LOG_ERR, "arp support not compiled into dhcpcd"); exit (EXIT_FAILURE); #endif options->doarp = false; break; case 'E': #ifndef ENABLE_INFO logger (LOG_ERR, "info support not compiled into dhcpcd"); exit (EXIT_FAILURE); #endif options->dolastlease = true; break; case 'F': if (strncmp (optarg, "none", strlen (optarg)) == 0) options->fqdn = FQDN_NONE; else if (strncmp (optarg, "ptr", strlen (optarg)) == 0) options->fqdn = FQDN_PTR; else if (strncmp (optarg, "both", strlen (optarg)) == 0) options->fqdn = FQDN_BOTH; else { logger (LOG_ERR, "invalid value `%s' for FQDN", optarg); exit (EXIT_FAILURE); } break; case 'G': options->dogateway = false; break; case 'H': options->dohostname++; break; case 'I': if (optarg) { if (strlen (optarg) > CLIENT_ID_MAX_LEN) { logger (LOG_ERR, "`%s' is too long for ClientID, max is %d", optarg, CLIENT_ID_MAX_LEN); exit (EXIT_FAILURE); } options->clientid_len = strlcpy (options->clientid, optarg, sizeof (options->clientid)); /* empty string disabled duid */ if (options->clientid_len == 0) options->clientid_len = -1; } else { memset (options->clientid, 0, sizeof (options->clientid)); options->clientid_len = -1; } break; case 'L': options->doipv4ll = false; break; case 'M': options->domtu = false; break; case 'N': options->dontp = false; break; case 'R': options->dodns = false; break; case 'T': #ifndef ENABLE_INFO logger (LOG_ERR, "info support not compiled into dhcpcd"); exit (EXIT_FAILURE); #endif options->test = true; options->persistent = true; break; case 'Y': options->donis = false; break; case '?': usage (); exit (EXIT_FAILURE); default: usage (); exit (EXIT_FAILURE); } } if (doversion) { printf (""PACKAGE" "VERSION"\n"); printf ("Compile time options:" #ifdef ENABLE_ARP " ARP" #endif #ifdef ENABLE_DUID " DUID" #endif #ifdef ENABLE_INFO " INFO" #endif #ifdef ENABLE_INFO_COMPAT " INFO_COMPAT" #endif #ifdef ENABLE_IPV4LL " IPV4LL" #endif #ifdef ENABLE_NIS " NIS" #endif #ifdef ENABLE_NTP " NTP" #endif #ifdef THERE_IS_NO_FORK " THERE_IS_NO_FORK" #endif "\n"); } if (dohelp) usage (); #ifdef THERE_IS_NO_FORK dhcpcd_argv = argv; dhcpcd_argc = argc; /* We need the full path to the dhcpcd */ if (*argv[0] == '/') strlcpy (dhcpcd, argv[0], sizeof (dhcpcd)); else { char pwd[PATH_MAX]; if (! getcwd (pwd, PATH_MAX)) { logger (LOG_ERR, "getcwd: %s", strerror (errno)); exit (EXIT_FAILURE); } snprintf (dhcpcd, sizeof (dhcpcd), "%s/%s", pwd, argv[0]); } #endif if (optind < argc) { if (strlen (argv[optind]) > IF_NAMESIZE) { logger (LOG_ERR, "`%s' is too long for an interface name (max=%d)", argv[optind], IF_NAMESIZE); exit (EXIT_FAILURE); } strlcpy (options->interface, argv[optind], sizeof (options->interface)); } else { /* If only version was requested then exit now */ if (doversion || dohelp) exit (EXIT_SUCCESS); logger (LOG_ERR, "no interface specified"); exit (EXIT_FAILURE); } if (strchr (options->hostname, '.')) { if (options->fqdn == FQDN_DISABLE) options->fqdn = FQDN_BOTH; } else options->fqdn = FQDN_DISABLE; if (options->request_address.s_addr == 0 && options->doinform) { if ((options->request_address.s_addr = get_address (options->interface)) != 0) options->keep_address = true; } if (IN_LINKLOCAL (options->request_address.s_addr)) { logger (LOG_ERR, "you are not allowed to request a link local address"); exit (EXIT_FAILURE); } if (geteuid ()) { logger (LOG_ERR, "you need to be root to run "PACKAGE); exit (EXIT_FAILURE); } prefix = xmalloc (sizeof (char) * (IF_NAMESIZE + 3)); snprintf (prefix, IF_NAMESIZE, "%s: ", options->interface); setlogprefix (prefix); snprintf (options->pidfile, sizeof (options->pidfile), PIDFILE, options->interface); free (prefix); chdir ("/"); umask (022); if (mkdir (CONFIGDIR, S_IRUSR |S_IWUSR |S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) && errno != EEXIST ) { logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", CONFIGDIR, strerror (errno)); exit (EXIT_FAILURE); } if (mkdir (ETCDIR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) && errno != EEXIST ) { logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", ETCDIR, strerror (errno)); exit (EXIT_FAILURE); } if (options->test) { if (options->dorequest || options->doinform) { logger (LOG_ERR, "cannot test with --inform or --request"); exit (EXIT_FAILURE); } if (options->dolastlease) { logger (LOG_ERR, "cannot test with --lastlease"); exit (EXIT_FAILURE); } if (sig != 0) { logger (LOG_ERR, "cannot test with --release or --renew"); exit (EXIT_FAILURE); } } if (sig != 0) { int killed = -1; pid = read_pid (options->pidfile); if (pid != 0) logger (LOG_INFO, "sending signal %d to pid %d", sig, pid); if (! pid || (killed = kill (pid, sig))) logger (sig == SIGALRM ? LOG_INFO : LOG_ERR, ""PACKAGE" not running"); if (pid != 0 && (sig != SIGALRM || killed != 0)) unlink (options->pidfile); if (killed == 0) exit (EXIT_SUCCESS); if (sig != SIGALRM) exit (EXIT_FAILURE); } if (! options->test && ! options->daemonised) { if ((pid = read_pid (options->pidfile)) > 0 && kill (pid, 0) == 0) { logger (LOG_ERR, ""PACKAGE" already running on pid %d (%s)", pid, options->pidfile); exit (EXIT_FAILURE); } pidfd = open (options->pidfile, O_WRONLY | O_CREAT | O_NONBLOCK, 0660); if (pidfd == -1) { logger (LOG_ERR, "open `%s': %s", options->pidfile, strerror (errno)); exit (EXIT_FAILURE); } /* Lock the file so that only one instance of dhcpcd runs on an interface */ if (flock (pidfd, LOCK_EX | LOCK_NB) == -1) { logger (LOG_ERR, "flock `%s': %s", options->pidfile, strerror (errno)); exit (EXIT_FAILURE); } /* dhcpcd.sh should not interhit this fd */ if ((i = fcntl (pidfd, F_GETFD, 0)) == -1 || fcntl (pidfd, F_SETFD, i | FD_CLOEXEC) == -1) logger (LOG_ERR, "fcntl: %s", strerror (errno)); writepid (pidfd, getpid ()); logger (LOG_INFO, PACKAGE " " VERSION " starting"); } /* Seed random */ srandomdev (); i = EXIT_FAILURE; if (dhcp_run (options, &pidfd) == 0) i = EXIT_SUCCESS; /* If we didn't daemonise then we need to punt the pidfile now */ if (pidfd > -1) { close (pidfd); unlink (options->pidfile); } free (options); #ifdef THERE_IS_NO_FORK /* There may have been an error before the dhcp_run function * clears this, so just do it here to be safe */ free (dhcpcd_skiproutes); #endif logger (LOG_INFO, "exiting"); exit (i); }
int main(int argc, char **argv) { options_t options; int doversion = 0; int dohelp = 0; int userclasses = 0; int ch; int option_index = 0; char prefix[IF_NAMESIZE + 3]; pid_t pid; int debug = 0; int i; const struct option longopts[] = { {"arp", no_argument, NULL, 'a'}, {"script", required_argument, NULL, 'c'}, {"debug", no_argument, NULL, 'd'}, {"hostname", required_argument, NULL, 'h'}, {"classid", required_argument, NULL, 'i'}, {"release", no_argument, NULL, 'k'}, {"leasetime", required_argument, NULL, 'l'}, {"metric", required_argument, NULL, 'm'}, {"renew", no_argument, NULL, 'n'}, {"persistent", no_argument, NULL, 'p'}, {"request", required_argument, NULL, 's'}, {"timeout", required_argument, NULL, 't'}, {"userclass", required_argument, NULL, 'u'}, {"fqdn", optional_argument, NULL, 'F'}, {"nogateway", no_argument, NULL, 'G'}, {"sethostname", no_argument, NULL, 'H'}, {"clientid", required_argument, NULL, 'I'}, {"nomtu", no_argument, NULL, 'M'}, {"nontp", no_argument, NULL, 'N'}, {"nodns", no_argument, NULL, 'R'}, {"nonis", no_argument, NULL, 'Y'}, {"help", no_argument, &dohelp, 1}, {"version", no_argument, &doversion, 1}, {NULL, 0, NULL, 0} }; /* Close any un-needed fd's */ for (i = getdtablesize() - 1; i >= 3; --i) close (i); openlog (PACKAGE, LOG_PID, LOG_LOCAL0); memset (&options, 0, sizeof (options_t)); options.script = (char *) DEFAULT_SCRIPT; snprintf (options.classid, CLASS_ID_MAX_LEN, "%s %s", PACKAGE, VERSION); options.doarp = false; options.dodns = true; options.domtu = true; options.donis = true; options.dontp = true; options.dogateway = true; options.daemonise = true; options.timeout = DEFAULT_TIMEOUT; while ((ch = getopt_long(argc, argv, "ac:dh:i:kl:m:nps:t:u:F:GHI:MNRY", longopts, &option_index)) != -1) switch (ch) { case 0: if (longopts[option_index].flag) break; logger (LOG_ERR, "option `%s' should set a flag", longopts[option_index].name); exit (EXIT_FAILURE); break; case 'a': options.doarp = true; break; case 'c': options.script = optarg; break; case 'd': debug++; switch (debug) { case 1: setloglevel (LOG_DEBUG); break; case 2: options.daemonise = false; break; } break; case 'h': if (strlen (optarg) > sizeof (options.hostname)) { logger (LOG_ERR, "`%s' too long for HostName string, max is %d", optarg, sizeof (options.hostname)); exit (EXIT_FAILURE); } else strlcpy (options.hostname, optarg, sizeof (options.hostname)); break; case 'i': if (strlen (optarg) > CLASS_ID_MAX_LEN) { logger (LOG_ERR, "`%s' too long for ClassID string, max is %d", optarg, CLASS_ID_MAX_LEN); exit (EXIT_FAILURE); } else strlcpy (options.classid, optarg, sizeof (options.classid)); break; case 'k': options.signal = SIGHUP; break; case 'l': STRINGINT (optarg, options.leasetime); if (options.leasetime <= 0) { logger (LOG_ERR, "leasetime must be a positive value"); exit (EXIT_FAILURE); } break; case 'm': STRINGINT (optarg, options.metric); break; case 'n': options.signal = SIGALRM; break; case 'p': options.persistent = true; break; case 's': if (! inet_aton (optarg, &options.requestaddress)) { logger (LOG_ERR, "`%s' is not a valid IP address", optarg); exit (EXIT_FAILURE); } break; case 't': STRINGINT (optarg, options.timeout); if (options.timeout < 0) { logger (LOG_ERR, "timeout must be a positive value"); exit (EXIT_FAILURE); } break; case 'u': { int offset = 0; for (i = 0; i < userclasses; i++) offset += (int) options.userclass[offset] + 1; if (offset + 1 + strlen (optarg) > USERCLASS_MAX_LEN) { logger (LOG_ERR, "userclass overrun, max is %d", USERCLASS_MAX_LEN); exit (EXIT_FAILURE); } userclasses++; memcpy (options.userclass + offset + 1 , optarg, strlen (optarg)); options.userclass[offset] = strlen (optarg); options.userclass_len += (strlen (optarg)) + 1; } break; case 'F': if (strncmp (optarg, "none", strlen (optarg)) == 0) options.fqdn = FQDN_NONE; else if (strncmp (optarg, "ptr", strlen (optarg)) == 0) options.fqdn = FQDN_PTR; else if (strncmp (optarg, "both", strlen (optarg)) == 0) options.fqdn = FQDN_BOTH; else { logger (LOG_ERR, "invalid value `%s' for FQDN", optarg); exit (EXIT_FAILURE); } break; case 'G': options.dogateway = false; break; case 'H': options.dohostname = true; break; case 'I': if (strlen (optarg) > CLIENT_ID_MAX_LEN) { logger (LOG_ERR, "`%s' is too long for ClientID, max is %d", optarg, CLIENT_ID_MAX_LEN); exit (EXIT_FAILURE); } else strlcpy (options.clientid, optarg, sizeof (options.clientid)); break; case 'M': options.domtu = false; break; case 'N': options.dontp = false; break; case 'R': options.dodns = false; break; case 'Y': options.donis = false; break; case '?': usage (); exit (EXIT_FAILURE); default: usage (); exit (EXIT_FAILURE); } if (doversion) printf (""PACKAGE" "VERSION"\n"); if (dohelp) usage (); if (optind < argc) { if (strlen (argv[optind]) > IF_NAMESIZE) { logger (LOG_ERR, "`%s' is too long for an interface name (max=%d)", argv[optind], IF_NAMESIZE); exit (EXIT_FAILURE); } strlcpy (options.interface, argv[optind], sizeof (options.interface)); } else { /* If only version was requested then exit now */ if (doversion || dohelp) exit (EXIT_SUCCESS); logger (LOG_ERR, "no interface specified"); exit (EXIT_FAILURE); } /* If we are given a hostname use it and set FQDN if it contains a . */ if (! options.hostname[0]) { gethostname (options.hostname, sizeof (options.hostname)); if (strcmp (options.hostname, "(none)") == 0 || strcmp (options.hostname, "localhost") == 0) memset (options.hostname, 0, sizeof (options.hostname)); } if (strchr (options.hostname, '.')) { if (options.fqdn == FQDN_DISABLE) options.fqdn = FQDN_BOTH; } else options.fqdn = FQDN_DISABLE; if (geteuid ()) { logger (LOG_ERR, "you need to be root to run "PACKAGE); exit (EXIT_FAILURE); } snprintf (prefix, IF_NAMESIZE, "%s: ", options.interface); setlogprefix (prefix); snprintf (options.pidfile, sizeof (options.pidfile), PIDFILE, options.interface); if (options.signal != 0) { int killed = -1; pid = read_pid (options.pidfile); if (pid != 0) logger (LOG_INFO, "sending signal %d to pid %d", options.signal, pid); if (! pid || (killed = kill (pid, options.signal))) logger (options.signal == SIGALRM ? LOG_INFO : LOG_ERR, ""PACKAGE" not running"); if (pid != 0 && (options.signal != SIGALRM || killed != 0)) unlink (options.pidfile); if (killed == 0) exit (EXIT_SUCCESS); if (options.signal != SIGALRM) exit (EXIT_FAILURE); } chdir ("/"); umask (022); if (mkdir (CONFIGDIR, S_IRUSR |S_IWUSR |S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) && errno != EEXIST ) { logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", CONFIGDIR, strerror (errno)); exit (EXIT_FAILURE); } if (mkdir (ETCDIR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) && errno != EEXIST ) { logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", ETCDIR, strerror (errno)); exit (EXIT_FAILURE); } if ((pid = read_pid (options.pidfile)) > 0 && kill (pid, 0) == 0) { logger (LOG_ERR, ""PACKAGE" already running (%s)", options.pidfile); exit (EXIT_FAILURE); } make_pid (options.pidfile); logger (LOG_INFO, PACKAGE " " VERSION " starting"); if (dhcp_run (&options)) { unlink (options.pidfile); exit (EXIT_FAILURE); } exit (EXIT_SUCCESS); }
int main (int argc, char **argv) { const char *prev_arg; const char *shname; const char *runprog = NULL; int remaining_args = 0; int exit_with_session; int c_shell_syntax = FALSE; int bourne_shell_syntax = FALSE; int auto_shell_syntax = FALSE; int i; int ret; int bus_pid_to_launcher_pipe[2]; int bus_pid_to_babysitter_pipe[2]; int bus_address_to_launcher_pipe[2]; char *config_file; exit_with_session = FALSE; config_file = NULL; prev_arg = NULL; i = 1; while (i < argc) { const char *arg = argv[i]; if (strcmp (arg, "--help") == 0 || strcmp (arg, "-h") == 0 || strcmp (arg, "-?") == 0) usage (0); else if (strcmp (arg, "--auto-syntax") == 0) auto_shell_syntax = TRUE; else if (strcmp (arg, "-c") == 0 || strcmp (arg, "--csh-syntax") == 0) c_shell_syntax = TRUE; else if (strcmp (arg, "-s") == 0 || strcmp (arg, "--sh-syntax") == 0) bourne_shell_syntax = TRUE; else if (strcmp (arg, "--version") == 0) version (); else if (strcmp (arg, "--exit-with-session") == 0) exit_with_session = TRUE; else if (strstr (arg, "--config-file=") == arg) { const char *file; if (config_file != NULL) { fprintf (stderr, "--config-file given twice\n"); exit (1); } file = strchr (arg, '='); ++file; config_file = xstrdup (file); } else if (prev_arg && strcmp (prev_arg, "--config-file") == 0) { if (config_file != NULL) { fprintf (stderr, "--config-file given twice\n"); exit (1); } config_file = xstrdup (arg); } else if (strcmp (arg, "--config-file") == 0) ; /* wait for next arg */ else { runprog = arg; remaining_args = i+1; break; } prev_arg = arg; ++i; } if (exit_with_session) verbose ("--exit-with-session enabled\n"); if (auto_shell_syntax) { if ((shname = getenv ("SHELL")) != NULL) { if (!strncmp (shname + strlen (shname) - 3, "csh", 3)) c_shell_syntax = TRUE; else bourne_shell_syntax = TRUE; } else bourne_shell_syntax = TRUE; } if (pipe (bus_pid_to_launcher_pipe) < 0 || pipe (bus_address_to_launcher_pipe) < 0) { fprintf (stderr, "Failed to create pipe: %s\n", strerror (errno)); exit (1); } bus_pid_to_babysitter_pipe[READ_END] = -1; bus_pid_to_babysitter_pipe[WRITE_END] = -1; ret = fork (); if (ret < 0) { fprintf (stderr, "Failed to fork: %s\n", strerror (errno)); exit (1); } if (ret == 0) { /* Child */ #define MAX_FD_LEN 64 char write_pid_fd_as_string[MAX_FD_LEN]; char write_address_fd_as_string[MAX_FD_LEN]; verbose ("=== Babysitter's intermediate parent created\n"); /* Fork once more to create babysitter */ if (pipe (bus_pid_to_babysitter_pipe) < 0) { fprintf (stderr, "Failed to create pipe: %s\n", strerror (errno)); exit (1); } ret = fork (); if (ret < 0) { fprintf (stderr, "Failed to fork: %s\n", strerror (errno)); exit (1); } if (ret > 0) { /* In babysitter */ verbose ("=== Babysitter's intermediate parent continues\n"); close (bus_pid_to_launcher_pipe[READ_END]); close (bus_address_to_launcher_pipe[READ_END]); close (bus_address_to_launcher_pipe[WRITE_END]); close (bus_pid_to_babysitter_pipe[WRITE_END]); /* babysit() will fork *again* * and will also reap the pre-forked bus * daemon */ babysit (exit_with_session, ret, bus_pid_to_babysitter_pipe[READ_END], bus_pid_to_launcher_pipe[WRITE_END]); exit (0); } verbose ("=== Bus exec process created\n"); /* Now we are the bus process (well, almost; * dbus-daemon itself forks again) */ close (bus_pid_to_launcher_pipe[READ_END]); close (bus_address_to_launcher_pipe[READ_END]); close (bus_pid_to_babysitter_pipe[READ_END]); close (bus_pid_to_launcher_pipe[WRITE_END]); sprintf (write_pid_fd_as_string, "%d", bus_pid_to_babysitter_pipe[WRITE_END]); sprintf (write_address_fd_as_string, "%d", bus_address_to_launcher_pipe[WRITE_END]); verbose ("Calling exec()\n"); execlp ("dbus-daemon", "dbus-daemon", "--fork", "--print-pid", write_pid_fd_as_string, "--print-address", write_address_fd_as_string, config_file ? "--config-file" : "--session", config_file, /* has to be last in this varargs list */ NULL); fprintf (stderr, "Failed to execute message bus daemon: %s\n", strerror (errno)); exit (1); } else { /* Parent */ #define MAX_ADDR_LEN 512 pid_t bus_pid; char bus_address[MAX_ADDR_LEN]; verbose ("=== Parent dbus-launch continues\n"); close (bus_pid_to_launcher_pipe[WRITE_END]); close (bus_address_to_launcher_pipe[WRITE_END]); verbose ("Waiting for babysitter's intermediate parent\n"); /* Immediately reap parent of babysitter * (which was created just for us to reap) */ if (do_waitpid (ret) < 0) { fprintf (stderr, "Failed to waitpid() for babysitter intermediate process: %s\n", strerror (errno)); exit (1); } verbose ("Reading address from bus\n"); /* Read the pipe data, print, and exit */ switch (read_line (bus_address_to_launcher_pipe[READ_END], bus_address, MAX_ADDR_LEN)) { case READ_STATUS_OK: break; case READ_STATUS_EOF: fprintf (stderr, "EOF in dbus-launch reading address from bus daemon\n"); exit (1); break; case READ_STATUS_ERROR: fprintf (stderr, "Error in dbus-launch reading address from bus daemon: %s\n", strerror (errno)); exit (1); break; } close (bus_address_to_launcher_pipe[READ_END]); verbose ("Reading PID from babysitter\n"); switch (read_pid (bus_pid_to_launcher_pipe[READ_END], &bus_pid)) { case READ_STATUS_OK: break; case READ_STATUS_EOF: fprintf (stderr, "EOF in dbus-launch reading address from bus daemon\n"); exit (1); break; case READ_STATUS_ERROR: fprintf (stderr, "Error in dbus-launch reading address from bus daemon: %s\n", strerror (errno)); exit (1); break; } close (bus_pid_to_launcher_pipe[READ_END]); if (runprog) { char *envvar; char **args; envvar = malloc (strlen ("DBUS_SESSION_BUS_ADDRESS=") + strlen (bus_address) + 1); args = malloc (sizeof (char *) * ((argc-remaining_args)+2)); if (envvar == NULL || args == NULL) goto oom; args[0] = xstrdup (runprog); if (!args[0]) goto oom; for (i = 1; i <= (argc-remaining_args); i++) { size_t len = strlen (argv[remaining_args+i-1])+1; args[i] = malloc (len); if (!args[i]) goto oom; strncpy (args[i], argv[remaining_args+i-1], len); } args[i] = NULL; strcpy (envvar, "DBUS_SESSION_BUS_ADDRESS="); strcat (envvar, bus_address); putenv (envvar); execvp (runprog, args); fprintf (stderr, "Couldn't exec %s: %s\n", runprog, strerror (errno)); exit (1); } else { if (c_shell_syntax) printf ("setenv DBUS_SESSION_BUS_ADDRESS '%s'\n", bus_address); else { printf ("DBUS_SESSION_BUS_ADDRESS='%s'\n", bus_address); if (bourne_shell_syntax) printf ("export DBUS_SESSION_BUS_ADDRESS\n"); } if (c_shell_syntax) printf ("set DBUS_SESSION_BUS_PID=%ld\n", (long) bus_pid); else printf ("DBUS_SESSION_BUS_PID=%ld\n", (long) bus_pid); } verbose ("dbus-launch exiting\n"); fflush (stdout); fflush (stderr); close (1); close (2); exit (0); } return 0; oom: fprintf (stderr, "Out of memory!"); exit (1); }
/** * Daemonise the process and start a daemon * * @param arguments `NULL`-terminated list of command line arguments, * the verb first, then the name of the daemon, followed * by optional additional script-dependent arguments * @return The function call not return, it will * however exit the image with a return * as an unlikely fallback */ int start_daemon(char** arguments) { #define return exit #define t(cond) if (cond) goto fail char* daemon_name = arguments[1]; char buf[3 * sizeof(pid_t) + 2]; int i, r, fd = -1, saved_errno; sigset_t set; char* pid_pathname = NULL; size_t n; pid_t pid, child; /* Get pathname of PID file. */ pid_pathname = malloc((strlen(RUNDIR "/.pid") + strlen(daemon_name) + 1) * sizeof(char)); t (pid_pathname == NULL); sprintf(pid_pathname, RUNDIR "/%s.pid", daemon_name); /* Close all file descriptors but stdin, stdout and stderr. */ close_nonstd_fds(); /* Reset all signals to SIG_DFL. */ for (i = 1; i < _NSIG; i++) signal(i, SIG_DFL); /* Reset signal mask. */ sigfillset(&set); sigprocmask(SIG_UNBLOCK, &set, NULL); /* Mark daemon with its name. */ t (setenv(ENV_DAEMON_NAME_TAG, daemon_name, 1) < 0); /* Set to child subreaper and set SIGCHLD listening. */ t (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0); t (signal(SIGCHLD, noop_sig_handler) == SIG_ERR); /* Fork */ t ((pid = fork(), pid == -1)); if (pid) goto wait_for_completion; /* Create session leader. */ setsid(); /* Reset some thinks. */ prctl(PR_SET_CHILD_SUBREAPER, 0); /* Fork again, and exit first child synchronously. */ if (pid = fork(), pid > 0) { pause(); exit(1); /* Failure, if the grandchild dies first */ } t (signal(SIGCHLD, noop_sig_handler) == SIG_ERR); t (prctl(PR_SET_PDEATHSIG, SIGCHLD) < 0); t (kill(getppid(), SIGCHLD) < 0); pause(); /* Reset some thinks. */ signal(SIGCHLD, SIG_DFL); /* Replace stdin and stdout, but not stderr, with /dev/null. */ close(STDIN_FILENO); close(STDOUT_FILENO); fd = open(DEV_NULL, O_RDWR); if ((fd >= 0) && (fd != STDIN_FILENO)) { dup2(fd, STDIN_FILENO); close(fd); } dup2(STDIN_FILENO, STDOUT_FILENO); fd = -1; /* Set umask to zero. */ umask(0); /* Write PID file. */ fd = open(pid_pathname, O_WRONLY | O_CREAT | O_TRUNC, 644); t (fd < 0); sprintf(buf, "%ji\n", (intmax_t)getpid()); n = strlen(buf) * sizeof(char); if (write(fd, buf, n) < (ssize_t)n) { saved_errno = errno, unlink(pid_pathname), errno = saved_errno; goto fail; } close(fd), fd = -1; free(pid_pathname), pid_pathname = NULL; /* `cd` into root. */ if (*SYSCONFDIR == '/') chdir("/"); /* Execute into daemon. */ arguments[1] = arguments[0]; arguments[0] = daemon_name; execvp(SYSCONFDIR "/" PKGNAME ".d/daemon-base", arguments); fail: perror(*argv); if (fd >= 0) close(fd); free(pid_pathname); return (1); wait_for_completion: pause(), pause(); /* Wait for child and grandchild. */ /* Exit like the grandchild. */ child = read_pid(pid_pathname); pid = waitpid(child, &r, WNOHANG); if (pid == -1) goto fail; r = pid ? WIFEXITED(r) ? WEXITSTATUS(r) : WTERMSIG(r) : 0; free(pid_pathname); return (r); #undef t #undef return }
int main(int argc, char *argv[]) { // Handle signals signal(SIGINT,shut_down); signal(SIGHUP,shut_down); signal(SIGTERM,shut_down); signal(SIGQUIT,shut_down); // HCI device number, MAC struct int device = 0; bdaddr_t bdaddr; bacpy(&bdaddr, BDADDR_ANY); // Time to scan. Scan time is roughly 1.28 seconds * scan_window // Originally this was always 8, now we adjust based on device: #ifdef OPENWRT int scan_window = 8; #elif PWNPLUG int scan_window = 5; #else int scan_window = 3; #endif // Maximum number of devices per scan int max_results = 255; int num_results; // Device cache and index int cache_index = 0; // HCI cache setting int flags = IREQ_CACHE_FLUSH; // Strings to hold MAC and name char addr[19] = {0}; char addr_buff[19] = {0}; // String for time char cur_time[20]; // Process ID read from PID file int ext_pid; // Pointers to filenames char *infofilename = LIVE_INF; // Change default filename based on date char OUT_FILE[1000] = OUT_PATH; strncat(OUT_FILE, file_timestamp(),sizeof(OUT_FILE)-strlen(OUT_FILE)-1); char *outfilename = OUT_FILE; // Mode to open output file in char *filemode = "a+"; // Output buffer char outbuffer[500]; // Buffer for data from the second loop char exitbuffer[500]; // Misc Variables int i, ri, opt; // Record numbner of BlueZ errors int error_count = 0; // Current epoch time long long int epoch; // Kernel version info struct utsname sysinfo; uname(&sysinfo); while ((opt=getopt_long(argc,argv,"+o:i:r:a:w:vxctghldbfenksmq", main_options, NULL)) != EOF) { switch (opt) { case 'i': if (!strncasecmp(optarg, "hci", 3)) hci_devba(atoi(optarg + 3), &bdaddr); else str2ba(optarg, &bdaddr); break; case 'o': outfilename = strdup(optarg); break; case 'r': config.retry_count = atoi(optarg); break; case 'a': config.amnesia = atoi(optarg); break; case 'w': config.scan_window = round((atoi(optarg) / 1.28)); break; case 'c': config.showclass = 1; break; case 'e': config.encode = 1; break; case 'f': config.friendlyclass = 1; break; case 'v': config.verbose = 1; break; case 'g': config.status = 1; break; case 't': config.showtime = 1; break; case 's': config.syslogonly = 1; break; case 'x': config.obfuscate = 1; break; case 'q': config.quiet = 1; break; case 'l': if(!LIVEMODE) { printf("Live mode has been disabled in this build. See documentation.\n"); exit(0); } else config.bluelive = 1; break; case 'b': config.bluepropro = 1; break; case 'd': config.daemon = 1; break; case 'n': config.getname = 1; break; case 'm': if(!OUILOOKUP) { printf("Manufacturer lookups have been disabled in this build. See documentation.\n"); exit(0); } else config.getmanufacturer = 1; break; case 'h': help(); exit(0); case 'k': // Read PID from file into variable ext_pid = read_pid(); if (ext_pid != 0) { printf("Killing Bluelog process with PID %i...",ext_pid); if(kill(ext_pid,15) != 0) { printf("ERROR!\n"); printf("Unable to kill Bluelog process. Check permissions.\n"); exit(1); } else printf("OK.\n"); // Delete PID file unlink(PID_FILE); } else printf("No running Bluelog process found.\n"); exit(0); default: printf("Unknown option. Use -h for help, or see README.\n"); exit(1); } } // See if there is already a process running if (read_pid() != 0) { printf("Another instance of Bluelog is already running!\n"); printf("Use the -k option to kill a running Bluelog process.\n"); exit(1); } // Load config from file if no options given on command line if(cfg_exists() && argc == 1) { if (cfg_read() != 0) { printf("Error opening config file!\n"); exit(1); } // Put interface into BT struct hci_devba(config.hci_device, &bdaddr); } // Perform sanity checks on varibles cfg_check(); // Setup libmackerel mac_init(); // Boilerplate if (!config.quiet) { printf("%s (v%s%s) by MS3FGX\n", APPNAME, VERSION, VER_MOD); #if defined OPENWRT || PWNPLUG printf("----"); #endif printf("---------------------------\n"); } // Show notification we loaded config from file if(cfg_exists() && argc == 1 && !config.quiet) printf("Config loaded from: %s\n", CFG_FILE); // Init Hardware ba2str(&bdaddr, config.addr); if (!strcmp(config.addr, "00:00:00:00:00:00")) { if (!config.quiet) printf("Autodetecting device..."); device = hci_get_route(NULL); // Put autodetected device MAC into addr hci_devba(device, &bdaddr); ba2str(&bdaddr, config.addr); } else { if (!config.quiet) printf("Initializing device..."); device = hci_devid(config.addr); } // Open device and catch errors config.bt_socket = hci_open_dev(device); if (device < 0 || config.bt_socket < 0) { // Failed to open device, that can't be good printf("\n"); printf("Error initializing Bluetooth device!\n"); exit(1); } // If we get here the device should be online. if (!config.quiet) printf("OK\n"); // Status message for BPP if (!config.quiet) if (config.bluepropro) printf("Output formatted for BlueProPro.\n" "More Info: www.hackfromacave.com\n"); // Open socket if (config.udponly) open_udp_socket(); // Open output file, unless in networking mode if (!config.syslogonly && !config.udponly) { if (config.bluelive) { // Change location of output file outfilename = LIVE_OUT; filemode = "w"; if (!config.quiet) printf("Starting Bluelog Live...\n"); } if (!config.quiet) printf("Opening output file: %s...", outfilename); if ((outfile = fopen(outfilename, filemode)) == NULL) { printf("\n"); printf("Error opening output file!\n"); exit(1); } if (!config.quiet) printf("OK\n"); } else if (!config.quiet) printf("Network mode enabled, not creating log file.\n"); // Open status file if (config.bluelive) { if (!config.quiet) printf("Opening info file: %s...", infofilename); if ((infofile = fopen(infofilename,"w")) == NULL) { printf("\n"); printf("Error opening info file!\n"); exit(1); } if (!config.quiet) printf("OK\n"); } // Write PID file if (!config.daemon) write_pid(getpid()); // Get and print time to console and file strcpy(cur_time, get_localtime()); if (!config.daemon) printf("Scan started at [%s] on %s\n", cur_time, config.addr); if (config.showtime && (outfile != NULL)) { fprintf(outfile,"[%s] Scan started on %s\n", cur_time, config.addr); // Make sure this gets written out fflush(outfile); } // Write info file for Bluelog Live if (config.bluelive) { fprintf(infofile,"<div class=\"sideitem\">%s Version: %s%s</div>\n", APPNAME, VERSION, VER_MOD); fprintf(infofile,"<div class=\"sideitem\">Device: %s</div>\n", config.addr); fprintf(infofile,"<div class=\"sideitem\">Started: %s</div>\n", cur_time); // Think we are done with you now fclose(infofile); } // Log success to this point syslog(LOG_INFO,"Init OK!"); // Daemon switch if (config.daemon) daemonize(); else if (!config.quiet) #if defined PWNPAD printf("Close this window to end scan.\n"); #else printf("Hit Ctrl+C to end scan.\n"); #endif // Init result struct results = (inquiry_info*)malloc(max_results * sizeof(inquiry_info)); // Start scan, be careful with this infinite loop... for(;;) { // Flush results buffer memset(results, '\0', max_results * sizeof(inquiry_info)); // Scan and return number of results num_results = hci_inquiry(device, scan_window, max_results, NULL, &results, flags); // A negative number here means an error during scan if(num_results < 0) { // Increment error count error_count++; // Ignore occasional errors on Pwn Plug and OpenWRT #if !defined PWNPLUG || OPENWRT // All other platforms, print error and bail out syslog(LOG_ERR,"Received error from BlueZ!"); printf("Scan failed!\n"); // Check for kernel 3.0.x if (!strncmp("3.0.",sysinfo.release,4)) { printf("\n"); printf("-----------------------------------------------------\n"); printf("Device scanning failed, and you are running a 3.0.x\n"); printf("Linux kernel. This failure is probably due to the\n"); printf("following kernel bug:\n"); printf("\n"); printf("http://marc.info/?l=linux-kernel&m=131629118406044\n"); printf("\n"); printf("You will need to upgrade your kernel to at least the\n"); printf("the 3.1 series to continue.\n"); printf("-----------------------------------------------------\n"); } shut_down(1); #else // Exit on back to back errors if (error_count > 5) { printf("Scan failed!\n"); syslog(LOG_ERR,"BlueZ not responding, unrecoverable!"); shut_down(1); } // Otherwise, throttle back a bit, might help sleep(1); #endif } else { // Clear error counter error_count = 0; } // Check if we need to reset device cache if ((cache_index + num_results) >= MAX_DEV) { syslog(LOG_INFO,"Resetting device cache..."); memset(dev_cache, 0, sizeof(dev_cache)); cache_index = 0; } // Loop through results for (i = 0; i < num_results; i++) { // Return current MAC from struct ba2str(&(results+i)->bdaddr, addr); // Compare to device cache for (ri = 0; ri <= cache_index; ri++) { // Determine if device is already logged if (strcmp (addr, dev_cache[ri].priv_addr) == 0) { // This device has been seen before // Increment seen count, update printed time dev_cache[ri].seen++; strcpy(dev_cache[ri].time, get_localtime()); dev_cache[ri].missing_count = 0; // If we don't have a name, query again if ((dev_cache[ri].print == 3) && (dev_cache[ri].seen > config.retry_count)) { syslog(LOG_INFO,"Unable to find name for %s!", addr); dev_cache[ri].print = 1; } else if ((dev_cache[ri].print == 3) && (dev_cache[ri].seen < config.retry_count)) { // Query name strcpy(dev_cache[ri].name, namequery(&(results+i)->bdaddr)); // Did we get one? if (strcmp (dev_cache[ri].name, "VOID") != 0) { syslog(LOG_INFO,"Name retry for %s successful!", addr); // Force print dev_cache[ri].print = 1; } else syslog(LOG_INFO,"Name retry %i for %s failed!",dev_cache[ri].seen, addr); } // Amnesia mode if (config.amnesia >= 0) { // Find current epoch time epoch = time(NULL); if ((epoch - dev_cache[ri].epoch) >= (config.amnesia * 60)) { // Update epoch time dev_cache[ri].epoch = epoch; // Set device to print dev_cache[ri].print = 1; } } // This device is seen before, but has been away if (strcmp (dev_cache[ri].status, "gone") == 0) { dev_cache[ri].print = 1; strcpy(dev_cache[ri].status, "returned"); } // Unless we need to get printed, move to next result if (dev_cache[ri].print != 1) break; } else if (strcmp (dev_cache[ri].addr, "") == 0) { // Write new device MAC (visible and internal use) strcpy(dev_cache[ri].addr, addr); strcpy(dev_cache[ri].priv_addr, addr); // Query for name if (config.getname) strcpy(dev_cache[ri].name, namequery(&(results+i)->bdaddr)); else strcpy(dev_cache[ri].name, "IGNORED"); // Get time found strcpy(dev_cache[ri].time, get_localtime()); dev_cache[ri].epoch = time(NULL); // Class info dev_cache[ri].flags = (results+i)->dev_class[2]; dev_cache[ri].major_class = (results+i)->dev_class[1]; dev_cache[ri].minor_class = (results+i)->dev_class[0]; // Init misc variables dev_cache[ri].seen = 1; dev_cache[ri].missing_count = 0; strcpy(dev_cache[ri].status, "new"); // Increment index cache_index++; // If we have a device name, get printed if (strcmp (dev_cache[ri].name, "VOID") != 0) dev_cache[ri].print = 1; else { // Found with no name. // Print message to syslog, prevent printing, and move on syslog(LOG_INFO,"Device %s discovered with no name, will retry", dev_cache[ri].addr); dev_cache[ri].print = 3; break; } } // Ready to print? if (dev_cache[ri].print == 1) { // Encode MAC if (config.encode || config.obfuscate) { // Clear buffer memset(addr_buff, '\0', sizeof(addr_buff)); if (config.obfuscate) strcpy(addr_buff, mac_obfuscate(dev_cache[ri].priv_addr)); if (config.encode) strcpy(addr_buff, mac_encode(dev_cache[ri].priv_addr)); // Copy to cache strcpy(dev_cache[ri].addr, addr_buff); } // Print everything to console if verbose is on, optionally friendly class info if (config.verbose) { if (config.friendlyclass) { printf("[%s] %s,%s,%s,(%s) - %s\n",\ dev_cache[ri].time, dev_cache[ri].addr,\ dev_cache[ri].name, device_class(dev_cache[ri].major_class,\ dev_cache[ri].minor_class), device_capability(dev_cache[ri].flags), dev_cache[ri].status); } else { printf("[%s] %s,%s,0x%02x%02x%02x - %s\n",\ dev_cache[ri].time, dev_cache[ri].addr,\ dev_cache[ri].name, dev_cache[ri].flags,\ dev_cache[ri].major_class, dev_cache[ri].minor_class, dev_cache[ri].status); } } if (config.bluelive) { // Write result with live function live_entry(ri); } else if (config.bluepropro) { // Set output format for BlueProPro fprintf(outfile,"%s", dev_cache[ri].addr); fprintf(outfile,",0x%02x%02x%02x", dev_cache[ri].flags,\ dev_cache[ri].major_class, dev_cache[ri].minor_class); fprintf(outfile,",%s\n", dev_cache[ri].name); } else { // Flush buffer memset(outbuffer, 0, sizeof(outbuffer)); // Print time first if enabled if (config.showtime) sprintf(outbuffer,"[%s],", dev_cache[ri].time); // Always output MAC sprintf(outbuffer+strlen(outbuffer),"%s", dev_cache[ri].addr); // Optionally output class if (config.showclass) sprintf(outbuffer+strlen(outbuffer),",0x%02x%02x%02x", dev_cache[ri].flags,\ dev_cache[ri].major_class, dev_cache[ri].minor_class); // "Friendly" version of class info if (config.friendlyclass) sprintf(outbuffer+strlen(outbuffer),",%s,(%s)",\ device_class(dev_cache[ri].major_class, dev_cache[ri].minor_class),\ device_capability(dev_cache[ri].flags)); // Get manufacturer if (config.getmanufacturer) sprintf(outbuffer+strlen(outbuffer),",%s", mac_get_vendor(dev_cache[ri].priv_addr)); // Append the name if (config.getname) sprintf(outbuffer+strlen(outbuffer),",%s", dev_cache[ri].name); // Append the status if (config.status) sprintf(outbuffer+strlen(outbuffer)," - %s", dev_cache[ri].status); // Send buffer, else file. File needs newline if (config.syslogonly) syslog(LOG_INFO,"%s", outbuffer); else if (config.udponly) { // Append newline to socket, kind of hacky sprintf(outbuffer+strlen(outbuffer),"\n"); send_udp_msg(outbuffer); } else fprintf(outfile,"%s\n",outbuffer); } dev_cache[ri].print = 0; break; } // If we make it this far, it means we will check next stored device } // If there's a file open, write changes if (outfile != NULL) fflush(outfile); } // Now check if any devices are missing // Loop through the cache for (ri = 0; ri < cache_index; ri++) { for (i = 0; i <= num_results; i++) { // Return current MAC from struct ba2str(&(results+i)->bdaddr, addr); // Determine if device still present if (strcmp (addr, dev_cache[ri].priv_addr) == 0) { break; } // Device not found. if (i == num_results) { // The device is missing but not marked as gone -> it has just disappeared if (strcmp(dev_cache[ri].status, "gone") != 0) { // Devices aren't present every time. Wait a while before marking it gone if (dev_cache[ri].missing_count < 10) { dev_cache[ri].missing_count++; } else // It's really gone :( { strcpy(dev_cache[ri].status,"gone"); // Print to console if (config.verbose) { printf("[%s] %s,%s - %s\n",\ dev_cache[ri].time, dev_cache[ri].addr,\ dev_cache[ri].name, dev_cache[ri].status); } // Flush buffer memset(exitbuffer, 0, sizeof(exitbuffer)); // Print time first if enabled if (config.showtime) sprintf(exitbuffer,"[%s],", dev_cache[ri].time); // Always output MAC sprintf(exitbuffer+strlen(exitbuffer),"%s", dev_cache[ri].addr); // Append the name if (config.getname) sprintf(exitbuffer+strlen(exitbuffer),",%s", dev_cache[ri].name); // Append the status if (config.status) sprintf(exitbuffer+strlen(exitbuffer)," - %s", dev_cache[ri].status); // Send buffer, else file. File needs newline if (config.syslogonly) syslog(LOG_INFO,"%s", exitbuffer); else if (config.udponly) { // Append newline to socket, kind of hacky sprintf(exitbuffer+strlen(exitbuffer),"\n"); send_udp_msg(exitbuffer); } else fprintf(outfile,"%s\n",exitbuffer); // If there's a file open, write changes if (outfile != NULL) fflush(outfile); } } } } } } // If we get here, shut down shut_down(0); // STFU return (1); }
static void babysit (int exit_with_session, pid_t child_pid, int read_bus_pid_fd) /* read pid from here */ { int ret; int dev_null_fd; const char *s; verbose ("babysitting, exit_with_session = %d, child_pid = %ld, read_bus_pid_fd = %d\n", exit_with_session, (long) child_pid, read_bus_pid_fd); /* We chdir ("/") since we are persistent and daemon-like, and fork * again so dbus-launch can reap the parent. However, we don't * setsid() or close fd 0 because the idea is to remain attached * to the tty and the X server in order to kill the message bus * when the session ends. */ if (chdir ("/") < 0) { fprintf (stderr, "Could not change to root directory: %s\n", strerror (errno)); exit (1); } /* Close stdout/stderr so we don't block an "eval" or otherwise * lock up. stdout is still chaining through to dbus-launch * and in turn to the parent shell. */ dev_null_fd = open ("/dev/null", O_RDWR); if (dev_null_fd >= 0) { if (!exit_with_session) dup2 (dev_null_fd, 0); dup2 (dev_null_fd, 1); s = getenv ("DBUS_DEBUG_OUTPUT"); if (s == NULL || *s == '\0') dup2 (dev_null_fd, 2); } else { fprintf (stderr, "Failed to open /dev/null: %s\n", strerror (errno)); /* continue, why not */ } ret = fork (); if (ret < 0) { fprintf (stderr, "fork() failed in babysitter: %s\n", strerror (errno)); exit (1); } if (ret > 0) { /* Parent reaps pre-fork part of bus daemon, then exits and is * reaped so the babysitter isn't a zombie */ verbose ("=== Babysitter's intermediate parent continues again\n"); if (do_waitpid (child_pid) < 0) { /* shouldn't happen */ fprintf (stderr, "Failed waitpid() waiting for bus daemon's parent\n"); exit (1); } verbose ("Babysitter's intermediate parent exiting\n"); exit (0); } /* Child continues */ verbose ("=== Babysitter process created\n"); verbose ("Reading PID from bus\n"); switch (read_pid (read_bus_pid_fd, &bus_pid_to_kill)) { case READ_STATUS_OK: break; case READ_STATUS_EOF: fprintf (stderr, "EOF in dbus-launch reading PID from bus daemon\n"); exit (1); break; case READ_STATUS_ERROR: fprintf (stderr, "Error in dbus-launch reading PID from bus daemon: %s\n", strerror (errno)); exit (1); break; } verbose ("Got PID %ld from daemon\n", (long) bus_pid_to_kill); if (exit_with_session) { /* Bus is now started and launcher has needed info; * we connect to X display and tty and wait to * kill bus if requested. */ kill_bus_when_session_ends (); } verbose ("Babysitter exiting\n"); exit (0); }
static ReadStatus read_data (DBusBabysitter *sitter, int fd) { int what; int got; DBusError error = DBUS_ERROR_INIT; ReadStatus r; r = read_ints (fd, &what, 1, &got, &error); switch (r) { case READ_STATUS_ERROR: _dbus_warn ("Failed to read data from fd %d: %s\n", fd, error.message); dbus_error_free (&error); return r; case READ_STATUS_EOF: return r; case READ_STATUS_OK: break; } if (got == 1) { switch (what) { case CHILD_EXITED: case CHILD_FORK_FAILED: case CHILD_EXEC_FAILED: { int arg; r = read_ints (fd, &arg, 1, &got, &error); switch (r) { case READ_STATUS_ERROR: _dbus_warn ("Failed to read arg from fd %d: %s\n", fd, error.message); dbus_error_free (&error); return r; case READ_STATUS_EOF: return r; case READ_STATUS_OK: break; } if (got == 1) { if (what == CHILD_EXITED) { /* Do not reset sitter->errnum to 0 here. We get here if * the babysitter reports that the grandchild process has * exited, and there are two ways that can happen: * * 1. grandchild successfully exec()s the desired process, * but then the desired process exits or is terminated * by a signal. The babysitter observes this and reports * CHILD_EXITED. * * 2. grandchild fails to exec() the desired process, * attempts to report the exec() failure (which * we will receive as CHILD_EXEC_FAILED), and then * exits itself (which will prompt the babysitter to * send CHILD_EXITED). We want the CHILD_EXEC_FAILED * to take precedence (and have its errno logged), * which _dbus_babysitter_set_child_exit_error() does. */ sitter->have_child_status = TRUE; sitter->status = arg; _dbus_verbose ("recorded child status exited = %d signaled = %d exitstatus = %d termsig = %d\n", WIFEXITED (sitter->status), WIFSIGNALED (sitter->status), WEXITSTATUS (sitter->status), WTERMSIG (sitter->status)); } else if (what == CHILD_FORK_FAILED) { sitter->have_fork_errnum = TRUE; sitter->errnum = arg; _dbus_verbose ("recorded fork errnum %d\n", sitter->errnum); } else if (what == CHILD_EXEC_FAILED) { sitter->have_exec_errnum = TRUE; sitter->errnum = arg; _dbus_verbose ("recorded exec errnum %d\n", sitter->errnum); } } } break; case CHILD_PID: { pid_t pid = -1; r = read_pid (fd, &pid, &error); switch (r) { case READ_STATUS_ERROR: _dbus_warn ("Failed to read PID from fd %d: %s\n", fd, error.message); dbus_error_free (&error); return r; case READ_STATUS_EOF: return r; case READ_STATUS_OK: break; } sitter->grandchild_pid = pid; _dbus_verbose ("recorded grandchild pid %d\n", sitter->grandchild_pid); } break; default: _dbus_warn ("Unknown message received from babysitter process\n"); break; } } return r; }
int ifplugd_main(int argc UNUSED_PARAM, char **argv) { int iface_status; int delay_time; const char *iface_status_str; struct pollfd netlink_pollfd[1]; unsigned opts; #if ENABLE_FEATURE_PIDFILE char *pidfile_name; pid_t pid_from_pidfile; #endif INIT_G(); opt_complementary = "t+:u+:d+"; opts = getopt32(argv, OPTION_STR, &G.iface, &G.script_name, &G.poll_time, &G.delay_up, &G.delay_down, &G.api_mode, &G.extra_arg); G.poll_time *= 1000; applet_name = xasprintf("ifplugd(%s)", G.iface); #if ENABLE_FEATURE_PIDFILE pidfile_name = xasprintf(_PATH_VARRUN"ifplugd.%s.pid", G.iface); pid_from_pidfile = read_pid(pidfile_name); if (opts & FLAG_KILL) { if (pid_from_pidfile > 0) kill(pid_from_pidfile, SIGQUIT); return EXIT_SUCCESS; } if (pid_from_pidfile > 0 && kill(pid_from_pidfile, 0) == 0) bb_error_msg_and_die("daemon already running"); #endif switch (G.api_mode[0]) { case API_AUTO: G.detect_link_func = detect_link_auto; break; case API_ETHTOOL: G.detect_link_func = detect_link_ethtool; break; case API_MII: G.detect_link_func = detect_link_mii; break; case API_PRIVATE: G.detect_link_func = detect_link_priv; break; case API_WLAN: G.detect_link_func = detect_link_wlan; break; case API_IFF: G.detect_link_func = detect_link_iff; break; default: bb_error_msg_and_die("unknown API mode '%s'", G.api_mode); } if (!(opts & FLAG_NO_DAEMON)) bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), ioctl_fd); if (opts & FLAG_MONITOR) { xmove_fd(netlink_open(), netlink_fd); } write_pidfile(pidfile_name); /* this can't be moved before socket creation */ if (!(opts & FLAG_NO_SYSLOG)) { openlog(applet_name, 0, LOG_DAEMON); logmode |= LOGMODE_SYSLOG; } bb_signals(0 | (1 << SIGINT ) | (1 << SIGTERM) | (1 << SIGQUIT) | (1 << SIGHUP ) /* why we ignore it? */ /* | (1 << SIGCHLD) - run_script does not use it anymore */ , record_signo); bb_error_msg("started: %s", bb_banner); if (opts & FLAG_MONITOR) { struct ifreq ifrequest; set_ifreq_to_ifname(&ifrequest); G.iface_exists = (network_ioctl(SIOCGIFINDEX, &ifrequest, NULL) == 0); } if (G.iface_exists) maybe_up_new_iface(); iface_status = detect_link(); if (iface_status == IFSTATUS_ERR) goto exiting; iface_status_str = strstatus(iface_status); if (opts & FLAG_MONITOR) { bb_error_msg("interface %s", G.iface_exists ? "exists" : "doesn't exist, waiting"); } /* else we assume it always exists, but don't mislead user * by potentially lying that it really exists */ if (G.iface_exists) { bb_error_msg("link is %s", iface_status_str); } if ((!(opts & FLAG_NO_STARTUP) && iface_status == IFSTATUS_UP ) || (opts & FLAG_INITIAL_DOWN) ) { if (run_script(iface_status_str) != 0) goto exiting; } /* Main loop */ netlink_pollfd[0].fd = netlink_fd; netlink_pollfd[0].events = POLLIN; delay_time = 0; while (1) { int iface_status_old; int iface_exists_old; switch (bb_got_signal) { case SIGINT: case SIGTERM: bb_got_signal = 0; goto cleanup; case SIGQUIT: bb_got_signal = 0; goto exiting; default: bb_got_signal = 0; break; } if (poll(netlink_pollfd, (opts & FLAG_MONITOR) ? 1 : 0, G.poll_time ) < 0 ) { if (errno == EINTR) continue; bb_perror_msg("poll"); goto exiting; } iface_status_old = iface_status; iface_exists_old = G.iface_exists; if ((opts & FLAG_MONITOR) && (netlink_pollfd[0].revents & POLLIN) ) { G.iface_exists = check_existence_through_netlink(); if (G.iface_exists < 0) /* error */ goto exiting; if (iface_exists_old != G.iface_exists) { bb_error_msg("interface %sappeared", G.iface_exists ? "" : "dis"); if (G.iface_exists) maybe_up_new_iface(); } } /* note: if !G.iface_exists, returns DOWN */ iface_status = detect_link(); if (iface_status == IFSTATUS_ERR) { if (!(opts & FLAG_MONITOR)) goto exiting; iface_status = IFSTATUS_DOWN; } iface_status_str = strstatus(iface_status); if (iface_status_old != iface_status) { bb_error_msg("link is %s", iface_status_str); if (delay_time) { /* link restored its old status before * we run script. don't run the script: */ delay_time = 0; } else { delay_time = monotonic_sec(); if (iface_status == IFSTATUS_UP) delay_time += G.delay_up; if (iface_status == IFSTATUS_DOWN) delay_time += G.delay_down; if (delay_time == 0) delay_time++; } } if (delay_time && (int)(monotonic_sec() - delay_time) >= 0) { delay_time = 0; if (run_script(iface_status_str) != 0) goto exiting; } } /* while (1) */ cleanup: if (!(opts & FLAG_NO_SHUTDOWN) && (iface_status == IFSTATUS_UP || (iface_status == IFSTATUS_DOWN && delay_time) ) ) { setenv(IFPLUGD_ENV_PREVIOUS, strstatus(iface_status), 1); setenv(IFPLUGD_ENV_CURRENT, strstatus(-1), 1); run_script("down\0up"); /* reusing string */ } exiting: remove_pidfile(pidfile_name); bb_error_msg_and_die("exiting"); }
/* * 1) When we enter the daylight saving time, add one hour. * 2) When we leave the daylight saving time, subtract one hour. * return the flag that if we have added one hour or not. */ int adjust_daylight(int done,time_t start_time,time_t end_time,int time_zone) { time_t cur_time; int i=0,check_flag=0; struct timeval tv; struct timezone tz; gettimeofday(&tv,&tz); cur_time = tv.tv_sec; /* * Since start_time and end_time are based on time which is not adjusted, * we need to recover cur_time to be an unadjusted one. */ if(done) cur_time -= ONE_HOUR; /* Check if it is in daylight saving time now */ if (((start_time <= end_time) && ((cur_time >= start_time) && (cur_time < end_time))) || ((start_time > end_time) && ((cur_time >= start_time) || (cur_time < end_time)))) { /* Check if we have not add one hour*/ if(!done) { /* Check the timezone */ for(i=0; i < EXCEPTION_ARRAY_SIZE;i++) { if(time_zone == timezone_daylight_savings_exception[i]) { check_flag = 1; break; } } if(check_flag == 0) { /* Add one hour */ DEBUG_MSG("Add one hour\n"); tv.tv_sec += ONE_HOUR; settimeofday(&tv, &tz); /* Tell web server to get the adjusted time */ kill(read_pid(HTTPD_PID), SIGUSR2); /* Record we have added one hour */ done=1; } } } /* It's not in daylight saving time now */ else { /* We have added one hour*/ if(done) { /* Check the timezone */ for(i=0; i < EXCEPTION_ARRAY_SIZE;i++) { if(time_zone == timezone_daylight_savings_exception[i]) { check_flag = 1; break; } } if(check_flag == 0) { /* Subtract one hour */ DEBUG_MSG("Subtract one hour\n"); tv.tv_sec -= ONE_HOUR; settimeofday(&tv, &tz); /* Tell web server to get the adjusted time */ kill(read_pid(HTTPD_PID), SIGUSR2); /* Record we have not add one hour */ done=0; } } } return done; }
int main(int argc, char *argv[]) { int count = argc; const char *file; file = _PATH_UTMP; list = (char**)malloc(SIZE*sizeof(char*)); for(i = 0;i<SIZE;i++) { list[i] = (char*)malloc(SIZE*sizeof(char)); } pid_list = (char**)malloc(SIZE*sizeof(char*)); for(i = 0;i<SIZE;i++) { pid_list[i] = (char*)malloc(SIZE*sizeof(char)); } buff = (char*)malloc(SIZE*sizeof(char)); name = (char*)malloc(SIZE*sizeof(char)); temp = (char*)malloc(SIZE*sizeof(char)); ptrmsg_copy = (char*)malloc(SIZE*sizeof(char)); sender_pid = (char*)malloc(SIZE*sizeof(char)); bzero(sender_pid,SIZE); // now set up the ipc for communication if ((msgid = msgget(msgkey, msgflg )) < 0) { perror("msgget"); exit(EXIT_FAILURE); } if ((sem1 = semget(sem1key,1, msgflg )) < 0) { perror("semget"); exit(EXIT_FAILURE); } if ((semctl(sem1, 0, SETVAL, 1)) < 0) { perror("semctl"); exit(EXIT_FAILURE); } if ((sem2 = semget(sem2key,1, msgflg )) < 0) { perror("semget"); exit(EXIT_FAILURE); } if ((semctl(sem2, 0, SETVAL, 0)) < 0) { perror("semctl"); exit(EXIT_FAILURE); } if ((shm1 = shmget(shm1key,500, msgflg )) < 0) { perror("shmget"); exit(EXIT_FAILURE); } if ((shm2 = shmget(shm2key,5000, msgflg )) < 0) { perror("shmget"); exit(EXIT_FAILURE); } ptrpid=shmat(shm1,NULL,0); ptrmsg=shmat(shm2,NULL,0); bzero(ptrpid,500); bzero(ptrmsg,5000); printf("--- Initialization complete\n"); // done // then read all names j = 0; while(argc>1) { strcpy(list[j],argv[--argc]); j++; } listsize = j; // open a file in excl to ensure that only one server is running fp = fopen("ser.txt","wx"); if(fp == NULL) { perror("server already running"); exit(EXIT_FAILURE); } bzero(buff,SIZE); sprintf(buff,"%d",getpid()); fwrite(buff,SIZE,1,fp); // here comes the UTMP part // we need to open the file in the linux for the various terminals opened if ((fputmp = fopen(file, "r")) == NULL) { err(1, "%s", file); } while (fread(&u, sizeof(u), 1, fputmp) == 1) { if (u.ut_name != NULL) { if(getpwnam(u.ut_name) != NULL) // means the file is not arbit { // printf("%s\n",u.ut_line ); for(i = 0;i<listsize;i++) { if(((strcmp(u.ut_name,list[i])) == 0) && (count > 1) && ((strcmp(u.ut_line,":0")) != 0)) // means it points to real user who should be in conference { // so we need to send the commencement notification to the corresponding user printf("--Sending commence notification to %s\n",u.ut_line ); sprintf(name, "./commence > /dev/%s", u.ut_line); system(name); count--; break; } } } } } // from here the infinite loop begins to broadcast the message to all // it waits until the value of the sem2 = 2 which indicates client has written the message while(1) { wait_for(sem2,2); // now read message strcpy(ptrmsg_copy,ptrmsg); printf("%s\n",ptrmsg_copy ); setvalue(sem2,0); // case 1 if the message is '.' then we need to simply ignore it if((strcmp(ptrmsg_copy,".")) == 0) { } // case 2 if the message is '*' then we need to terminate server as there is no client else if((strcmp(ptrmsg_copy,"*")) == 0) { terminate(); } // case 3 now we need to broadcast the message to all the clients available except // the one who send the message else { down(sem1); read_pid(); up(sem1); strcpy(msg_send.mtext,ptrmsg_copy); int l = strlen(ptrmsg_copy)+1; k = 0,j = 0; while(ptrmsg_copy[j] != '/') { j++; } j++; while(ptrmsg_copy[j] != ':') { sender_pid[k] = ptrmsg_copy[j]; j++; k++; } sender_pid[k] = '\0'; for(i = 0;i<pid_list_size;i++) { if((strcmp(pid_list[i],sender_pid)) != 0) { // then send message as it is different user sscanf(pid_list[i],"%d",&send_pid); printf("%d %d %d\n%s\n", msgid,l,send_pid,msg_send.mtext); msg_send.mtype = (long)send_pid; if(msgsnd(msgid,&msg_send,l,0)==-1) //User to Kernel memory space { printf("error in msg_send\n"); exit(1); } else { printf("sending message to %d\n",send_pid ); } } } } } // deleting all the ipc return 0; }