source: MondoRescue/branches/3.1/mondo/src/common/libmondo-string.c@ 3190

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