Line data Source code
1 : #include "../burp.h"
2 : #include "../alloc.h"
3 : #include "../asfd.h"
4 : #include "../fsops.h"
5 : #include "../log.h"
6 : #include "../prepend.h"
7 : #include "../run_script.h"
8 : #include "../strlist.h"
9 : #include "../times.h"
10 : #include "sdirs.h"
11 : #include "timestamp.h"
12 :
13 : static int is_dir_stat(const char *path)
14 : {
15 : struct stat buf;
16 16 : if(stat(path, &buf))
17 : return -1;
18 15 : return S_ISDIR(buf.st_mode);
19 : }
20 :
21 21 : static int check_manual_file(struct sdirs *sdirs, const char *cname)
22 : {
23 21 : int ret=-1;
24 21 : char *manual=NULL;
25 :
26 : // A 'backup' file placed in the storage directory tells this script
27 : // that a backup needs to be done right now.
28 : // This gives the 'server initiates a manual backup' feature.
29 : // The path should probably be part of sdirs so we do not have to build
30 : // it here.
31 21 : if(astrcat(&manual, sdirs->clients, __func__)
32 21 : || astrcat(&manual, "/", __func__)
33 21 : || astrcat(&manual, cname, __func__)
34 21 : || astrcat(&manual, "/backup", __func__))
35 : goto end;
36 21 : if(is_reg_lstat(manual)>0)
37 : {
38 1 : logp("Found %s\n", manual);
39 1 : unlink(manual);
40 1 : ret=0;
41 : goto end;
42 : }
43 : ret=1;
44 : end:
45 21 : free_w(&manual);
46 21 : return ret;
47 : }
48 :
49 1 : static void get_current_day_and_hour_and_unixtime(
50 : char **d,
51 : char **h,
52 : time_t *t)
53 : {
54 : static char day[4]="";
55 : static char hour[3]="";
56 1 : const struct tm *ctm=NULL;
57 1 : *t=time(NULL);
58 1 : ctm=localtime(t);
59 1 : strftime(day, sizeof(day), "%a", ctm);
60 1 : strftime(hour, sizeof(hour), "%H", ctm);
61 1 : *d=day;
62 1 : *h=hour;
63 1 : }
64 :
65 73 : static void strtolower(char *str)
66 : {
67 : char *cp;
68 1099 : for(cp=str; *cp; cp++)
69 1026 : *cp=tolower(*cp);
70 73 : }
71 :
72 20 : static int check_timebands(const char *day_now, const char *hour_now,
73 : struct strlist *timebands)
74 : {
75 20 : char *lower_tb=NULL;
76 20 : int in_timeband=0;
77 : struct strlist *t;
78 20 : char *lower_day_now=NULL;
79 20 : char *lower_hour_now=NULL;
80 :
81 20 : if(!(lower_day_now=strdup_w(day_now, __func__))
82 20 : || !(lower_hour_now=strdup_w(hour_now, __func__)))
83 : {
84 : in_timeband=-1;
85 : goto end;
86 : }
87 20 : strtolower(lower_day_now);
88 20 : strtolower(lower_hour_now);
89 :
90 53 : for(t=timebands; t; t=t->next)
91 : {
92 33 : free_w(&lower_tb);
93 33 : if(!(lower_tb=strdup_w(t->path, __func__)))
94 : {
95 : in_timeband=-1;
96 : goto end;
97 : }
98 33 : strtolower(lower_tb);
99 :
100 33 : if(!strcmp(lower_tb, "always")
101 33 : || (strstr(lower_tb, lower_day_now)
102 17 : && strstr(lower_tb, lower_hour_now)))
103 : {
104 16 : logp("In timeband: %s\n", t->path);
105 16 : in_timeband=1;
106 : }
107 : else
108 17 : logp("Out of timeband: %s\n", t->path);
109 : }
110 :
111 : end:
112 20 : free_w(&lower_day_now);
113 20 : free_w(&lower_hour_now);
114 20 : free_w(&lower_tb);
115 :
116 20 : return in_timeband;
117 : }
118 :
119 15 : static long get_interval_in_seconds(const char *str, const char *cname)
120 : {
121 : int s;
122 : long seconds;
123 : char unit;
124 15 : if(sscanf(str, "%d%c", &s, &unit)!=2)
125 : goto error;
126 15 : seconds=(long)s;
127 15 : switch(unit)
128 : {
129 : case 's':
130 : return seconds;
131 : case 'm':
132 2 : return seconds*60;
133 : case 'h':
134 4 : return seconds*60*60;
135 : case 'd':
136 2 : return seconds*60*60*24;
137 : case 'w':
138 2 : return seconds*60*60*24*7;
139 : case 'n':
140 2 : return seconds*60*60*24*30;
141 : }
142 : error:
143 1 : logp("interval %s not understood for %s\n", str, cname);
144 1 : return -1;
145 : }
146 :
147 15 : static int check_interval(
148 : struct strlist *interval,
149 : const char *cname,
150 : const char *ctimestamp,
151 : time_t time_now)
152 : {
153 : char *cp;
154 : long min_time;
155 15 : long seconds=0;
156 15 : char tstmp[64]="";
157 15 : char min_time_buf[64]="";
158 :
159 15 : if((seconds=get_interval_in_seconds(interval->path, cname))<0)
160 : return -1;
161 14 : if(timestamp_read(ctimestamp, tstmp, sizeof(tstmp)))
162 : {
163 0 : logp("Could not read timestamp %s\n", ctimestamp);
164 : return 0; // Backup now.
165 : }
166 :
167 14 : min_time=timestamp_to_long(tstmp)+seconds;
168 14 : strftime(min_time_buf, sizeof(min_time_buf),
169 14 : DEFAULT_TIMESTAMP_FORMAT, localtime(&min_time));
170 14 : cp=strchr(tstmp, ' ');
171 14 : if(cp)
172 14 : cp++;
173 : else
174 : cp=tstmp;
175 :
176 14 : logp("Last backup: %s\n", cp);
177 14 : logp("Next after : %s (interval %s)\n", min_time_buf, interval->path);
178 :
179 14 : if(min_time < time_now)
180 : return 0;
181 : return 1;
182 : }
183 :
184 : #ifndef UTEST
185 : static
186 : #endif
187 21 : int run_timer_internal(
188 : const char *cname,
189 : struct sdirs *sdirs,
190 : struct strlist *timer_args,
191 : char *day_now,
192 : char *hour_now,
193 : time_t time_now
194 : )
195 : {
196 21 : int ret=-1;
197 21 : struct strlist *interval=NULL;
198 21 : struct strlist *timebands=NULL;
199 21 : char *ctimestamp=NULL;
200 :
201 21 : logp("Running timer for %s\n", cname);
202 :
203 21 : interval=timer_args;
204 21 : if(timer_args)
205 20 : timebands=timer_args->next;
206 :
207 21 : switch((ret=check_manual_file(sdirs, cname)))
208 : {
209 : case -1:
210 : goto end;
211 : case 0:
212 : goto end;
213 : }
214 :
215 20 : switch(check_timebands(day_now, hour_now, timebands))
216 : {
217 : case 0:
218 4 : ret=1;
219 4 : goto end;
220 : case -1: // Error;
221 : goto end;
222 : }
223 :
224 32 : if(is_dir_stat(sdirs->current)<=0)
225 : {
226 1 : logp("No prior backup of %s\n", cname);
227 1 : ret=0;
228 1 : goto end;
229 : }
230 15 : if(!(ctimestamp=prepend_s(sdirs->current, "timestamp")))
231 : {
232 : ret=-1;
233 : goto end;
234 : }
235 :
236 15 : ret=check_interval(interval, cname, ctimestamp, time_now);
237 :
238 : end:
239 21 : free_w(&ctimestamp);
240 21 : switch(ret)
241 : {
242 : case 0:
243 9 : logp("Do a backup of %s now\n", cname);
244 9 : break;
245 : case 1:
246 11 : logp("Not yet time for a backup of %s\n", cname);
247 11 : break;
248 : }
249 21 : return ret;
250 : }
251 :
252 1 : static int run_timer_internal_w(
253 : const char *cname,
254 : struct sdirs *sdirs,
255 : struct strlist *timer_args
256 : )
257 : {
258 1 : char *day_now=NULL;
259 1 : char *hour_now=NULL;
260 1 : time_t time_now=0;
261 1 : get_current_day_and_hour_and_unixtime(&day_now, &hour_now, &time_now);
262 1 : return run_timer_internal(cname, sdirs, timer_args,
263 : day_now, hour_now, time_now);
264 : }
265 :
266 :
267 : static int run_timer_script(
268 : struct asfd *asfd,
269 : const char *timer_script,
270 : const char *cname,
271 : struct sdirs *sdirs,
272 : struct strlist *timer_args,
273 : struct conf **cconfs)
274 : {
275 1 : int a=0;
276 : const char *args[12];
277 1 : args[a++]=timer_script;
278 1 : args[a++]=cname;
279 1 : args[a++]=sdirs->current;
280 1 : args[a++]=sdirs->clients;
281 1 : args[a++]="reserved1";
282 1 : args[a++]="reserved2";
283 1 : args[a++]=NULL;
284 1 : return run_script(asfd, args,
285 : timer_args,
286 : cconfs,
287 : 1 /* wait */,
288 : 1 /* use logp */,
289 : 0 /* no log_remote */);
290 : }
291 :
292 : // Return -1 for error, 0 to backup, 1 to not backup.
293 2 : int run_timer(
294 : struct asfd *asfd,
295 : struct sdirs *sdirs,
296 : struct conf **cconfs)
297 : {
298 2 : const char *cname=get_string(cconfs[OPT_CNAME]);
299 2 : const char *timer_script=NULL;
300 2 : struct strlist *timer_args=get_strlist(cconfs[OPT_TIMER_ARG]);
301 :
302 2 : if((timer_script=get_string(cconfs[OPT_TIMER_SCRIPT])))
303 2 : return run_timer_script(asfd, timer_script,
304 : cname, sdirs, timer_args, cconfs);
305 :
306 1 : return run_timer_internal_w(cname, sdirs, timer_args);
307 : }
|