]> mj.ucw.cz Git - eval.git/blob - submit/tasks.c
00df760f0882bbb76d1d6a55fd9d08cbf49b942a
[eval.git] / submit / tasks.c
1 /*
2  *  The Submit Daemon: Tasks
3  *
4  *  (c) 2007 Martin Mares <mj@ucw.cz>
5  */
6
7 #include "lib/lib.h"
8 #include "lib/conf.h"
9 #include "lib/fastbuf.h"
10 #include "lib/stkstring.h"
11 #include "lib/simple-lists.h"
12 #include "lib/mempool.h"
13 #include "sherlock/object.h"
14
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <unistd.h>
18 #include <errno.h>
19
20 #include "submitd.h"
21
22 clist task_list;
23 static clist extensions;
24 static clist open_data_extensions;
25
26 static byte *
27 tasks_conf_commit(void *p UNUSED)
28 {
29   // We do not do any journaling here as we do not switch config files on the fly
30   CLIST_FOR_EACH(struct task *, t, task_list)
31     {
32       clist_init(&t->parts);
33       if (t->open_data)
34         {
35           for (uns i=1; i<=t->open_data; i++)
36             simp_append(cf_pool, &t->parts)->s = mp_printf(cf_pool, "%d", i);
37           t->extensions = &open_data_extensions;
38         }
39       else
40         {
41           simp_append(cf_pool, &t->parts)->s = t->name;
42           t->extensions = &extensions;
43         }
44     }
45   return NULL;
46 }
47
48 static struct cf_section task_conf = {
49   CF_TYPE(struct task),
50   CF_ITEMS {
51     CF_STRING("Name", PTR_TO(struct task, name)),
52     CF_UNS("OpenData", PTR_TO(struct task, open_data)),
53     CF_UNS("MaxSize", PTR_TO(struct task, max_size)),
54     CF_END
55   }
56 };
57
58 struct cf_section tasks_conf = {
59   CF_COMMIT(tasks_conf_commit),
60   CF_ITEMS {
61     CF_LIST("Task", &task_list, &task_conf),
62     CF_LIST("Extension", &extensions, &cf_string_list_config),
63     CF_LIST("OpenDataExt", &open_data_extensions, &cf_string_list_config),
64     CF_END
65   }
66 };
67
68 struct task *
69 task_find(byte *name)
70 {
71   CLIST_FOR_EACH(struct task *, t, task_list)
72     if (!strcasecmp(t->name, name))
73       return t;
74   return NULL;
75 }
76
77 int
78 part_exists_p(struct task *t, byte *name)
79 {
80   CLIST_FOR_EACH(simp_node *, p, t->parts)
81     if (!strcmp(p->s, name))
82       return 1;
83   return 0;
84 }
85
86 int
87 ext_exists_p(struct task *t, byte *ext)
88 {
89   CLIST_FOR_EACH(simp_node *, x, *t->extensions)
90     if (!strcmp(x->s, ext))
91       return 1;
92   return 0;
93 }
94
95 int
96 user_exists_p(byte *user)
97 {
98   byte *fn = stk_printf("solutions/%s", user);
99   struct stat st;
100   return !stat(fn, &st) && S_ISDIR(st.st_mode);
101 }
102
103 void
104 task_load_status(struct conn *c)
105 {
106   struct fastbuf *fb = bopen_try(stk_printf("solutions/%s/status", c->user), O_RDONLY, 4096);
107   c->task_status = obj_new(c->pool);
108   if (fb)
109     {
110       obj_read(fb, c->task_status);
111       bclose(fb);
112     }
113 }
114
115 void
116 task_lock_status(struct conn *c)
117 {
118   ASSERT(!c->task_lock_fd);
119   if ((c->task_lock_fd = open(stk_printf("solutions/%s/status.lock", c->user), O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0)
120     die("Cannot create task lock: %m");
121   struct flock fl = {
122     .l_type = F_WRLCK,
123     .l_whence = SEEK_SET,
124     .l_start = 0,
125     .l_len = 1
126   };
127   if (fcntl(c->task_lock_fd, F_SETLKW, &fl) < 0)
128     die("Cannot lock status file: %m");
129   task_load_status(c);
130 }
131
132 void
133 task_unlock_status(struct conn *c, uns write_back)
134 {
135   ASSERT(c->task_lock_fd);
136
137   if (write_back)
138     {
139       struct fastbuf *fb = bopen_tmp(4096);
140       obj_write(fb, c->task_status, BUCKET_TYPE_PLAIN);
141       brewind(fb);
142       bconfig(fb, BCONFIG_IS_TEMP_FILE, 0);
143       byte *name = stk_printf("solutions/%s/status", c->user);
144       if (rename(fb->name, name) < 0)
145         die("Unable to rename %s to %s: %m", fb->name, name);
146       bclose(fb);
147     }
148
149   struct flock fl = {
150     .l_type = F_UNLCK,
151     .l_whence = SEEK_SET,
152     .l_start = 0,
153     .l_len = 1
154   };
155   if (fcntl(c->task_lock_fd, F_SETLKW, &fl) < 0)
156     die("Cannot unlock status file: %m");
157   c->task_lock_fd = 0;
158 }
159
160 struct odes *
161 task_status_find_task(struct conn *c, struct task *t, uns create)
162 {
163   for (struct oattr *a = obj_find_attr(c->task_status, 'T' + OBJ_ATTR_SON); a; a=a->same)
164     {
165       struct odes *o = a->son;
166       byte *name = obj_find_aval(o, 'T');
167       ASSERT(name);
168       if (!strcmp(name, t->name))
169         return o;
170     }
171   if (!create)
172     return NULL;
173   struct odes *o = obj_add_son(c->task_status, 'T' + OBJ_ATTR_SON);
174   obj_set_attr(o, 'T', t->name);
175   return o;
176 }
177
178 struct odes *
179 task_status_find_part(struct odes *to, byte *part, uns create)
180 {
181   for (struct oattr *a = obj_find_attr(to, 'P' + OBJ_ATTR_SON); a; a=a->same)
182     {
183       struct odes *o = a->son;
184       byte *name = obj_find_aval(o, 'P');
185       ASSERT(name);
186       if (!strcmp(name, part))
187         return o;
188     }
189   if (!create)
190     return NULL;
191   struct odes *o = obj_add_son(to, 'P' + OBJ_ATTR_SON);
192   obj_set_attr(o, 'P', part);
193   return o;
194 }
195
196 void task_submit_part(byte *user, byte *task, byte *part, byte *ext, uns version UNUSED, struct fastbuf *fb)
197 {
198   byte *dir = stk_printf("solutions/%s/%s", user, task);
199   byte *name = stk_printf("%s/%s.%s", dir, part, ext);
200
201   struct stat st;
202   if (stat(dir, &st) < 0 && errno == ENOENT && mkdir(dir, 0777) < 0)
203     die("Cannot create %s: %m", dir);
204
205   bconfig(fb, BCONFIG_IS_TEMP_FILE, 0);
206   if (rename(fb->name, name) < 0)
207     die("Cannot rename %s to %s: %m", fb->name, name);
208 }
209
210 void task_delete_part(byte *user, byte *task, byte *part, byte *ext, uns version UNUSED)
211 {
212   byte *dir = stk_printf("solutions/%s/%s", user, task);
213   byte *name = stk_printf("%s/%s.%s", dir, part, ext);
214   if (unlink(name) < 0)
215     msg(L_ERROR, "Cannot delete %s: %m", name);
216 }