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