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 650 : static void cntr_ent_free_content(struct cntr_ent *cntr_ent)
25 : {
26 1300 : 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 1300 : if(!cntr_ent || !*cntr_ent) return;
34 650 : 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 : 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 341 : void cntr_free(struct cntr **cntr)
187 : {
188 682 : if(!cntr || !*cntr) return;
189 26 : cntr_free_content(*cntr);
190 26 : free_v((void **)cntr);
191 : }
192 :
193 154 : void cntrs_free(struct cntr **cntrs)
194 : {
195 : struct cntr *c;
196 : struct cntr *chead;
197 307 : 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 2 : const char *bytes_to_human(uint64_t counter)
209 : {
210 : static char ret[32]="";
211 2 : float div=(float)counter;
212 2 : char units[3]="";
213 :
214 2 : if(div<1024) return "";
215 :
216 0 : if((div/=1024)<1024)
217 : snprintf(units, sizeof(units), "KB");
218 0 : else if((div/=1024)<1024)
219 : snprintf(units, sizeof(units), "MB");
220 0 : else if((div/=1024)<1024)
221 : snprintf(units, sizeof(units), "GB");
222 0 : else if((div/=1024)<1024)
223 : snprintf(units, sizeof(units), "TB");
224 0 : else if((div/=1024)<1024)
225 : snprintf(units, sizeof(units), "EB");
226 : else
227 : {
228 0 : div/=1024;
229 : 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 0 : 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 25 : 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 5 : return incr_count_val(cntr, ch, 1);
317 : }
318 :
319 : static void incr_same(struct cntr *cntr, char ch)
320 : {
321 37878 : return incr_same_val(cntr, ch, 1);
322 : }
323 :
324 : static void incr_changed(struct cntr *cntr, char ch)
325 : {
326 12 : return incr_changed_val(cntr, ch, 1);
327 : }
328 :
329 : static void incr_deleted(struct cntr *cntr, char ch)
330 : {
331 6 : 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 42393 : void cntr_add(struct cntr *c, char ch, int print)
345 : {
346 : struct cntr_ent *grand_total_ent;
347 42393 : 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 : incr_changed(c, CMD_FILE);
357 : incr_changed(c, CMD_TOTAL);
358 : incr_changed(c, CMD_GRAND_TOTAL);
359 : }
360 : else
361 : {
362 5 : 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 12626 : incr_same(c, ch);
400 : incr_same(c, CMD_TOTAL);
401 : 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 : incr_same_val(c, CMD_TOTAL, val);
408 : incr_same_val(c, CMD_GRAND_TOTAL, val);
409 0 : }
410 :
411 4 : void cntr_add_changed(struct cntr *c, char ch)
412 : {
413 4 : incr_changed(c, ch);
414 : incr_changed(c, CMD_TOTAL);
415 : 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 : incr_changed_val(c, CMD_TOTAL, val);
422 : incr_changed_val(c, CMD_GRAND_TOTAL, val);
423 0 : }
424 :
425 2 : void cntr_add_deleted(struct cntr *c, char ch)
426 : {
427 2 : incr_deleted(c, ch);
428 : incr_deleted(c, CMD_TOTAL);
429 : incr_deleted(c, CMD_GRAND_TOTAL);
430 2 : }
431 :
432 20 : void cntr_add_bytes(struct cntr *c, uint64_t bytes)
433 : {
434 : incr_count_val(c, CMD_BYTES, bytes);
435 20 : }
436 :
437 : static void cntr_set_sentbytes(struct cntr *c, uint64_t bytes)
438 : {
439 : 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 0 : static void quint_print(struct cntr_ent *ent, enum action act)
448 : {
449 : uint64_t a;
450 : uint64_t b;
451 : uint64_t c;
452 : uint64_t d;
453 : uint64_t e;
454 0 : if(!ent) return;
455 0 : a=ent->count;
456 0 : b=ent->changed;
457 0 : c=ent->same;
458 0 : d=ent->deleted;
459 0 : e=ent->phase1;
460 :
461 0 : if(!(ent->flags & CNTR_TABULATE)) return;
462 :
463 0 : if(!e && !a && !b && !c) return;
464 0 : logc("%18s:", ent->label);
465 0 : if(act==ACTION_BACKUP
466 0 : || act==ACTION_BACKUP_TIMED)
467 : {
468 0 : logc("%9" PRIu64 " ", a);
469 0 : logc("%9" PRIu64 " ", b);
470 0 : logc("%9" PRIu64 " ", c);
471 0 : logc("%9" PRIu64 " ", d);
472 : }
473 0 : if(act==ACTION_RESTORE
474 0 : || act==ACTION_VERIFY)
475 : {
476 0 : logc("%9s ", "");
477 : //logc("%9s ", "");
478 : //logc("%9s ", "");
479 : //logc("%9s ", "");
480 : }
481 0 : if(act==ACTION_ESTIMATE)
482 : {
483 0 : logc("%9s ", "");
484 0 : logc("%9s ", "");
485 0 : logc("%9" PRIu64 "\n", e);
486 : }
487 : else
488 : {
489 0 : logc("%9" PRIu64 " |", a+b+c);
490 0 : logc("%9" PRIu64 "\n", e);
491 : }
492 : }
493 :
494 : static uint64_t get_count(struct cntr_ent **ent, enum cmd cmd)
495 : {
496 0 : if(!ent[(uint8_t)cmd]) return 0;
497 0 : return ent[(uint8_t)cmd]->count;
498 : }
499 :
500 0 : static void bottom_part(struct cntr *c, enum action act)
501 : {
502 : uint64_t l;
503 0 : struct cntr_ent **e=c->ent;
504 0 : logc("\n");
505 0 : logc(" Messages: %11" PRIu64 "\n", get_count(e, CMD_MESSAGE));
506 0 : logc(" Warnings: %11" PRIu64 "\n", get_count(e, CMD_WARNING));
507 0 : logc("\n");
508 0 : logc(" Bytes estimated: %11" PRIu64, get_count(e, CMD_BYTES_ESTIMATED));
509 0 : logc("%s\n", bytes_to_human(get_count(e, CMD_BYTES_ESTIMATED)));
510 :
511 0 : if(act==ACTION_ESTIMATE) return;
512 :
513 0 : if(act==ACTION_BACKUP
514 0 : || act==ACTION_BACKUP_TIMED)
515 : {
516 0 : l=get_count(e, CMD_BYTES);
517 0 : logc(" Bytes in backup: %11" PRIu64, l);
518 0 : logc("%s\n", bytes_to_human(l));
519 : }
520 0 : if(act==ACTION_RESTORE)
521 : {
522 0 : l=get_count(e, CMD_BYTES);
523 0 : logc(" Bytes attempted: %11" PRIu64, l);
524 0 : logc("%s\n", bytes_to_human(l));
525 : }
526 0 : if(act==ACTION_VERIFY)
527 : {
528 0 : l=get_count(e, CMD_BYTES);
529 0 : logc(" Bytes checked: %11" PRIu64, l);
530 0 : logc("%s\n", bytes_to_human(l));
531 : }
532 :
533 0 : l=get_count(e, CMD_BYTES_RECV);
534 0 : logc(" Bytes received: %11" PRIu64, l);
535 0 : logc("%s\n", bytes_to_human(l));
536 :
537 0 : l=get_count(e, CMD_BYTES_SENT);
538 0 : logc(" Bytes sent: %11" PRIu64, l);
539 0 : logc("%s\n", bytes_to_human(l));
540 : }
541 :
542 28 : void cntr_print(struct cntr *cntr, enum action act, struct asfd *asfd)
543 : {
544 : struct cntr_ent *e;
545 : time_t now;
546 : time_t start;
547 : char time_start_str[32];
548 : char time_end_str[32];
549 56 : if(!cntr) return;
550 :
551 0 : if(asfd)
552 : {
553 0 : cntr_set_sentbytes(cntr, asfd->sent);
554 0 : cntr_set_recvbytes(cntr, asfd->rcvd);
555 : }
556 0 : now=time(NULL);
557 0 : start=(time_t)cntr->ent[(uint8_t)CMD_TIMESTAMP]->count;
558 0 : cntr->ent[(uint8_t)CMD_TIMESTAMP_END]->count=(uint64_t)now;
559 :
560 : border();
561 0 : encode_time(start, time_start_str);
562 0 : encode_time(now, time_end_str);
563 0 : logc("Start time: %s\n", time_start_str);
564 0 : logc(" End time: %s\n", time_end_str);
565 0 : logc("Time taken: %s\n", time_taken(now-start));
566 0 : if(act==ACTION_BACKUP
567 0 : || act==ACTION_BACKUP_TIMED)
568 : {
569 0 : logc("%18s %9s %9s %9s %9s %9s |%9s\n",
570 : " ", "New", "Changed", "Duplicate", "Deleted", "Total", "Scanned");
571 : }
572 0 : if(act==ACTION_RESTORE
573 0 : || act==ACTION_VERIFY)
574 : {
575 0 : logc("%18s %9s %9s |%9s\n",
576 : " ", "", "Attempted", "Expected");
577 : }
578 0 : if(act==ACTION_ESTIMATE)
579 : {
580 0 : logc("%18s %9s %9s %9s\n",
581 : " ", "", "", "Scanned");
582 : }
583 0 : table_border(act);
584 :
585 0 : for(e=cntr->list; e; e=e->next)
586 0 : quint_print(e, act);
587 :
588 0 : table_border(act);
589 0 : bottom_part(cntr, act);
590 :
591 : border();
592 : }
593 :
594 : #ifndef HAVE_WIN32
595 :
596 6 : int cntr_stats_to_file(struct cntr *cntr,
597 : const char *directory, enum action act)
598 : {
599 6 : int ret=-1;
600 6 : int fd=-1;
601 6 : char *path=NULL;
602 6 : const char *fname=NULL;
603 6 : struct async *as=NULL;
604 6 : struct asfd *wfd=NULL;
605 6 : if(!cntr)
606 : return 0;
607 0 : cntr->ent[(uint8_t)CMD_TIMESTAMP_END]->count
608 0 : =(uint64_t)time(NULL);
609 :
610 0 : if(act==ACTION_BACKUP
611 0 : || act==ACTION_BACKUP_TIMED)
612 : fname="backup_stats";
613 0 : else if(act==ACTION_RESTORE)
614 : fname="restore_stats";
615 0 : else if(act==ACTION_VERIFY)
616 : fname="verify_stats";
617 : else
618 : return 0;
619 :
620 0 : if(!(path=prepend_s(directory, fname)))
621 : goto end;
622 0 : if((fd=open(path, O_WRONLY|O_CREAT, 0666))<0)
623 : {
624 0 : logp("Could not open %s for writing in %s: %s\n",
625 0 : path, __func__, strerror(errno));
626 0 : goto end;
627 : }
628 :
629 0 : if(!(as=async_alloc())
630 0 : || as->init(as, 0)
631 0 : || !(wfd=setup_asfd_linebuf_write(as, "stats file", &fd)))
632 : goto end;
633 :
634 0 : if(json_cntr(wfd, cntr))
635 : goto end;
636 :
637 0 : ret=0;
638 : end:
639 0 : close_fd(&fd);
640 0 : free_w(&path);
641 0 : async_free(&as);
642 0 : asfd_free(&wfd);
643 0 : return ret;
644 : }
645 :
646 : #endif
647 :
648 22 : void cntr_print_end(struct cntr *cntr)
649 : {
650 : struct cntr_ent *grand_total_ent;
651 44 : if(!cntr) return;
652 0 : grand_total_ent=cntr->ent[CMD_GRAND_TOTAL];
653 0 : if(grand_total_ent)
654 : {
655 0 : print_end(grand_total_ent->count);
656 0 : logc("\n");
657 : }
658 : }
659 :
660 0 : void cntr_print_end_phase1(struct cntr *cntr)
661 : {
662 : struct cntr_ent *grand_total_ent;
663 0 : if(!cntr) return;
664 0 : grand_total_ent=cntr->ent[CMD_GRAND_TOTAL];
665 0 : if(grand_total_ent)
666 : {
667 0 : print_end(grand_total_ent->phase1);
668 0 : logc("\n");
669 : }
670 : }
671 :
672 : #ifndef HAVE_WIN32
673 : // Return string length.
674 0 : size_t cntr_to_str(struct cntr *cntr, const char *path)
675 : {
676 : static char tmp[CNTR_PATH_BUF_LEN+3]="";
677 0 : struct cntr_ent *e=NULL;
678 0 : char *str=cntr->str;
679 :
680 0 : cntr->ent[(uint8_t)CMD_TIMESTAMP_END]->count=time(NULL);
681 :
682 0 : snprintf(str, cntr->str_max_len-1, "cntr\t%s.%d.%d\t%d\t%d\t",
683 : cntr->cname, cntr->pid, cntr->bno,
684 0 : CNTR_VERSION, cntr->cntr_status);
685 :
686 0 : for(e=cntr->list; e; e=e->next)
687 : {
688 0 : if(e->flags & CNTR_SINGLE_FIELD)
689 0 : snprintf(tmp, sizeof(tmp),
690 0 : "%c%" PRIu64"\t", e->cmd, e->count);
691 : else
692 0 : snprintf(tmp, sizeof(tmp),
693 : "%c%" PRIu64
694 : "/%" PRIu64
695 : "/%" PRIu64
696 : "/%" PRIu64
697 : "/%" PRIu64
698 : "\t",
699 0 : e->cmd, e->count, e->changed,
700 : e->same, e->deleted, e->phase1);
701 : strcat(str, tmp);
702 : }
703 :
704 : // Abuse CMD_DATAPTH.
705 0 : snprintf(tmp, sizeof(tmp), "%c%s\t\n", CMD_DATAPTH, path?path:"");
706 : strcat(str, tmp);
707 :
708 0 : return strlen(str);
709 : }
710 : #endif
711 :
712 0 : static int extract_ul(const char *value, struct cntr_ent *ent)
713 : {
714 0 : char *as=NULL;
715 0 : char *bs=NULL;
716 0 : char *cs=NULL;
717 0 : char *ds=NULL;
718 0 : char *es=NULL;
719 0 : char *copy=NULL;
720 0 : if(!value || !(copy=strdup_w(value, __func__))) return -1;
721 :
722 : // Do not want to use strtok, just in case I end up running more
723 : // than one at a time.
724 0 : as=copy;
725 0 : if((bs=strchr(as, '/')))
726 : {
727 0 : *bs='\0';
728 0 : ent->count=strtoull(as, NULL, 10);
729 0 : if((cs=strchr(++bs, '/')))
730 : {
731 0 : *cs='\0';
732 0 : ent->changed=strtoull(bs, NULL, 10);
733 0 : if((ds=strchr(++cs, '/')))
734 : {
735 0 : *ds='\0';
736 0 : ent->same=strtoull(cs, NULL, 10);
737 0 : if((es=strchr(++ds, '/')))
738 : {
739 0 : ent->deleted=strtoull(ds, NULL, 10);
740 0 : *es='\0';
741 0 : es++;
742 0 : ent->phase1=strtoull(es, NULL, 10);
743 : }
744 : }
745 : }
746 : }
747 : else
748 : {
749 : // Single field.
750 0 : ent->count=strtoull(as, NULL, 10);
751 : }
752 0 : free_w(©);
753 0 : return 0;
754 : }
755 :
756 : /*
757 : static char *get_backup_str(const char *s, int *deletable)
758 : {
759 : static char str[32]="";
760 : const char *cp=NULL;
761 : const char *dp=NULL;
762 : if(!s || !*s) return NULL;
763 : if(!(cp=strchr(s, ' '))
764 : || !(dp=strchr(cp+1, ' ')))
765 : snprintf(str, sizeof(str), "never");
766 : else
767 : {
768 : uint64_t backupnum=0;
769 : backupnum=strtoul(s, NULL, 10);
770 : snprintf(str, sizeof(str),
771 : "%07lu %s", backupnum, getdatestr(atol(dp+1)));
772 : if(*(cp+1)=='1') *deletable=1;
773 : }
774 : return str;
775 : }
776 : */
777 :
778 : /*
779 : static int add_to_backup_list(struct strlist **backups, const char *tok)
780 : {
781 : int deletable=0;
782 : const char *str=NULL;
783 : if(!(str=get_backup_str(tok, &deletable))) return 0;
784 : if(strlist_add(backups, (char *)str, deletable)) return -1;
785 : return 0;
786 : }
787 : */
788 :
789 0 : static int extract_cntrs(struct cntr *cntr, char **path)
790 : {
791 : char *tok;
792 0 : while((tok=strtok(NULL, "\t\n")))
793 : {
794 0 : switch(tok[0])
795 : {
796 : case CMD_DATAPTH:
797 0 : free_w(path);
798 0 : if(!(*path=strdup_w(tok+1, __func__)))
799 : return -1;
800 : break;
801 : default:
802 0 : if(cntr->ent[(uint8_t)tok[0]]
803 0 : && extract_ul(tok+1,
804 : cntr->ent[(uint8_t)tok[0]]))
805 : return -1;
806 : break;
807 : }
808 : }
809 : return 0;
810 : }
811 :
812 9 : int extract_client_pid_bno(char *buf, char **cname, pid_t *pid, int *bno)
813 : {
814 9 : char *cp=NULL;
815 9 : char *pp=NULL;
816 :
817 : // Extract the client name.
818 9 : if((cp=strchr(buf, '\t')))
819 3 : *cp='\0';
820 9 : if(!(*cname=strdup_w(buf, __func__)))
821 : return -1;
822 9 : if(cp)
823 3 : *cp='\t';
824 :
825 : // Extract the bno.
826 9 : if((pp=strrchr(*cname, '.')))
827 : {
828 4 : *pp='\0';
829 8 : *bno=(int)atoi(pp+1);
830 : // Extract the pid.
831 4 : if((pp=strrchr(*cname, '.')))
832 : {
833 0 : *pp='\0';
834 0 : *pid=(pid_t)atoi(pp+1);
835 : }
836 : }
837 : return 0;
838 : }
839 :
840 1 : int str_to_cntr(const char *str, struct cntr *cntr, char **path)
841 : {
842 1 : int ret=-1;
843 1 : char *tok=NULL;
844 1 : char *copy=NULL;
845 :
846 1 : if(!(copy=strdup_w(str, __func__)))
847 : return -1;
848 :
849 1 : if((tok=strtok(copy, "\t\n")))
850 : {
851 1 : int bno=0;
852 1 : pid_t pid=-1;
853 1 : char *tmp=NULL;
854 1 : char *cname=NULL;
855 : // First token is 'cntr'.
856 : // Second is client name/pid/bno.
857 1 : if(!(tmp=strtok(NULL, "\t\n")))
858 : {
859 0 : logp("Parsing problem in %s: null client\n",
860 : __func__);
861 0 : goto end;
862 : }
863 1 : if(extract_client_pid_bno(tmp, &cname, &pid, &bno))
864 : goto end;
865 1 : free_w(&cname);
866 1 : cntr->pid=pid;
867 1 : cntr->bno=bno;
868 : // Third is the cntr version.
869 1 : if(!(tmp=strtok(NULL, "\t\n")))
870 : {
871 0 : logp("Parsing problem in %s: null version\n",
872 : __func__);
873 0 : goto end;
874 : }
875 1 : if(atoi(tmp)!=CNTR_VERSION)
876 : {
877 : ret=0;
878 : goto end;
879 : }
880 : // Fourth is cntr_status.
881 0 : if(!(tmp=strtok(NULL, "\t\n")))
882 : {
883 0 : logp("Parsing problem in %s: null cntr_status\n",
884 : __func__);
885 0 : goto end;
886 : }
887 0 : cntr->cntr_status=(enum cntr_status)atoi(tmp);
888 :
889 0 : if(extract_cntrs(cntr, path)) goto end;
890 : }
891 :
892 : ret=0;
893 : end:
894 1 : free_w(©);
895 1 : return ret;
896 : }
897 :
898 : #ifndef HAVE_WIN32
899 6 : int cntr_send_bu(struct asfd *asfd, struct bu *bu, struct conf **confs,
900 : enum cntr_status cntr_status)
901 : {
902 6 : int ret=-1;
903 : uint16_t flags;
904 6 : struct cstat *clist=NULL;
905 6 : struct cstat *cstat=NULL;
906 :
907 6 : if(!get_int(confs[OPT_SEND_CLIENT_CNTR]))
908 : return 0;
909 :
910 0 : flags=bu->flags;
911 :
912 : // Want to setup a cstat and a bu so that we can piggy-back on the
913 : // status monitor cntr json code.
914 :
915 0 : if(!(cstat=cstat_alloc())
916 0 : || cstat_init(cstat,
917 0 : get_string(confs[OPT_CNAME]), NULL/*clientconfdir*/))
918 : goto end;
919 0 : cstat->cntrs=get_cntr(confs);
920 0 : cstat->protocol=get_protocol(confs);
921 0 : cstat->cntrs->cntr_status=cntr_status;
922 0 : cstat->run_status=RUN_STATUS_RUNNING;
923 :
924 : // Hacky provocation to get the json stuff to send counters in the
925 : // case where we are actually doing a restore.
926 0 : bu->flags|=BU_WORKING;
927 0 : cstat->bu=bu;
928 :
929 0 : clist=cstat;
930 :
931 0 : ret=json_send(asfd,
932 : clist,
933 : cstat,
934 : bu,
935 : NULL /* logfile */,
936 : NULL /* browse */,
937 : 0 /* use_cache */,
938 0 : version_to_long(get_string(confs[OPT_PEER_VERSION])));
939 : end:
940 0 : cstat->bu=NULL; // 'bu' was not ours to mess with.
941 0 : cstat->cntrs=NULL; // 'cntrs' was not ours to mess with.
942 0 : bu->flags=flags; // Set flags back to what the were before.
943 0 : cstat_free(&cstat);
944 0 : return ret;
945 : }
946 :
947 0 : int cntr_send_sdirs(struct asfd *asfd,
948 : struct sdirs *sdirs, struct conf **confs, enum cntr_status cntr_status)
949 : {
950 0 : int ret=-1;
951 0 : struct bu *bu=NULL;
952 0 : struct bu *bu_list=NULL;
953 :
954 : // FIX THIS:
955 : // It would be better just to set up the correct 'bu' entry instead
956 : // of loading everything and then looking through the list.
957 0 : if(bu_get_list_with_working(sdirs, &bu_list, NULL))
958 : goto end;
959 0 : for(bu=bu_list; bu; bu=bu->next)
960 0 : if((bu->flags & BU_WORKING)
961 0 : || (bu->flags & BU_FINISHING))
962 : break;
963 0 : if(!bu)
964 : {
965 0 : logp("could not find working or finishing backup in %s\n",
966 : __func__);
967 0 : goto end;
968 : }
969 0 : ret=cntr_send_bu(asfd, bu, confs, cntr_status);
970 : end:
971 0 : bu_list_free(&bu_list);
972 0 : return ret;
973 : }
974 : #endif
975 :
976 0 : static enum asl_ret cntr_recv_func(struct asfd *asfd,
977 : struct conf **confs,
978 : void *param)
979 : {
980 0 : struct sel *sel=(struct sel *)param;
981 0 : switch(json_input(asfd, sel))
982 : {
983 : case 0: return ASL_CONTINUE;
984 : case 1:
985 0 : case 2: return ASL_END_OK;
986 0 : default: return ASL_END_ERROR;
987 : }
988 : }
989 :
990 8 : int cntr_recv(struct asfd *asfd, struct conf **confs)
991 : {
992 8 : int ret=-1;
993 8 : struct sel *sel=NULL;
994 : struct cntr_ent *e;
995 8 : struct cntr *cntr=get_cntr(confs);
996 :
997 8 : if(!(sel=sel_alloc()))
998 : goto end;
999 8 : if(!get_int(confs[OPT_SEND_CLIENT_CNTR]))
1000 : goto ok;
1001 0 : if(json_input_init())
1002 : goto end;
1003 0 : if(asfd->simple_loop(asfd, confs, sel, __func__, cntr_recv_func)
1004 0 : || !sel->clist || !sel->clist->cntrs)
1005 : goto end;
1006 0 : for(e=sel->clist->cntrs->list; e; e=e->next)
1007 : {
1008 0 : set_count_val(cntr, e->cmd, e->count);
1009 0 : set_changed_val(cntr, e->cmd, e->changed);
1010 0 : set_same_val(cntr, e->cmd, e->same);
1011 0 : set_deleted_val(cntr, e->cmd, e->deleted);
1012 0 : set_phase1_val(cntr, e->cmd, e->phase1);
1013 : }
1014 : ok:
1015 : ret=0;
1016 : end:
1017 8 : json_input_free();
1018 8 : sel_free(&sel);
1019 8 : return ret;
1020 : }
1021 :
1022 0 : const char *cntr_status_to_str(struct cntr *cntr)
1023 : {
1024 0 : switch(cntr->cntr_status)
1025 : {
1026 : case CNTR_STATUS_SCANNING: return CNTR_STATUS_STR_SCANNING;
1027 : case CNTR_STATUS_BACKUP: return CNTR_STATUS_STR_BACKUP;
1028 : case CNTR_STATUS_MERGING: return CNTR_STATUS_STR_MERGING;
1029 : case CNTR_STATUS_SHUFFLING: return CNTR_STATUS_STR_SHUFFLING;
1030 : case CNTR_STATUS_LISTING: return CNTR_STATUS_STR_LISTING;
1031 : case CNTR_STATUS_RESTORING: return CNTR_STATUS_STR_RESTORING;
1032 : case CNTR_STATUS_VERIFYING: return CNTR_STATUS_STR_VERIFYING;
1033 : case CNTR_STATUS_DELETING: return CNTR_STATUS_STR_DELETING;
1034 : case CNTR_STATUS_DIFFING: return CNTR_STATUS_STR_DIFFING;
1035 : default: return "unknown";
1036 : }
1037 : }
1038 :
1039 0 : enum cntr_status cntr_str_to_status(const char *str)
1040 : {
1041 0 : if(!strcmp(str, CNTR_STATUS_STR_SCANNING))
1042 : return CNTR_STATUS_SCANNING;
1043 0 : else if(!strcmp(str, CNTR_STATUS_STR_BACKUP))
1044 : return CNTR_STATUS_BACKUP;
1045 0 : else if(!strcmp(str, CNTR_STATUS_STR_MERGING))
1046 : return CNTR_STATUS_MERGING;
1047 0 : else if(!strcmp(str, CNTR_STATUS_STR_SHUFFLING))
1048 : return CNTR_STATUS_SHUFFLING;
1049 0 : else if(!strcmp(str, CNTR_STATUS_STR_LISTING))
1050 : return CNTR_STATUS_LISTING;
1051 0 : else if(!strcmp(str, CNTR_STATUS_STR_RESTORING))
1052 : return CNTR_STATUS_RESTORING;
1053 0 : else if(!strcmp(str, CNTR_STATUS_STR_VERIFYING))
1054 : return CNTR_STATUS_VERIFYING;
1055 0 : else if(!strcmp(str, CNTR_STATUS_STR_DELETING))
1056 : return CNTR_STATUS_DELETING;
1057 0 : else if(!strcmp(str, CNTR_STATUS_STR_DIFFING))
1058 : return CNTR_STATUS_DIFFING;
1059 0 : return CNTR_STATUS_UNSET;
1060 : }
1061 :
1062 0 : const char *cntr_status_to_action_str(struct cntr *cntr)
1063 : {
1064 0 : switch(cntr->cntr_status)
1065 : {
1066 : case CNTR_STATUS_SCANNING:
1067 : case CNTR_STATUS_BACKUP:
1068 : case CNTR_STATUS_MERGING:
1069 : case CNTR_STATUS_SHUFFLING:
1070 : return "backup";
1071 : case CNTR_STATUS_LISTING:
1072 : return "list";
1073 : case CNTR_STATUS_RESTORING:
1074 : return "restore";
1075 : case CNTR_STATUS_VERIFYING:
1076 : return "verify";
1077 : case CNTR_STATUS_DELETING:
1078 : return "delete";
1079 : case CNTR_STATUS_DIFFING:
1080 : return "diff";
1081 : default:
1082 : return "unknown";
1083 : }
1084 : }
|