Added #:redirect option to manifest.scm
[tlb/tomd.git] / src / guile_helpers.c
CommitLineData
4f839c09
TB
1/* Copyright (C) 2018 Thomas Balzer */
2
3/* This file is part of tomd. */
4
5/* tomd is free software: you can redistribute it and/or modify */
6/* it under the terms of the GNU General Public License as published by */
7/* the Free Software Foundation, either version 3 of the License, or */
8/* (at your option) any later version. */
9
10/* tomd is distributed in the hope that it will be useful, */
11/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
12/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
13/* GNU General Public License for more details. */
14
15/* You should have received a copy of the GNU General Public License */
16/* along with tomd. If not, see <http://www.gnu.org/licenses/>. */
17
82ff7d81 18#include <pwd.h>
06570394
TB
19#include <fcntl.h>
20#include <string.h>
b6ca5637 21#include <stdio.h>
11e636da 22#include <stdbool.h>
229b92de 23#include <sys/wait.h>
82ff7d81 24
b6ca5637
TB
25#include "../include/job.h"
26#include "../include/macros.h"
1cf0620c
TB
27
28#ifdef GUILE_CAPABLE
b6ca5637
TB
29#include <libguile.h>
30#include "../include/scm_interface.h"
1cf0620c 31#endif
81643445 32
82ff7d81
TB
33#define MANIFEST_LOC "/.config/tomd/init/manifest.scm"
34
2599cbf7
TB
35#define MAX_JOBS 10
36
229b92de
TB
37static int root_job = -1;
38
1cf0620c
TB
39#ifdef GUILE_CAPABLE
40static struct job jobs[MAX_JOBS] =
229b92de
TB
41 {
42 {
43 "bash", /* name */
44 "/bin/bash", /* cmd */
45 {}, /* args */
46 0, /* pid */
47 0, /* last_status */
48 0, /* redirect */
49 1, /* root */
50 },
51 /* rest null */
52 {}
53 };
1cf0620c
TB
54#else
55static struct job jobs[MAX_JOBS] = {};
56#endif
229b92de 57
0a325e56
TB
58#ifdef GUILE_CAPABLE
59static struct job load_job(SCM job_list, int index)
60{
61 struct job ret = { NULL };
62 SCM scm_cur_job = SCM_ARR(job_list, index);
63
64 if(scm_is_false(job_predicate(scm_cur_job))){
65 tomd_p("job %d wasn't a real job type.", index);
66 return ret;
67 }
68
69 SCM scm_name = get_name(scm_cur_job);
70 SCM scm_cmd = get_cmd(scm_cur_job);
71 SCM scm_args = get_args(scm_cur_job);
11e636da 72 SCM scm_redirect = get_redirect(scm_cur_job);
0a325e56
TB
73
74 /* TODO > Handle these. */
75 /* planned is to be able to run at different points, and at */
76 /* the request of a user. for testing we do things all at */
77 /* boot up. */
78 SCM scm_start_trigger = get_start_trigger(scm_cur_job);
79 SCM scm_end_trigger = get_end_trigger(scm_cur_job);
80
11e636da 81 bool redirect = scm_to_bool(scm_redirect);
0a325e56
TB
82 char *job_name = scm_to_locale_string(scm_name);
83 char *job_cmd = scm_to_locale_string(scm_cmd);
84 char *real_args[10];
85 int jlen = scm_to_int(scm_length(scm_args));
86 for(int j = 0;
87 j < jlen;
88 j++){
89 real_args[j] =
90 scm_to_locale_string(SCM_ARR(scm_args, j));
91 }
92
93 ret.name = job_name;
94 ret.cmd = job_cmd;
11e636da 95 ret.redirect = redirect;
0a325e56
TB
96
97 for(int j = 1;
98 j <= jlen;
99 j++){
100 ret.args[j] = real_args[j - 1];
101 }
102 ret.args[jlen + 1] = NULL;
103 ret.args[0] = ret.cmd;
104
105 return ret;
106}
107
108static void *load_manifest(void *args)
109{
110 char *manifest_loc;
111 if(!args){
112 tomd_p("arg to load_manifest is NULL");
113 exit(EXIT_FAILURE);
114 }
115 manifest_loc = (char *)args;
116
117 scm_c_primitive_load(args);
118
119 SCM scm_job_list =
120 scm_c_public_ref("tomd manifest", "job-list");
121
122 if(scm_is_false(scm_job_list)){
123 tomd_p("no job-list found in manifest.scm");
124 return NULL;
125 }
126
127 if(scm_is_false(scm_list_p(scm_job_list))){
128 tomd_p("job-list found, but isn't a list.");
129 return NULL;
130 }
131
132 int i;
133 int len = SCM_LIST_LEN(scm_job_list);
134 tomd_p("len=%d, max=%d", len, MAX_JOBS);
135 for(i = 0;
136 i < len && i < MAX_JOBS;
137 i++){
138 jobs[i] = load_job(scm_job_list, i);
139 }
140 tomd_p("looked at %d jobs.", i);
141 jobs[i].cmd = NULL;
142}
143#endif
82ff7d81
TB
144
145static char *lookup_user_folder(void)
146{
0a325e56
TB
147#ifdef GUILE_CAPABLE
148 uid_t user = getuid();
149 struct passwd *userpasswd =
150 getpwuid(user);
151
152 /* take the manifest location and sub ~ for pw_dir */
153 char *buffer = (char *)malloc(sizeof(char) * 300);
154 strcpy(buffer, userpasswd->pw_dir);
155 int len = strlen(userpasswd->pw_dir);
156 strcpy(buffer + len, MANIFEST_LOC);
157 return buffer;
158#else
229b92de 159 return NULL;
0a325e56 160#endif
81643445
TB
161}
162
163void load_jobs(void)
164{
82ff7d81 165 char *manifest = lookup_user_folder();
0a325e56
TB
166#ifdef GUILE_CAPABLE
167 tomd_p("Loading jobs from '%s'", manifest);
229b92de 168
0a325e56
TB
169 void *res =
170 scm_with_guile(load_manifest,
171 (void *) manifest);
172#endif
229b92de 173 tomd_p("Stubbed job loading.");
82ff7d81
TB
174
175 tomd_p("Finished loading.");
2599cbf7
TB
176
177 int i = 0;
178 while(1){
179 if(i >= MAX_JOBS ||
180 jobs[i].cmd == NULL) {
181 break;
182 }
183 tomd_p("JOB <%d>:", i);
11e636da 184 tomd_p(" cmd:'%s'", jobs[i].cmd);
7813ae49 185 int j = 1;
2599cbf7
TB
186 while(1){
187 if(i >= 10 ||
188 jobs[i].args[j] == NULL){
189 break;
190 }
11e636da 191 tomd_p("arg [%d]:'%s'", j, jobs[i].args[j]);
2599cbf7
TB
192 j++;
193 }
194 i++;
195 }
81643445 196}
7813ae49 197
229b92de
TB
198static int stdincache;
199static int stdoutcache;
200static int stderrcache;
201
202void silent(void)
203{
204 /* cache all filedes */
205 stdincache = dup(STDIN_FILENO);
206 stdoutcache = dup(STDOUT_FILENO);
207 stderrcache = dup(STDERR_FILENO);
208
209 tomd_p("going silent.");
210
211 /* close default filedes */
212 close(STDIN_FILENO);
213 close(STDOUT_FILENO);
214 close(STDERR_FILENO);
215
216 tomd_p("now silent.");
217}
218
06570394
TB
219#define LOG_DIR "/var/log/tomd/"
220
7813ae49
TB
221void run_job(int index)
222{
223 struct job *job = &jobs[index];
224
225 pid_t pid = fork();
226 if(pid == 0){ /* child */
229b92de
TB
227 if(job->redirect){
228 /* redirect to a file */
229 char buf[100];
230 strcpy(buf, LOG_DIR);
231 strcpy(buf + strlen(LOG_DIR), job->name);
232 tomd_p("redirecting stdout to %s.", buf);
233 if(unlink(buf) != 0){
234 tomd_p("file couldn't be removed.");
235 }
06570394 236
229b92de
TB
237 int fd = open(buf, O_WRONLY | O_CREAT, 0644);
238 if(fd < 0){
239 tomd_p("couldn't open file.");
240 return;
241 }
06570394 242
229b92de
TB
243 dup2(fd, STDOUT_FILENO);
244 dup2(fd, STDERR_FILENO);
245 close(fd);
246 }
7813ae49 247 execvp(job->cmd, job->args);
229b92de 248 tomd_panic("execvp for '%s' failed", job->cmd);
7813ae49
TB
249 }else{ /* parent */
250 tomd_p("forked [%d] to run '%s'", pid, job->cmd);
81215080 251 job->pid = pid;
229b92de 252 waitpid(job->pid, &job->last_status, WNOHANG);
7813ae49
TB
253 }
254}
255
7bd7fa83 256struct job *lookup_job(char *my_job_name)
81215080 257{
7bd7fa83
TB
258 for(int i = 0;
259 i < MAX_JOBS;
260 i++){
261 if(jobs[i].name == NULL){
262 continue;
263 }
264 if(strcmp(jobs[i].name, my_job_name) == 0){
265 return &jobs[i];
266 }
267 }
268 return NULL;
81215080
TB
269}
270
7813ae49
TB
271void run_jobs(void)
272{
273 int i;
274 for(i = 0;
275 i < MAX_JOBS;
276 i++){
277 if(jobs[i].cmd == NULL){
278 tomd_p("out of jobs");
279 return;
280 }else{
281 tomd_p("running job [%d] '%s'", i, jobs[i].cmd);
282 run_job(i);
229b92de
TB
283 if(jobs[i].root){
284 if(root_job != i && root_job != -1){
285 tomd_p("error! only one job can be root.");
286 }else{
287 root_job = i;
288 }
289 }
7813ae49 290 }
229b92de
TB
291 }
292}
293
294static int delay = 0;
295
296void check_root_job(void)
297{
298 delay++;
299 if(delay % 100 != 0){
300 return;
301 }else{
302 delay = 0;
303 }
304 if(root_job != -1){
229b92de
TB
305 int n_pid = waitpid(jobs[root_job].pid, &jobs[root_job].last_status, WNOHANG);
306 if(n_pid != jobs[root_job].pid){
229b92de
TB
307 return;
308 }
309
310 if(WIFEXITED(jobs[root_job].last_status)){
311 /* we died, restart it */
312 tomd_p("restarting root job. (last pid = %d, last status = %d)",
313 jobs[root_job].pid, jobs[root_job].last_status);
314 run_job(root_job);
315 }
229b92de 316 }
7813ae49 317}