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