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