#include <pwd.h>
#include <fcntl.h>
#include <string.h>
+#include <sys/wait.h>
#include "../../include/job.h"
#include "../../include/macros.h"
-#include "../../include/scm_interface.h"
+/* #include "../../include/scm_interface.h" */
#define MANIFEST_LOC "/.config/tomd/init/manifest.scm"
#define MAX_JOBS 10
-static struct job jobs[MAX_JOBS];
-
-static struct job load_job(SCM job_list, int index)
-{
- struct job ret = { NULL };
- SCM scm_cur_job = SCM_ARR(job_list, index);
-
- if(scm_is_false(job_predicate(scm_cur_job))){
- tomd_p("job %d wasn't a real job type.", index);
- return ret;
- }
-
- SCM scm_name = get_name(scm_cur_job);
- SCM scm_cmd = get_cmd(scm_cur_job);
- SCM scm_args = get_args(scm_cur_job);
-
- /* TODO > Handle these. */
- /* planned is to be able to run at different points, and at */
- /* the request of a user. for testing we do things all at */
- /* boot up. */
- SCM scm_start_trigger = get_start_trigger(scm_cur_job);
- SCM scm_end_trigger = get_end_trigger(scm_cur_job);
-
- char *job_name = scm_to_locale_string(scm_name);
- char *job_cmd = scm_to_locale_string(scm_cmd);
- char *real_args[10];
- int jlen = scm_to_int(scm_length(scm_args));
- for(int j = 0;
- j < jlen;
- j++){
- real_args[j] =
- scm_to_locale_string(SCM_ARR(scm_args, j));
- }
-
- ret.name = job_name;
- ret.cmd = job_cmd;
-
- for(int j = 1;
- j <= jlen;
- j++){
- ret.args[j] = real_args[j - 1];
- }
- ret.args[jlen + 1] = NULL;
- ret.args[0] = ret.cmd;
-
- return ret;
-}
-
-static void *load_manifest(void *args)
-{
- char *manifest_loc;
- if(!args){
- tomd_p("arg to load_manifest is NULL");
- exit(EXIT_FAILURE);
- }
- manifest_loc = (char *)args;
-
- scm_c_primitive_load(args);
-
- SCM scm_job_list =
- scm_c_public_ref("tomd manifest", "job-list");
-
- if(scm_is_false(scm_job_list)){
- tomd_p("no job-list found in manifest.scm");
- return NULL;
- }
-
- if(scm_is_false(scm_list_p(scm_job_list))){
- tomd_p("job-list found, but isn't a list.");
- return NULL;
- }
-
- int i;
- int len = SCM_LIST_LEN(scm_job_list);
- tomd_p("len=%d, max=%d", len, MAX_JOBS);
- for(i = 0;
- i < len && i < MAX_JOBS;
- i++){
- jobs[i] = load_job(scm_job_list, i);
- }
- tomd_p("looked at %d jobs.", i);
- jobs[i].cmd = NULL;
-}
+static int root_job = -1;
+
+static struct job jobs[MAX_JOBS]=
+ {
+ {
+ "bash", /* name */
+ "/bin/bash", /* cmd */
+ {}, /* args */
+ 0, /* pid */
+ 0, /* last_status */
+ 0, /* redirect */
+ 1, /* root */
+ },
+ /* rest null */
+ {}
+ };
+
+/* static struct job load_job(SCM job_list, int index) */
+/* { */
+/* struct job ret = { NULL }; */
+/* SCM scm_cur_job = SCM_ARR(job_list, index); */
+
+/* if(scm_is_false(job_predicate(scm_cur_job))){ */
+/* tomd_p("job %d wasn't a real job type.", index); */
+/* return ret; */
+/* } */
+
+/* SCM scm_name = get_name(scm_cur_job); */
+/* SCM scm_cmd = get_cmd(scm_cur_job); */
+/* SCM scm_args = get_args(scm_cur_job); */
+
+/* /\* TODO > Handle these. *\/ */
+/* /\* planned is to be able to run at different points, and at *\/ */
+/* /\* the request of a user. for testing we do things all at *\/ */
+/* /\* boot up. *\/ */
+/* SCM scm_start_trigger = get_start_trigger(scm_cur_job); */
+/* SCM scm_end_trigger = get_end_trigger(scm_cur_job); */
+
+/* char *job_name = scm_to_locale_string(scm_name); */
+/* char *job_cmd = scm_to_locale_string(scm_cmd); */
+/* char *real_args[10]; */
+/* int jlen = scm_to_int(scm_length(scm_args)); */
+/* for(int j = 0; */
+/* j < jlen; */
+/* j++){ */
+/* real_args[j] = */
+/* scm_to_locale_string(SCM_ARR(scm_args, j)); */
+/* } */
+
+/* ret.name = job_name; */
+/* ret.cmd = job_cmd; */
+
+/* for(int j = 1; */
+/* j <= jlen; */
+/* j++){ */
+/* ret.args[j] = real_args[j - 1]; */
+/* } */
+/* ret.args[jlen + 1] = NULL; */
+/* ret.args[0] = ret.cmd; */
+
+/* return ret; */
+/* } */
+
+/* static void *load_manifest(void *args) */
+/* { */
+/* char *manifest_loc; */
+/* if(!args){ */
+/* tomd_p("arg to load_manifest is NULL"); */
+/* exit(EXIT_FAILURE); */
+/* } */
+/* manifest_loc = (char *)args; */
+
+/* scm_c_primitive_load(args); */
+
+/* SCM scm_job_list = */
+/* scm_c_public_ref("tomd manifest", "job-list"); */
+
+/* if(scm_is_false(scm_job_list)){ */
+/* tomd_p("no job-list found in manifest.scm"); */
+/* return NULL; */
+/* } */
+
+/* if(scm_is_false(scm_list_p(scm_job_list))){ */
+/* tomd_p("job-list found, but isn't a list."); */
+/* return NULL; */
+/* } */
+
+/* int i; */
+/* int len = SCM_LIST_LEN(scm_job_list); */
+/* tomd_p("len=%d, max=%d", len, MAX_JOBS); */
+/* for(i = 0; */
+/* i < len && i < MAX_JOBS; */
+/* i++){ */
+/* jobs[i] = load_job(scm_job_list, i); */
+/* } */
+/* tomd_p("looked at %d jobs.", i); */
+/* jobs[i].cmd = NULL; */
+/* } */
static char *lookup_user_folder(void)
{
- uid_t user = getuid();
- struct passwd *userpasswd =
- getpwuid(user);
-
- /* take the manifest location and sub ~ for pw_dir */
- char *buffer = (char *)malloc(sizeof(char) * 300);
- strcpy(buffer, userpasswd->pw_dir);
- int len = strlen(userpasswd->pw_dir);
- strcpy(buffer + len, MANIFEST_LOC);
- return buffer;
+ return NULL;
+ /* uid_t user = getuid(); */
+ /* struct passwd *userpasswd = */
+ /* getpwuid(user); */
+
+ /* /\* take the manifest location and sub ~ for pw_dir *\/ */
+ /* char *buffer = (char *)malloc(sizeof(char) * 300); */
+ /* strcpy(buffer, userpasswd->pw_dir); */
+ /* int len = strlen(userpasswd->pw_dir); */
+ /* strcpy(buffer + len, MANIFEST_LOC); */
+ /* return buffer; */
}
void load_jobs(void)
{
char *manifest = lookup_user_folder();
- tomd_p("Loading jobs from '%s'", manifest);
-
- void *res =
- scm_with_guile(load_manifest,
- (void *) manifest);
+ /* tomd_p("Loading jobs from '%s'", manifest); */
+
+ /* void *res = */
+ /* scm_with_guile(load_manifest, */
+ /* (void *) manifest); */
+ tomd_p("Stubbed job loading.");
tomd_p("Finished loading.");
}
}
+
+static int stdincache;
+static int stdoutcache;
+static int stderrcache;
+
+void silent(void)
+{
+ /* cache all filedes */
+ stdincache = dup(STDIN_FILENO);
+ stdoutcache = dup(STDOUT_FILENO);
+ stderrcache = dup(STDERR_FILENO);
+
+ tomd_p("going silent.");
+
+ /* close default filedes */
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+
+ tomd_p("now silent.");
+}
+
#define LOG_DIR "/var/log/tomd/"
void run_job(int index)
pid_t pid = fork();
if(pid == 0){ /* child */
- /* redirect to a file */
- char buf[100];
- strcpy(buf, LOG_DIR);
- strcpy(buf + strlen(LOG_DIR), job->name);
- tomd_p("redirecting stdout to %s.", buf);
- if(unlink(buf) != 0){
- perror("file couldn't be removed.");
- }
+ if(job->redirect){
+ /* redirect to a file */
+ char buf[100];
+ strcpy(buf, LOG_DIR);
+ strcpy(buf + strlen(LOG_DIR), job->name);
+ tomd_p("redirecting stdout to %s.", buf);
+ if(unlink(buf) != 0){
+ tomd_p("file couldn't be removed.");
+ }
- int fd = open(buf, O_WRONLY | O_CREAT, 0644);
- if(fd < 0){
- perror("[tomd] couldn't open file.");
- return;
- }
+ int fd = open(buf, O_WRONLY | O_CREAT, 0644);
+ if(fd < 0){
+ tomd_p("couldn't open file.");
+ return;
+ }
- dup2(fd, STDOUT_FILENO);
- dup2(fd, STDERR_FILENO);
- close(fd);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ close(fd);
+ }
execvp(job->cmd, job->args);
- tomd_p("execvp for '%s' failed", job->cmd);
- perror("");
- exit(EXIT_FAILURE);
+ tomd_panic("execvp for '%s' failed", job->cmd);
}else{ /* parent */
tomd_p("forked [%d] to run '%s'", pid, job->cmd);
job->pid = pid;
+ waitpid(job->pid, &job->last_status, WNOHANG);
}
}
}else{
tomd_p("running job [%d] '%s'", i, jobs[i].cmd);
run_job(i);
+ if(jobs[i].root){
+ if(root_job != i && root_job != -1){
+ tomd_p("error! only one job can be root.");
+ }else{
+ root_job = i;
+ }
+ }
}
- }
+ }
+}
+
+static int delay = 0;
+
+void check_root_job(void)
+{
+ delay++;
+ if(delay % 100 != 0){
+ return;
+ }else{
+ delay = 0;
+ }
+ if(root_job != -1){
+ /* tomd_p("checking root job pid %d", jobs[root_job].pid); */
+ int n_pid = waitpid(jobs[root_job].pid, &jobs[root_job].last_status, WNOHANG);
+ if(n_pid != jobs[root_job].pid){
+ /* tomd_p("status of root not available."); */
+ return;
+ }
+
+ if(WIFEXITED(jobs[root_job].last_status)){
+ /* we died, restart it */
+ tomd_p("restarting root job. (last pid = %d, last status = %d)",
+ jobs[root_job].pid, jobs[root_job].last_status);
+ run_job(root_job);
+ }
+ /* else { */
+ /* tomd_p("checking root job pid %d", jobs[root_job].pid); */
+ /* int n_pid = waitpid(jobs[root_job].pid, &jobs[root_job].last_status, WNOHANG); */
+ /* } */
+ }
}
/* You should have received a copy of the GNU General Public License */
/* along with tomd. If not, see <http://www.gnu.org/licenses/>. */
+#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#include <errno.h>
tomd_p("making dir '%s'", socket_dirname);
/* lazy way */
- char buf[100];
- sprintf(buf, "mkdir -p %s", socket_dirname);
- system(buf);
- /* if(mkdir(socket_dirname, S_IRWXU) != 0){ */
- /* perror("socket mkdir"); */
- /* exit(EXIT_FAILURE); */
- /* } */
+ /* char buf[100]; */
+ /* sprintf(buf, "mkdir -p %s", socket_dirname); */
+ /* system(buf); */
+
+ if(mkdir(socket_dirname, S_IRWXU) != 0){
+ if(errno != EEXIST){
+ tomd_panic("socket mkdir");
+ }else{
+ tomd_p("socket dir exists.");
+ }
+ }
tomd_p("removing file '%s'", socket_filename);
if(unlink(socket_filename) != 0){
if(errno == ENOENT){
tomd_p("socket file doesn't exist");
}else{
- perror("[tomd] socket unlink");
- exit(EXIT_FAILURE);
+ tomd_panic("socket unlink");
}
}
}
0); /* protocol */
if(sfd < 0){
- perror("[tomd] socket");
- exit(EXIT_FAILURE);
+ tomd_panic("socket");
+ }
+
+ if(fcntl(sfd, F_SETFL, O_NONBLOCK) == -1){
+ tomd_panic("fnctl");
}
struct sockaddr_un name;
if(bind(sfd,
(struct sockaddr *) &name,
size) < 0){
- perror("[tomd] bind");
- exit(EXIT_FAILURE);
+ tomd_panic("bind");
}
tomd_p("initialized tomd socket connections");
load_jobs();
}
-#define SEND_ACK { \
- int size; \
- char ACK[4];\
- ACK[0] = 'A';\
- ACK[1] = 'C';\
- ACK[2] = 'K';\
- ACK[3] = '\0';\
-if(size = write(asfd, ACK, sizeof(ACK)) != sizeof(ACK)) { \
- tomd_p("didn't send as much as we though (%d != %d)",\
- size, sizeof(ACK)); \
- } \
+#define SEND_ACK { \
+ int size; \
+ char ACK[4]; \
+ ACK[0] = 'A'; \
+ ACK[1] = 'C'; \
+ ACK[2] = 'K'; \
+ ACK[3] = '\0'; \
+ if(size = write(asfd, ACK, sizeof(ACK)) != sizeof(ACK)) { \
+ tomd_p("didn't send as much as we though (%d != %d)", \
+ size, sizeof(ACK)); \
+ } \
}
#define CHDIR 0
/* arg2 - 0 closes all pipes (/dev/null) */
/* WARNING > THIS BEHAVIOR IS SILENT AND EASY TO MISPLACE THE
PROCESS */
+ /* daemon will exit the original process. */
daemon(DONT_CHDIR, DONT_CLOSE_PIPES);
}
-#define READ_SOCKET {\
+#define READ_SOCKET { \
memset(buf, 0, sizeof(buf)); \
int size = read(asfd, buf, 100); \
buf[size] = '\0'; \
tomd_p("looking up '%s'", buf);
SEND_ACK;
struct job *jp = lookup_job(buf);
- #define DOUBLE_DUTY(...) { \
- char tmp[100]; \
- tomd_p(__VA_ARGS__); \
- sprintf(tmp, __VA_ARGS__); \
- int tmplen = strlen(tmp); \
- tomd_p("__debug__:'%s'", tmp);\
- write(asfd, tmp, tmplen); \
- }
+#define DOUBLE_DUTY(...) { \
+ char tmp[100]; \
+ tomd_p(__VA_ARGS__); \
+ sprintf(tmp, __VA_ARGS__); \
+ int tmplen = strlen(tmp); \
+ tomd_p("__debug__:'%s'", tmp); \
+ write(asfd, tmp, tmplen); \
+ }
if(jp == NULL){
DOUBLE_DUTY("lookup of '%s' failed.\n", buf);
} else {
-
tomd_p("-----");
DOUBLE_DUTY("found job record for '%s'\n", jp->name);
listen(sfd,
10); /* max connection limit is 10 for arbitrary reasons */
if(listen_bool == -1){
- perror("[tomd] listen");
- exit(EXIT_FAILURE);
+ tomd_panic("listen");
}
- int i = 0;
for(;;){
struct sockaddr addr;
/* sometimes gives EINVAL if not initialized. */
socklen_t size = sizeof(addr);
- tomd_p("accept loop [%d]", i++);
errno = 0;
int accept_sfd =
accept(sfd,
if(accept_sfd < 0){
if(errno == EINVAL){
tomd_p("EINVAL");
+ }else if(errno == EWOULDBLOCK || errno == EAGAIN){
+ /* no worries */
+ }else {
+ tomd_panic("accept socket");
}
- perror("[tomd] accept socket");
- exit(EXIT_FAILURE);
+ } else {
+ handle_connection(accept_sfd);
}
- handle_connection(accept_sfd);
+ check_root_job();
+ usleep(10);
}
}
{
header();
init();
- run_jobs();
/* daemonize(); */
+ run_jobs();
+ /* silent(); */
run();
cleanup();