source: MondoRescue/trunk/mondo/src/common/libmondo-string.c@ 979

Last change on this file since 979 was 900, checked in by Bruno Cornec, 18 years ago

Huge patch to introduce low level functions that will bw used everywhere (mr_free, mr_asprintf, ...)
Nearly linking now due to that.

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