Add ceod
[public/pyceo-broken.git] / src / ops.c
1 #include <errno.h>
2 #include <inttypes.h>
3 #include <unistd.h>
4 #include <fcntl.h>
5 #include <netdb.h>
6
7 #include "strbuf.h"
8 #include "ops.h"
9 #include "net.h"
10 #include "util.h"
11 #include "config.h"
12
13 static struct op *ops;
14
15 static const char *default_op_dir = "/usr/lib/ceod";
16 static const char *op_dir;
17
18 static void add_op(char *host, char *name, uint32_t id) {
19     struct op *new = xmalloc(sizeof(struct op));
20     errno = 0;
21     new->next = ops;
22     new->name = xstrdup(name);
23     new->id = id;
24     new->path = NULL;
25
26     struct hostent *hostent = gethostbyname(host);
27     if (!hostent)
28         badconf("cannot add op %s: %s: %s", name, host, hstrerror(h_errno));
29     new->hostname = strdup(hostent->h_name);
30     new->local = !strcmp(fqdn.buf, hostent->h_name);
31     new->addr = *(struct in_addr *)hostent->h_addr_list[0];
32
33     if (new->local) {
34         new->path = xmalloc(strlen(op_dir) + strlen("/op-") + strlen(name) + 1);
35         sprintf(new->path, "%s/op-%s", op_dir, name);
36         if (access(new->path, X_OK))
37             fatalpe("cannot add op: %s: %s", name, new->path);
38     }
39
40     ops = new;
41     debug("added op %s (%s%s)", new->name, new->local ? "" : "on ",
42             new->local ? "local" : host);
43 }
44
45 struct op *get_local_op(uint32_t id) {
46     for (struct op *op = ops; op; op = op->next) {
47         if (op->local && op->id == id)
48             return op;
49     }
50     return NULL;
51 }
52
53 struct op *find_op(const char *name) {
54     for (struct op *op = ops; op; op = op->next) {
55         if (!strcmp(name, op->name))
56             return op;
57     }
58     return NULL;
59 }
60
61 void setup_ops(void) {
62     char op_config_dir[1024];
63     DIR *dp;
64     struct dirent *de;
65     struct strbuf line = STRBUF_INIT;
66     unsigned lineno = 0;
67     unsigned op_count = 0;
68
69     op_dir = getenv("CEO_LIB_DIR") ?: default_op_dir;
70
71     if (snprintf(op_config_dir, sizeof(op_config_dir), "%s/%s", config_dir, "ops.d") >= sizeof(op_config_dir))
72         fatal("ops dir path too long");
73
74     dp = opendir(op_config_dir);
75     if (!dp)
76         fatalpe("opendir: %s", op_config_dir);
77
78     while ((de = readdir(dp))) {
79         FILE *fp = fopenat(dp, de->d_name, O_RDONLY);
80         if (!fp)
81             warnpe("open: %s/%s", op_config_dir, de->d_name);
82         while (strbuf_getline(&line, fp, '\n') != EOF) {
83             lineno++;
84             strbuf_trim(&line);
85
86             if (!line.len || line.buf[0] == '#')
87                 continue;
88
89             struct strbuf **words = strbuf_splitws(&line);
90
91             if (strbuf_list_len(words) != 3)
92                 badconf("%s/%s: expected three words on line %d", op_config_dir, de->d_name, lineno);
93
94             errno = 0;
95             char *end;
96             int id = strtol(words[2]->buf, &end, 0);
97             if (errno || *end)
98                 badconf("%s/%s: invalid id '%s' on line %d", op_config_dir, de->d_name, words[2]->buf, lineno);
99
100             add_op(words[0]->buf, words[1]->buf, id);
101             op_count++;
102
103             strbuf_list_free(words);
104         }
105     }
106
107     closedir(dp);
108     strbuf_release(&line);
109 }
110