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