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 353 : void cntr_free(struct cntr **cntr)
187 : {
188 353 : 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 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 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 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 0 : 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 29 : 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 58 : 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 7 : int cntr_stats_to_file(struct cntr *cntr,
597 : const char *directory, enum action act)
598 : {
599 7 : int ret=-1;
600 7 : int fd=-1;
601 7 : char *path=NULL;
602 7 : const char *fname=NULL;
603 7 : struct async *as=NULL;
604 7 : struct asfd *wfd=NULL;
605 7 : 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 : {
633 0 : close_fd(&fd);
634 0 : goto end;
635 : }
636 :
637 0 : if(json_cntr(wfd, cntr))
638 : goto end;
639 :
640 0 : ret=0;
641 : end:
642 0 : free_w(&path);
643 0 : async_free(&as);
644 0 : asfd_free(&wfd);
645 0 : return ret;
646 : }
647 :
648 : #endif
649 :
650 22 : void cntr_print_end(struct cntr *cntr)
651 : {
652 : struct cntr_ent *grand_total_ent;
653 22 : if(!cntr) return;
654 0 : grand_total_ent=cntr->ent[CMD_GRAND_TOTAL];
655 0 : if(grand_total_ent)
656 : {
657 0 : print_end(grand_total_ent->count);
658 0 : logc("\n");
659 : }
660 : }
661 :
662 0 : void cntr_print_end_phase1(struct cntr *cntr)
663 : {
664 : struct cntr_ent *grand_total_ent;
665 0 : if(!cntr) return;
666 0 : grand_total_ent=cntr->ent[CMD_GRAND_TOTAL];
667 0 : if(grand_total_ent)
668 : {
669 0 : print_end(grand_total_ent->phase1);
670 0 : logc("\n");
671 : }
672 : }
673 :
674 : #ifndef HAVE_WIN32
675 : // Return string length.
676 0 : size_t cntr_to_str(struct cntr *cntr, const char *path)
677 : {
678 : static char tmp[CNTR_PATH_BUF_LEN+3]="";
679 0 : struct cntr_ent *e=NULL;
680 0 : char *str=cntr->str;
681 :
682 0 : cntr->ent[(uint8_t)CMD_TIMESTAMP_END]->count=time(NULL);
683 :
684 0 : snprintf(str, cntr->str_max_len-1, "cntr\t%s.%d.%d\t%d\t%d\t",
685 : cntr->cname, cntr->pid, cntr->bno,
686 0 : CNTR_VERSION, cntr->cntr_status);
687 :
688 0 : for(e=cntr->list; e; e=e->next)
689 : {
690 0 : if(e->flags & CNTR_SINGLE_FIELD)
691 0 : snprintf(tmp, sizeof(tmp),
692 0 : "%c%" PRIu64"\t", e->cmd, e->count);
693 : else
694 0 : snprintf(tmp, sizeof(tmp),
695 : "%c%" PRIu64
696 : "/%" PRIu64
697 : "/%" PRIu64
698 : "/%" PRIu64
699 : "/%" PRIu64
700 : "\t",
701 0 : e->cmd, e->count, e->changed,
702 : e->same, e->deleted, e->phase1);
703 0 : strcat(str, tmp);
704 : }
705 :
706 : // Abuse CMD_DATAPTH.
707 0 : snprintf(tmp, sizeof(tmp), "%c%s\t\n", CMD_DATAPTH, path?path:"");
708 0 : strcat(str, tmp);
709 :
710 0 : return strlen(str);
711 : }
712 : #endif
713 :
714 0 : static int extract_ul(const char *value, struct cntr_ent *ent)
715 : {
716 0 : char *as=NULL;
717 0 : char *bs=NULL;
718 0 : char *cs=NULL;
719 0 : char *ds=NULL;
720 0 : char *es=NULL;
721 0 : char *copy=NULL;
722 0 : if(!value || !(copy=strdup_w(value, __func__))) return -1;
723 :
724 : // Do not want to use strtok, just in case I end up running more
725 : // than one at a time.
726 0 : as=copy;
727 0 : if((bs=strchr(as, '/')))
728 : {
729 0 : *bs='\0';
730 0 : ent->count=strtoull(as, NULL, 10);
731 0 : if((cs=strchr(++bs, '/')))
732 : {
733 0 : *cs='\0';
734 0 : ent->changed=strtoull(bs, NULL, 10);
735 0 : if((ds=strchr(++cs, '/')))
736 : {
737 0 : *ds='\0';
738 0 : ent->same=strtoull(cs, NULL, 10);
739 0 : if((es=strchr(++ds, '/')))
740 : {
741 0 : ent->deleted=strtoull(ds, NULL, 10);
742 0 : *es='\0';
743 0 : es++;
744 0 : ent->phase1=strtoull(es, NULL, 10);
745 : }
746 : }
747 : }
748 : }
749 : else
750 : {
751 : // Single field.
752 0 : ent->count=strtoull(as, NULL, 10);
753 : }
754 0 : free_w(©);
755 0 : return 0;
756 : }
757 :
758 : /*
759 : static char *get_backup_str(const char *s, int *deletable)
760 : {
761 : static char str[32]="";
762 : const char *cp=NULL;
763 : const char *dp=NULL;
764 : if(!s || !*s) return NULL;
765 : if(!(cp=strchr(s, ' '))
766 : || !(dp=strchr(cp+1, ' ')))
767 : snprintf(str, sizeof(str), "never");
768 : else
769 : {
770 : uint64_t backupnum=0;
771 : backupnum=strtoul(s, NULL, 10);
772 : snprintf(str, sizeof(str),
773 : "%07lu %s", backupnum, getdatestr(atol(dp+1)));
774 : if(*(cp+1)=='1') *deletable=1;
775 : }
776 : return str;
777 : }
778 : */
779 :
780 : /*
781 : static int add_to_backup_list(struct strlist **backups, const char *tok)
782 : {
783 : int deletable=0;
784 : const char *str=NULL;
785 : if(!(str=get_backup_str(tok, &deletable))) return 0;
786 : if(strlist_add(backups, (char *)str, deletable)) return -1;
787 : return 0;
788 : }
789 : */
790 :
791 0 : static int extract_cntrs(struct cntr *cntr, char **path)
792 : {
793 : char *tok;
794 0 : while((tok=strtok(NULL, "\t\n")))
795 : {
796 0 : switch(tok[0])
797 : {
798 : case CMD_DATAPTH:
799 0 : free_w(path);
800 0 : if(!(*path=strdup_w(tok+1, __func__)))
801 : return -1;
802 : break;
803 : default:
804 0 : if(cntr->ent[(uint8_t)tok[0]]
805 0 : && extract_ul(tok+1,
806 : cntr->ent[(uint8_t)tok[0]]))
807 : return -1;
808 : break;
809 : }
810 : }
811 : return 0;
812 : }
813 :
814 9 : int extract_client_pid_bno(char *buf, char **cname, pid_t *pid, int *bno)
815 : {
816 9 : char *cp=NULL;
817 9 : char *pp=NULL;
818 :
819 : // Extract the client name.
820 9 : if((cp=strchr(buf, '\t')))
821 3 : *cp='\0';
822 9 : if(!(*cname=strdup_w(buf, __func__)))
823 : return -1;
824 9 : if(cp)
825 3 : *cp='\t';
826 :
827 : // Extract the bno.
828 9 : if((pp=strrchr(*cname, '.')))
829 : {
830 4 : *pp='\0';
831 8 : *bno=(int)atoi(pp+1);
832 : // Extract the pid.
833 4 : if((pp=strrchr(*cname, '.')))
834 : {
835 0 : *pp='\0';
836 0 : *pid=(pid_t)atoi(pp+1);
837 : }
838 : }
839 : return 0;
840 : }
841 :
842 1 : int str_to_cntr(const char *str, struct cntr *cntr, char **path)
843 : {
844 1 : int ret=-1;
845 1 : char *tok=NULL;
846 1 : char *copy=NULL;
847 :
848 1 : if(!(copy=strdup_w(str, __func__)))
849 : return -1;
850 :
851 1 : if((tok=strtok(copy, "\t\n")))
852 : {
853 1 : int bno=0;
854 1 : pid_t pid=-1;
855 1 : char *tmp=NULL;
856 1 : char *cname=NULL;
857 : // First token is 'cntr'.
858 : // Second is client name/pid/bno.
859 1 : if(!(tmp=strtok(NULL, "\t\n")))
860 : {
861 0 : logp("Parsing problem in %s: null client\n",
862 : __func__);
863 0 : goto end;
864 : }
865 1 : if(extract_client_pid_bno(tmp, &cname, &pid, &bno))
866 : goto end;
867 1 : free_w(&cname);
868 1 : cntr->pid=pid;
869 1 : cntr->bno=bno;
870 : // Third is the cntr version.
871 1 : if(!(tmp=strtok(NULL, "\t\n")))
872 : {
873 0 : logp("Parsing problem in %s: null version\n",
874 : __func__);
875 0 : goto end;
876 : }
877 1 : if(atoi(tmp)!=CNTR_VERSION)
878 : {
879 : ret=0;
880 : goto end;
881 : }
882 : // Fourth is cntr_status.
883 0 : if(!(tmp=strtok(NULL, "\t\n")))
884 : {
885 0 : logp("Parsing problem in %s: null cntr_status\n",
886 : __func__);
887 0 : goto end;
888 : }
889 0 : cntr->cntr_status=(enum cntr_status)atoi(tmp);
890 :
891 0 : if(extract_cntrs(cntr, path)) goto end;
892 : }
893 :
894 : ret=0;
895 : end:
896 1 : free_w(©);
897 1 : return ret;
898 : }
899 :
900 : #ifndef HAVE_WIN32
901 7 : int cntr_send_bu(struct asfd *asfd, struct bu *bu, struct conf **confs,
902 : enum cntr_status cntr_status)
903 : {
904 7 : int ret=-1;
905 : uint16_t flags;
906 7 : struct cstat *clist=NULL;
907 7 : struct cstat *cstat=NULL;
908 :
909 7 : if(!get_int(confs[OPT_SEND_CLIENT_CNTR]))
910 : return 0;
911 :
912 0 : flags=bu->flags;
913 :
914 : // Want to setup a cstat and a bu so that we can piggy-back on the
915 : // status monitor cntr json code.
916 :
917 0 : if(!(cstat=cstat_alloc())
918 0 : || cstat_init(cstat,
919 0 : get_string(confs[OPT_CNAME]), NULL/*clientconfdir*/))
920 : goto end;
921 0 : cstat->cntrs=get_cntr(confs);
922 0 : cstat->protocol=get_protocol(confs);
923 0 : cstat->cntrs->cntr_status=cntr_status;
924 0 : cstat->run_status=RUN_STATUS_RUNNING;
925 :
926 : // Hacky provocation to get the json stuff to send counters in the
927 : // case where we are actually doing a restore.
928 0 : bu->flags|=BU_WORKING;
929 0 : cstat->bu=bu;
930 :
931 0 : clist=cstat;
932 :
933 0 : ret=json_send(asfd,
934 : clist,
935 : cstat,
936 : bu,
937 : NULL /* logfile */,
938 : NULL /* browse */,
939 : 0 /* use_cache */,
940 0 : version_to_long(get_string(confs[OPT_PEER_VERSION])));
941 : end:
942 0 : cstat->bu=NULL; // 'bu' was not ours to mess with.
943 0 : cstat->cntrs=NULL; // 'cntrs' was not ours to mess with.
944 0 : bu->flags=flags; // Set flags back to what the were before.
945 0 : cstat_free(&cstat);
946 0 : return ret;
947 : }
948 :
949 0 : int cntr_send_sdirs(struct asfd *asfd,
950 : struct sdirs *sdirs, struct conf **confs, enum cntr_status cntr_status)
951 : {
952 0 : int ret=-1;
953 0 : struct bu *bu=NULL;
954 0 : struct bu *bu_list=NULL;
955 :
956 : // FIX THIS:
957 : // It would be better just to set up the correct 'bu' entry instead
958 : // of loading everything and then looking through the list.
959 0 : if(bu_get_list_with_working(sdirs, &bu_list))
960 : goto end;
961 0 : for(bu=bu_list; bu; bu=bu->next)
962 0 : if((bu->flags & BU_WORKING)
963 : || (bu->flags & BU_FINISHING))
964 : break;
965 0 : if(!bu)
966 : {
967 0 : logp("could not find working or finishing backup in %s\n",
968 : __func__);
969 0 : goto end;
970 : }
971 0 : ret=cntr_send_bu(asfd, bu, confs, cntr_status);
972 : end:
973 0 : bu_list_free(&bu_list);
974 0 : return ret;
975 : }
976 : #endif
977 :
978 0 : static enum asl_ret cntr_recv_func(struct asfd *asfd,
979 : struct conf **confs,
980 : void *param)
981 : {
982 0 : struct sel *sel=(struct sel *)param;
983 0 : switch(json_input(asfd, sel))
984 : {
985 : case 0: return ASL_CONTINUE;
986 : case 1:
987 0 : case 2: return ASL_END_OK;
988 0 : default: return ASL_END_ERROR;
989 : }
990 : }
991 :
992 8 : int cntr_recv(struct asfd *asfd, struct conf **confs)
993 : {
994 8 : int ret=-1;
995 8 : struct sel *sel=NULL;
996 : struct cntr_ent *e;
997 8 : struct cntr *cntr=get_cntr(confs);
998 :
999 8 : if(!(sel=sel_alloc()))
1000 : goto end;
1001 8 : if(!get_int(confs[OPT_SEND_CLIENT_CNTR]))
1002 : goto ok;
1003 0 : if(json_input_init())
1004 : goto end;
1005 0 : if(asfd->simple_loop(asfd, confs, sel, __func__, cntr_recv_func)
1006 0 : || !sel->clist || !sel->clist->cntrs)
1007 : goto end;
1008 0 : for(e=sel->clist->cntrs->list; e; e=e->next)
1009 : {
1010 0 : set_count_val(cntr, e->cmd, e->count);
1011 0 : set_changed_val(cntr, e->cmd, e->changed);
1012 0 : set_same_val(cntr, e->cmd, e->same);
1013 0 : set_deleted_val(cntr, e->cmd, e->deleted);
1014 0 : set_phase1_val(cntr, e->cmd, e->phase1);
1015 : }
1016 : ok:
1017 : ret=0;
1018 : end:
1019 8 : json_input_free();
1020 8 : sel_free(&sel);
1021 8 : return ret;
1022 : }
1023 :
1024 0 : const char *cntr_status_to_str(struct cntr *cntr)
1025 : {
1026 0 : switch(cntr->cntr_status)
1027 : {
1028 : case CNTR_STATUS_SCANNING: return CNTR_STATUS_STR_SCANNING;
1029 0 : case CNTR_STATUS_BACKUP: return CNTR_STATUS_STR_BACKUP;
1030 0 : case CNTR_STATUS_MERGING: return CNTR_STATUS_STR_MERGING;
1031 0 : case CNTR_STATUS_SHUFFLING: return CNTR_STATUS_STR_SHUFFLING;
1032 0 : case CNTR_STATUS_LISTING: return CNTR_STATUS_STR_LISTING;
1033 0 : case CNTR_STATUS_RESTORING: return CNTR_STATUS_STR_RESTORING;
1034 0 : case CNTR_STATUS_VERIFYING: return CNTR_STATUS_STR_VERIFYING;
1035 0 : case CNTR_STATUS_DELETING: return CNTR_STATUS_STR_DELETING;
1036 0 : case CNTR_STATUS_DIFFING: return CNTR_STATUS_STR_DIFFING;
1037 0 : default: return "unknown";
1038 : }
1039 : }
1040 :
1041 0 : enum cntr_status cntr_str_to_status(const char *str)
1042 : {
1043 0 : if(!strcmp(str, CNTR_STATUS_STR_SCANNING))
1044 : return CNTR_STATUS_SCANNING;
1045 0 : else if(!strcmp(str, CNTR_STATUS_STR_BACKUP))
1046 : return CNTR_STATUS_BACKUP;
1047 0 : else if(!strcmp(str, CNTR_STATUS_STR_MERGING))
1048 : return CNTR_STATUS_MERGING;
1049 0 : else if(!strcmp(str, CNTR_STATUS_STR_SHUFFLING))
1050 : return CNTR_STATUS_SHUFFLING;
1051 0 : else if(!strcmp(str, CNTR_STATUS_STR_LISTING))
1052 : return CNTR_STATUS_LISTING;
1053 0 : else if(!strcmp(str, CNTR_STATUS_STR_RESTORING))
1054 : return CNTR_STATUS_RESTORING;
1055 0 : else if(!strcmp(str, CNTR_STATUS_STR_VERIFYING))
1056 : return CNTR_STATUS_VERIFYING;
1057 0 : else if(!strcmp(str, CNTR_STATUS_STR_DELETING))
1058 : return CNTR_STATUS_DELETING;
1059 0 : else if(!strcmp(str, CNTR_STATUS_STR_DIFFING))
1060 : return CNTR_STATUS_DIFFING;
1061 0 : return CNTR_STATUS_UNSET;
1062 : }
1063 :
1064 0 : const char *cntr_status_to_action_str(struct cntr *cntr)
1065 : {
1066 0 : switch(cntr->cntr_status)
1067 : {
1068 : case CNTR_STATUS_SCANNING:
1069 : case CNTR_STATUS_BACKUP:
1070 : case CNTR_STATUS_MERGING:
1071 : case CNTR_STATUS_SHUFFLING:
1072 : return "backup";
1073 : case CNTR_STATUS_LISTING:
1074 0 : return "list";
1075 : case CNTR_STATUS_RESTORING:
1076 0 : return "restore";
1077 : case CNTR_STATUS_VERIFYING:
1078 0 : return "verify";
1079 : case CNTR_STATUS_DELETING:
1080 0 : return "delete";
1081 : case CNTR_STATUS_DIFFING:
1082 0 : return "diff";
1083 : default:
1084 0 : return "unknown";
1085 : }
1086 : }
|