Broken comm stuff.
[tlb/tomd.git] / src / tomd / main.c
CommitLineData
72af8b59
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
18#include <stddef.h>
19#include <stdio.h>
20#include <errno.h>
21#include <stdlib.h>
22#include <unistd.h>
23#include <string.h>
24#include <sys/un.h>
25#include <sys/stat.h>
26#include <sys/socket.h>
7bd7fa83 27#include <sys/wait.h>
72af8b59 28
57c82614
TB
29#include "../../include/macros.h"
30#include "../../include/manifest.h"
7bd7fa83 31#include "../../include/job.h"
57c82614 32
72af8b59
TB
33static void header(void)
34{
57c82614
TB
35 tomd_p("Tom's Daemon, Copyright (C) 2018 Thomas Balzer");
36 tomd_p("GPL v3 or later license.");
72af8b59
TB
37}
38
39static int sfd;
40static char socket_dirname[100];
41static char socket_filename[100];
42
43static void gen_socket_filename(void)
44{
45 uid_t this_user_id =
46 getuid();
47 sprintf(socket_dirname,
48 "/run/user/%d/tomd",
49 this_user_id);
50 sprintf(socket_filename,
51 "/run/user/%d/tomd/socket",
52 this_user_id);
53
57c82614 54 tomd_p("making dir '%s'", socket_dirname);
72af8b59
TB
55 /* lazy way */
56 char buf[100];
57 sprintf(buf, "mkdir -p %s", socket_dirname);
58 system(buf);
59 /* if(mkdir(socket_dirname, S_IRWXU) != 0){ */
60 /* perror("socket mkdir"); */
61 /* exit(EXIT_FAILURE); */
62 /* } */
63
57c82614 64 tomd_p("removing file '%s'", socket_filename);
72af8b59
TB
65 if(unlink(socket_filename) != 0){
66 if(errno == ENOENT){
57c82614 67 tomd_p("socket file doesn't exist");
72af8b59 68 }else{
da4c0e62 69 perror("[tomd] socket unlink");
72af8b59
TB
70 exit(EXIT_FAILURE);
71 }
72 }
73}
74
57c82614 75static void socket_init(void)
72af8b59
TB
76{
77 gen_socket_filename();
78
79 /* listen on socket, respond to requests. */
80 /* perform all registered 'tick' operations */
81 sfd =
82 socket(PF_LOCAL, /* namespace - local unix socket */
83 SOCK_STREAM, /* style */
84 0); /* protocol */
85
86 if(sfd < 0){
da4c0e62 87 perror("[tomd] socket");
72af8b59
TB
88 exit(EXIT_FAILURE);
89 }
90
91 struct sockaddr_un name;
92 size_t size;
93
94 name.sun_family = AF_LOCAL;
95 strncpy(name.sun_path,
96 socket_filename,
97 sizeof(name.sun_path));
98
99 size = SUN_LEN(&name);
57c82614 100 tomd_p("attempting to bind to '%s'",
72af8b59
TB
101 socket_filename);
102 if(bind(sfd,
103 (struct sockaddr *) &name,
104 size) < 0){
da4c0e62 105 perror("[tomd] bind");
72af8b59
TB
106 exit(EXIT_FAILURE);
107 }
108
57c82614
TB
109 tomd_p("initialized tomd socket connections");
110}
111
112static void init(void)
113{
114 socket_init();
115 load_jobs();
72af8b59
TB
116}
117
81215080
TB
118#define SEND_ACK { \
119 int size; \
7bd7fa83
TB
120 if(size = write(asfd, "ACK\n", sizeof "ACK\n") != sizeof "ACK\n") { \
121 tomd_p("didn't send as much as we though (%d != %d)", size, sizeof "ACK\n"); \
81215080
TB
122 } \
123 }
124
72af8b59
TB
125#define CHDIR 0
126#define DONT_CHDIR 1
127#define CLOSE_PIPES 0
128#define DONT_CLOSE_PIPES 1
129
130static void daemonize(void)
131{
132 /* daemon is in unistd. */
133 /* arg1 - 0 changes dir to / */
134 /* arg2 - 0 closes all pipes (/dev/null) */
135 /* WARNING > THIS BEHAVIOR IS SILENT AND EASY TO MISPLACE THE
136 PROCESS */
137 daemon(DONT_CHDIR, DONT_CLOSE_PIPES);
138}
139
81215080
TB
140#define READ_SOCKET {\
141 int size = read(asfd, buf, 100); \
142 buf[size] = '\0'; \
143 }
144
145static int validate_sender(int asfd, char *buf)
146{
147 READ_SOCKET;
148 if(strcmp(buf, "client:tomc") == 0){
149 SEND_ACK;
150 return 0;
151 }
152 tomd_p("received '%s' instead of client:tomc", buf);
153 return -1;
154}
155
156enum requests { KILL, STATUS, STOP, START, UNKNOWN};
157#define X(a, b) { a, b }
158static struct {
159 char *str;
160 enum requests request;
161} request_types[] =
162 {
163 X("kill", KILL),
164 X("status", STATUS),
165 X("start", START),
166 X("stop", STOP),
167 X(NULL, -1)
168 };
169#undef X
170
171static void handle_request(int asfd, char *buf)
172{
173 READ_SOCKET;
174 enum requests request = UNKNOWN;
175 int i = 0;
176 while(1){
177 if(request_types[i].str == NULL){
178 break;
179 }
180
181 tomd_p("loop [%d]: comparing '%s' to '%s'",
182 i, buf, request_types[i].str);
183 if(strcmp(buf, request_types[i].str) == 0){
184 request = request_types[i].request;
185 break;
186 }
187
188 i++;
189 }
190
191 if(request == UNKNOWN){
192 tomd_p("unknown request type!");
193 return;
194 }
195
196 SEND_ACK;
197 READ_SOCKET;
198 // cross reference given name against known services
199 tomd_p("looking up '%s'", buf);
200 SEND_ACK;
7bd7fa83
TB
201 struct job *jp = lookup_job(buf);
202 #define DOUBLE_DUTY(...) { \
203 char tmp[100]; \
204 tomd_p(__VA_ARGS__); \
205 sprintf(tmp, __VA_ARGS__); \
206 int tmplen = strlen(tmp); \
207 tomd_p("__debug__:'%s'", tmp);\
208 write(asfd, tmp, tmplen); \
209 }
210 if(jp == NULL){
211 DOUBLE_DUTY("lookup of '%s' failed.\n", buf);
212 } else {
213
214 tomd_p("-----");
215 DOUBLE_DUTY("found job record for '%s'\n", jp->name);
216
217 if(request == STATUS){
218 if(jp->pid != -1){
219 int status = 0;
220 int n_pid = waitpid(jp->pid, &status, WNOHANG);
221 if(n_pid < 0){
222 perror("[tomd] waitpid");
223 }else if(n_pid == 0){
224 DOUBLE_DUTY("waitpid == 0, check manual\n");
225 }else{
226 DOUBLE_DUTY("running: %s\n",
227 !WIFEXITED(status) ? "yes"
228 : "no");
229
230 if(WIFEXITED(status)){
231 DOUBLE_DUTY(" status: %d\n", WEXITSTATUS(status));
232 jp->pid = -1;
233 jp->last_status = status;
234 }
235 }
236 }else{
237 DOUBLE_DUTY("running: no\n");
238 DOUBLE_DUTY(" status: %d\n", jp->last_status);
239 }
240
241 if(jp->pid != -1){
242 DOUBLE_DUTY(" pid: %d\n", jp->pid);
243 }
244 }else{
245 DOUBLE_DUTY("don't know how to handle that request.\n");
246 }
247 }
248 tomd_p("-----");
249 tomd_p("sending ack.");
250 SEND_ACK;
251 tomd_p("ack is sent.");
81215080
TB
252}
253
254static void handle_connection(int asfd)
255{
256 char buf[100] = {};
257
258 if(validate_sender(asfd, buf) != 0){
259 tomd_p("invalid sender.");
260 return;
261 }
262
263 tomd_p("validated client");
264 handle_request(asfd, buf);
265
7bd7fa83 266 shutdown(asfd, SHUT_WR);
81215080
TB
267}
268
72af8b59
TB
269static void run(void)
270{
271 /* loop: */
272 /* 1 listen */
273 /* 2 accept/select */
274 /* 3 handle dgram */
275 int listen_bool =
276 listen(sfd,
277 10); /* max connection limit is 10 for arbitrary reasons */
278 if(listen_bool == -1){
da4c0e62 279 perror("[tomd] listen");
72af8b59
TB
280 exit(EXIT_FAILURE);
281 }
282
81215080 283 int i = 0;
72af8b59 284 for(;;){
da4c0e62 285 struct sockaddr addr;
81215080
TB
286 /* sometimes gives EINVAL if not initialized. */
287 socklen_t size = sizeof(addr);
288 tomd_p("accept loop [%d]", i++);
289 errno = 0;
72af8b59
TB
290 int accept_sfd =
291 accept(sfd,
bd11173e 292 &addr, /* requester info */
da4c0e62 293 &size); /* len of requester info */
72af8b59 294 if(accept_sfd < 0){
81215080
TB
295 if(errno == EINVAL){
296 tomd_p("EINVAL");
297 }
da4c0e62 298 perror("[tomd] accept socket");
72af8b59
TB
299 exit(EXIT_FAILURE);
300 }
da4c0e62 301
81215080 302 handle_connection(accept_sfd);
72af8b59
TB
303 }
304}
305
306static void cleanup(void)
307{
308 if(sfd >= 0){
309 close(sfd);
310 }
311}
312
313int main(int argc, char **argv)
314{
315 header();
316 init();
7813ae49 317 run_jobs();
7bd7fa83 318 /* daemonize(); */
952aba97 319 run();
72af8b59
TB
320 cleanup();
321
322 return EXIT_SUCCESS;
323}