source: MondoRescue/branches/3.0/mondo/src/common/libmondo-string.c@ 3192

Last change on this file since 3192 was 3192, checked in by Bruno Cornec, 11 years ago
  • revert r3188 & r3189 as I started to work on branch 3.0 before deciding it was much better to do it in 3.2. This will allow some small maintenance work on 3.0 if needed, while pushing all the rest to 3.2 and providing early access to it.
  • Property svn:keywords set to Id
File size: 29.3 KB
Line 
1/* $Id: libmondo-string.c 3192 2013-09-25 07:03:25Z bruno $ */
2
3
4/**
5 * @file
6 * Functions for handling strings.
7 */
8
9#include "my-stuff.h"
10#include "mr_mem.h"
11#include "mondostructures.h"
12#include "libmondo-string.h"
13#include "lib-common-externs.h"
14#include "libmondo-files-EXT.h"
15#include "libmondo-gui-EXT.h"
16#include "libmondo-tools-EXT.h"
17
18/*@unused@*/
19//static char cvsid[] = "$Id: libmondo-string.c 3192 2013-09-25 07:03:25Z bruno $";
20
21extern int g_current_media_number;
22extern long long g_tape_posK;
23
24/* Reference to global bkpinfo */
25extern struct s_bkpinfo *bkpinfo;
26
27
28/**
29 * @addtogroup stringGroup
30 * @{
31 */
32/**
33 * Build a partition name from a drive and a partition number.
34 * @param drive The drive basename of the partition name (e.g. /dev/hda)
35 * @param partno The partition number (e.g. 1)
36 * @param partition Where to put the partition name (e.g. /dev/hda1)
37 * @return @p partition.
38 * @note If @p drive ends in a digit, then 'p' (on Linux) or 's' (on *BSD) is added before @p partno.
39 */
40char *build_partition_name(char *partition, const char *drive, int partno)
41{
42 char *p, *c;
43
44 assert(partition != NULL);
45 assert_string_is_neither_NULL_nor_zerolength(drive);
46 assert(partno >= 0);
47
48 p = strcpy(partition, drive);
49 /* is this a devfs device path? */
50 c = strrchr(partition, '/');
51 if (c && strncmp(c, "/disc", 5) == 0) {
52 /* yup it's devfs, return the "part" path */
53 strcpy(c + 1, "part");
54 p = c + 5;
55 } else {
56 p += strlen(p);
57 if (isdigit(p[-1])) {
58 *p++ =
59#ifdef BSD
60 's';
61#else
62 'p';
63#endif
64 }
65 }
66 sprintf(p, "%d", partno);
67 return (partition);
68}
69
70
71
72
73
74
75
76
77
78
79
80
81
82/**
83 * Pad a string on both sides so it appears centered.
84 * @param in_out The string to be center-padded (modified).
85 * @param width The width of the final result.
86 */
87void center_string(char *in_out, int width)
88{
89 char scratch[MAX_STR_LEN];
90 char *p;
91 int i; /* purpose */
92 int len; /* purpose */
93 int mid; /* purpose */
94 int x; /* purpose */
95
96 assert(in_out != NULL);
97 assert(width > 2);
98
99 if (strlen(in_out) == 0) {
100 return;
101 }
102 for (p = in_out; *p == ' '; p++);
103 strcpy(scratch, p);
104 strip_spaces (scratch);
105 len = (int) strlen(scratch);
106 mid = width / 2;
107 x = mid - len / 2;
108 for (i = 0; i < x; i++) {
109 in_out[i] = ' ';
110 }
111 in_out[i] = '\0';
112 strcat(in_out, scratch);
113 for (i = x + len ; i < width - 1; i++) {
114 in_out[i] = ' ';
115 }
116 in_out[i] = '\0';
117}
118
119
120
121
122inline void turn_wildcard_chars_into_literal_chars(char *sout, char *sin)
123{
124 char *p, *q;
125
126 for (p = sin, q = sout; *p != '\0'; *(q++) = *(p++)) {
127 if (strchr("[]*?", *p)) {
128 *(q++) = '\\';
129 }
130 }
131 *q = *p; // for the final '\0'
132}
133
134
135
136/**
137 * Add commas every third place in @p input.
138 * @param input The string to commarize.
139 * @return The string with commas.
140 * @note The returned string points to static storage that will be overwritten with each call.
141 */
142char *commarize(char *input)
143{
144 char pos_w_commas[MAX_STR_LEN];
145 static char output[MAX_STR_LEN];
146 char tmp[MAX_STR_LEN];
147 int j;
148
149 assert(input != NULL);
150
151 strcpy(tmp, input);
152 if (strlen(tmp) > 6) {
153 strcpy(pos_w_commas, tmp);
154 j = (int) strlen(pos_w_commas);
155 tmp[j - 6] = ',';
156 strcpy(tmp + j - 5, pos_w_commas + j - 6);
157// tmp[j-2] = ',';
158// strcpy(tmp+j-1, pos_w_commas+j-3);
159 strcpy(pos_w_commas, tmp);
160 }
161 if (strlen(tmp) > 3) {
162 j = (int) strlen(tmp);
163 strcpy(pos_w_commas, tmp);
164 pos_w_commas[j - 3] = ',';
165 strcpy(pos_w_commas + j - 2, tmp + j - 3);
166 } else {
167 strcpy(pos_w_commas, tmp);
168 }
169 strcpy(output, pos_w_commas);
170 return (output);
171}
172
173
174
175
176
177
178
179
180
181/**
182 * Turn an entry from the RAID editor's disklist into a GUI-friendly string.
183 * The format is: the device left-aligned and padded to 24 places, followed by a space and the
184 * index, right-aligned and padded to eight places. The total string length
185 * is exactly 33.
186 * @param disklist The disklist to operate on.
187 * @param lino The line number from @p disklist to convert to a string.
188 * @return The string form of the disklist entry.
189 * @note The returned string points to static storage and will be overwritten with each call.
190 */
191char *disklist_entry_to_string(struct list_of_disks *disklist, int lino)
192{
193
194 /*@ buffers ********************************************************** */
195 static char output[MAX_STR_LEN];
196
197 assert(disklist != NULL);
198
199 sprintf(output, "%-24s %8d", disklist->el[lino].device,
200 disklist->el[lino].index);
201 return (output);
202}
203
204
205
206
207
208/**
209 * Turn a "friendly" sizestring into a number of megabytes.
210 * Supports the suffixes 'k'/'K', 'm'/'M', and 'g'/'G'. Calls
211 * fatal_error() if an unknown suffix is encountered.
212 * @param incoming The sizestring to convert (e.g. "40m", "2g").
213 * @return The size in megabytes.
214 */
215long friendly_sizestr_to_sizelong(char *incoming)
216{
217 long outval;
218 int i;
219 char *tmp;
220 char ch;
221
222 assert_string_is_neither_NULL_nor_zerolength(incoming);
223
224 if (!incoming[0]) {
225 return (0);
226 }
227 if (strchr(incoming, '.')) {
228 fatal_error("Please use integers only. No decimal points.");
229 }
230 malloc_string(tmp);
231 strcpy(tmp, incoming);
232 i = (int) strlen(tmp);
233 if (tmp[i - 1] == 'B' || tmp[i - 1] == 'b') {
234 tmp[i - 1] = '\0';
235 }
236 for (i = 0; i < (int) strlen(tmp) && isdigit(tmp[i]); i++);
237 ch = tmp[i];
238 tmp[i] = '\0';
239 outval = atol(tmp);
240 if (ch == 'g' || ch == 'G') {
241 outval = outval * 1024;
242 } else if (ch == 'k' || ch == 'K') {
243 outval = outval / 1024;
244 } else if (ch == 't' || ch == 'T') // terabyte
245 {
246 outval *= 1048576;
247 } else if (ch == 'Y' || ch == 'y') // yottabyte - the biggest measure in the info file
248 {
249 log_it
250 ("Oh my gosh. You actually think a YOTTABYTE will get you anywhere? What're you going to do with 1,208,925,819,614,629,174,706,176 bytes of data?!?!");
251 popup_and_OK
252 ("That sizespec is more than 1,208,925,819,614,629,174,706,176 bytes. You have a shocking amount of data. Please send a screenshot to the list :-)");
253 fatal_error("Integer overflow.");
254 } else if (ch != 'm' && ch != 'M') {
255 sprintf(tmp, "Re: parameter '%s' - bad multiplier ('%c')",
256 incoming, ch);
257 fatal_error(tmp);
258 }
259 paranoid_free(tmp);
260 return (outval);
261}
262
263
264
265/**
266 * Add spaces to the right of @p incoming to make it @p width characters wide.
267 * @param incoming The string to left-pad.
268 * @param width The width to pad it to.
269 * @return The left-padded string.
270 * @note The returned string points to static storage that will be overwritten with each call.
271 * @bug Why does center_string() modify its argument but leftpad_string() returns a modified copy?
272 */
273char *leftpad_string(char *incoming, int width)
274{
275 /*@ buffers ***************************************************** */
276 static char output[MAX_STR_LEN];
277
278 /*@ ints ******************************************************** */
279 int i;
280
281 /*@ end vars **************************************************** */
282 assert(incoming != NULL);
283 assert(width > 2);
284
285 strcpy(output, incoming);
286 for (i = (int) strlen(output); i < width; i++) {
287 output[i] = ' ';
288 }
289 output[i] = '\0';
290 return (output);
291}
292
293
294
295/**
296 * Turn a marker byte (e.g. BLK_START_OF_BACKUP) into a string (e.g. "BLK_START_OF_BACKUP").
297 * Unknown markers are identified as "BLK_UNKNOWN (%d)" where %d is the decimal value.
298 * @param marker The marker byte to stringify.
299 * @return @p marker as a string.
300 * @note The returned string points to static storage that will be overwritten with each call.
301 */
302char *marker_to_string(int marker)
303{
304 /*@ buffer ****************************************************** */
305 static char outstr[MAX_STR_LEN];
306
307
308 /*@ end vars *************************************************** */
309
310 switch (marker) {
311 case BLK_START_OF_BACKUP:
312 strcpy(outstr, "BLK_START_OF_BACKUP");
313 break;
314 case BLK_START_OF_TAPE:
315 strcpy(outstr, "BLK_START_OF_TAPE");
316 break;
317 case BLK_START_AN_AFIO_OR_SLICE:
318 strcpy(outstr, "BLK_START_AN_AFIO_OR_SLICE");
319 break;
320 case BLK_STOP_AN_AFIO_OR_SLICE:
321 strcpy(outstr, "BLK_STOP_AN_AFIO_OR_SLICE");
322 break;
323 case BLK_START_AFIOBALLS:
324 strcpy(outstr, "BLK_START_AFIOBALLS");
325 break;
326 case BLK_STOP_AFIOBALLS:
327 strcpy(outstr, "BLK_STOP_AFIOBALLS");
328 break;
329 case BLK_STOP_BIGGIEFILES:
330 strcpy(outstr, "BLK_STOP_BIGGIEFILES");
331 break;
332 case BLK_START_A_NORMBIGGIE:
333 strcpy(outstr, "BLK_START_A_NORMBIGGIE");
334 break;
335 case BLK_START_A_PIHBIGGIE:
336 strcpy(outstr, "BLK_START_A_PIHBIGGIE");
337 break;
338 case BLK_START_EXTENDED_ATTRIBUTES:
339 strcpy(outstr, "BLK_START_EXTENDED_ATTRIBUTES");
340 break;
341 case BLK_STOP_EXTENDED_ATTRIBUTES:
342 strcpy(outstr, "BLK_STOP_EXTENDED_ATTRIBUTES");
343 break;
344 case BLK_START_EXAT_FILE:
345 strcpy(outstr, "BLK_START_EXAT_FILE");
346 break;
347 case BLK_STOP_EXAT_FILE:
348 strcpy(outstr, "BLK_STOP_EXAT_FILE");
349 break;
350 case BLK_START_BIGGIEFILES:
351 strcpy(outstr, "BLK_START_BIGGIEFILES");
352 break;
353 case BLK_STOP_A_BIGGIE:
354 strcpy(outstr, "BLK_STOP_A_BIGGIE");
355 break;
356 case BLK_END_OF_TAPE:
357 strcpy(outstr, "BLK_END_OF_TAPE");
358 break;
359 case BLK_END_OF_BACKUP:
360 strcpy(outstr, "BLK_END_OF_BACKUP");
361 break;
362 case BLK_ABORTED_BACKUP:
363 strcpy(outstr, "BLK_ABORTED_BACKUP");
364 break;
365 case BLK_START_FILE:
366 strcpy(outstr, "BLK_START_FILE");
367 break;
368 case BLK_STOP_FILE:
369 strcpy(outstr, "BLK_STOP_FILE");
370 break;
371 default:
372 sprintf(outstr, "BLK_UNKNOWN (%d)", marker);
373 break;
374 }
375 return (outstr);
376}
377
378
379
380
381/**
382 * Turn a line from the mountlist into a GUI-friendly string.
383 * The format is as follows: the left-aligned @p device field padded to 24 places,
384 * a space, the left-aligned @p mountpoint field again padded to 24 places, a space,
385 * the left-aligned @p format field padded to 10 places, a space, and the right-aligned
386 * @p size field (in MB) padded to 8 places. The total string length is exactly 69.
387 * @param mountlist The mountlist to operate on.
388 * @param lino The line number in @p mountlist to stringify.
389 * @return The string form of <tt>mountlist</tt>-\>el[<tt>lino</tt>].
390 * @note The returned string points to static storage and will be overwritten with each call.
391 */
392char *mountlist_entry_to_string(struct mountlist_itself *mountlist,
393 int lino)
394{
395
396 /*@ buffer *********************************************************** */
397 static char output[MAX_STR_LEN];
398
399 assert(mountlist != NULL);
400
401 sprintf(output, "%-24s %-24s %-10s %8lld", mountlist->el[lino].device,
402 mountlist->el[lino].mountpoint, mountlist->el[lino].format,
403 mountlist->el[lino].size / 1024L);
404 return (output);
405}
406
407
408
409
410
411
412/**
413 * Generate a friendly string containing "X blah blah disk(s)"
414 * @param noof_disks The number of disks (the X).
415 * @param label The "blah blah" part in the middle. If you leave this blank
416 * there will be a weird double space in the middle, so pass *something*.
417 * @return The string containing "X blah blah disk(s)".
418 * @note The returned string points to static storage and will be overwritten with each call.
419 */
420char *number_of_disks_as_string(int noof_disks, char *label)
421{
422
423 /*@ buffers ********************************************************* */
424 static char output[MAX_STR_LEN];
425
426 /*@ char ******************************************************** */
427 char p;
428
429 assert(label != NULL);
430
431 if (noof_disks > 1) {
432 p = 's';
433 } else {
434 p = ' ';
435 }
436 sprintf(output, "%d %s disk%c", noof_disks, label, p);
437 while (strlen(output) < 14) {
438 strcat(output, " ");
439 }
440 return (output);
441}
442
443
444
445/**
446 * Change @p i into a friendly string. If @p i is \<= 10 then write out the
447 * number (e.g. "one", "two", ..., "nine", "ten", "11", ...).
448 * @param i The number to stringify.
449 * @return The string form of @p i.
450 * @note The returned value points to static strorage that will be overwritten with each call.
451 */
452char *number_to_text(int i)
453{
454
455 /*@ buffers ***************************************************** */
456 static char output[MAX_STR_LEN];
457
458
459 /*@ end vars *************************************************** */
460
461 switch (i) {
462 case 0:
463 strcpy(output, "zero");
464 break;
465 case 1:
466 strcpy(output, "one");
467 break;
468 case 2:
469 strcpy(output, "two");
470 break;
471 case 3:
472 strcpy(output, "three");
473 break;
474 case 4:
475 strcpy(output, "four");
476 break;
477 case 5:
478 strcpy(output, "five");
479 break;
480 case 6:
481 strcpy(output, "six");
482 break;
483 case 7:
484 strcpy(output, "seven");
485 break;
486 case 8:
487 strcpy(output, "eight");
488 break;
489 case 9:
490 strcpy(output, "nine");
491 case 10:
492 strcpy(output, "ten");
493 default:
494 sprintf(output, "%d", i);
495 }
496 return (output);
497}
498
499
500
501
502/**
503 * Replace all occurences of @p token with @p value while copying @p ip to @p output.
504 * @param ip The input string containing zero or more <tt>token</tt>s.
505 * @param output The output string written with the <tt>token</tt>s replaced by @p value.
506 * @param token The token to be relaced with @p value.
507 * @param value The value to replace @p token.
508 */
509void resolve_naff_tokens(char *output, char *ip, char *value, char *token)
510{
511 /*@ buffers *** */
512 char *input;
513
514 /*@ pointers * */
515 char *p;
516
517 input = malloc(2000);
518 // BERLIOS: seems to cause invalid errors
519 //assert_string_is_neither_NULL_nor_zerolength(ip);
520 assert_string_is_neither_NULL_nor_zerolength(token);
521 assert(value != NULL);
522
523 strcpy(output, ip); /* just in case the token doesn't appear in string at all */
524 for (strcpy(input, ip); strstr(input, token); strcpy(input, output)) {
525 strcpy(output, input);
526 p = strstr(output, token);
527 *p = '\0';
528 strcat(output, value);
529 p = strstr(input, token) + strlen(token);
530 strcat(output, p);
531 }
532 paranoid_free(input);
533}
534
535
536
537
538
539/**
540 * Generate the filename of slice @p sliceno of biggiefile @p bigfileno
541 * in @p path with suffix @p s. The format is as follows: @p path, followed
542 * by "/slice-" and @p bigfileno zero-padded to 7 places, followed by
543 * a dot and @p sliceno zero-padded to 5 places, followed by ".dat" and the
544 * suffix. The string is a minimum of 24 characters long.
545 * @param bigfileno The biggiefile number. Starts from 0.
546 * @param sliceno The slice number of biggiefile @p bigfileno. 0 is a "header"
547 * slice (no suffix) containing the biggiestruct, then are the compressed
548 * slices, then an empty uncompressed "trailer" slice.
549 * @param path The path to append (with a / in the middle) to the slice filename.
550 * @param s If not "" then add a "." and this to the end.
551 * @return The slice filename.
552 * @note The returned value points to static storage and will be overwritten with each call.
553 */
554char *slice_fname(long bigfileno, long sliceno, char *path, char *s)
555{
556
557 /*@ buffers **************************************************** */
558 static char output[MAX_STR_LEN];
559 static char suffix[MAX_STR_LEN];
560
561 /*@ end vars *************************************************** */
562
563 assert_string_is_neither_NULL_nor_zerolength(path);
564 if (s[0] != '\0') {
565 sprintf(suffix, ".%s", s);
566 } else {
567 suffix[0] = '\0';
568 }
569 sprintf(output, "%s/slice-%07ld.%05ld.dat%s", path, bigfileno, sliceno,
570 suffix);
571 return (output);
572}
573
574
575/**
576 * Generate a spinning symbol based on integer @p i.
577 * The symbol rotates through the characters / - \ | to form an ASCII "spinner"
578 * if successively written to the same location on screen.
579 * @param i The amount of progress or whatever else to use to determine the character
580 * for this iteration of the spinner.
581 * @return The character for this iteration.
582 */
583int special_dot_char(int i)
584{
585 switch (i % 4) {
586 case 0:
587 return ('/');
588 case 1:
589 return ('-');
590 case 2:
591 return ('\\');
592 case 3:
593 return ('|');
594 default:
595 return ('.');
596 }
597 return ('.');
598}
599
600
601/**
602 * Compare @p stringA and @p stringB. This uses an ASCII sort for everything
603 * up to the digits on the end but a numerical sort for the digits on the end.
604 * @param stringA The first string to compare.
605 * @param stringB The second string to compare.
606 * @return The same as strcmp() - <0 if A<B, 0 if A=B, >0 if A>B.
607 * @note This function only does a numerical sort on the @e last set of numbers. If
608 * there are any in the middle those will be sorted ASCIIbetically.
609 */
610int strcmp_inc_numbers(char *stringA, char *stringB)
611{
612 /*@ int ********************************************************* */
613 int i;
614 int start_of_numbers_in_A;
615 int start_of_numbers_in_B;
616 int res;
617
618 /*@ long ******************************************************* */
619 long numA;
620 long numB;
621
622 /*@ end vars *************************************************** */
623 assert(stringA != NULL);
624 assert(stringB != NULL);
625
626 if (strlen(stringA) == strlen(stringB)) {
627 return (strcmp(stringA, stringB));
628 }
629 for (i = (int) strlen(stringA); i > 0 && isdigit(stringA[i - 1]); i--);
630 if (i == (int) strlen(stringA)) {
631 return (strcmp(stringA, stringB));
632 }
633 start_of_numbers_in_A = i;
634 for (i = (int) strlen(stringB); i > 0 && isdigit(stringB[i - 1]); i--);
635 if (i == (int) strlen(stringB)) {
636 return (strcmp(stringA, stringB));
637 }
638 start_of_numbers_in_B = i;
639 if (start_of_numbers_in_A != start_of_numbers_in_B) {
640 return (strcmp(stringA, stringB));
641 }
642 res = strncmp(stringA, stringB, (size_t) i);
643 if (res) {
644 return (res);
645 }
646 numA = atol(stringA + start_of_numbers_in_A);
647 numB = atol(stringB + start_of_numbers_in_B);
648 /*
649 sprintf(tmp,"Comparing %s and %s --> %ld,%ld\n",stringA,stringB,numA,numB);
650 log_to_screen(tmp);
651 */
652 return ((int) (numA - numB));
653}
654
655
656
657/**
658 * Strip excess baggage from @p input, which should be a line from afio.
659 * For now this copies the whole line unless it finds a set of quotes, in which case
660 * it copies their contents only.
661 * @param input The input line (presumably from afio).
662 * @return The stripped line.
663 * @note The returned string points to static storage that will be overwritten with each call.
664 */
665char *strip_afio_output_line(char *input)
666{
667 /*@ buffer ****************************************************** */
668 static char output[MAX_STR_LEN];
669
670 /*@ pointers **************************************************** */
671 char *p;
672 char *q;
673 /*@ end vars *************************************************** */
674
675 assert(input != NULL);
676 strcpy(output, input);
677 p = strchr(input, '\"');
678 if (p) {
679 q = strchr(++p, '\"');
680 if (q) {
681 strcpy(output, p);
682 *(strchr(output, '\"')) = '\0';
683 }
684 }
685 return (output);
686}
687
688
689
690/**
691 * Remove all characters whose ASCII value is less than or equal to 32
692 * (spaces and control characters) from both sides of @p in_out.
693 * @param in_out The string to strip spaces/control characters from (modified).
694 */
695void strip_spaces(char *in_out)
696{
697 /*@ buffers ***************************************************** */
698 char *tmp = NULL;
699
700 /*@ int ******************************************************** */
701 int i;
702
703 /*@ end vars *************************************************** */
704
705 assert(in_out != NULL);
706 malloc_string(tmp);
707 for (i = 0; in_out[i] <= ' ' && i < (int) strlen(in_out) -1; i++);
708 strcpy(tmp, in_out + i);
709 for (i = (int) strlen(tmp) -1; i >= 0 && tmp[i] <= ' '; i--);
710 i++;
711 tmp[i] = '\0';
712
713 // Now tmp contains the stripped string
714 strcpy(in_out,tmp);
715 paranoid_free(tmp);
716}
717
718/**
719 * Remove all characters whose ASCII value is less than or equal to 32
720 * (spaces and control characters) from both sides of @p in_out.
721 * @param in_out The string to strip spaces/control characters from (modified).
722 */
723void strip_spaces2(char *in_out)
724{
725 /*@ buffers ***************************************************** */
726 char *tmp;
727
728 /*@ pointers **************************************************** */
729 char *p;
730
731 /*@ int ******************************************************** */
732 int i;
733 int original_incoming_length;
734
735 /*@ end vars *************************************************** */
736
737 assert(in_out != NULL);
738 malloc_string(tmp);
739 original_incoming_length = (int) strlen(in_out);
740 for (i = 0; in_out[i] <= ' ' && i < (int) strlen(in_out); i++);
741 strcpy(tmp, in_out + i);
742 for (i = (int) strlen(tmp); i > 0 && tmp[i - 1] <= 32; i--);
743 tmp[i] = '\0';
744 for (i = 0; i < original_incoming_length && MAX_STR_LEN; i++) {
745 in_out[i] = ' ';
746 }
747 in_out[i] = '\0';
748 i = 0;
749 p = tmp;
750 while (*p != '\0') {
751 in_out[i] = *(p++);
752 in_out[i + 1] = '\0';
753 if (in_out[i] < 32 && i > 0) {
754 if (in_out[i] == 8) {
755 i--;
756 } else if (in_out[i] == 9) {
757 in_out[i++] = ' ';
758 } else if (in_out[i] == '\r') // added 1st October 2003 -- FIXME
759 {
760 strcpy(tmp, in_out + i);
761 strcpy(in_out, tmp);
762 i = -1;
763 continue;
764 } else if (in_out[i] == '\t') {
765 for (i++; i % 5; i++);
766 } else if (in_out[i] >= 10 && in_out[i] <= 13) {
767 break;
768 } else {
769 i--;
770 }
771 } else {
772 i++;
773 }
774 }
775 in_out[i] = '\0';
776 paranoid_free(tmp);
777/* for(i=strlen(in_out); i>0 && in_out[i-1]<=32; i--) {in_out[i-1]='\0';} */
778}
779
780
781/**
782 * If there are double quotes "" around @p incoming then remove them.
783 * This does not affect other quotes that may be embedded within the string.
784 * @param incoming The string to trim quotes from (modified).
785 * @return @p incoming.
786 */
787char *trim_empty_quotes(char *incoming)
788{
789 /*@ buffer ****************************************************** */
790 static char outgoing[MAX_STR_LEN];
791
792 /*@ end vars *************************************************** */
793 assert(incoming != NULL);
794
795 if (incoming[0] == '\"' && incoming[strlen(incoming) - 1] == '\"') {
796 strcpy(outgoing, incoming + 1);
797 outgoing[strlen(outgoing) - 1] = '\0';
798 } else {
799 strcpy(outgoing, incoming);
800 }
801 return (outgoing);
802}
803
804
805
806
807/**
808 * Remove any partition info from @p partition, leaving just the drive name.
809 * @param partition The partition name soon-to-become drive name. (modified)
810 * @return @p partition.
811 */
812char *truncate_to_drive_name(const char *partition)
813{
814 int i = strlen(partition) - 1;
815 char *c;
816 char *trunc = NULL;
817
818 assert_string_is_neither_NULL_nor_zerolength(partition);
819 mr_asprintf(trunc, "%s", partition);
820
821#ifdef __FreeBSD__
822
823 if (islower(trunc[i])) // BSD subpartition
824 i--;
825 if (trunc[i-1] == 's') {
826 while (isdigit(trunc[i]))
827 i--;
828 i--;
829 }
830 trunc[i+1] = '\0';
831
832#else
833
834 /* first see if it's a devfs style device */
835 c = strrchr(trunc, '/');
836 if (c && strncmp(c, "/part", 5) == 0) {
837 /* yup it's devfs, return the "disc" path */
838 strcpy(c + 1, "disc");
839 return trunc;
840 }
841 /* then see if it's a dm style device */
842 if (c && strncmp(c, "/dm-", 4) == 0) {
843 /* yup it's dm, return the full path */
844 return trunc;
845 }
846
847
848 for (i = strlen(trunc); isdigit(trunc[i-1]); i--)
849 continue;
850 if (trunc[i-1] == 'p' && isdigit(trunc[i-2])) {
851 i--;
852 } else {
853 /* Some full devices like this /dev/mapper/mpath0
854 /dev/cciss/c0d0 may be used as partition names */
855 if ((strstr(trunc,"/dev/mapper/mpath") != NULL) ||
856 (strstr(trunc,"/dev/cciss/c") != NULL) ||
857 (strstr(trunc,"/dev/rd/") != NULL)) {
858 return trunc;
859 }
860 }
861 trunc[i] = '\0';
862
863#endif
864
865 return trunc;
866}
867
868
869
870
871
872/**
873 * Turn a RAID level number (-1 to 5) into a friendly string. The string
874 * is either "Linear RAID" for -1, or " RAID %-2d " (%d = @p raid_level)
875 * for anything else.
876 * @param raid_level The RAID level to stringify.
877 * @return The string form of @p raid_level.
878 * @note The returned value points to static storage that will be overwritten with each call.
879 */
880char *turn_raid_level_number_to_string(int raid_level)
881{
882
883 /*@ buffer ********************************************************** */
884 static char output[MAX_STR_LEN];
885
886
887
888 if (raid_level >= 0) {
889 sprintf(output, " RAID %-2d ", raid_level);
890 } else {
891 sprintf(output, "Linear RAID");
892 }
893 return (output);
894}
895
896
897
898
899
900
901
902
903
904/**
905 * Determine the severity (1-3, 1 being low) of the fact that
906 * @p fn changed in the live filesystem (verify/compare).
907 * @param fn The filename that changed.
908 * @param out_reason If non-NULL, a descriptive reason for the difference will be copied here.
909 * @return The severity (1-3).
910 */
911int severity_of_difference(char *fn, char *out_reason)
912{
913 int sev;
914 char *reason;
915 char *filename;
916
917 malloc_string(reason);
918 malloc_string(filename);
919// out_reason might be null on purpose, so don't bomb if it is :) OK?
920 assert_string_is_neither_NULL_nor_zerolength(fn);
921 if (!strncmp(fn, MNT_RESTORING, strlen(MNT_RESTORING))) {
922 strcpy(filename, fn + strlen(MNT_RESTORING));
923 } else if (fn[0] != '/') {
924 sprintf(filename, "/%s", fn);
925 } else {
926 strcpy(filename, fn);
927 }
928
929 sev = 3;
930 sprintf(reason,
931 "Changed since backup. Consider running a differential backup in a day or two.");
932 if (!strncmp(filename, "/var/", 5)) {
933 sev = 2;
934 sprintf(reason,
935 "/var's contents will change regularly, inevitably.");
936 }
937 if (!strncmp(filename, "/home", 5)) {
938 sev = 2;
939 sprintf(reason,
940 "It's in your /home directory. Therefore, it is important.");
941 }
942 if (!strncmp(filename, "/usr/", 5)) {
943 sev = 3;
944 sprintf(reason,
945 "You may have installed/removed software during the backup.");
946 }
947 if (!strncmp(filename, "/etc/", 5)) {
948 sev = 3;
949 sprintf(reason,
950 "Do not edit config files while backing up your PC.");
951 }
952 if (!strcmp(filename, "/etc/adjtime")
953 || !strcmp(filename, "/etc/mtab")) {
954 sev = 1;
955 sprintf(reason, "This file changes all the time. It's OK.");
956 }
957 if (!strncmp(filename, "/root/", 6)) {
958 sev = 3;
959 sprintf(reason, "Were you compiling/editing something in /root?");
960 }
961 if (!strncmp(filename, "/root/.", 7)) {
962 sev = 2;
963 sprintf(reason, "Temp or 'dot' files changed in /root.");
964 }
965 if (!strncmp(filename, "/var/lib/", 9)) {
966 sev = 2;
967 sprintf(reason, "Did you add/remove software during backing?");
968 }
969 if (!strncmp(filename, "/var/lib/rpm", 12)) {
970 sev = 3;
971 sprintf(reason, "Did you add/remove software during backing?");
972 }
973 if (!strncmp(filename, "/var/lib/slocate", 16)) {
974 sev = 1;
975 sprintf(reason,
976 "The 'update' daemon ran during backup. This does not affect the integrity of your backup.");
977 }
978 if (!strncmp(filename, "/var/log/", 9)
979 || strstr(filename, "/.xsession")
980 || !strcmp(filename + strlen(filename) - 4, ".log")) {
981 sev = 1;
982 sprintf(reason,
983 "Log files change frequently as the computer runs. Fret not.");
984 }
985 if (!strncmp(filename, "/var/spool", 10)) {
986 sev = 1;
987 sprintf(reason,
988 "Background processes or printers were active. This does not affect the integrity of your backup.");
989 }
990 if (!strncmp(filename, "/var/spool/mail", 10)) {
991 sev = 2;
992 sprintf(reason, "Mail was sent/received during backup.");
993 }
994 if (filename[strlen(filename) - 1] == '~') {
995 sev = 1;
996 sprintf(reason,
997 "Backup copy of another file which was modified recently.");
998 }
999 if (strstr(filename, "cache")) {
1000 sev = 1;
1001 sprintf(reason,
1002 "Part of a cache of data. Caches change from time to time. Don't worry.");
1003 }
1004 if (!strncmp(filename, "/var/run/", 9)
1005 || !strncmp(filename, "/var/lock", 8)
1006 || strstr(filename, "/.DCOPserver") || strstr(filename, "/.MCOP")
1007 || strstr(filename, "/.Xauthority")) {
1008 sev = 1;
1009 sprintf(reason,
1010 "Temporary file (a lockfile, perhaps) used by software such as X or KDE to register its presence.");
1011 }
1012 if (out_reason) {
1013 strcpy(out_reason, reason);
1014 }
1015 paranoid_free(filename);
1016 paranoid_free(reason);
1017 return (sev);
1018}
1019
1020
1021
1022/**
1023 * Compare the filenames in two filelist entries (s_filelist_entry*) casted
1024 * to void*.
1025 * @param va The first filelist entry, cast as a @c void pointer.
1026 * @param vb The second filelist entry, cast as a @c void pointer.
1027 * @return The return value of strcmp().
1028 */
1029int compare_two_filelist_entries(void *va, void *vb)
1030{
1031 static int res;
1032 struct s_filelist_entry *fa, *fb;
1033
1034 assert(va != NULL);
1035 assert(vb != NULL);
1036 fa = (struct s_filelist_entry *) va;
1037 fb = (struct s_filelist_entry *) vb;
1038 res = strcmp(fa->filename, fb->filename);
1039 return (res);
1040}
1041
1042
1043
1044
1045
1046
1047
1048/**
1049 * Generate a line intended to be passed to update_evalcall_form(), indicating
1050 * the current media fill percentage (or number of kilobytes if size is not known).
1051 * @param bkpinfo The backup media structure. Fields used:
1052 * - @c bkpinfo->backup_media_type
1053 * - @c bkpinfo->media_size
1054 * - @c bkpinfo->scratchdir
1055 * @return The string indicating media fill.
1056 * @note The returned string points to static storage that will be overwritten with each call.
1057 */
1058char *percent_media_full_comment()
1059{
1060 /*@ int *********************************************** */
1061 int percentage;
1062 int j;
1063
1064 /*@ buffers ******************************************* */
1065 static char outstr[MAX_STR_LEN];
1066 char *pos_w_commas, *tmp;
1067 char *mds = NULL;
1068
1069 assert(bkpinfo != NULL);
1070 malloc_string(pos_w_commas);
1071 malloc_string(tmp);
1072 sprintf(tmp, "%lld", g_tape_posK);
1073 strcpy(pos_w_commas, commarize(tmp));
1074
1075
1076
1077 if (bkpinfo->media_size <= 0)
1078// { fatal_error( "percentage_media_full_comment() - unknown media size"); }
1079 {
1080 sprintf(outstr, "Volume %d: %s kilobytes archived so far",
1081 g_current_media_number, pos_w_commas);
1082 return (outstr);
1083 }
1084
1085/* update screen */
1086 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1087 percentage = (int) (g_tape_posK / 10 / bkpinfo->media_size);
1088 if (percentage > 100) {
1089 percentage = 100;
1090 }
1091 sprintf(outstr, "Volume %d: [", g_current_media_number);
1092 } else {
1093 percentage =
1094 (int) (space_occupied_by_cd(bkpinfo->scratchdir) * 100 / 1024 / bkpinfo->media_size);
1095 mds = media_descriptor_string(bkpinfo->backup_media_type);
1096 sprintf(outstr, "%s %d: [", mds, g_current_media_number);
1097 mr_free(mds);
1098 }
1099 for (j = 0; j < percentage; j += 5) {
1100 strcat(outstr, "*");
1101 }
1102 for (; j < 100; j += 5) {
1103 strcat(outstr, ".");
1104 }
1105 j = (int) strlen(outstr);
1106 sprintf(outstr + j, "] %d%% used", percentage);
1107 paranoid_free(pos_w_commas);
1108 paranoid_free(tmp);
1109 return (outstr);
1110}
1111
1112/**
1113 * Get a string form of @p type_of_bkp.
1114 * @param type_of_bkp The backup type to stringify.
1115 * @return The stringification of @p type_of_bkp.
1116 * @note The returned string points to static storage that will be overwritten with each call.
1117 */
1118char *media_descriptor_string(t_bkptype type_of_bkp) {
1119
1120 char *type_of_backup = NULL;
1121
1122 switch (type_of_bkp) {
1123 case dvd:
1124 mr_asprintf(type_of_backup, "DVD");
1125 break;
1126 case cdr:
1127 mr_asprintf(type_of_backup, "CDR");
1128 break;
1129 case cdrw:
1130 mr_asprintf(type_of_backup, "CDRW");
1131 break;
1132 case tape:
1133 mr_asprintf(type_of_backup, "tape");
1134 break;
1135 case cdstream:
1136 mr_asprintf(type_of_backup, "CDR");
1137 break;
1138 case udev:
1139 mr_asprintf(type_of_backup, "udev");
1140 break;
1141 case iso:
1142 mr_asprintf(type_of_backup, "ISO");
1143 break;
1144 case netfs:
1145 mr_asprintf(type_of_backup, "%s", bkpinfo->netfs_proto);
1146 break;
1147 case usb:
1148 mr_asprintf(type_of_backup, "USB");
1149 break;
1150 default:
1151 mr_asprintf(type_of_backup, "ISO");
1152 }
1153 return (type_of_backup);
1154}
Note: See TracBrowser for help on using the repository browser.