int handle_start_proc(struct request * r) { fprintf(stderr, "starting proc\n"); struct child_process * c = make_child_proc((struct svc_packet *)r->data); if (0 == c) { fprintf(stderr, "failed to created child process structure\n"); return -1; } else { if (c->start_calendar_interval) { struct timeval now; gettimeofday(&now, 0); c->last_restart = *(next_start(&now, c->start_calendar_interval)); queue_proc(c); } else { fprintf(stderr, "starting proc %s\n", c->label); gettimeofday(&c->last_restart, 0); spawn_proc(c); } return 0; } }
int main() { struct cron_spec test_spec; memset(&test_spec, 0, sizeof(test_spec)); test_spec.sec[10] = 1; test_spec.sec_flag = 1; test_spec.min[3] = 1; test_spec.min[45] = 1; test_spec.min_flag = 1; test_spec.hour[11] = 1; test_spec.hour_flag = 1; test_spec.mday[15] = 1; test_spec.mday_flag = 1; test_spec.mon[6] = 1; test_spec.mon[9] = 1; test_spec.mon[2] = 1; test_spec.mon_flag = 1; test_spec.wday[4] = 1; test_spec.wday_flag = 1; struct timeval now; gettimeofday(&now, 0); struct timeval * timeout; timeout = next_start(&now, &test_spec); for(int i = 0; i < 1000; i++) { struct timeval t; if (timeout) { t = *timeout; free(timeout); } timeout = next_start(&t, &test_spec); } return 0; }
/* * See if we can expand region rgn by nextra bytes by using up * free space after or before the region. */ static int ft_shuffle(struct ft_cxt *cxt, char **pp, enum ft_rgn_id rgn, int nextra) { char *p = *pp; char *rgn_start, *rgn_end; rgn_start = cxt->rgn[rgn].start; rgn_end = rgn_start + cxt->rgn[rgn].size; if (nextra <= 0 || rgn_end + nextra <= next_start(cxt, rgn)) { /* move following stuff */ if (p < rgn_end) { if (nextra < 0) memmove(p, p - nextra, rgn_end - p + nextra); else memmove(p + nextra, p, rgn_end - p); if (rgn == FT_STRUCT) ft_node_update_after(cxt, p, nextra); } cxt->rgn[rgn].size += nextra; if (rgn == FT_STRINGS) /* assumes strings only added at beginning */ cxt->str_anchor += nextra; return 1; } if (prev_end(cxt, rgn) <= rgn_start - nextra) { /* move preceding stuff */ if (p > rgn_start) { memmove(rgn_start - nextra, rgn_start, p - rgn_start); if (rgn == FT_STRUCT) ft_node_update_before(cxt, p, -nextra); } *pp -= nextra; cxt->rgn[rgn].start -= nextra; cxt->rgn[rgn].size += nextra; return 1; } return 0; }
static int ft_make_space(struct ft_cxt *cxt, char **pp, enum ft_rgn_id rgn, int nextra) { unsigned long size, ssize, tot; char *str, *next; enum ft_rgn_id r; if (!cxt->isordered) { unsigned long rgn_off = *pp - cxt->rgn[rgn].start; if (!ft_reorder(cxt, nextra)) return 0; *pp = cxt->rgn[rgn].start + rgn_off; } if (ft_shuffle(cxt, pp, rgn, nextra)) return 1; /* See if there is space after the strings section */ ssize = cxt->rgn[FT_STRINGS].size; if (cxt->rgn[FT_STRINGS].start + ssize < (char *)cxt->bph + cxt->max_size) { /* move strings up as far as possible */ str = (char *)cxt->bph + cxt->max_size - ssize; cxt->str_anchor += str - cxt->rgn[FT_STRINGS].start; memmove(str, cxt->rgn[FT_STRINGS].start, ssize); cxt->rgn[FT_STRINGS].start = str; /* enough space now? */ if (rgn >= FT_STRUCT && ft_shuffle(cxt, pp, rgn, nextra)) return 1; } /* how much total free space is there following this region? */ tot = 0; for (r = rgn; r < FT_STRINGS; ++r) { char *r_end = cxt->rgn[r].start + cxt->rgn[r].size; tot += next_start(cxt, rgn) - r_end; } /* cast is to shut gcc up; we know nextra >= 0 */ if (tot < (unsigned int)nextra) { /* have to reallocate */ char *newp, *new_start; int shift; if (!cxt->realloc) return 0; size = _ALIGN(cxt->max_size + (nextra - tot) + EXPAND_INCR, 8); newp = cxt->realloc(cxt->bph, size); if (!newp) return 0; cxt->max_size = size; shift = newp - (char *)cxt->bph; if (shift) { /* realloc can return same addr */ cxt->bph = (struct boot_param_header *)newp; ft_node_update_after(cxt, cxt->rgn[FT_STRUCT].start, shift); for (r = FT_RSVMAP; r <= FT_STRINGS; ++r) { new_start = cxt->rgn[r].start + shift; cxt->rgn[r].start = new_start; } *pp += shift; cxt->str_anchor += shift; } /* move strings up to the end */ str = newp + size - ssize; cxt->str_anchor += str - cxt->rgn[FT_STRINGS].start; memmove(str, cxt->rgn[FT_STRINGS].start, ssize); cxt->rgn[FT_STRINGS].start = str; if (ft_shuffle(cxt, pp, rgn, nextra)) return 1; } /* must be FT_RSVMAP and we need to move FT_STRUCT up */ if (rgn == FT_RSVMAP) { next = cxt->rgn[FT_RSVMAP].start + cxt->rgn[FT_RSVMAP].size + nextra; ssize = cxt->rgn[FT_STRUCT].size; if (next + ssize >= cxt->rgn[FT_STRINGS].start) return 0; /* "can't happen" */ memmove(next, cxt->rgn[FT_STRUCT].start, ssize); ft_node_update_after(cxt, cxt->rgn[FT_STRUCT].start, nextra); cxt->rgn[FT_STRUCT].start = next; if (ft_shuffle(cxt, pp, rgn, nextra)) return 1; } return 0; /* "can't happen" */ }
int main(int argc, char * argv[]) { int fd; struct sigaction sig; struct passwd * pwd = 0; if (argc == 2) { if (argv[1]) { errno = 0; pwd = getpwnam(argv[1]); if (0 == pwd) { fprintf(stderr, "getpwnam failed: %s\n", strerror(errno)); while(1) { pause(); } } } } if (pwd) { sprintf(process_manager_run_dir, "/run/process-manager.%s", pwd->pw_name); sprintf(process_manager_socket_path, "/run/process-manager.%s/procman", pwd->pw_name); } else { sprintf(process_manager_run_dir, "/run/process-manager"); sprintf(process_manager_socket_path, "/run/process-manager/procman"); we_are_root = 1; } (void)fprintf(stderr, "process-manager: process-manager starting...\n"); memset(&sig, 0, sizeof(sig)); sigfillset(&sig.sa_mask); sig.sa_flags = SA_SIGINFO; sig.sa_sigaction = handle_sigterm; sigaction(SIGTERM, &sig, 0); memset(&sig, 0, sizeof(sig)); sigfillset(&sig.sa_mask); sig.sa_flags = SA_SIGINFO; sig.sa_sigaction = handle_sigchild; sigaction(SIGCHLD, &sig, 0); memset(&sig, 0, sizeof(sig)); sigfillset(&sig.sa_mask); sig.sa_flags = SA_SIGINFO; sig.sa_sigaction = handle_sigalarm; sigaction(SIGALRM, &sig, 0); fd = open("/dev/console", O_RDWR | O_NOCTTY); if (fd >= 0) { dup2(fd,0); dup2(fd,1); dup2(fd,2); if (fd > 2) close(fd); (void)fprintf(stderr, "process-manager: console reopened...\n"); } else { (void)fprintf(stderr, "failed to open console"); } if (we_are_root) { struct stat stat_buf; memset(&stat_buf, 0, sizeof(stat_buf)); if (-1 == stat("/run/process-manager", &stat_buf)) { fprintf(stderr, "expected stat error: %s\n", strerror(errno)); if (-1 == mount("none", "/run", "tmpfs", 0, 0)) { fprintf(stderr, "failed to mount tmpfs on /run: %s\n", strerror(errno)); while(1) pause(); } fprintf(stderr, "we are root\n"); if (-1 == mkdir("/run/process-manager", 0770)) { fprintf(stderr, "failed to make dir /run/process-manager: %s\n", strerror(errno)); while(1) pause(); } struct group * g = getgrnam("process-manager"); if (g) { if (-1 == chown("/run/process-manager", -1, g->gr_gid)) fprintf(stderr, "chown gid %d failed: %s\n", g->gr_gid, strerror(errno)); if (-1 == chmod("/run/process-manager", S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP |S_IXGRP)) fprintf(stderr, "chmod failed: %s\n", strerror(errno)); } else { fprintf(stderr, "getgrnam process-manager failed: %s\n", strerror(errno)); } } } else { mkdir(process_manager_run_dir, 0700); if (-1 == chown(process_manager_run_dir, pwd->pw_uid, pwd->pw_gid)) fprintf(stderr, "chown failed: %s\n", strerror(errno)); } running = malloc(sizeof(*running)); memset(running, 0, sizeof(*running)); running->next = running; waiting = malloc(sizeof(*waiting)); memset(waiting, 0, sizeof(*waiting)); waiting->next = waiting; waiting->pid = 0x7fffffff; waiting->last_restart.tv_sec = 0x7fffffffffffffff; inactive = malloc(sizeof(*inactive)); memset(inactive,0 ,sizeof(*inactive)); inactive->next = inactive; struct sockaddr_un ctl_un; pid_t ctl_pid; socklen_t ctl_len; int ctl_p_endp = launch_control_proc(pwd, process_manager_socket_path, &ctl_un, &ctl_len, &ctl_pid); if (ctl_p_endp < 0) //socket already exists and another instance is running { fprintf(stderr, "socket in use, ctl_p_endp: %d\n", ctl_p_endp); return 1; } if (we_are_root) spawn_proc(&arbitrator); while(0 == run_state) { int status; pid_t child_pid = -1; struct child_process * proc; unsigned char restart_proc = 0; if (waiting->next == waiting) { alarm(0); } else { struct timeval now; gettimeofday(&now, 0); alarm(waiting->next->last_restart.tv_sec - now.tv_sec); } timeout = 0; fprintf(stderr, "waiting for exiting childern...\n"); unsigned char data[1024]; unsigned int len = sizeof(data); if (-1 == recvfrom(ctl_p_endp, data, len, 0, &ctl_un, &ctl_len)) { if (errno == EINTR) { fprintf(stderr, "process-manager: signal received: %d, run_state == %d\n", signum, run_state); if (timeout) { timeout = 0; struct timeval now; gettimeofday(&now, 0); fprintf(stderr, "we got timeout. next timeout %ld, it is now %ld\n", waiting->next->last_restart.tv_sec, now.tv_sec); while(waiting->next->last_restart.tv_sec <= now.tv_sec) { struct child_process * c = dequeue_proc(); fprintf(stderr, "restarting queued proc %s\n", c->label); spawn_proc(c); } } if (got_sigchild) { got_sigchild = 0; while((child_pid = waitpid(-1, &status, WNOHANG))) { if (child_pid < 0) { fprintf(stderr, "failed to get child status: %s\n", strerror(errno)); if (EINTR != errno) break; } else { proc = get_process(child_pid); child_pid = -1; if (proc) { kill(-proc->pid, SIGTERM); restart_proc = 0; if (proc->start_calendar_interval) { struct timeval now; gettimeofday(&now, 0); proc->last_restart = *(next_start(&now, proc->start_calendar_interval)); queue_proc(proc); } else if (proc->keepalive_opts) { int i = 0; while(proc->keepalive_opts[i]) { fprintf(stderr, "keepalive opts %d:%d\n", proc->keepalive_opts[i], proc->keepalive_opts[i + 1]); if (SUCCESSFUL_EXIT == proc->keepalive_opts[i]) { if (0 < proc->keepalive_opts[i + 1]) { if (WIFEXITED(status)) { restart_proc |= 1; } } else { if (WIFSIGNALED(status)) { restart_proc |= 1; } } } i += 2; } } if (restart_proc) { fprintf(stderr, "restarting %s, exec file %s\n", proc->label, proc->exec_file_path); struct timeval now; gettimeofday(&now, 0); fprintf(stderr, "%s last restart %ld it is now %ld\n", proc->label, proc->last_restart.tv_sec, now.tv_sec); if ((proc->last_restart.tv_sec + 10) < now.tv_sec) { gettimeofday(&proc->last_restart, 0); spawn_proc(proc); fprintf(stderr, "spawn %s pid %d\n", proc->exec_file_path, proc->pid); } else { if (proc->throttle_count < 40) { fprintf(stderr, "throttling %s\n", proc->label); gettimeofday(&proc->last_restart, 0); proc->last_restart.tv_sec += 10; proc->throttle_count++; fprintf(stderr, "%s throttle_count %d restart at %ld\n", proc->label, proc->throttle_count, proc->last_restart.tv_sec); queue_proc(proc); } else { fprintf(stderr, "%s exceeded throttle limit\n", proc->label); destroy_proc_struct(proc); } } } else { if (WIFEXITED(status)) fprintf(stderr, "process %s:%d %s exited with %d\n", proc->label, proc->pid, proc->exec_file_path, WEXITSTATUS(status)); else if (WIFSIGNALED(status)) fprintf(stderr, "process %s:%d signaled with %d\n", proc->label, proc->pid, WTERMSIG(status)); destroy_proc_struct(proc); } } } } } } else { fprintf(stderr, "recvfrom failed: %s\n", strerror(errno)); sleep(3); } } else { handle_data(data, len); } } unsigned char any_child_exists = 1; int status = 0; fprintf(stderr, "sending SIGTERM to all children...\n"); struct child_process * v = running->next; while(running != v) { if (-1 == kill(-v->pid, SIGTERM)) { fprintf(stderr, "process-manager: kill process group %d failed: %s\n", -v->pid, strerror(errno)); if (-1 == kill(v->pid, SIGTERM)) { fprintf(stderr, "process-manager: kill %d failed: %s\n", v->pid, strerror(errno)); } } v = v->next; } kill(ctl_pid, SIGTERM); alarm(5); while (any_child_exists) { pid_t child = wait(&status); if (0 > child) { if (ECHILD == errno) { any_child_exists = 0; fprintf(stderr, "process-manager: no more children left...\n"); } else if (EINTR == errno) { if (timeout) { timeout = 0; any_child_exists = 0; } } } } alarm(0); sleep(1); close(ctl_p_endp); unlink(process_manager_socket_path); return 0; }