Fixed inconsistent socket io.
[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();
1110e851 78
72af8b59
TB
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; \
1110e851
TB
120 char ACK[4];\
121 ACK[0] = 'A';\
122 ACK[1] = 'C';\
123 ACK[2] = 'K';\
124 ACK[3] = '\0';\
125if(size = write(asfd, ACK, sizeof(ACK)) != sizeof(ACK)) { \
126 tomd_p("didn't send as much as we though (%d != %d)",\
127 size, sizeof(ACK)); \
81215080
TB
128 } \
129 }
130
72af8b59
TB
131#define CHDIR 0
132#define DONT_CHDIR 1
133#define CLOSE_PIPES 0
134#define DONT_CLOSE_PIPES 1
135
136static void daemonize(void)
137{
138 /* daemon is in unistd. */
139 /* arg1 - 0 changes dir to / */
140 /* arg2 - 0 closes all pipes (/dev/null) */
141 /* WARNING > THIS BEHAVIOR IS SILENT AND EASY TO MISPLACE THE
142 PROCESS */
143 daemon(DONT_CHDIR, DONT_CLOSE_PIPES);
144}
145
81215080 146#define READ_SOCKET {\
1110e851 147 memset(buf, 0, sizeof(buf)); \
81215080
TB
148 int size = read(asfd, buf, 100); \
149 buf[size] = '\0'; \
150 }
151
152static int validate_sender(int asfd, char *buf)
153{
154 READ_SOCKET;
155 if(strcmp(buf, "client:tomc") == 0){
156 SEND_ACK;
157 return 0;
158 }
159 tomd_p("received '%s' instead of client:tomc", buf);
160 return -1;
161}
162
163enum requests { KILL, STATUS, STOP, START, UNKNOWN};
164#define X(a, b) { a, b }
165static struct {
166 char *str;
167 enum requests request;
168} request_types[] =
169 {
170 X("kill", KILL),
171 X("status", STATUS),
172 X("start", START),
173 X("stop", STOP),
174 X(NULL, -1)
175 };
176#undef X
177
178static void handle_request(int asfd, char *buf)
179{
180 READ_SOCKET;
181 enum requests request = UNKNOWN;
182 int i = 0;
183 while(1){
184 if(request_types[i].str == NULL){
185 break;
186 }
187
188 tomd_p("loop [%d]: comparing '%s' to '%s'",
189 i, buf, request_types[i].str);
190 if(strcmp(buf, request_types[i].str) == 0){
191 request = request_types[i].request;
192 break;
193 }
1110e851 194
81215080
TB
195 i++;
196 }
197
198 if(request == UNKNOWN){
199 tomd_p("unknown request type!");
200 return;
201 }
202
203 SEND_ACK;
204 READ_SOCKET;
205 // cross reference given name against known services
206 tomd_p("looking up '%s'", buf);
207 SEND_ACK;
7bd7fa83
TB
208 struct job *jp = lookup_job(buf);
209 #define DOUBLE_DUTY(...) { \
210 char tmp[100]; \
211 tomd_p(__VA_ARGS__); \
212 sprintf(tmp, __VA_ARGS__); \
213 int tmplen = strlen(tmp); \
214 tomd_p("__debug__:'%s'", tmp);\
215 write(asfd, tmp, tmplen); \
216 }
217 if(jp == NULL){
218 DOUBLE_DUTY("lookup of '%s' failed.\n", buf);
219 } else {
220
221 tomd_p("-----");
222 DOUBLE_DUTY("found job record for '%s'\n", jp->name);
223
224 if(request == STATUS){
225 if(jp->pid != -1){
226 int status = 0;
227 int n_pid = waitpid(jp->pid, &status, WNOHANG);
228 if(n_pid < 0){
229 perror("[tomd] waitpid");
230 }else if(n_pid == 0){
231 DOUBLE_DUTY("waitpid == 0, check manual\n");
1110e851 232 }else{
7bd7fa83
TB
233 DOUBLE_DUTY("running: %s\n",
234 !WIFEXITED(status) ? "yes"
235 : "no");
1110e851 236
7bd7fa83
TB
237 if(WIFEXITED(status)){
238 DOUBLE_DUTY(" status: %d\n", WEXITSTATUS(status));
239 jp->pid = -1;
240 jp->last_status = status;
241 }
242 }
243 }else{
244 DOUBLE_DUTY("running: no\n");
245 DOUBLE_DUTY(" status: %d\n", jp->last_status);
246 }
1110e851 247
7bd7fa83
TB
248 if(jp->pid != -1){
249 DOUBLE_DUTY(" pid: %d\n", jp->pid);
250 }
251 }else{
252 DOUBLE_DUTY("don't know how to handle that request.\n");
253 }
254 }
255 tomd_p("-----");
256 tomd_p("sending ack.");
257 SEND_ACK;
258 tomd_p("ack is sent.");
1110e851
TB
259 get_ack:
260 READ_SOCKET;
261 if(strcmp(buf, "ACK") != 0)
262 goto get_ack;
263 tomd_p("ack was ack'd.");
81215080
TB
264}
265
266static void handle_connection(int asfd)
267{
268 char buf[100] = {};
269
270 if(validate_sender(asfd, buf) != 0){
271 tomd_p("invalid sender.");
272 return;
273 }
274
275 tomd_p("validated client");
276 handle_request(asfd, buf);
277
7bd7fa83 278 shutdown(asfd, SHUT_WR);
1110e851 279 close(asfd);
81215080
TB
280}
281
72af8b59
TB
282static void run(void)
283{
284 /* loop: */
285 /* 1 listen */
286 /* 2 accept/select */
287 /* 3 handle dgram */
288 int listen_bool =
289 listen(sfd,
290 10); /* max connection limit is 10 for arbitrary reasons */
291 if(listen_bool == -1){
da4c0e62 292 perror("[tomd] listen");
72af8b59
TB
293 exit(EXIT_FAILURE);
294 }
295
81215080 296 int i = 0;
72af8b59 297 for(;;){
da4c0e62 298 struct sockaddr addr;
81215080
TB
299 /* sometimes gives EINVAL if not initialized. */
300 socklen_t size = sizeof(addr);
301 tomd_p("accept loop [%d]", i++);
302 errno = 0;
72af8b59
TB
303 int accept_sfd =
304 accept(sfd,
bd11173e 305 &addr, /* requester info */
da4c0e62 306 &size); /* len of requester info */
72af8b59 307 if(accept_sfd < 0){
81215080
TB
308 if(errno == EINVAL){
309 tomd_p("EINVAL");
310 }
da4c0e62 311 perror("[tomd] accept socket");
72af8b59
TB
312 exit(EXIT_FAILURE);
313 }
1110e851 314
81215080 315 handle_connection(accept_sfd);
72af8b59
TB
316 }
317}
318
319static void cleanup(void)
320{
321 if(sfd >= 0){
322 close(sfd);
323 }
324}
325
326int main(int argc, char **argv)
327{
328 header();
329 init();
7813ae49 330 run_jobs();
7bd7fa83 331 /* daemonize(); */
952aba97 332 run();
72af8b59 333 cleanup();
1110e851 334
72af8b59
TB
335 return EXIT_SUCCESS;
336}