]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - repair/progress.c
Fix build when gettext is enabled
[thirdparty/xfsprogs-dev.git] / repair / progress.c
CommitLineData
06fbdda9
MV
1
2#include <libxfs.h>
06fbdda9 3#include "globals.h"
2556c98b 4#include "progress.h"
06fbdda9
MV
5#include "err_protos.h"
6#include <signal.h>
7
8#define ONEMINUTE 60
9#define ONEHOUR (60*ONEMINUTE)
10#define ONEDAY (24*ONEHOUR)
11#define ONEWEEK (7*ONEDAY)
12
13static
14char *rpt_types[] = {
15#define TYPE_INODE 0
97294b22 16 N_("inodes"),
06fbdda9 17#define TYPE_BLOCK 1
97294b22 18 N_("blocks"),
06fbdda9 19#define TYPE_DIR 2
97294b22 20 N_("directories"),
06fbdda9 21#define TYPE_AG 3
97294b22 22 N_("allocation groups"),
06fbdda9 23#define TYPE_AGI_BUCKET 4
97294b22 24 N_("AGI unlinked buckets"),
06fbdda9 25#define TYPE_EXTENTS 5
97294b22 26 N_("extents"),
06fbdda9 27#define TYPE_RTEXTENTS 6
97294b22 28 N_("realtime extents"),
06fbdda9 29#define TYPE_UNLINKED_LIST 7
97294b22 30 N_("unlinked lists")
06fbdda9
MV
31};
32
33
34static
35char *rpt_fmts[] = {
36#define FMT1 0
97294b22 37N_(" - %02d:%02d:%02d: %s - %llu of %llu %s done\n"),
06fbdda9 38#define FMT2 1
97294b22 39N_(" - %02d:%02d:%02d: %s - %llu %s done\n"),
06fbdda9
MV
40};
41
42typedef struct progress_rpt_s {
43 short format;
44 char *msg;
45 char **fmt;
46 char **type;
47} progress_rpt_t;
48
49static
50progress_rpt_t progress_rpt_reports[] = {
97294b22 51{FMT1, N_("scanning filesystem freespace"), /* 0 */
06fbdda9 52 &rpt_fmts[FMT1], &rpt_types[TYPE_AG]},
97294b22 53{FMT1, N_("scanning agi unlinked lists"), /* 1 */
06fbdda9 54 &rpt_fmts[FMT1], &rpt_types[TYPE_AG]},
97294b22 55{FMT2, N_("check uncertain AG inodes"), /* 2 */
06fbdda9 56 &rpt_fmts[FMT2], &rpt_types[TYPE_AGI_BUCKET]},
97294b22 57{FMT1, N_("process known inodes and inode discovery"), /* 3 */
06fbdda9 58 &rpt_fmts[FMT1], &rpt_types[TYPE_INODE]},
97294b22 59{FMT1, N_("process newly discovered inodes"), /* 4 */
06fbdda9 60 &rpt_fmts[FMT1], &rpt_types[TYPE_AG]},
97294b22 61{FMT1, N_("setting up duplicate extent list"), /* 5 */
06fbdda9 62 &rpt_fmts[FMT1], &rpt_types[TYPE_AG]},
97294b22 63{FMT1, N_("initialize realtime bitmap"), /* 6 */
06fbdda9 64 &rpt_fmts[FMT1], &rpt_types[TYPE_BLOCK]},
97294b22 65{FMT1, N_("reset realtime bitmaps"), /* 7 */
06fbdda9 66 &rpt_fmts[FMT1], &rpt_types[TYPE_AG]},
97294b22 67{FMT1, N_("check for inodes claiming duplicate blocks"), /* 8 */
06fbdda9 68 &rpt_fmts[FMT1], &rpt_types[TYPE_INODE]},
97294b22 69{FMT1, N_("rebuild AG headers and trees"), /* 9 */
06fbdda9 70 &rpt_fmts[FMT1], &rpt_types[TYPE_AG]},
97294b22 71{FMT1, N_("traversing filesystem"), /* 10 */
06fbdda9 72 &rpt_fmts[FMT1], &rpt_types[TYPE_AG]},
97294b22 73{FMT2, N_("traversing all unattached subtrees"), /* 11 */
06fbdda9 74 &rpt_fmts[FMT2], &rpt_types[TYPE_DIR]},
97294b22 75{FMT2, N_("moving disconnected inodes to lost+found"), /* 12 */
06fbdda9 76 &rpt_fmts[FMT2], &rpt_types[TYPE_INODE]},
97294b22 77{FMT1, N_("verify and correct link counts"), /* 13 */
06fbdda9 78 &rpt_fmts[FMT1], &rpt_types[TYPE_INODE]},
97294b22 79{FMT1, N_("verify link counts"), /* 14 */
06fbdda9
MV
80 &rpt_fmts[FMT1], &rpt_types[TYPE_INODE]}
81};
82
83pthread_t report_thread;
84
85typedef struct msg_block_s {
86 pthread_mutex_t mutex;
87 progress_rpt_t *format;
88 __uint64_t *done;
89 __uint64_t *total;
90 int count;
91 int interval;
92} msg_block_t;
93static msg_block_t global_msgs;
94
95typedef struct phase_times_s {
96 time_t start;
97 time_t end;
98 time_t duration;
2556c98b 99 __uint64_t item_counts[4];
06fbdda9
MV
100} phase_times_t;
101static phase_times_t phase_times[8];
102
103static void *progress_rpt_thread(void *);
104static int current_phase;
105static int running;
106static __uint64_t prog_rpt_total;
107
108void
109init_progress_rpt (void)
110{
111
112 /*
113 * allocate the done vector
114 */
115
116 if ((prog_rpt_done = (__uint64_t *)
117 malloc(sizeof(__uint64_t)*glob_agcount)) == NULL ) {
118 do_error(_("cannot malloc pointer to done vector\n"));
119 }
120 bzero(prog_rpt_done, sizeof(__uint64_t)*glob_agcount);
121
122 /*
123 * Setup comm block, start the thread
124 */
125
126 pthread_mutex_init(&global_msgs.mutex, NULL);
127 global_msgs.count = glob_agcount;
128 global_msgs.interval = report_interval;
129 global_msgs.done = prog_rpt_done;
130 global_msgs.total = &prog_rpt_total;
131
132 if (pthread_create (&report_thread, NULL,
133 progress_rpt_thread, (void *)&global_msgs))
134 do_error(_("unable to create progress report thread\n"));
135
136 return;
137}
138
139void
140stop_progress_rpt(void)
141{
142
143 /*
144 * Tell msg thread to shutdown,
145 * wait for all threads to finished
146 */
147
148 running = 0;
149 pthread_kill (report_thread, SIGHUP);
150 pthread_join (report_thread, NULL);
151 free(prog_rpt_done);
152 return;
153}
154
155static void *
156progress_rpt_thread (void *p)
157{
158
159 int i;
160 int caught;
161 sigset_t sigs_to_catch;
162 struct tm *tmp;
163 time_t now, elapsed;
164 timer_t timerid;
165 struct itimerspec timespec;
166 char *msgbuf;
167 __uint64_t *donep;
168 __uint64_t sum;
169 msg_block_t *msgp = (msg_block_t *)p;
170 __uint64_t percent;
171
172 if ((msgbuf = (char *)malloc(DURATION_BUF_SIZE)) == NULL)
173 do_error (_("progress_rpt: cannot malloc progress msg buffer\n"));
174
175 running = 1;
176
177 /*
178 * Specify a repeating timer that fires each MSG_INTERVAL seconds.
179 */
2556c98b 180
06fbdda9
MV
181 timespec.it_value.tv_sec = msgp->interval;
182 timespec.it_value.tv_nsec = 0;
183 timespec.it_interval.tv_sec = msgp->interval;
184 timespec.it_interval.tv_nsec = 0;
185
186 if (timer_create (CLOCK_REALTIME, NULL, &timerid))
187 do_error(_("progress_rpt: cannot create timer\n"));
188
189 if (timer_settime (timerid, 0, &timespec, NULL))
190 do_error(_("progress_rpt: cannot set timer\n"));
191
192 /*
193 * Main loop - output messages based on periodic signal arrival
194 * set this thread's signal mask to block out all other signals
195 */
196
197 sigemptyset (&sigs_to_catch);
198 sigaddset (&sigs_to_catch, SIGALRM);
199 sigaddset (&sigs_to_catch, SIGHUP);
200 sigwait (&sigs_to_catch, &caught);
201
202 while (caught != SIGHUP) {
203 /*
204 * Allow the mainline to hold off messages by holding
205 * the lock. We don't want to just skip a period in case the
206 * reporting interval is very long... people get nervous. But,
207 * if the interval is very short, we can't let the timer go
208 * off again without sigwait'ing for it. So disarm the timer
209 * while we try to get the lock and giveup the cpu... the
210 * mainline shouldn't take that long.
211 */
212
213 if (pthread_mutex_lock(&msgp->mutex)) {
214 do_error(_("progress_rpt: cannot lock progress mutex\n"));
215 }
216
217 if (!running)
218 break;
219
220 now = time (NULL);
221 tmp = localtime ((const time_t *) &now);
222
223 /*
224 * Sum the work
225 */
226
227 sum = 0;
228 donep = msgp->done;
229 for (i = 0; i < msgp->count; i++) {
230 sum += *donep++;
231 }
232
233 percent = 0;
234 switch(msgp->format->format) {
235 case FMT1:
236 if (*msgp->total)
237 percent = (sum * 100) / ( *msgp->total );
238 sprintf (msgbuf, *msgp->format->fmt,
239 tmp->tm_hour, tmp->tm_min, tmp->tm_sec,
240 msgp->format->msg, sum,
241 *msgp->total, *msgp->format->type);
242 break;
243 case FMT2:
244 sprintf (msgbuf, *msgp->format->fmt,
245 tmp->tm_hour, tmp->tm_min, tmp->tm_sec,
246 msgp->format->msg, sum,
247 *msgp->format->type);
248 break;
249 }
250
251 do_log(_("%s"), msgbuf);
252 elapsed = now - phase_times[current_phase].start;
253 if ((msgp->format->format == FMT1) && sum && elapsed &&
254 ((current_phase == 3) ||
255 (current_phase == 4) ||
256 (current_phase == 7))) {
257 /* for inode phase report % complete */
258 do_log(
259 _("\t- %02d:%02d:%02d: Phase %d: elapsed time %s - processed %d %s per minute\n"),
260 tmp->tm_hour, tmp->tm_min, tmp->tm_sec,
261 current_phase, duration(elapsed, msgbuf),
262 (int) (60*sum/(elapsed)), *msgp->format->type);
263 do_log(
264 _("\t- %02d:%02d:%02d: Phase %d: %llu%% done - estimated remaining time %s\n"),
265 tmp->tm_hour, tmp->tm_min, tmp->tm_sec,
266 current_phase, percent,
267 duration((int) ((*msgp->total - sum) * (elapsed)/sum), msgbuf));
268 }
269
270 if (pthread_mutex_unlock(&msgp->mutex) != 0) {
271 do_error(
272 _("progress_rpt: error unlock msg mutex\n"));
273 }
274 sigwait (&sigs_to_catch, &caught);
275 }
276
277 if (timer_delete (timerid))
278 do_warn(_("cannot delete timer\n"));
279
280 free (msgbuf);
281 return (NULL);
282}
283
284int
285set_progress_msg (int report, __uint64_t total)
286{
287
2556c98b 288 if (!ag_stride)
06fbdda9
MV
289 return (0);
290
291 if (pthread_mutex_lock(&global_msgs.mutex))
292 do_error(_("set_progress_msg: cannot lock progress mutex\n"));
293
294 prog_rpt_total = total;
295 global_msgs.format = &progress_rpt_reports[report];
296
297 /* reset all the accumulative totals */
298 if (prog_rpt_done)
299 bzero(prog_rpt_done, sizeof(__uint64_t)*glob_agcount);
300
301 if (pthread_mutex_unlock(&global_msgs.mutex))
302 do_error(_("set_progress_msg: cannot unlock progress mutex\n"));
303
304 return (0);
305}
306
307__uint64_t
308print_final_rpt(void)
309{
310 int i;
311 struct tm *tmp;
312 time_t now;
313 __uint64_t *donep;
314 __uint64_t sum;
315 msg_block_t *msgp = &global_msgs;
316 char msgbuf[DURATION_BUF_SIZE];
2556c98b
BN
317
318 if (!ag_stride)
06fbdda9
MV
319 return 0;
320
321 if (pthread_mutex_lock(&global_msgs.mutex))
322 do_error(_("print_final_rpt: cannot lock progress mutex\n"));
323
324 bzero(&msgbuf, sizeof(msgbuf));
325
326 now = time (NULL);
327 tmp = localtime ((const time_t *) &now);
328
329 /*
330 * Sum the work
331 */
332
333 sum = 0;
334 donep = msgp->done;
335 for (i = 0; i < msgp->count; i++) {
336 sum += *donep++;
337 }
338
339 if (report_interval) {
340 switch(msgp->format->format) {
341 case FMT1:
342 sprintf (msgbuf, *msgp->format->fmt,
343 tmp->tm_hour, tmp->tm_min, tmp->tm_sec,
344 msgp->format->msg, sum,
345 *msgp->total, *msgp->format->type);
346 break;
347 case FMT2:
348 sprintf (msgbuf, *msgp->format->fmt,
349 tmp->tm_hour, tmp->tm_min, tmp->tm_sec,
350 msgp->format->msg, sum,
351 *msgp->format->type);
352 break;
353 }
354 do_log(_("%s"), msgbuf);
355 }
356
357 if (pthread_mutex_unlock(&global_msgs.mutex))
358 do_error(_("print_final_rpt: cannot unlock progress mutex\n"));
359
360 return(sum);
361}
362
363void
364timediff(int phase)
365{
366 phase_times[phase].duration =
367 phase_times[phase].end - phase_times[phase].start;
368
369}
370
371/*
372** Get the time and save in the phase time
373** array.
374*/
375char *
376timestamp(int end, int phase, char *buf)
377{
378
379 time_t now;
380 struct tm *tmp;
381
2556c98b
BN
382 if (verbose > 1)
383 cache_report(stderr, "libxfs_bcache", libxfs_bcache);
384
06fbdda9
MV
385 now = time(NULL);
386
387 if (end) {
388 phase_times[phase].end = now;
389 timediff(phase);
390
391 /* total time in slot zero */
392 phase_times[0].end = now;
393 timediff(0);
394
395 if (phase < 7) {
396 phase_times[phase+1].start = now;
397 current_phase = phase + 1;
398 }
399 }
400 else {
401 phase_times[phase].start = now;
402 current_phase = phase;
403 }
404
405 if (buf) {
406 tmp = localtime((const time_t *)&now);
407 sprintf(buf, _("%02d:%02d:%02d"), tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
408 }
409 return(buf);
410}
411
412char *
413duration(int length, char *buf)
414{
415 int sum;
416 int weeks;
417 int days;
418 int hours;
419 int minutes;
420 int seconds;
421 char temp[128];
422
423 *buf = '\0';
424 weeks = days = hours = minutes = seconds = sum = 0;
425 if (length >= ONEWEEK) {
426 weeks = length / ONEWEEK;
427 sum = (weeks * ONEWEEK);
428 if (weeks) {
429 sprintf(buf, _("%d week"), weeks);
430 if (weeks > 1) strcat(buf, _("s"));
431 if ((length-sum) == 0)
432 return(buf);
433 }
434 }
435 if (length >= ONEDAY) {
436 days = (length - sum) / ONEDAY;
437 sum += (days * ONEDAY);
438 if (days) {
439 sprintf(temp, _("%d day"), days);
440 if (days > 1) strcat(temp, _("s"));
441 if (((length-sum) == 0) && (!weeks)) {
442 strcpy(buf, temp);
443 return(buf);
444 }
445 else if (weeks) {
446 strcat(buf, _(", "));
447 }
448 strcat(buf, temp);
449 }
450 }
451 if (length >= ONEHOUR) {
452 hours = (length - sum) / ONEHOUR;
453 sum += (hours * ONEHOUR);
454 if (hours) {
455 sprintf(temp, _("%d hour"), hours);
456 if (hours > 1) strcat(temp, _("s"));
457 if (((length-sum) == 0) &&
458 (!weeks) && (!days)) {
459 strcpy(buf, temp);
460 return(buf);
461 }
462 else if ((weeks) || (days)) {
463 strcat(buf, _(", "));
464 }
465 strcat(buf, temp);
466 }
2556c98b 467
06fbdda9
MV
468 }
469 if (length >= ONEMINUTE) {
470 minutes = (length - sum) / ONEMINUTE;
471 sum += (minutes * ONEMINUTE);
472 if (minutes) {
473 sprintf(temp, _("%d minute"), minutes);
474 if (minutes > 1) strcat(temp, _("s"));
475 if (((length-sum) == 0) &&
476 (!weeks) && (!days) && (!hours)) {
477 strcpy(buf, temp);
478 return(buf);
479 }
480 else if ((weeks)||(days)||(hours)) {
481 strcat(buf, _(", "));
482 }
483 strcat(buf, temp);
484 }
485 }
486 seconds = length - sum;
487 if (seconds) {
488 sprintf(temp, _("%d second"), seconds);
489 if (seconds > 1) strcat(temp, _("s"));
490 if ((weeks)||(days)||(hours)||(minutes))
491 strcat(buf, _(", "));
492 strcat(buf, temp);
493 }
2556c98b 494
06fbdda9
MV
495 return(buf);
496}
497
498void
499summary_report(void)
500{
501 int i;
502 time_t now;
503 struct tm end;
504 struct tm start;
505 char msgbuf[DURATION_BUF_SIZE];
506
507 now = time(NULL);
508
509 do_log(_("\n XFS_REPAIR Summary %s\n"),
510 ctime((const time_t *)&now));
511 do_log(_("Phase\t\tStart\t\tEnd\t\tDuration\n"));
512 for (i = 1; i < 8; i++) {
513 localtime_r((const time_t *)&phase_times[i].start, &start);
514 localtime_r((const time_t *)&phase_times[i].end, &end);
515 if ((no_modify) && (i == 5)) {
516 do_log(_("Phase %d:\tSkipped\n"), i);
517 }
518 else if ((bad_ino_btree) && ((i == 6) || (i == 7))) {
519 do_log(_("Phase %d:\tSkipped\n"), i);
520 }
521 else {
522 do_log(
523 _("Phase %d:\t%02d/%02d %02d:%02d:%02d\t%02d/%02d %02d:%02d:%02d\t%s\n"), i,
524 start.tm_mon+1, start.tm_mday, start.tm_hour, start.tm_min, start.tm_sec,
525 end.tm_mon+1, end.tm_mday, end.tm_hour, end.tm_min, end.tm_sec,
526 duration(phase_times[i].duration, msgbuf));
527 }
528 }
529 do_log(_("\nTotal run time: %s\n"), duration(phase_times[0].duration, msgbuf));
530}