Line data Source code
1 : #include "burp.h"
2 : #include "alloc.h"
3 : #include "asfd.h"
4 : #include "async.h"
5 : #include "cmd.h"
6 : #include "cntr.h"
7 : #include "cstat.h"
8 : #include "fsops.h"
9 : #include "handy.h"
10 : #include "iobuf.h"
11 : #include "log.h"
12 : #include "times.h"
13 :
14 : #include "client/monitor/sel.h"
15 : #include "client/monitor/json_input.h"
16 : #include "server/bu_get.h"
17 : #include "server/monitor/json_output.h"
18 :
19 : #include <limits.h>
20 :
21 : #define CNTR_VERSION 3
22 : #define CNTR_PATH_BUF_LEN 256
23 :
24 : static void cntr_ent_free_content(struct cntr_ent *cntr_ent)
25 : {
26 : if(!cntr_ent) return;
27 600 : free_w(&cntr_ent->field);
28 600 : free_w(&cntr_ent->label);
29 : }
30 :
31 600 : static void cntr_ent_free(struct cntr_ent **cntr_ent)
32 : {
33 600 : if(!cntr_ent || !*cntr_ent) return;
34 1200 : cntr_ent_free_content(*cntr_ent);
35 600 : free_v((void **)cntr_ent);
36 : }
37 :
38 25 : struct cntr *cntr_alloc(void)
39 : {
40 25 : return (struct cntr *)calloc_w(1, sizeof(struct cntr), __func__);
41 : }
42 :
43 600 : static int add_cntr_ent(struct cntr *cntr, int flags,
44 : enum cmd cmd, const char *field, const char *label)
45 : {
46 600 : struct cntr_ent *cenew=NULL;
47 600 : if(!(cenew=(struct cntr_ent *)
48 600 : calloc_w(1, sizeof(struct cntr_ent), __func__))
49 600 : || !(cenew->field=strdup_w(field, __func__))
50 600 : || !(cenew->label=strdup_w(label, __func__)))
51 : goto error;
52 600 : cenew->flags=flags;
53 600 : cenew->cmd=cmd;
54 :
55 600 : if(cntr->list) cenew->next=cntr->list;
56 600 : cntr->list=cenew;
57 :
58 600 : cntr->ent[(uint8_t)cmd]=cenew;
59 600 : return 0;
60 : error:
61 0 : cntr_ent_free(&cenew);
62 0 : return -1;
63 : }
64 :
65 25 : static size_t calc_max_str_len(struct cntr *cntr, const char *cname)
66 : {
67 25 : size_t slen=0;
68 : char ullmax[64];
69 25 : struct cntr_ent *e=NULL;
70 :
71 : // See cntr_to_str().
72 : // First section - name/version/status
73 25 : slen+=strlen(cname);
74 25 : slen+=32; // More than enough space.
75 :
76 : // Second section.
77 25 : snprintf(ullmax, sizeof(ullmax),
78 : " %" PRIu64 "\n", (uint64_t)ULLONG_MAX);
79 625 : for(e=cntr->list; e; e=e->next)
80 : {
81 600 : if(e->flags & CNTR_SINGLE_FIELD)
82 : // %c%llu\t
83 225 : slen+=strlen(ullmax)+2;
84 : else
85 : // %c%llu/%llu/%llu/%llu/%llu\t
86 375 : slen+=(strlen(ullmax)*5)+6;
87 : }
88 :
89 : // Fourth section - a path. Cannot know how long this might be. Guess.
90 25 : slen+=CNTR_PATH_BUF_LEN+3; // %c%s\t\n
91 :
92 25 : slen+=1; // Terminating character.
93 :
94 25 : return slen;
95 : }
96 :
97 25 : int cntr_init(struct cntr *cntr, const char *cname, pid_t pid)
98 : {
99 25 : if(!cname)
100 : {
101 0 : logp("%s called with no client name\n", __func__);
102 0 : return -1;
103 : }
104 :
105 : // Add in reverse order, so that iterating over from the beginning
106 : // comes out in the right order.
107 25 : if(
108 25 : add_cntr_ent(cntr, CNTR_SINGLE_FIELD,
109 : CMD_TIMESTAMP_END, "time_end", "End time")
110 25 : || add_cntr_ent(cntr, CNTR_SINGLE_FIELD,
111 : CMD_TIMESTAMP, "time_start", "Start time")
112 25 : || add_cntr_ent(cntr, CNTR_SINGLE_FIELD,
113 : CMD_BYTES_SENT, "bytes_sent", "Bytes sent")
114 25 : || add_cntr_ent(cntr, CNTR_SINGLE_FIELD,
115 : CMD_BYTES_RECV, "bytes_received", "Bytes received")
116 25 : || add_cntr_ent(cntr, CNTR_SINGLE_FIELD,
117 : CMD_BYTES, "bytes", "Bytes")
118 25 : || add_cntr_ent(cntr, CNTR_SINGLE_FIELD,
119 : CMD_BYTES_ESTIMATED, "bytes_estimated", "Bytes estimated")
120 25 : || add_cntr_ent(cntr, CNTR_SINGLE_FIELD,
121 : CMD_MESSAGE, "messages", "Messages")
122 25 : || add_cntr_ent(cntr, CNTR_SINGLE_FIELD,
123 : CMD_WARNING, "warnings", "Warnings")
124 25 : || add_cntr_ent(cntr, CNTR_TABULATE,
125 : CMD_GRAND_TOTAL, "grand_total", "Grand total")
126 25 : || add_cntr_ent(cntr, 0,
127 : CMD_TOTAL, "total", "Total")
128 25 : || add_cntr_ent(cntr, CNTR_SINGLE_FIELD,
129 : CMD_ERROR, "errors", "Errors")
130 25 : || add_cntr_ent(cntr, CNTR_TABULATE,
131 : CMD_EFS_FILE, "efs_files", "EFS files")
132 25 : || add_cntr_ent(cntr, CNTR_TABULATE,
133 : CMD_ENC_VSS_T, "vss_footers_encrypted", "VSS footers (enc)")
134 25 : || add_cntr_ent(cntr, CNTR_TABULATE,
135 : CMD_VSS_T, "vss_footers", "VSS footers")
136 25 : || add_cntr_ent(cntr, CNTR_TABULATE,
137 : CMD_ENC_VSS, "vss_headers_encrypted", "VSS headers (enc)")
138 25 : || add_cntr_ent(cntr, CNTR_TABULATE,
139 : CMD_VSS, "vss_headers", "VSS headers")
140 25 : || add_cntr_ent(cntr, CNTR_TABULATE,
141 : CMD_SPECIAL, "special_files", "Special files")
142 25 : || add_cntr_ent(cntr, CNTR_TABULATE,
143 : CMD_SOFT_LINK, "hard_links", "Soft links")
144 25 : || add_cntr_ent(cntr, CNTR_TABULATE,
145 : CMD_HARD_LINK, "soft_links", "Hard links")
146 25 : || add_cntr_ent(cntr, CNTR_TABULATE,
147 : CMD_DIRECTORY, "directories", "Directories")
148 25 : || add_cntr_ent(cntr, CNTR_TABULATE,
149 : CMD_ENC_METADATA, "meta_data_encrypted", "Meta data (enc)")
150 25 : || add_cntr_ent(cntr, CNTR_TABULATE,
151 : CMD_METADATA, "meta_data", "Meta data")
152 25 : || add_cntr_ent(cntr, CNTR_TABULATE,
153 : CMD_ENC_FILE, "files_encrypted", "Files (encrypted)")
154 25 : || add_cntr_ent(cntr, CNTR_TABULATE,
155 : CMD_FILE, "files", "Files")
156 : )
157 : return -1;
158 :
159 25 : cntr->ent[(uint8_t)CMD_TIMESTAMP]->count=(uint64_t)time(NULL);
160 :
161 25 : cntr->str_max_len=calc_max_str_len(cntr, cname);
162 25 : if(!(cntr->str=(char *)calloc_w(1, cntr->str_max_len, __func__))
163 25 : || !(cntr->cname=strdup_w(cname, __func__)))
164 : return -1;
165 25 : cntr->pid=pid;
166 :
167 25 : return 0;
168 : }
169 :
170 25 : static void cntr_free_content(struct cntr *cntr)
171 : {
172 : struct cntr_ent *e;
173 25 : struct cntr_ent *l=NULL;
174 625 : for(e=cntr->list; e; e=l)
175 : {
176 600 : l=e->next;
177 600 : cntr_ent_free(&e);
178 : }
179 25 : cntr->list=NULL;
180 25 : free_w(&cntr->str);
181 25 : free_w(&cntr->cname);
182 25 : }
183 :
184 309 : void cntr_free(struct cntr **cntr)
185 : {
186 309 : if(!cntr || !*cntr) return;
187 25 : cntr_free_content(*cntr);
188 25 : free_v((void **)cntr);
189 : }
190 :
191 145 : void cntrs_free(struct cntr **cntrs)
192 : {
193 : struct cntr *c;
194 : struct cntr *chead;
195 289 : if(!cntrs || !*cntrs) return;
196 : chead=*cntrs;
197 2 : while(chead)
198 : {
199 1 : c=chead;
200 1 : chead=chead->next;
201 1 : cntr_free(&c);
202 : }
203 1 : *cntrs=NULL;
204 : }
205 :
206 3 : const char *bytes_to_human(uint64_t counter)
207 : {
208 : static char ret[32]="";
209 3 : float div=(float)counter;
210 3 : char units[3]="";
211 :
212 3 : if(div<1024) return "";
213 :
214 0 : if((div/=1024)<1024)
215 0 : snprintf(units, sizeof(units), "KB");
216 0 : else if((div/=1024)<1024)
217 0 : snprintf(units, sizeof(units), "MB");
218 0 : else if((div/=1024)<1024)
219 0 : snprintf(units, sizeof(units), "GB");
220 0 : else if((div/=1024)<1024)
221 0 : snprintf(units, sizeof(units), "TB");
222 0 : else if((div/=1024)<1024)
223 0 : snprintf(units, sizeof(units), "EB");
224 : else
225 : {
226 0 : div/=1024;
227 0 : snprintf(units, sizeof(units), "PB");
228 : }
229 0 : snprintf(ret, sizeof(ret), " (%.2f %s)", div, units);
230 0 : return ret;
231 : }
232 :
233 : static void border(void)
234 : {
235 0 : logc("--------------------------------------------------------------------------------\n");
236 : }
237 :
238 0 : static void table_border(enum action act)
239 : {
240 0 : if(act==ACTION_BACKUP
241 0 : || act==ACTION_BACKUP_TIMED)
242 : {
243 0 : logc("%18s ------------------------------------------------------------\n", "");
244 : }
245 0 : if(act==ACTION_RESTORE
246 0 : || act==ACTION_VERIFY)
247 : {
248 0 : logc("%18s ------------------------------\n", "");
249 : }
250 0 : }
251 :
252 : static void set_count_val(struct cntr *cntr, char ch, uint64_t val)
253 : {
254 22 : if(!cntr) return;
255 0 : if(cntr->ent[(uint8_t)ch]) cntr->ent[(uint8_t)ch]->count=val;
256 : }
257 :
258 : static void set_changed_val(struct cntr *cntr, char ch, uint64_t val)
259 : {
260 0 : if(!cntr) return;
261 0 : if(cntr->ent[(uint8_t)ch]) cntr->ent[(uint8_t)ch]->changed=val;
262 : }
263 :
264 : static void set_same_val(struct cntr *cntr, char ch, uint64_t val)
265 : {
266 0 : if(!cntr) return;
267 0 : if(cntr->ent[(uint8_t)ch]) cntr->ent[(uint8_t)ch]->same=val;
268 : }
269 :
270 : static void set_deleted_val(struct cntr *cntr, char ch, uint64_t val)
271 : {
272 0 : if(!cntr) return;
273 0 : if(cntr->ent[(uint8_t)ch]) cntr->ent[(uint8_t)ch]->deleted=val;
274 : }
275 :
276 : static void set_phase1_val(struct cntr *cntr, char ch, uint64_t val)
277 : {
278 0 : if(!cntr) return;
279 0 : if(cntr->ent[(uint8_t)ch]) cntr->ent[(uint8_t)ch]->phase1=val;
280 : }
281 :
282 : static void incr_count_val(struct cntr *cntr, char ch, uint64_t val)
283 : {
284 20 : if(!cntr) return;
285 5 : if(cntr->ent[(uint8_t)ch]) cntr->ent[(uint8_t)ch]->count+=val;
286 : }
287 :
288 : static void incr_same_val(struct cntr *cntr, char ch, uint64_t val)
289 : {
290 18 : if(!cntr) return;
291 0 : if(cntr->ent[(uint8_t)ch]) cntr->ent[(uint8_t)ch]->same+=val;
292 : }
293 :
294 : static void incr_changed_val(struct cntr *cntr, char ch, uint64_t val)
295 : {
296 12 : if(!cntr) return;
297 0 : if(cntr->ent[(uint8_t)ch]) cntr->ent[(uint8_t)ch]->changed+=val;
298 : }
299 :
300 : static void incr_deleted_val(struct cntr *cntr, char ch, uint64_t val)
301 : {
302 6 : if(!cntr) return;
303 0 : if(cntr->ent[(uint8_t)ch]) cntr->ent[(uint8_t)ch]->deleted+=val;
304 : }
305 :
306 : static void incr_phase1_val(struct cntr *cntr, char ch, uint64_t val)
307 : {
308 0 : if(!cntr) return;
309 0 : if(cntr->ent[(uint8_t)ch]) cntr->ent[(uint8_t)ch]->phase1+=val;
310 : }
311 :
312 : static void incr_count(struct cntr *cntr, char ch)
313 : {
314 10 : return incr_count_val(cntr, ch, 1);
315 : }
316 :
317 : static void incr_same(struct cntr *cntr, char ch)
318 : {
319 36 : return incr_same_val(cntr, ch, 1);
320 : }
321 :
322 : static void incr_changed(struct cntr *cntr, char ch)
323 : {
324 24 : return incr_changed_val(cntr, ch, 1);
325 : }
326 :
327 : static void incr_deleted(struct cntr *cntr, char ch)
328 : {
329 12 : return incr_deleted_val(cntr, ch, 1);
330 : }
331 :
332 : static void incr_phase1(struct cntr *cntr, char ch)
333 : {
334 0 : return incr_phase1_val(cntr, ch, 1);
335 : }
336 :
337 : static void print_end(uint64_t val)
338 : {
339 0 : if(val) logc(" %" PRIu64 "\n", val);
340 : }
341 :
342 112 : void cntr_add(struct cntr *c, char ch, int print)
343 : {
344 : struct cntr_ent *grand_total_ent;
345 112 : if(!c) return;
346 5 : if(!(grand_total_ent=c->ent[CMD_GRAND_TOTAL])) return;
347 5 : if(print)
348 : {
349 5 : if(ch!=CMD_MESSAGE && ch!=CMD_WARNING)
350 0 : logc("%c", ch);
351 : }
352 5 : if(ch==CMD_FILE_CHANGED)
353 : {
354 0 : incr_changed(c, CMD_FILE);
355 0 : incr_changed(c, CMD_TOTAL);
356 : incr_changed(c, CMD_GRAND_TOTAL);
357 : }
358 : else
359 : {
360 10 : incr_count(c, ch);
361 5 : if(ch==CMD_WARNING || ch==CMD_MESSAGE) return;
362 : incr_count(c, CMD_TOTAL);
363 : }
364 :
365 0 : if(!((++grand_total_ent->count)%64) && print)
366 0 : print_end(grand_total_ent->count);
367 0 : fflush(stdout);
368 : }
369 :
370 0 : void cntr_add_phase1(struct cntr *c, char ch, int print)
371 : {
372 : static struct cntr_ent *total;
373 0 : incr_phase1(c, ch);
374 :
375 0 : total=c->ent[(uint8_t)CMD_GRAND_TOTAL];
376 0 : ++total->phase1;
377 0 : if(!print) return;
378 0 : if(total->phase1==1) logc("\n");
379 0 : logc("%c", ch);
380 0 : if(!((total->phase1)%64))
381 0 : print_end(total->phase1);
382 0 : fflush(stdout);
383 : }
384 :
385 0 : void cntr_add_val(struct cntr *c, char ch, uint64_t val)
386 : {
387 0 : incr_count_val(c, ch, val);
388 0 : }
389 :
390 0 : void cntr_add_new(struct cntr *c, char ch)
391 : {
392 0 : cntr_add(c, ch, 0);
393 0 : }
394 :
395 6 : void cntr_add_same(struct cntr *c, char ch)
396 : {
397 12 : incr_same(c, ch);
398 6 : incr_same(c, CMD_TOTAL);
399 6 : incr_same(c, CMD_GRAND_TOTAL);
400 6 : }
401 :
402 0 : void cntr_add_same_val(struct cntr *c, char ch, uint64_t val)
403 : {
404 0 : incr_same_val(c, ch, val);
405 0 : incr_same_val(c, CMD_TOTAL, val);
406 0 : incr_same_val(c, CMD_GRAND_TOTAL, val);
407 0 : }
408 :
409 4 : void cntr_add_changed(struct cntr *c, char ch)
410 : {
411 8 : incr_changed(c, ch);
412 4 : incr_changed(c, CMD_TOTAL);
413 4 : incr_changed(c, CMD_GRAND_TOTAL);
414 4 : }
415 :
416 0 : void cntr_add_changed_val(struct cntr *c, char ch, uint64_t val)
417 : {
418 0 : incr_changed_val(c, ch, val);
419 0 : incr_changed_val(c, CMD_TOTAL, val);
420 0 : incr_changed_val(c, CMD_GRAND_TOTAL, val);
421 0 : }
422 :
423 2 : void cntr_add_deleted(struct cntr *c, char ch)
424 : {
425 4 : incr_deleted(c, ch);
426 2 : incr_deleted(c, CMD_TOTAL);
427 2 : incr_deleted(c, CMD_GRAND_TOTAL);
428 2 : }
429 :
430 20 : void cntr_add_bytes(struct cntr *c, uint64_t bytes)
431 : {
432 20 : incr_count_val(c, CMD_BYTES, bytes);
433 20 : }
434 :
435 : static void cntr_set_sentbytes(struct cntr *c, uint64_t bytes)
436 : {
437 11 : set_count_val(c, CMD_BYTES_SENT, bytes);
438 : }
439 :
440 : static void cntr_set_recvbytes(struct cntr *c, uint64_t bytes)
441 : {
442 : set_count_val(c, CMD_BYTES_RECV, bytes);
443 : }
444 :
445 12 : void cntr_set_bytes(struct cntr *c, struct asfd *asfd)
446 : {
447 12 : if(!asfd)
448 : return;
449 22 : cntr_set_sentbytes(c, asfd->sent);
450 11 : cntr_set_recvbytes(c, asfd->rcvd);
451 : }
452 :
453 0 : static void quint_print(struct cntr_ent *ent, enum action act)
454 : {
455 : uint64_t a;
456 : uint64_t b;
457 : uint64_t c;
458 : uint64_t d;
459 : uint64_t e;
460 0 : if(!ent) return;
461 0 : a=ent->count;
462 0 : b=ent->changed;
463 0 : c=ent->same;
464 0 : d=ent->deleted;
465 0 : e=ent->phase1;
466 :
467 0 : if(!(ent->flags & CNTR_TABULATE)) return;
468 :
469 0 : if(!e && !a && !b && !c) return;
470 0 : logc("%18s:", ent->label);
471 0 : if(act==ACTION_BACKUP
472 0 : || act==ACTION_BACKUP_TIMED)
473 : {
474 0 : logc("%9" PRIu64 " ", a);
475 0 : logc("%9" PRIu64 " ", b);
476 0 : logc("%9" PRIu64 " ", c);
477 0 : logc("%9" PRIu64 " ", d);
478 : }
479 0 : if(act==ACTION_RESTORE
480 0 : || act==ACTION_VERIFY)
481 : {
482 0 : logc("%9s ", "");
483 : //logc("%9s ", "");
484 : //logc("%9s ", "");
485 : //logc("%9s ", "");
486 : }
487 0 : if(act==ACTION_ESTIMATE)
488 : {
489 0 : logc("%9s ", "");
490 0 : logc("%9s ", "");
491 0 : logc("%9" PRIu64 "\n", e);
492 : }
493 : else
494 : {
495 0 : logc("%9" PRIu64 " |", a+b+c);
496 0 : logc("%9" PRIu64 "\n", e);
497 : }
498 : }
499 :
500 : static uint64_t get_count(struct cntr_ent **ent, enum cmd cmd)
501 : {
502 0 : if(!ent[(uint8_t)cmd]) return 0;
503 0 : return ent[(uint8_t)cmd]->count;
504 : }
505 :
506 0 : static void bottom_part(struct cntr *c, enum action act)
507 : {
508 : uint64_t l;
509 0 : struct cntr_ent **e=c->ent;
510 0 : logc("\n");
511 0 : logc(" Messages: %11" PRIu64 "\n", get_count(e, CMD_MESSAGE));
512 0 : logc(" Warnings: %11" PRIu64 "\n", get_count(e, CMD_WARNING));
513 0 : logc("\n");
514 0 : logc(" Bytes estimated: %11" PRIu64, get_count(e, CMD_BYTES_ESTIMATED));
515 0 : logc("%s\n", bytes_to_human(get_count(e, CMD_BYTES_ESTIMATED)));
516 :
517 0 : if(act==ACTION_ESTIMATE) return;
518 :
519 0 : if(act==ACTION_BACKUP
520 0 : || act==ACTION_BACKUP_TIMED)
521 : {
522 0 : l=get_count(e, CMD_BYTES);
523 0 : logc(" Bytes in backup: %11" PRIu64, l);
524 0 : logc("%s\n", bytes_to_human(l));
525 : }
526 0 : if(act==ACTION_RESTORE)
527 : {
528 0 : l=get_count(e, CMD_BYTES);
529 0 : logc(" Bytes attempted: %11" PRIu64, l);
530 0 : logc("%s\n", bytes_to_human(l));
531 : }
532 0 : if(act==ACTION_VERIFY)
533 : {
534 0 : l=get_count(e, CMD_BYTES);
535 0 : logc(" Bytes checked: %11" PRIu64, l);
536 0 : logc("%s\n", bytes_to_human(l));
537 : }
538 :
539 0 : l=get_count(e, CMD_BYTES_RECV);
540 0 : logc(" Bytes received: %11" PRIu64, l);
541 0 : logc("%s\n", bytes_to_human(l));
542 :
543 0 : l=get_count(e, CMD_BYTES_SENT);
544 0 : logc(" Bytes sent: %11" PRIu64, l);
545 0 : logc("%s\n", bytes_to_human(l));
546 : }
547 :
548 12 : void cntr_print(struct cntr *cntr, enum action act)
549 : {
550 : struct cntr_ent *e;
551 : time_t now;
552 : time_t start;
553 : char time_start_str[32];
554 : char time_end_str[32];
555 24 : if(!cntr) return;
556 :
557 0 : now=time(NULL);
558 0 : start=(time_t)cntr->ent[(uint8_t)CMD_TIMESTAMP]->count;
559 0 : cntr->ent[(uint8_t)CMD_TIMESTAMP_END]->count=(uint64_t)now;
560 :
561 : border();
562 0 : encode_time(start, time_start_str);
563 0 : encode_time(now, time_end_str);
564 0 : logc("Start time: %s\n", time_start_str);
565 0 : logc(" End time: %s\n", time_end_str);
566 0 : logc("Time taken: %s\n", time_taken(now-start));
567 0 : if(act==ACTION_BACKUP
568 0 : || act==ACTION_BACKUP_TIMED)
569 : {
570 0 : logc("%18s %9s %9s %9s %9s %9s |%9s\n",
571 : " ", "New", "Changed", "Duplicate", "Deleted", "Total", "Scanned");
572 : }
573 0 : if(act==ACTION_RESTORE
574 0 : || act==ACTION_VERIFY)
575 : {
576 0 : logc("%18s %9s %9s |%9s\n",
577 : " ", "", "Attempted", "Expected");
578 : }
579 0 : if(act==ACTION_ESTIMATE)
580 : {
581 0 : logc("%18s %9s %9s %9s\n",
582 : " ", "", "", "Scanned");
583 : }
584 0 : table_border(act);
585 :
586 0 : for(e=cntr->list; e; e=e->next)
587 0 : quint_print(e, act);
588 :
589 0 : table_border(act);
590 0 : bottom_part(cntr, act);
591 :
592 : border();
593 : }
594 :
595 : #ifndef HAVE_WIN32
596 :
597 1 : int cntr_stats_to_file(struct cntr *cntr,
598 : const char *directory, enum action act)
599 : {
600 1 : int ret=-1;
601 1 : int fd=-1;
602 1 : char *path=NULL;
603 1 : char *pathtmp=NULL;
604 1 : const char *fname=NULL;
605 1 : struct async *as=NULL;
606 1 : struct asfd *wfd=NULL;
607 1 : if(!cntr)
608 : return 0;
609 0 : cntr->ent[(uint8_t)CMD_TIMESTAMP_END]->count
610 0 : =(uint64_t)time(NULL);
611 :
612 0 : if(act==ACTION_BACKUP
613 0 : || act==ACTION_BACKUP_TIMED)
614 : fname="backup_stats";
615 0 : else if(act==ACTION_RESTORE)
616 : fname="restore_stats";
617 0 : else if(act==ACTION_VERIFY)
618 : fname="verify_stats";
619 : else
620 : return 0;
621 :
622 0 : if(!(path=prepend_s(directory, fname))
623 0 : || !(pathtmp=prepend(path, ".tmp")))
624 : goto end;
625 0 : if((fd=open(
626 : pathtmp,
627 : #ifdef O_NOFOLLOW
628 : O_NOFOLLOW|
629 : #endif
630 : O_WRONLY|O_CREAT,
631 : 0666))<0)
632 : {
633 0 : logp("Could not open %s for writing in %s: %s\n",
634 0 : pathtmp, __func__, strerror(errno));
635 0 : goto end;
636 : }
637 :
638 0 : if(!(as=async_alloc())
639 0 : || as->init(as, 0)
640 0 : || !(wfd=setup_asfd_linebuf_write(as, "stats file", &fd)))
641 : {
642 0 : close_fd(&fd);
643 0 : goto end;
644 : }
645 :
646 0 : if(json_cntr(wfd, cntr))
647 : goto end;
648 :
649 0 : ret=0;
650 : end:
651 0 : async_free(&as);
652 0 : asfd_free(&wfd);
653 0 : if(!ret && do_rename(pathtmp, path))
654 0 : ret=-1;
655 :
656 0 : free_w(&path);
657 0 : free_w(&pathtmp);
658 0 : return ret;
659 : }
660 :
661 : #endif
662 :
663 11 : void cntr_print_end(struct cntr *cntr)
664 : {
665 : struct cntr_ent *grand_total_ent;
666 11 : if(!cntr) return;
667 0 : grand_total_ent=cntr->ent[CMD_GRAND_TOTAL];
668 0 : if(grand_total_ent)
669 : {
670 0 : print_end(grand_total_ent->count);
671 0 : logc("\n");
672 : }
673 : }
674 :
675 0 : void cntr_print_end_phase1(struct cntr *cntr)
676 : {
677 : struct cntr_ent *grand_total_ent;
678 0 : if(!cntr) return;
679 0 : grand_total_ent=cntr->ent[CMD_GRAND_TOTAL];
680 0 : if(grand_total_ent)
681 : {
682 0 : print_end(grand_total_ent->phase1);
683 0 : logc("\n");
684 : }
685 : }
686 :
687 : #ifndef HAVE_WIN32
688 : // Return string length.
689 0 : size_t cntr_to_str(struct cntr *cntr, const char *path)
690 : {
691 : static char tmp[CNTR_PATH_BUF_LEN+3]="";
692 0 : struct cntr_ent *e=NULL;
693 0 : char *str=cntr->str;
694 :
695 0 : cntr->ent[(uint8_t)CMD_TIMESTAMP_END]->count=time(NULL);
696 :
697 0 : snprintf(str, cntr->str_max_len-1, "cntr\t%s.%d.%d\t%d\t%d\t",
698 : cntr->cname, cntr->pid, cntr->bno,
699 0 : CNTR_VERSION, cntr->cntr_status);
700 :
701 0 : for(e=cntr->list; e; e=e->next)
702 : {
703 0 : if(e->flags & CNTR_SINGLE_FIELD)
704 0 : snprintf(tmp, sizeof(tmp),
705 0 : "%c%" PRIu64"\t", e->cmd, e->count);
706 : else
707 0 : snprintf(tmp, sizeof(tmp),
708 : "%c%" PRIu64
709 : "/%" PRIu64
710 : "/%" PRIu64
711 : "/%" PRIu64
712 : "/%" PRIu64
713 : "\t",
714 0 : e->cmd, e->count, e->changed,
715 : e->same, e->deleted, e->phase1);
716 0 : strcat(str, tmp);
717 : }
718 :
719 : // Abuse CMD_DATAPTH.
720 0 : snprintf(tmp, sizeof(tmp), "%c%s\t\n", CMD_DATAPTH, path?path:"");
721 0 : strcat(str, tmp);
722 :
723 0 : return strlen(str);
724 : }
725 : #endif
726 :
727 0 : static int extract_ul(const char *value, struct cntr_ent *ent)
728 : {
729 0 : char *as=NULL;
730 0 : char *bs=NULL;
731 0 : char *cs=NULL;
732 0 : char *ds=NULL;
733 0 : char *es=NULL;
734 0 : char *copy=NULL;
735 0 : if(!value || !(copy=strdup_w(value, __func__))) return -1;
736 :
737 : // Do not want to use strtok, just in case I end up running more
738 : // than one at a time.
739 0 : as=copy;
740 0 : if((bs=strchr(as, '/')))
741 : {
742 0 : *bs='\0';
743 0 : ent->count=strtoull(as, NULL, 10);
744 0 : if((cs=strchr(++bs, '/')))
745 : {
746 0 : *cs='\0';
747 0 : ent->changed=strtoull(bs, NULL, 10);
748 0 : if((ds=strchr(++cs, '/')))
749 : {
750 0 : *ds='\0';
751 0 : ent->same=strtoull(cs, NULL, 10);
752 0 : if((es=strchr(++ds, '/')))
753 : {
754 0 : ent->deleted=strtoull(ds, NULL, 10);
755 0 : *es='\0';
756 0 : es++;
757 0 : ent->phase1=strtoull(es, NULL, 10);
758 : }
759 : }
760 : }
761 : }
762 : else
763 : {
764 : // Single field.
765 0 : ent->count=strtoull(as, NULL, 10);
766 : }
767 0 : free_w(©);
768 0 : return 0;
769 : }
770 :
771 : /*
772 : static char *get_backup_str(const char *s, int *deletable)
773 : {
774 : static char str[32]="";
775 : const char *cp=NULL;
776 : const char *dp=NULL;
777 : if(!s || !*s) return NULL;
778 : if(!(cp=strchr(s, ' '))
779 : || !(dp=strchr(cp+1, ' ')))
780 : snprintf(str, sizeof(str), "never");
781 : else
782 : {
783 : uint64_t backupnum=0;
784 : backupnum=strtoul(s, NULL, 10);
785 : snprintf(str, sizeof(str),
786 : "%07lu %s", backupnum, getdatestr(atol(dp+1)));
787 : if(*(cp+1)=='1') *deletable=1;
788 : }
789 : return str;
790 : }
791 : */
792 :
793 : /*
794 : static int add_to_backup_list(struct strlist **backups, const char *tok)
795 : {
796 : int deletable=0;
797 : const char *str=NULL;
798 : if(!(str=get_backup_str(tok, &deletable))) return 0;
799 : if(strlist_add(backups, (char *)str, deletable)) return -1;
800 : return 0;
801 : }
802 : */
803 :
804 0 : static int extract_cntrs(struct cntr *cntr, char **path)
805 : {
806 : char *tok;
807 0 : while((tok=strtok(NULL, "\t\n")))
808 : {
809 0 : switch(tok[0])
810 : {
811 : case CMD_DATAPTH:
812 0 : free_w(path);
813 0 : if(!(*path=strdup_w(tok+1, __func__)))
814 : return -1;
815 : break;
816 : default:
817 0 : if(cntr->ent[(uint8_t)tok[0]]
818 0 : && extract_ul(tok+1,
819 : cntr->ent[(uint8_t)tok[0]]))
820 : return -1;
821 : break;
822 : }
823 : }
824 : return 0;
825 : }
826 :
827 9 : int extract_client_pid_bno(char *buf, char **cname, pid_t *pid, int *bno)
828 : {
829 9 : char *cp=NULL;
830 9 : char *pp=NULL;
831 :
832 : // Extract the client name.
833 9 : if((cp=strchr(buf, '\t')))
834 3 : *cp='\0';
835 9 : if(!(*cname=strdup_w(buf, __func__)))
836 : return -1;
837 9 : if(cp)
838 3 : *cp='\t';
839 :
840 : // Extract the bno.
841 9 : if((pp=strrchr(*cname, '.')))
842 : {
843 4 : *pp='\0';
844 8 : *bno=(int)atoi(pp+1);
845 : // Extract the pid.
846 4 : if((pp=strrchr(*cname, '.')))
847 : {
848 0 : *pp='\0';
849 0 : *pid=(pid_t)atoi(pp+1);
850 : }
851 : }
852 : return 0;
853 : }
854 :
855 1 : int str_to_cntr(const char *str, struct cntr *cntr, char **path)
856 : {
857 1 : int ret=-1;
858 1 : char *tok=NULL;
859 1 : char *copy=NULL;
860 :
861 1 : if(!(copy=strdup_w(str, __func__)))
862 : return -1;
863 :
864 1 : if((tok=strtok(copy, "\t\n")))
865 : {
866 1 : int bno=0;
867 1 : pid_t pid=-1;
868 1 : char *tmp=NULL;
869 1 : char *cname=NULL;
870 : // First token is 'cntr'.
871 : // Second is client name/pid/bno.
872 1 : if(!(tmp=strtok(NULL, "\t\n")))
873 : {
874 0 : logp("Parsing problem in %s: null client\n",
875 : __func__);
876 0 : goto end;
877 : }
878 1 : if(extract_client_pid_bno(tmp, &cname, &pid, &bno))
879 : goto end;
880 1 : free_w(&cname);
881 1 : cntr->pid=pid;
882 1 : cntr->bno=bno;
883 : // Third is the cntr version.
884 1 : if(!(tmp=strtok(NULL, "\t\n")))
885 : {
886 0 : logp("Parsing problem in %s: null version\n",
887 : __func__);
888 0 : goto end;
889 : }
890 1 : if(atoi(tmp)!=CNTR_VERSION)
891 : {
892 : ret=0;
893 : goto end;
894 : }
895 : // Fourth is cntr_status.
896 0 : if(!(tmp=strtok(NULL, "\t\n")))
897 : {
898 0 : logp("Parsing problem in %s: null cntr_status\n",
899 : __func__);
900 0 : goto end;
901 : }
902 0 : cntr->cntr_status=(enum cntr_status)atoi(tmp);
903 :
904 0 : if(extract_cntrs(cntr, path)) goto end;
905 : }
906 :
907 : ret=0;
908 : end:
909 1 : free_w(©);
910 1 : return ret;
911 : }
912 :
913 : #ifndef HAVE_WIN32
914 1 : int cntr_send_bu(struct asfd *asfd, struct bu *bu, struct conf **confs,
915 : enum cntr_status cntr_status)
916 : {
917 1 : int ret=-1;
918 : uint16_t flags;
919 1 : struct cstat *clist=NULL;
920 1 : struct cstat *cstat=NULL;
921 :
922 1 : if(!get_int(confs[OPT_SEND_CLIENT_CNTR]))
923 : return 0;
924 :
925 0 : flags=bu->flags;
926 :
927 : // Want to setup a cstat and a bu so that we can piggy-back on the
928 : // status monitor cntr json code.
929 :
930 0 : if(!(cstat=cstat_alloc())
931 0 : || cstat_init(cstat,
932 0 : get_string(confs[OPT_CNAME]), NULL/*clientconfdir*/))
933 : goto end;
934 0 : cstat->cntrs=get_cntr(confs);
935 0 : cstat->cntrs->cntr_status=cntr_status;
936 0 : cstat->run_status=RUN_STATUS_RUNNING;
937 :
938 : // Hacky provocation to get the json stuff to send counters in the
939 : // case where we are actually doing a restore.
940 0 : bu->flags|=BU_WORKING;
941 0 : cstat->bu=bu;
942 :
943 0 : clist=cstat;
944 :
945 0 : ret=json_send(asfd,
946 : clist,
947 : cstat,
948 : bu,
949 : NULL /* logfile */,
950 : NULL /* browse */,
951 : 0 /* use_cache */,
952 0 : version_to_long(get_string(confs[OPT_PEER_VERSION])));
953 : end:
954 0 : cstat->bu=NULL; // 'bu' was not ours to mess with.
955 0 : cstat->cntrs=NULL; // 'cntrs' was not ours to mess with.
956 0 : bu->flags=flags; // Set flags back to what the were before.
957 0 : cstat_free(&cstat);
958 0 : return ret;
959 : }
960 :
961 0 : int cntr_send_sdirs(struct asfd *asfd,
962 : struct sdirs *sdirs, struct conf **confs, enum cntr_status cntr_status)
963 : {
964 0 : int ret=-1;
965 0 : struct bu *bu=NULL;
966 0 : struct bu *bu_list=NULL;
967 :
968 : // FIX THIS:
969 : // It would be better just to set up the correct 'bu' entry instead
970 : // of loading everything and then looking through the list.
971 0 : if(bu_get_list_with_working(sdirs, &bu_list))
972 : goto end;
973 0 : for(bu=bu_list; bu; bu=bu->next)
974 0 : if((bu->flags & BU_WORKING)
975 : || (bu->flags & BU_FINISHING))
976 : break;
977 0 : if(!bu)
978 : {
979 0 : logp("could not find working or finishing backup in %s\n",
980 : __func__);
981 0 : goto end;
982 : }
983 0 : ret=cntr_send_bu(asfd, bu, confs, cntr_status);
984 : end:
985 0 : bu_list_free(&bu_list);
986 0 : return ret;
987 : }
988 : #endif
989 :
990 0 : static enum asl_ret cntr_recv_func(struct asfd *asfd,
991 : struct conf **confs,
992 : void *param)
993 : {
994 0 : struct sel *sel=(struct sel *)param;
995 0 : switch(json_input(asfd, sel))
996 : {
997 : case 0: return ASL_CONTINUE;
998 : case 1:
999 0 : case 2: return ASL_END_OK;
1000 0 : default: return ASL_END_ERROR;
1001 : }
1002 : }
1003 :
1004 5 : int cntr_recv(struct asfd *asfd, struct conf **confs)
1005 : {
1006 5 : int ret=-1;
1007 5 : struct sel *sel=NULL;
1008 : struct cntr_ent *e;
1009 5 : struct cntr *cntr=get_cntr(confs);
1010 :
1011 5 : if(!(sel=sel_alloc()))
1012 : goto end;
1013 5 : if(!get_int(confs[OPT_SEND_CLIENT_CNTR]))
1014 : goto ok;
1015 0 : if(json_input_init())
1016 : goto end;
1017 0 : if(asfd->simple_loop(asfd, confs, sel, __func__, cntr_recv_func)
1018 0 : || !sel->clist || !sel->clist->cntrs)
1019 : goto end;
1020 0 : for(e=sel->clist->cntrs->list; e; e=e->next)
1021 : {
1022 0 : set_count_val(cntr, e->cmd, e->count);
1023 0 : set_changed_val(cntr, e->cmd, e->changed);
1024 0 : set_same_val(cntr, e->cmd, e->same);
1025 0 : set_deleted_val(cntr, e->cmd, e->deleted);
1026 0 : set_phase1_val(cntr, e->cmd, e->phase1);
1027 : }
1028 : ok:
1029 : ret=0;
1030 : end:
1031 5 : json_input_free();
1032 5 : sel_free(&sel);
1033 5 : return ret;
1034 : }
1035 :
1036 0 : const char *cntr_status_to_str(struct cntr *cntr)
1037 : {
1038 0 : switch(cntr->cntr_status)
1039 : {
1040 : case CNTR_STATUS_SCANNING: return CNTR_STATUS_STR_SCANNING;
1041 0 : case CNTR_STATUS_BACKUP: return CNTR_STATUS_STR_BACKUP;
1042 0 : case CNTR_STATUS_MERGING: return CNTR_STATUS_STR_MERGING;
1043 0 : case CNTR_STATUS_SHUFFLING: return CNTR_STATUS_STR_SHUFFLING;
1044 0 : case CNTR_STATUS_LISTING: return CNTR_STATUS_STR_LISTING;
1045 0 : case CNTR_STATUS_RESTORING: return CNTR_STATUS_STR_RESTORING;
1046 0 : case CNTR_STATUS_VERIFYING: return CNTR_STATUS_STR_VERIFYING;
1047 0 : case CNTR_STATUS_DELETING: return CNTR_STATUS_STR_DELETING;
1048 0 : case CNTR_STATUS_DIFFING: return CNTR_STATUS_STR_DIFFING;
1049 0 : default: return "unknown";
1050 : }
1051 : }
1052 :
1053 0 : enum cntr_status cntr_str_to_status(const char *str)
1054 : {
1055 0 : if(!strcmp(str, CNTR_STATUS_STR_SCANNING))
1056 : return CNTR_STATUS_SCANNING;
1057 0 : else if(!strcmp(str, CNTR_STATUS_STR_BACKUP))
1058 : return CNTR_STATUS_BACKUP;
1059 0 : else if(!strcmp(str, CNTR_STATUS_STR_MERGING))
1060 : return CNTR_STATUS_MERGING;
1061 0 : else if(!strcmp(str, CNTR_STATUS_STR_SHUFFLING))
1062 : return CNTR_STATUS_SHUFFLING;
1063 0 : else if(!strcmp(str, CNTR_STATUS_STR_LISTING))
1064 : return CNTR_STATUS_LISTING;
1065 0 : else if(!strcmp(str, CNTR_STATUS_STR_RESTORING))
1066 : return CNTR_STATUS_RESTORING;
1067 0 : else if(!strcmp(str, CNTR_STATUS_STR_VERIFYING))
1068 : return CNTR_STATUS_VERIFYING;
1069 0 : else if(!strcmp(str, CNTR_STATUS_STR_DELETING))
1070 : return CNTR_STATUS_DELETING;
1071 0 : else if(!strcmp(str, CNTR_STATUS_STR_DIFFING))
1072 : return CNTR_STATUS_DIFFING;
1073 0 : return CNTR_STATUS_UNSET;
1074 : }
1075 :
1076 0 : const char *cntr_status_to_action_str(struct cntr *cntr)
1077 : {
1078 0 : switch(cntr->cntr_status)
1079 : {
1080 : case CNTR_STATUS_SCANNING:
1081 : case CNTR_STATUS_BACKUP:
1082 : case CNTR_STATUS_MERGING:
1083 : case CNTR_STATUS_SHUFFLING:
1084 : return "backup";
1085 : case CNTR_STATUS_LISTING:
1086 0 : return "list";
1087 : case CNTR_STATUS_RESTORING:
1088 0 : return "restore";
1089 : case CNTR_STATUS_VERIFYING:
1090 0 : return "verify";
1091 : case CNTR_STATUS_DELETING:
1092 0 : return "delete";
1093 : case CNTR_STATUS_DIFFING:
1094 0 : return "diff";
1095 : default:
1096 0 : return "unknown";
1097 : }
1098 : }
1099 :
1100 927 : int check_fail_on_warning(int fail_on_warning, struct cntr_ent *warn_ent)
1101 : {
1102 927 : if(!fail_on_warning || !warn_ent || !warn_ent->count)
1103 : return 0;
1104 0 : logp("fail_on_warning is set and warning count is %" PRIu64 "\n",
1105 : warn_ent->count);
1106 0 : return -1;
1107 : }
|