#include <sys/un.h>
#include <sys/stat.h>
#include <sys/socket.h>
+#include <sys/wait.h>
+
+#include "../../include/macros.h"
+#include "../../include/manifest.h"
+#include "../../include/job.h"
static void header(void)
{
- printf("[tomd] Tom's Daemon, Copyright (C) 2018 Thomas Balzer\n");
- printf("[tomd] GPL v3 or later license.\n");
+ tomd_p("Tom's Daemon, Copyright (C) 2018 Thomas Balzer");
+ tomd_p("GPL v3 or later license.");
}
static int sfd;
"/run/user/%d/tomd/socket",
this_user_id);
- printf("[tomd] making dir '%s'\n", socket_dirname);
+ tomd_p("making dir '%s'", socket_dirname);
/* lazy way */
char buf[100];
sprintf(buf, "mkdir -p %s", socket_dirname);
/* exit(EXIT_FAILURE); */
/* } */
- printf("[tomd] removing file '%s'\n", socket_filename);
+ tomd_p("removing file '%s'", socket_filename);
if(unlink(socket_filename) != 0){
if(errno == ENOENT){
- printf("[tomd] socket file doesn't exist\n");
+ tomd_p("socket file doesn't exist");
}else{
perror("[tomd] socket unlink");
exit(EXIT_FAILURE);
}
}
-static void init(void)
+static void socket_init(void)
{
gen_socket_filename();
-
+
/* listen on socket, respond to requests. */
/* perform all registered 'tick' operations */
sfd =
sizeof(name.sun_path));
size = SUN_LEN(&name);
- printf("[tomd] attempting to bind to '%s'\n",
+ tomd_p("attempting to bind to '%s'",
socket_filename);
if(bind(sfd,
(struct sockaddr *) &name,
exit(EXIT_FAILURE);
}
- printf("[tomd] initialized tomd socket connections\n");
+ tomd_p("initialized tomd socket connections");
}
-/* These defines are here to improve the local readability */
+static void init(void)
+{
+ socket_init();
+ load_jobs();
+}
+
+#define SEND_ACK { \
+ int size; \
+ char ACK[4];\
+ ACK[0] = 'A';\
+ ACK[1] = 'C';\
+ ACK[2] = 'K';\
+ ACK[3] = '\0';\
+if(size = write(asfd, ACK, sizeof(ACK)) != sizeof(ACK)) { \
+ tomd_p("didn't send as much as we though (%d != %d)",\
+ size, sizeof(ACK)); \
+ } \
+ }
+
#define CHDIR 0
#define DONT_CHDIR 1
#define CLOSE_PIPES 0
daemon(DONT_CHDIR, DONT_CLOSE_PIPES);
}
+#define READ_SOCKET {\
+ memset(buf, 0, sizeof(buf)); \
+ int size = read(asfd, buf, 100); \
+ buf[size] = '\0'; \
+ }
+
+static int validate_sender(int asfd, char *buf)
+{
+ READ_SOCKET;
+ if(strcmp(buf, "client:tomc") == 0){
+ SEND_ACK;
+ return 0;
+ }
+ tomd_p("received '%s' instead of client:tomc", buf);
+ return -1;
+}
+
+enum requests { KILL, STATUS, STOP, START, UNKNOWN};
+#define X(a, b) { a, b }
+static struct {
+ char *str;
+ enum requests request;
+} request_types[] =
+ {
+ X("kill", KILL),
+ X("status", STATUS),
+ X("start", START),
+ X("stop", STOP),
+ X(NULL, -1)
+ };
+#undef X
+
+static void handle_request(int asfd, char *buf)
+{
+ READ_SOCKET;
+ enum requests request = UNKNOWN;
+ int i = 0;
+ while(1){
+ if(request_types[i].str == NULL){
+ break;
+ }
+
+ tomd_p("loop [%d]: comparing '%s' to '%s'",
+ i, buf, request_types[i].str);
+ if(strcmp(buf, request_types[i].str) == 0){
+ request = request_types[i].request;
+ break;
+ }
+
+ i++;
+ }
+
+ if(request == UNKNOWN){
+ tomd_p("unknown request type!");
+ return;
+ }
+
+ SEND_ACK;
+ READ_SOCKET;
+ // cross reference given name against known services
+ tomd_p("looking up '%s'", buf);
+ SEND_ACK;
+ struct job *jp = lookup_job(buf);
+ #define DOUBLE_DUTY(...) { \
+ char tmp[100]; \
+ tomd_p(__VA_ARGS__); \
+ sprintf(tmp, __VA_ARGS__); \
+ int tmplen = strlen(tmp); \
+ tomd_p("__debug__:'%s'", tmp);\
+ write(asfd, tmp, tmplen); \
+ }
+ if(jp == NULL){
+ DOUBLE_DUTY("lookup of '%s' failed.\n", buf);
+ } else {
+
+ tomd_p("-----");
+ DOUBLE_DUTY("found job record for '%s'\n", jp->name);
+
+ if(request == STATUS){
+ if(jp->pid != -1){
+ int status = 0;
+ int n_pid = waitpid(jp->pid, &status, WNOHANG);
+ if(n_pid < 0){
+ perror("[tomd] waitpid");
+ }else if(n_pid == 0){
+ DOUBLE_DUTY("waitpid == 0, check manual\n");
+ }else{
+ DOUBLE_DUTY("running: %s\n",
+ !WIFEXITED(status) ? "yes"
+ : "no");
+
+ if(WIFEXITED(status)){
+ DOUBLE_DUTY(" status: %d\n", WEXITSTATUS(status));
+ jp->pid = -1;
+ jp->last_status = status;
+ }
+ }
+ }else{
+ DOUBLE_DUTY("running: no\n");
+ DOUBLE_DUTY(" status: %d\n", jp->last_status);
+ }
+
+ if(jp->pid != -1){
+ DOUBLE_DUTY(" pid: %d\n", jp->pid);
+ }
+ }else{
+ DOUBLE_DUTY("don't know how to handle that request.\n");
+ }
+ }
+ tomd_p("-----");
+ tomd_p("sending ack.");
+ SEND_ACK;
+ tomd_p("ack is sent.");
+ get_ack:
+ READ_SOCKET;
+ if(strcmp(buf, "ACK") != 0)
+ goto get_ack;
+ tomd_p("ack was ack'd.");
+}
+
+static void handle_connection(int asfd)
+{
+ char buf[100] = {};
+
+ if(validate_sender(asfd, buf) != 0){
+ tomd_p("invalid sender.");
+ return;
+ }
+
+ tomd_p("validated client");
+ handle_request(asfd, buf);
+
+ shutdown(asfd, SHUT_WR);
+ close(asfd);
+}
+
static void run(void)
{
/* loop: */
exit(EXIT_FAILURE);
}
+ int i = 0;
for(;;){
struct sockaddr addr;
- socklen_t size;
+ /* sometimes gives EINVAL if not initialized. */
+ socklen_t size = sizeof(addr);
+ tomd_p("accept loop [%d]", i++);
+ errno = 0;
int accept_sfd =
accept(sfd,
&addr, /* requester info */
&size); /* len of requester info */
if(accept_sfd < 0){
+ if(errno == EINVAL){
+ tomd_p("EINVAL");
+ }
perror("[tomd] accept socket");
exit(EXIT_FAILURE);
}
- /* int getsockname(accept_sfd, */
- /* addr, */
- /* size); */
-
- printf("[tomd] accepted socket connection from '%s'\n",
- ((struct sockaddr_un *) &addr)->sun_path);
-
- char accept_buf[100] = {};
-
- read(accept_sfd, accept_buf, 100);
- printf("[tomd] got message '%s'\n, accept_buf");
- close(accept_sfd);
+ handle_connection(accept_sfd);
}
}
{
header();
init();
- daemonize();
+ run_jobs();
+ /* daemonize(); */
run();
cleanup();
-
+
return EXIT_SUCCESS;
}