/* $Id: libmondo-string.c 3859 2024-03-07 00:33:54Z bruno $ */
/**
* @file
* Functions for handling strings.
*/
#include "my-stuff.h"
#include "mr_mem.h"
#include "mr_str.h"
#include "mondostructures.h"
#include "libmondo-string.h"
#include "lib-common-externs.h"
#include "libmondo-files-EXT.h"
#include "libmondo-gui-EXT.h"
#include "libmondo-tools-EXT.h"
/*@unused@*/
//static char cvsid[] = "$Id: libmondo-string.c 3859 2024-03-07 00:33:54Z bruno $";
extern int g_current_media_number;
extern long long g_tape_posK;
/* Reference to global bkpinfo */
extern struct s_bkpinfo *bkpinfo;
/**
* @addtogroup stringGroup
* @{
*/
/**
* Build a partition name from a drive and a partition number.
* @param drive The drive basename of the partition name (e.g. /dev/hda)
* @param partno The partition number (e.g. 1)
* @return @p the partition name (e.g. /dev/hda1)
* @note If @p drive ends in a digit, then 'p' (on Linux) or 's' (on *BSD) is added before @p partno.
*/
char *build_partition_name(const char *drive, int partno)
{
char *p, *c;
assert_string_is_neither_NULL_nor_zerolength(drive);
assert(partno >= 0);
mr_free(partition);
mr_asprintf(partition, "%s", drive);
p = partition;
/* is this a devfs device path? */
c = strrchr(partition, '/');
if (c && strncmp(c, "/disc", 5) == 0) {
/* yup it's devfs, return the "part" path */
/* This strcpy is safe */
strcpy(c + 1, "part");
} else {
p += strlen(p);
if (isdigit(p[-1])) {
mr_strcat(partition, "%c",
#ifdef BSD
's';
#else
'p';
#endif
);
}
}
mr_strcat(partition, "%d", partno);
return(partition);
}
/**
* Pad a string on both sides so it appears centered.
* @param in The string to be center-padded (modified).
* @param width The width of the final result.
*/
char *mr_center_string(char *in, int width)
{
char *scratch = NULL;
char *out = NULL;
int i; /* purpose */
int len; /* purpose */
int mid; /* purpose */
int x; /* purpose */
assert(in != NULL);
assert(width > 2);
if (strlen(in) == 0) {
return(NULL);
}
/* skip initial spaces */
scratch = mr_strip_spaces(in);
len = (int)strlen(scratch);
mid = width / 2;
x = mid - len / 2;
for (i = 0; i < x; i++) {
mr_strcat(out," ");
}
mr_strcat(out, scratch);
mr_free(scratch);
for (i = x + len ; i < width - 1; i++) {
mr_strcat(out," ");
}
return(out);
}
/**
* Turn an entry from the RAID editor's disklist into a GUI-friendly string.
* The format is: the device left-aligned and padded to 24 places, followed by a space and the
* index, right-aligned and padded to eight places. The total string length
* is exactly 33.
* @param disklist The disklist to operate on.
* @param lino The line number from @p disklist to convert to a string.
* @return The string form of the disklist entry.
* @note The returned string points to storage that needs to be freed by
* caller
*/
char *disklist_entry_to_string(struct list_of_disks *disklist, int lino)
{
/*@ buffers ********************************************************** */
char *output = NULL;
assert(disklist != NULL);
mr_asprintf(output, "%-24s %8d", disklist->el[lino].device, disklist->el[lino].index);
return(output);
}
/**
* Turn a "friendly" sizestring into a number of megabytes.
* Supports the suffixes 'k'/'K', 'm'/'M', and 'g'/'G'. Calls
* fatal_error() if an unknown suffix is encountered.
* @param incoming The sizestring to convert (e.g. "40m", "2g").
* @return The size in megabytes.
*/
long friendly_sizestr_to_sizelong(char *incoming)
{
long outval;
int i;
char *tmp = NULL;
char ch;
assert_string_is_neither_NULL_nor_zerolength(incoming);
if (!incoming[0]) {
return (0);
}
if (strchr(incoming, '.')) {
fatal_error("Please use integers only. No decimal points.");
}
mr_asprintf(tmp, "%s", incoming);
i = (int) strlen(tmp);
if (tmp[i - 1] == 'B' || tmp[i - 1] == 'b') {
tmp[i - 1] = '\0';
}
for (i = 0; i < (int) strlen(tmp) && isdigit(tmp[i]); i++);
ch = tmp[i];
tmp[i] = '\0';
outval = atol(tmp);
mr_free(tmp);
if (ch == 'g' || ch == 'G') {
outval = outval * 1024;
} else if (ch == 'k' || ch == 'K') {
outval = outval / 1024;
} else if (ch == 't' || ch == 'T') // terabyte
{
outval *= 1048576;
} else if (ch == 'Y' || ch == 'y') // yottabyte - the biggest measure in the info file
{
log_it
("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?!?!");
popup_and_OK
("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 :-)");
fatal_error("Integer overflow.");
} else if (ch != 'm' && ch != 'M') {
mr_asprintf(tmp, "Re: parameter '%s' - bad multiplier ('%c')", incoming, ch);
fatal_error(tmp);
}
return (outval);
}
/**
* Add spaces to the right of @p incoming to make it @p width characters wide.
* @param incoming The string to left-pad.
* @param width The width to pad it to.
* @return The left-padded string.
* @note The returned string points to static storage that will be overwritten with each call.
*/
char *leftpad_string(char *incoming, int width)
{
/*@ buffers ***************************************************** */
static char output[MAX_STR_LEN];
/*@ ints ******************************************************** */
int i;
/*@ end vars **************************************************** */
assert(incoming != NULL);
assert(width > 2);
strcpy(output, incoming);
for (i = (int) strlen(output); i < width; i++) {
output[i] = ' ';
}
output[i] = '\0';
return (output);
}
/**
* Turn a marker byte (e.g. BLK_START_OF_BACKUP) into a string (e.g. "BLK_START_OF_BACKUP").
* Unknown markers are identified as "BLK_UNKNOWN (%d)" where %d is the decimal value.
* @param marker The marker byte to stringify.
* @return @p marker as a string.
* @note The returned string points to storage that needs to be freed by
* caller
*/
char *marker_to_string(int marker)
{
/*@ buffer ****************************************************** */
char *outstr = NULL;
/*@ end vars *************************************************** */
switch (marker) {
case BLK_START_OF_BACKUP:
mr_asprintf(outstr, "BLK_START_OF_BACKUP");
break;
case BLK_START_OF_TAPE:
mr_asprintf(outstr, "BLK_START_OF_TAPE");
break;
case BLK_START_AN_AFIO_OR_SLICE:
mr_asprintf(outstr, "BLK_START_AN_AFIO_OR_SLICE");
break;
case BLK_STOP_AN_AFIO_OR_SLICE:
mr_asprintf(outstr, "BLK_STOP_AN_AFIO_OR_SLICE");
break;
case BLK_START_AFIOBALLS:
mr_asprintf(outstr, "BLK_START_AFIOBALLS");
break;
case BLK_STOP_AFIOBALLS:
mr_asprintf(outstr, "BLK_STOP_AFIOBALLS");
break;
case BLK_STOP_BIGGIEFILES:
mr_asprintf(outstr, "BLK_STOP_BIGGIEFILES");
break;
case BLK_START_A_NORMBIGGIE:
mr_asprintf(outstr, "BLK_START_A_NORMBIGGIE");
break;
case BLK_START_A_PIHBIGGIE:
mr_asprintf(outstr, "BLK_START_A_PIHBIGGIE");
break;
case BLK_START_EXTENDED_ATTRIBUTES:
mr_asprintf(outstr, "BLK_START_EXTENDED_ATTRIBUTES");
break;
case BLK_STOP_EXTENDED_ATTRIBUTES:
mr_asprintf(outstr, "BLK_STOP_EXTENDED_ATTRIBUTES");
break;
case BLK_START_EXAT_FILE:
mr_asprintf(outstr, "BLK_START_EXAT_FILE");
break;
case BLK_STOP_EXAT_FILE:
mr_asprintf(outstr, "BLK_STOP_EXAT_FILE");
break;
case BLK_START_BIGGIEFILES:
mr_asprintf(outstr, "BLK_START_BIGGIEFILES");
break;
case BLK_STOP_A_BIGGIE:
mr_asprintf(outstr, "BLK_STOP_A_BIGGIE");
break;
case BLK_END_OF_TAPE:
mr_asprintf(outstr, "BLK_END_OF_TAPE");
break;
case BLK_END_OF_BACKUP:
mr_asprintf(outstr, "BLK_END_OF_BACKUP");
break;
case BLK_ABORTED_BACKUP:
mr_asprintf(outstr, "BLK_ABORTED_BACKUP");
break;
case BLK_START_FILE:
mr_asprintf(outstr, "BLK_START_FILE");
break;
case BLK_STOP_FILE:
mr_asprintf(outstr, "BLK_STOP_FILE");
break;
default:
mr_asprintf(outstr, "BLK_UNKNOWN (%d)", marker);
break;
}
return (outstr);
}
/**
* Turn a line from the mountlist into a GUI-friendly string.
* The format is as follows: the left-aligned @p device field padded to 24 places,
* a space, the left-aligned @p mountpoint field again padded to 24 places, a space,
* the left-aligned @p format field padded to 10 places, a space, and the right-aligned
* @p size field (in MB) padded to 8 places. The total string length is exactly 69.
* @param mountlist The mountlist to operate on.
* @param lino The line number in @p mountlist to stringify.
* @return The string form of mountlist-\>el[lino].
* @note The returned string points to storage that needs to be freed by
* caller
*/
char *mountlist_entry_to_string(struct mountlist_itself *mountlist, int lino) {
/*@ buffer *********************************************************** */
char *output = NULL;
assert(mountlist != NULL);
mr_asprintf(output, "%-24s %-24s %-10s %8lld", mountlist->el[lino].device, mountlist->el[lino].mountpoint, mountlist->el[lino].format, mountlist->el[lino].size / 1024L);
return(output);
}
/**
* Generate a friendly string containing "X blah blah disk(s)"
* @param noof_disks The number of disks (the X).
* @param label The "blah blah" part in the middle. If you leave this blank
* there will be a weird double space in the middle, so pass *something*.
* @return The string containing "X blah blah disk(s)".
* @note The returned string is dynamically allocated and should be freed by caller
*/
char *number_of_disks_as_string(int noof_disks, char *label)
{
/*@ buffers ********************************************************* */
char *output = NULL;
/*@ char ******************************************************** */
char p;
assert(label != NULL);
if (noof_disks > 1) {
p = 's';
} else {
p = ' ';
}
mr_asprintf(output, "%d %s disk%c", noof_disks, label, p);
/* Useful ??
while (strlen(output) < 14) {
strcat(output, " ");
}
*/
return (output);
}
/**
* Change @p i into a friendly string. If @p i is \<= 10 then write out the
* number (e.g. "one", "two", ..., "nine", "ten", "11", ...).
* @param i The number to stringify.
* @return The string form of @p i.
* @note The returned value points to strorage that needs to be freed by
* caller
*/
char *number_to_text(int i)
{
/*@ buffers ***************************************************** */
char *output = NULL;
/*@ end vars *************************************************** */
switch (i) {
case 0:
mr_asprintf(output, "zero");
break;
case 1:
mr_asprintf(output, "one");
break;
case 2:
mr_asprintf(output, "two");
break;
case 3:
mr_asprintf(output, "three");
break;
case 4:
mr_asprintf(output, "four");
break;
case 5:
mr_asprintf(output, "five");
break;
case 6:
mr_asprintf(output, "six");
break;
case 7:
mr_asprintf(output, "seven");
break;
case 8:
mr_asprintf(output, "eight");
break;
case 9:
mr_asprintf(output, "nine");
case 10:
mr_asprintf(output, "ten");
default:
mr_asprintf(output, "%d", i);
}
return (output);
}
/**
* Replace all occurences of @p token with @p value while copying @p ip to @p output.
* @param ip The input string containing zero or more tokens.
* @param output The output string written with the tokens replaced by @p value.
* @param token The token to be relaced with @p value.
* @param value The value to replace @p token.
*/
/* TODO: consider mr_strtok */
void resolve_naff_tokens(char *output, char *ip, char *value, const char *token)
{
/*@ buffers *** */
char *input;
/*@ pointers * */
char *p;
input = malloc(2000);
assert(value != NULL);
strcpy(output, ip); /* just in case the token doesn't appear in string at all */
for (strcpy(input, ip); strstr(input, token); strcpy(input, output)) {
strcpy(output, input);
p = strstr(output, token);
*p = '\0';
strcat(output, value);
p = strstr(input, token) + strlen(token);
strcat(output, p);
}
paranoid_free(input);
}
/**
* Generate the filename of slice @p sliceno of biggiefile @p bigfileno
* in @p path with suffix @p s. The format is as follows: @p path, followed
* by "/slice-" and @p bigfileno zero-padded to 7 places, followed by
* a dot and @p sliceno zero-padded to 5 places, followed by ".dat" and the
* suffix. The string is a minimum of 24 characters long.
* @param bigfileno The biggiefile number. Starts from 0.
* @param sliceno The slice number of biggiefile @p bigfileno. 0 is a "header"
* slice (no suffix) containing the biggiestruct, then are the compressed
* slices, then an empty uncompressed "trailer" slice.
* @param path The path to append (with a / in the middle) to the slice filename.
* @param s If not "" then add a "." and this to the end.
* @return The slice filename.
* @note The returned value points to static storage and will be overwritten with each call.
*/
char *slice_fname(long bigfileno, long sliceno, char *path, char *s)
{
/*@ buffers **************************************************** */
static char output[MAX_STR_LEN];
char *suffix = NULL;
/*@ end vars *************************************************** */
assert_string_is_neither_NULL_nor_zerolength(path);
if (s[0] != '\0') {
mr_asprintf(suffix, ".%s", s);
} else {
mr_asprintf(suffix, "");
}
sprintf(output, "%s/slice-%07ld.%05ld.dat%s", path, bigfileno, sliceno, suffix);
mr_free(suffix);
return (output);
}
/**
* Generate a spinning symbol based on integer @p i.
* The symbol rotates through the characters / - \ | to form an ASCII "spinner"
* if successively written to the same location on screen.
* @param i The amount of progress or whatever else to use to determine the character
* for this iteration of the spinner.
* @return The character for this iteration.
*/
int special_dot_char(int i)
{
switch (i % 4) {
case 0:
return ('/');
case 1:
return ('-');
case 2:
return ('\\');
case 3:
return ('|');
default:
return ('.');
}
return ('.');
}
/**
* Compare @p stringA and @p stringB. This uses an ASCII sort for everything
* up to the digits on the end but a numerical sort for the digits on the end.
* @param stringA The first string to compare.
* @param stringB The second string to compare.
* @return The same as strcmp() - <0 if A0 if A>B.
* @note This function only does a numerical sort on the @e last set of numbers. If
* there are any in the middle those will be sorted ASCIIbetically.
*/
int strcmp_inc_numbers(char *stringA, char *stringB)
{
/*@ int ********************************************************* */
int i;
int start_of_numbers_in_A;
int start_of_numbers_in_B;
int res;
/*@ long ******************************************************* */
long numA;
long numB;
/*@ end vars *************************************************** */
assert(stringA != NULL);
assert(stringB != NULL);
if (strlen(stringA) == strlen(stringB)) {
return (strcmp(stringA, stringB));
}
for (i = (int) strlen(stringA); i > 0 && isdigit(stringA[i - 1]); i--);
if (i == (int) strlen(stringA)) {
return (strcmp(stringA, stringB));
}
start_of_numbers_in_A = i;
for (i = (int) strlen(stringB); i > 0 && isdigit(stringB[i - 1]); i--);
if (i == (int) strlen(stringB)) {
return (strcmp(stringA, stringB));
}
start_of_numbers_in_B = i;
if (start_of_numbers_in_A != start_of_numbers_in_B) {
return (strcmp(stringA, stringB));
}
res = strncmp(stringA, stringB, (size_t) i);
if (res) {
return (res);
}
numA = atol(stringA + start_of_numbers_in_A);
numB = atol(stringB + start_of_numbers_in_B);
return ((int) (numA - numB));
}
/**
* Strip excess baggage from @p input, which should be a line from afio.
* For now this copies the whole line unless it finds a set of quotes, in which case
* it copies their contents only.
* @param input The input line (presumably from afio).
* @return The stripped line.
* @note The returned string points to static storage that will be overwritten with each call.
*/
char *strip_afio_output_line(char *input)
{
/*@ buffer ****************************************************** */
static char output[MAX_STR_LEN];
/*@ pointers **************************************************** */
char *p;
char *q;
/*@ end vars *************************************************** */
assert(input != NULL);
strcpy(output, input);
p = strchr(input, '\"');
if (p) {
q = strchr(++p, '\"');
if (q) {
strcpy(output, p);
*(strchr(output, '\"')) = '\0';
}
}
return (output);
}
/**
* Remove all characters whose ASCII value is less than or equal to 32
* (spaces and control characters) from both sides of @p in_out.
* @param in_out The string to strip spaces/control characters from (modified).
*/
void strip_spaces(char *in_out)
{
/*@ buffers ***************************************************** */
char *tmp = NULL;
/*@ int ******************************************************** */
int i;
/*@ end vars *************************************************** */
assert(in_out != NULL);
malloc_string(tmp);
for (i = 0; in_out[i] <= ' ' && i < (int) strlen(in_out) -1; i++);
strcpy(tmp, in_out + i);
for (i = (int) strlen(tmp) -1; i >= 0 && tmp[i] <= ' '; i--);
i++;
tmp[i] = '\0';
// Now tmp contains the stripped string
strcpy(in_out,tmp);
paranoid_free(tmp);
}
/**
* Remove all characters whose ASCII value is less than or equal to 32
* (spaces and control characters) from both sides of @p in_out.
* @param in_out The string to strip spaces/control characters from (modified).
*/
void strip_spaces2(char *in_out)
{
/*@ buffers ***************************************************** */
char *tmp;
/*@ pointers **************************************************** */
char *p;
/*@ int ******************************************************** */
int i;
int original_incoming_length;
/*@ end vars *************************************************** */
assert(in_out != NULL);
malloc_string(tmp);
original_incoming_length = (int) strlen(in_out);
for (i = 0; in_out[i] <= ' ' && i < (int) strlen(in_out); i++);
strcpy(tmp, in_out + i);
for (i = (int) strlen(tmp); i > 0 && tmp[i - 1] <= 32; i--);
tmp[i] = '\0';
for (i = 0; i < original_incoming_length && MAX_STR_LEN; i++) {
in_out[i] = ' ';
}
in_out[i] = '\0';
i = 0;
p = tmp;
while (*p != '\0') {
in_out[i] = *(p++);
in_out[i + 1] = '\0';
if (in_out[i] < 32 && i > 0) {
if (in_out[i] == 8) {
i--;
} else if (in_out[i] == 9) {
in_out[i++] = ' ';
} else if (in_out[i] == '\r') // added 1st October 2003 -- FIXME
{
strcpy(tmp, in_out + i);
strcpy(in_out, tmp);
i = -1;
continue;
} else if (in_out[i] == '\t') {
for (i++; i % 5; i++);
} else if (in_out[i] >= 10 && in_out[i] <= 13) {
break;
} else {
i--;
}
} else {
i++;
}
}
in_out[i] = '\0';
paranoid_free(tmp);
}
/**
* If there are double quotes "" around @p incoming then remove them.
* This does not affect other quotes that may be embedded within the string.
* @param incoming The string to trim quotes from (modified).
* @return @p incoming.
*/
char *trim_empty_quotes(char *incoming)
{
/*@ buffer ****************************************************** */
static char outgoing[MAX_STR_LEN];
/*@ end vars *************************************************** */
assert(incoming != NULL);
if (incoming[0] == '\"' && incoming[strlen(incoming) - 1] == '\"') {
strcpy(outgoing, incoming + 1);
outgoing[strlen(outgoing) - 1] = '\0';
} else {
strcpy(outgoing, incoming);
}
return (outgoing);
}
/**
* Remove any partition info from @p partition, leaving just the drive name.
* @param partition The partition name soon-to-become drive name. (modified)
* @return @p partition.
*/
char *truncate_to_drive_name(const char *partition)
{
int i = strlen(partition) - 1;
char *c;
char *trunc = NULL;
assert_string_is_neither_NULL_nor_zerolength(partition);
mr_asprintf(trunc, "%s", partition);
#ifdef __FreeBSD__
if (islower(trunc[i])) // BSD subpartition
i--;
if (trunc[i-1] == 's') {
while (isdigit(trunc[i]))
i--;
i--;
}
trunc[i+1] = '\0';
#else
/* first see if it's a devfs style device */
c = strrchr(trunc, '/');
if (c && strncmp(c, "/part", 5) == 0) {
/* yup it's devfs, return the "disc" path */
strcpy(c + 1, "disc");
return trunc;
}
/* then see if it's a dm style device */
if (c && strncmp(c, "/dm-", 4) == 0) {
/* yup it's dm, return the full path */
return trunc;
}
for (i = strlen(trunc); isdigit(trunc[i-1]); i--)
continue;
if (trunc[i-1] == 'p' && isdigit(trunc[i-2])) {
i--;
} else {
/* Some full devices like this /dev/mapper/mpath0
/dev/cciss/c0d0 may be used as partition names */
if ((strstr(trunc,"/dev/mapper/mpath") != NULL) ||
(strstr(trunc,"/dev/cciss/c") != NULL) ||
(strstr(trunc,"/dev/rd/") != NULL)) {
return trunc;
}
}
trunc[i] = '\0';
#endif
return trunc;
}
/**
* Turn a RAID level number (-1 to 5) into a friendly string. The string
* is either "Linear RAID" for -1, or " RAID %-2d " (%d = @p raid_level)
* for anything else.
* @param raid_level The RAID level to stringify.
* @return The string form of @p raid_level.
* @note The returned value points to storage that needs to be freed by caller
*/
char *turn_raid_level_number_to_string(int raid_level)
{
/*@ buffer ********************************************************** */
char *output = NULL;
if (raid_level >= 0) {
mr_asprintf(output, " RAID %-2d ", raid_level);
} else {
mr_asprintf(output, "Linear RAID");
}
return(output);
}
/**
* Determine the severity (1-3, 1 being low) of the fact that
* @p fn changed in the live filesystem (verify/compare).
* @param fn The filename that changed.
* @param out_reason If non-NULL, a descriptive reason for the difference will be copied here.
* @return The severity (1-3).
*/
int severity_of_difference(char *fn, char **out_reason) {
int sev = 3;
char *reason = NULL;
char *filename = NULL;
// out_reason might be null on purpose, so don't bomb if it is :) OK?
assert_string_is_neither_NULL_nor_zerolength(fn);
if (!strncmp(fn, MNT_RESTORING, strlen(MNT_RESTORING))) {
mr_asprintf(filename, "%s", fn + strlen(MNT_RESTORING));
} else if (fn[0] != '/') {
mr_asprintf(filename, "/%s", fn);
} else {
mr_asprintf(filename, "%s", fn);
}
mr_asprintf(reason, "Changed since backup. Consider running a differential backup in a day or two.");
if (!strncmp(filename, "/var/", 5)) {
sev = 2;
mr_free(reason);
mr_asprintf(reason, "/var's contents will change regularly, inevitably.");
}
if (!strncmp(filename, "/home", 5)) {
sev = 2;
mr_free(reason);
mr_asprintf(reason, "It's in your /home directory. Therefore, it is important.");
}
if (!strncmp(filename, "/usr/", 5)) {
sev = 3;
mr_free(reason);
mr_asprintf(reason, "You may have installed/removed software during the backup.");
}
if (!strncmp(filename, "/etc/", 5)) {
sev = 3;
mr_free(reason);
mr_asprintf(reason, "Do not edit config files while backing up your machine.");
}
if (!strcmp(filename, "/etc/adjtime")
|| !strcmp(filename, "/etc/mtab")) {
sev = 1;
mr_free(reason);
mr_asprintf(reason, "This file changes all the time. It's OK.");
}
if (!strncmp(filename, "/root/", 6)) {
sev = 3;
mr_free(reason);
mr_asprintf(reason, "Were you compiling/editing something in /root?");
}
if (!strncmp(filename, "/root/.", 7)) {
sev = 2;
mr_free(reason);
mr_asprintf(reason, "Temp or 'dot' files changed in /root.");
}
if (!strncmp(filename, "/var/lib/", 9)) {
sev = 2;
mr_free(reason);
mr_asprintf(reason, "Did you add/remove software during backing?");
}
if (!strncmp(filename, "/var/lib/rpm", 12)) {
sev = 3;
mr_free(reason);
mr_asprintf(reason, "Did you add/remove software during backing?");
}
if (!strncmp(filename, "/var/lib/slocate", 16)) {
sev = 1;
mr_free(reason);
mr_asprintf(reason, "The 'update' daemon ran during backup. This does not affect the integrity of your backup.");
}
if (!strncmp(filename, "/var/log/", 9)
|| strstr(filename, "/.xsession")
|| !strcmp(filename + strlen(filename) - 4, ".log")) {
sev = 1;
mr_free(reason);
mr_asprintf(reason, "Log files change frequently as the computer runs. Fret not.");
}
if (!strncmp(filename, "/var/spool", 10)) {
sev = 1;
mr_free(reason);
mr_asprintf(reason, "Background processes or printers were active. This does not affect the integrity of your backup.");
}
if (!strncmp(filename, "/var/spool/mail", 10)) {
sev = 2;
mr_free(reason);
mr_asprintf(reason, "Mail was sent/received during backup.");
}
if (filename[strlen(filename) - 1] == '~') {
sev = 1;
mr_free(reason);
mr_asprintf(reason, "Backup copy of another file which was modified recently.");
}
if (strstr(filename, "cache")) {
sev = 1;
mr_free(reason);
mr_asprintf(reason, "Part of a cache of data. Caches change from time to time. Don't worry.");
}
if (!strncmp(filename, "/var/run/", 9)
|| !strncmp(filename, "/var/lock", 8)
|| strstr(filename, "/.DCOPserver") || strstr(filename, "/.MCOP")
|| strstr(filename, "/.Xauthority")) {
sev = 1;
mr_free(reason);
mr_asprintf(reason, "Temporary file (a lockfile, perhaps) used by software such as X or KDE to register its presence.");
}
if (out_reason) {
strcpy(*out_reason, reason);
}
mr_free(filename);
mr_free(reason);
return (sev);
}
/**
* Compare the filenames in two filelist entries (s_filelist_entry*) casted
* to void*.
* @param va The first filelist entry, cast as a @c void pointer.
* @param vb The second filelist entry, cast as a @c void pointer.
* @return The return value of strcmp().
*/
int compare_two_filelist_entries(void *va, void *vb)
{
static int res;
struct s_filelist_entry *fa, *fb;
assert(va != NULL);
assert(vb != NULL);
fa = (struct s_filelist_entry *) va;
fb = (struct s_filelist_entry *) vb;
res = strcmp(fa->filename, fb->filename);
return (res);
}
/**
* Generate a line intended to be passed to update_evalcall_form(), indicating
* the current media fill percentage (or number of kilobytes if size is not known).
* @param bkpinfo The backup media structure. Fields used:
* - @c bkpinfo->backup_media_type
* - @c bkpinfo->media_size
* - @c bkpinfo->scratchdir
* @return The string indicating media fill.
* @note The returned string points to static storage that will be overwritten with each call.
*/
char *percent_media_full_comment()
{
/*@ int *********************************************** */
int percentage;
int j;
/*@ buffers ******************************************* */
char * outstr = NULL;
char *pos_w_commas = NULL;
char *mds = NULL;
assert(bkpinfo != NULL);
if (bkpinfo->media_size <= 0) {
mr_asprintf(pos_w_commas, "%lld", g_tape_posK);
mr_asprintf(outstr, "Volume %d: %s kilobytes archived so far", g_current_media_number, pos_w_commas);
mr_free(pos_w_commas);
return (outstr);
}
/* update screen */
if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
percentage = (int) (g_tape_posK / 10 / bkpinfo->media_size);
if (percentage > 100) {
percentage = 100;
}
mr_asprintf(outstr, "Volume %d: [", g_current_media_number);
} else {
percentage = (int) (space_occupied_by_cd(bkpinfo->scratchdir) * 100 / 1024 / bkpinfo->media_size);
mds = media_descriptor_string(bkpinfo->backup_media_type);
mr_asprintf(outstr, "%s %d: [", mds, g_current_media_number);
mr_free(mds);
}
for (j = 0; j < percentage; j += 5) {
mr_strcat(outstr, "*");
}
for (; j < 100; j += 5) {
mr_strcat(outstr, ".");
}
mr_strcat(outstr, "] %d%% used", percentage);
return (outstr);
}
/**
* Get a string form of @p type_of_bkp.
* @param type_of_bkp The backup type to stringify.
* @return The stringification of @p type_of_bkp.
* @note The returned string points to static storage that will be overwritten with each call.
*/
char *media_descriptor_string(t_bkptype type_of_bkp) {
char *type_of_backup = NULL;
switch (type_of_bkp) {
case dvd:
mr_asprintf(type_of_backup, "DVD");
break;
case cdr:
mr_asprintf(type_of_backup, "CDR");
break;
case cdrw:
mr_asprintf(type_of_backup, "CDRW");
break;
case tape:
mr_asprintf(type_of_backup, "tape");
break;
case cdstream:
mr_asprintf(type_of_backup, "CDR");
break;
case udev:
mr_asprintf(type_of_backup, "udev");
break;
case iso:
mr_asprintf(type_of_backup, "ISO");
break;
case netfs:
mr_asprintf(type_of_backup, "%s", bkpinfo->netfs_proto);
break;
case usb:
mr_asprintf(type_of_backup, "USB");
break;
default:
mr_asprintf(type_of_backup, "ISO");
}
return (type_of_backup);
}