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 0 : free_w(&lower_day_now);
85 0 : free_w(&lower_hour_now);
86 0 : return -1;
87 : }
88 20 : strtolower(lower_day_now);
89 20 : strtolower(lower_hour_now);
90 :
91 53 : for(t=timebands; t; t=t->next)
92 : {
93 33 : free_w(&lower_tb);
94 33 : if(!(lower_tb=strdup_w(t->path, __func__)))
95 : return -1;
96 33 : strtolower(lower_tb);
97 :
98 33 : if(!strcmp(lower_tb, "always")
99 33 : || (strstr(lower_tb, lower_day_now)
100 17 : && strstr(lower_tb, lower_hour_now)))
101 : {
102 16 : logp("In timeband: %s\n", t->path);
103 16 : in_timeband=1;
104 : }
105 : else
106 17 : logp("Out of timeband: %s\n", t->path);
107 : }
108 20 : free_w(&lower_tb);
109 :
110 20 : return in_timeband;
111 : }
112 :
113 15 : static long get_interval_in_seconds(const char *str, const char *cname)
114 : {
115 : int s;
116 : long seconds;
117 : char unit;
118 15 : if(sscanf(str, "%d%c", &s, &unit)!=2)
119 : goto error;
120 15 : seconds=(long)s;
121 15 : switch(unit)
122 : {
123 : case 's':
124 : return seconds;
125 : case 'm':
126 2 : return seconds*60;
127 : case 'h':
128 4 : return seconds*60*60;
129 : case 'd':
130 2 : return seconds*60*60*24;
131 : case 'w':
132 2 : return seconds*60*60*24*7;
133 : case 'n':
134 2 : return seconds*60*60*24*30;
135 : }
136 : error:
137 1 : logp("interval %s not understood for %s\n", str, cname);
138 1 : return -1;
139 : }
140 :
141 15 : static int check_interval(
142 : struct strlist *interval,
143 : const char *cname,
144 : const char *ctimestamp,
145 : time_t time_now)
146 : {
147 : char *cp;
148 : long min_time;
149 15 : long seconds=0;
150 15 : char tstmp[64]="";
151 15 : char min_time_buf[64]="";
152 :
153 15 : if((seconds=get_interval_in_seconds(interval->path, cname))<0)
154 : return -1;
155 14 : if(timestamp_read(ctimestamp, tstmp, sizeof(tstmp)))
156 : {
157 0 : logp("Could not read timestamp %s\n", ctimestamp);
158 : return 0; // Backup now.
159 : }
160 :
161 14 : min_time=timestamp_to_long(tstmp)+seconds;
162 14 : strftime(min_time_buf, sizeof(min_time_buf),
163 14 : DEFAULT_TIMESTAMP_FORMAT, localtime(&min_time));
164 14 : cp=strchr(tstmp, ' ');
165 14 : if(cp)
166 14 : cp++;
167 : else
168 : cp=tstmp;
169 :
170 14 : logp("Last backup: %s\n", cp);
171 14 : logp("Next after : %s (interval %s)\n", min_time_buf, interval->path);
172 :
173 14 : if(min_time < time_now)
174 : return 0;
175 : return 1;
176 : }
177 :
178 : #ifndef UTEST
179 : static
180 : #endif
181 21 : int run_timer_internal(
182 : const char *cname,
183 : struct sdirs *sdirs,
184 : struct strlist *timer_args,
185 : char *day_now,
186 : char *hour_now,
187 : time_t time_now
188 : )
189 : {
190 21 : int ret=-1;
191 21 : struct strlist *interval=NULL;
192 21 : struct strlist *timebands=NULL;
193 21 : char *ctimestamp=NULL;
194 :
195 21 : logp("Running timer for %s\n", cname);
196 :
197 21 : interval=timer_args;
198 21 : if(timer_args)
199 20 : timebands=timer_args->next;
200 :
201 21 : switch((ret=check_manual_file(sdirs, cname)))
202 : {
203 : case -1:
204 : goto end;
205 : case 0:
206 : goto end;
207 : }
208 :
209 20 : switch(check_timebands(day_now, hour_now, timebands))
210 : {
211 : case 0:
212 4 : ret=1;
213 4 : goto end;
214 : case -1: // Error;
215 : goto end;
216 : }
217 :
218 32 : if(is_dir_stat(sdirs->current)<=0)
219 : {
220 1 : logp("No prior backup of %s\n", cname);
221 1 : ret=0;
222 1 : goto end;
223 : }
224 15 : if(!(ctimestamp=prepend_s(sdirs->current, "timestamp")))
225 : {
226 : ret=-1;
227 : goto end;
228 : }
229 :
230 15 : ret=check_interval(interval, cname, ctimestamp, time_now);
231 :
232 : end:
233 21 : free_w(&ctimestamp);
234 21 : switch(ret)
235 : {
236 : case 0:
237 9 : logp("Do a backup of %s now\n", cname);
238 9 : break;
239 : case 1:
240 11 : logp("Not yet time for a backup of %s\n", cname);
241 11 : break;
242 : }
243 21 : return ret;
244 : }
245 :
246 1 : static int run_timer_internal_w(
247 : const char *cname,
248 : struct sdirs *sdirs,
249 : struct strlist *timer_args
250 : )
251 : {
252 1 : char *day_now=NULL;
253 1 : char *hour_now=NULL;
254 1 : time_t time_now=0;
255 1 : get_current_day_and_hour_and_unixtime(&day_now, &hour_now, &time_now);
256 1 : return run_timer_internal(cname, sdirs, timer_args,
257 : day_now, hour_now, time_now);
258 : }
259 :
260 :
261 : static int run_timer_script(
262 : struct asfd *asfd,
263 : const char *timer_script,
264 : const char *cname,
265 : struct sdirs *sdirs,
266 : struct strlist *timer_args,
267 : struct conf **cconfs)
268 : {
269 1 : int a=0;
270 : const char *args[12];
271 1 : args[a++]=timer_script;
272 1 : args[a++]=cname;
273 1 : args[a++]=sdirs->current;
274 1 : args[a++]=sdirs->clients;
275 1 : args[a++]="reserved1";
276 1 : args[a++]="reserved2";
277 1 : args[a++]=NULL;
278 1 : return run_script(asfd, args,
279 : timer_args,
280 : cconfs,
281 : 1 /* wait */,
282 : 1 /* use logp */,
283 : 0 /* no log_remote */);
284 : }
285 :
286 : // Return -1 for error, 0 to backup, 1 to not backup.
287 2 : int run_timer(
288 : struct asfd *asfd,
289 : struct sdirs *sdirs,
290 : struct conf **cconfs)
291 : {
292 2 : const char *cname=get_string(cconfs[OPT_CNAME]);
293 2 : const char *timer_script=NULL;
294 2 : struct strlist *timer_args=get_strlist(cconfs[OPT_TIMER_ARG]);
295 :
296 2 : if((timer_script=get_string(cconfs[OPT_TIMER_SCRIPT])))
297 2 : return run_timer_script(asfd, timer_script,
298 : cname, sdirs, timer_args, cconfs);
299 :
300 1 : return run_timer_internal_w(cname, sdirs, timer_args);
301 : }
|