f4bf04bc40fd30404200cd0188de5f4feb662f89
1 /* Copyright (C) 2018 Thomas Balzer */
3 /* This file is part of tomd. */
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. */
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. */
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/>. */
27 #include <sys/socket.h>
30 #include "../../include/macros.h"
31 #include "../../include/manifest.h"
32 #include "../../include/job.h"
34 static void header(void)
36 tomd_p("Tom's Daemon, Copyright (C) 2018 Thomas Balzer");
37 tomd_p("GPL v3 or later license.");
41 static char socket_dirname
[100];
42 static char socket_filename
[100];
44 static void gen_socket_filename(void)
48 sprintf(socket_dirname
,
51 sprintf(socket_filename
,
52 "/run/user/%d/tomd/socket",
55 tomd_p("making dir '%s'", socket_dirname
);
58 /* sprintf(buf, "mkdir -p %s", socket_dirname); */
61 if(mkdir(socket_dirname
, S_IRWXU
) != 0){
63 tomd_panic("socket mkdir");
65 tomd_p("socket dir exists.");
69 tomd_p("removing file '%s'", socket_filename
);
70 if(unlink(socket_filename
) != 0){
72 tomd_p("socket file doesn't exist");
74 tomd_panic("socket unlink");
79 static void socket_init(void)
81 gen_socket_filename();
83 /* listen on socket, respond to requests. */
84 /* perform all registered 'tick' operations */
86 socket(PF_LOCAL
, /* namespace - local unix socket */
87 SOCK_STREAM
, /* style */
94 if(fcntl(sfd
, F_SETFL
, O_NONBLOCK
) == -1){
98 struct sockaddr_un name
;
101 name
.sun_family
= AF_LOCAL
;
102 strncpy(name
.sun_path
,
104 sizeof(name
.sun_path
));
106 size
= SUN_LEN(&name
);
107 tomd_p("attempting to bind to '%s'",
110 (struct sockaddr
*) &name
,
115 tomd_p("initialized tomd socket connections");
118 static void init(void)
131 if(size = write(asfd, ACK, sizeof(ACK)) != sizeof(ACK)) { \
132 tomd_p("didn't send as much as we though (%d != %d)", \
133 size, sizeof(ACK)); \
139 #define CLOSE_PIPES 0
140 #define DONT_CLOSE_PIPES 1
142 static void daemonize(void)
144 /* daemon is in unistd. */
145 /* arg1 - 0 changes dir to / */
146 /* arg2 - 0 closes all pipes (/dev/null) */
147 /* WARNING > THIS BEHAVIOR IS SILENT AND EASY TO MISPLACE THE
149 /* daemon will exit the original process. */
150 daemon(DONT_CHDIR
, DONT_CLOSE_PIPES
);
153 #define READ_SOCKET { \
154 memset(buf, 0, sizeof(buf)); \
155 int size = read(asfd, buf, 100); \
159 static int validate_sender(int asfd
, char *buf
)
162 if(strcmp(buf
, "client:tomc") == 0){
166 tomd_p("received '%s' instead of client:tomc", buf
);
170 enum requests
{ KILL
, STATUS
, STOP
, START
, UNKNOWN
};
171 #define X(a, b) { a, b }
174 enum requests request
;
185 static void handle_request(int asfd
, char *buf
)
188 enum requests request
= UNKNOWN
;
191 if(request_types
[i
].str
== NULL
){
195 tomd_p("loop [%d]: comparing '%s' to '%s'",
196 i
, buf
, request_types
[i
].str
);
197 if(strcmp(buf
, request_types
[i
].str
) == 0){
198 request
= request_types
[i
].request
;
205 if(request
== UNKNOWN
){
206 tomd_p("unknown request type!");
212 // cross reference given name against known services
213 tomd_p("looking up '%s'", buf
);
215 struct job
*jp
= lookup_job(buf
);
216 #define DOUBLE_DUTY(...) { \
218 tomd_p(__VA_ARGS__); \
219 sprintf(tmp, __VA_ARGS__); \
220 int tmplen = strlen(tmp); \
221 tomd_p("__debug__:'%s'", tmp); \
222 write(asfd, tmp, tmplen); \
225 DOUBLE_DUTY("lookup of '%s' failed.\n", buf
);
228 DOUBLE_DUTY("found job record for '%s'\n", jp
->name
);
230 if(request
== STATUS
){
233 int n_pid
= waitpid(jp
->pid
, &status
, WNOHANG
);
235 perror("[tomd] waitpid");
236 }else if(n_pid
== 0){
237 DOUBLE_DUTY("waitpid == 0, check manual\n");
239 DOUBLE_DUTY("running: %s\n",
240 !WIFEXITED(status
) ? "yes"
243 if(WIFEXITED(status
)){
244 DOUBLE_DUTY(" status: %d\n", WEXITSTATUS(status
));
246 jp
->last_status
= status
;
250 DOUBLE_DUTY("running: no\n");
251 DOUBLE_DUTY(" status: %d\n", jp
->last_status
);
255 DOUBLE_DUTY(" pid: %d\n", jp
->pid
);
258 DOUBLE_DUTY("don't know how to handle that request.\n");
262 tomd_p("sending ack.");
264 tomd_p("ack is sent.");
267 if(strcmp(buf
, "ACK") != 0)
269 tomd_p("ack was ack'd.");
272 static void handle_connection(int asfd
)
276 if(validate_sender(asfd
, buf
) != 0){
277 tomd_p("invalid sender.");
281 tomd_p("validated client");
282 handle_request(asfd
, buf
);
284 shutdown(asfd
, SHUT_WR
);
288 static void run(void)
292 /* 2 accept/select */
296 10); /* max connection limit is 10 for arbitrary reasons */
297 if(listen_bool
== -1){
298 tomd_panic("listen");
302 struct sockaddr addr
;
303 /* sometimes gives EINVAL if not initialized. */
304 socklen_t size
= sizeof(addr
);
308 &addr
, /* requester info */
309 &size
); /* len of requester info */
313 }else if(errno
== EWOULDBLOCK
|| errno
== EAGAIN
){
316 tomd_panic("accept socket");
319 handle_connection(accept_sfd
);
327 static void cleanup(void)
334 int main(int argc
, char **argv
)