Add a customization option for rsync's flags

This commit is contained in:
Tomas Rivera
2026-04-17 13:19:43 +02:00
parent a458a5bc3d
commit c063a6abe3
8 changed files with 55 additions and 29 deletions
+1
View File
@@ -6,3 +6,4 @@ error.log
output.log output.log
result result
massif.out.* massif.out.*
*.out.*
+3 -2
View File
@@ -67,7 +67,8 @@ Change `~/.config/notewrapper/config.json`. If it does not exist, the program sh
"backup": { "backup": {
"enable": false, "enable": false,
"directory": "/path/to/backup", "directory": "/path/to/backup",
"interval": "weekly" "interval": "weekly",
"rsyncArgs": ["-Lqah", "--update"]
} }
} }
``` ```
@@ -90,7 +91,7 @@ Change `~/.config/notewrapper/config.json`. If it does not exist, the program sh
`backup.directory` is the directory where the backup will go. `backup.directory` is the directory where the backup will go.
`backup.interval` can either be `daily`, `weekly`, `monthly` or an integer. It specifies the interval between two backups. `backup.interval` can either be `daily`, `weekly`, `monthly` or an integer. It specifies the interval between two backups.
`rsyncArgs` are the array of arguments that will be passed into rsync. See `man rsync` or `rsync --help`.
### What needs to be done (a lot) ### What needs to be done (a lot)
+1
View File
@@ -7,5 +7,6 @@ pkgs.mkShell {
pkgs.pkg-config pkgs.pkg-config
pkgs.gdb pkgs.gdb
pkgs.valgrind pkgs.valgrind
pkgs.kdePackages.kcachegrind
]; ];
} }
+31 -10
View File
@@ -1,6 +1,8 @@
#include "cjson/cJSON.h"
#include "ui.h" #include "ui.h"
#include "utils.h" #include "utils.h"
#include "notes.h" #include "notes.h"
#include <stdlib.h>
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
int shouldDebug = 0; int shouldDebug = 0;
@@ -177,12 +179,15 @@ arg_next:
int doesBackup = 0; int doesBackup = 0;
int interval = 0; // this is an int. But some times it will be inputed a string. We must translate it. int interval = 0; // this is an int. But some times it will be inputed a string. We must translate it.
char *pathToBackup = malloc(PATH_MAX); char *pathToBackup = malloc(PATH_MAX);
char **rsyncArgs = NULL;
int rsyncArgsNumber = 0;
cJSON *backupJSON = cJSON_GetObjectItem(json, "backup"); cJSON *backupJSON = cJSON_GetObjectItem(json, "backup");
if (backupJSON && cJSON_IsObject(backupJSON)) { if (backupJSON && cJSON_IsObject(backupJSON)) {
cJSON *doesBackupJSON = cJSON_GetObjectItem(backupJSON, "enable"); cJSON *doesBackupJSON = cJSON_GetObjectItem(backupJSON, "enable");
if (doesBackupJSON && cJSON_IsBool(doesBackupJSON)) { if (doesBackupJSON && cJSON_IsBool(doesBackupJSON)) {
doesBackup = cJSON_IsTrue(doesBackupJSON) ? 1 : 0; doesBackup = cJSON_IsTrue(doesBackupJSON) ? 1 : 0;
debug("doesBackup is set to %d", doesBackup); debug("doesBackup is set to %d", doesBackup);
// handles the path to the backup
cJSON *pathToBackupJSON = cJSON_GetObjectItem(backupJSON, "directory"); cJSON *pathToBackupJSON = cJSON_GetObjectItem(backupJSON, "directory");
if (pathToBackupJSON && cJSON_IsString(pathToBackupJSON)) { if (pathToBackupJSON && cJSON_IsString(pathToBackupJSON)) {
char *temp = cJSON_GetStringValue(pathToBackupJSON); // we name it temp. As we can't directly set pathToBackup because snprintf doesn't like when a pointer is both an arg and the destination // temp should be freed when free(json), because cJSON_GetStringValue returns a pointer. char *temp = cJSON_GetStringValue(pathToBackupJSON); // we name it temp. As we can't directly set pathToBackup because snprintf doesn't like when a pointer is both an arg and the destination // temp should be freed when free(json), because cJSON_GetStringValue returns a pointer.
@@ -192,30 +197,46 @@ arg_next:
debug("~ was expanded to %s\nThe backup path is %s", homedir, pathToBackup); debug("~ was expanded to %s\nThe backup path is %s", homedir, pathToBackup);
} else { } else {
pathToBackup = strndup(temp, PATH_MAX); // temp will be freed later so strndup pathToBackup = strndup(temp, PATH_MAX); // temp will be freed later so strndup
debug("Directory for backup is set to %s in config.json", pathToBackup); debug("Directory for backup is set to %s in %s", pathToBackup, configPath);
} }
} else {error(1, "user", "config.json did not contained a directory inside the backup section or the value is from an unexpected type");} } else {error(1, "user", "%s did not contained a directory inside the backup section or the value is from an unexpected type", configPath);}
// handles the interval of backup
cJSON *intervalJSON = cJSON_GetObjectItem(backupJSON, "interval"); cJSON *intervalJSON = cJSON_GetObjectItem(backupJSON, "interval");
if (intervalJSON && cJSON_IsString(intervalJSON)) { if (intervalJSON && cJSON_IsString(intervalJSON)) {
char *temp = cJSON_GetStringValue(intervalJSON); // se comment higher. temp will be freed when calling free(json) char *temp = cJSON_GetStringValue(intervalJSON); // se comment higher. temp will be freed when calling free(json)
if (strcmp(temp, "daily") == 0) { if (strcmp(temp, "daily") == 0) {
interval = DAILY; interval = DAILY;
debug("interval in config.json is set to \"daily\" which is %d", DAILY); debug("interval in %s is set to \"daily\" which is %d", configPath, DAILY);
} else if (strcmp(temp, "weekly") == 0) { } else if (strcmp(temp, "weekly") == 0) {
interval = WEEKLY; interval = WEEKLY;
debug("interval in config.json is set to \"weekly\" which is %d", WEEKLY); debug("interval in %s is set to \"weekly\" which is %d", configPath, WEEKLY);
} else if (strcmp(temp, "monthly") == 0) { } else if (strcmp(temp, "monthly") == 0) {
interval = MONTHLY; interval = MONTHLY;
debug("interval in config.json is set to \"monthly\" which is %d", MONTHLY); debug("interval in %s is set to \"monthly\" which is %d", configPath, MONTHLY);
} else {error(1, "user", "Unexpected string %s for entry \"interval\" in config.json. You must put an int (number of seconds) or \"daily\" or \"weekly\" or \"monthly\".", intervalJSON->valuestring);} } else {error(1, "user", "Unexpected string %s for entry \"interval\" in %s. You must put an int (number of seconds) or \"daily\" or \"weekly\" or \"monthly\".", intervalJSON->valuestring, configPath);}
} else if (intervalJSON && cJSON_IsNumber(intervalJSON)) { } else if (intervalJSON && cJSON_IsNumber(intervalJSON)) {
interval = (int)cJSON_GetNumberValue(intervalJSON); interval = (int)cJSON_GetNumberValue(intervalJSON);
debug("interval in config.json is set to %d", interval); debug("interval in %s is set to %d", configPath, interval);
} else {error(1, "user", "config.json did not contained an interval value inside the backup section or the value is from an unexpected type");} } else {error(1, "user", "%s did not contained an interval value inside the backup section or the value is from an unexpected type", configPath);}
} else{error(1, "user", "config.json did not contained a enable value inside the backup section or the value is from an unexpected type");} } else{error(1, "user", "%s did not contained a enable value inside the backup section or the value is from an unexpected type", configPath);}
// handle rsyncs array of arguments.
cJSON *rsyncArgsJSON = cJSON_GetObjectItem(backupJSON, "rsyncArgs");
if (rsyncArgsJSON && cJSON_IsArray(rsyncArgsJSON)) { // if it is what we expected
rsyncArgsNumber = cJSON_GetArraySize(rsyncArgsJSON);
rsyncArgs = realloc(rsyncArgs, (size_t)rsyncArgsNumber);
for (int i = 0; i < rsyncArgsNumber; i++) {
cJSON *argJSON = cJSON_GetArrayItem(rsyncArgsJSON, i);
if (argJSON && cJSON_IsString(argJSON)) {
rsyncArgs[i] = cJSON_GetStringValue(argJSON);
} else {error(1, "user", "One element in rsyncArgs array in %s is not a string", configPath);}
}
} else {error(1, "user", "%s did not contained a rsyncArgs array inside the backup section or the value is from an unexpected type", configPath);}
} else { } else {
debug("In %s, \"backup\" wasn't set or we encountered a abnormal type. Defaulting to {\"enable\": false}.", configPath); debug("In %s, \"backup\" wasn't set or we encountered a abnormal type. Defaulting to {\"enable\": false}.", configPath);
} }
//cleans up //cleans up
cJSON_Delete(json); cJSON_Delete(json);
free(data); free(data);
@@ -402,7 +423,7 @@ next_arg:
debug("Finished parsing the attribute flags"); debug("Finished parsing the attribute flags");
if (doesBackup) { // (TODO LATER) when implementing multiple directories for vault we should verifiy this works. if (doesBackup) { // (TODO LATER) when implementing multiple directories for vault we should verifiy this works.
handleBackups(notesDirectoryString, pathToBackup, homedir, interval, shouldDebug); handleBackups(notesDirectoryString, pathToBackup, homedir, interval, (const char**)rsyncArgs, rsyncArgsNumber, shouldDebug);
} }
initscr(); //initialize ncurses initscr(); //initialize ncurses
+1 -1
View File
@@ -24,7 +24,7 @@ input_screen:
attroff(COLOR_PAIR(2)); attroff(COLOR_PAIR(2));
} }
move(1, 1); // replace cursor move(1, 1); // replace cursor
wgetnstr(stdscr, vaultName, sizeof(vaultName)-1); wgetnstr(stdscr, vaultName, PATH_MAX-1);
refresh(); refresh();
endwin(); endwin();
reset_shell_mode(); reset_shell_mode();
+15 -14
View File
@@ -70,7 +70,7 @@ void _error(const int shouldDebug, const int condition, const char *type, const
} }
} }
void copyDir(const char *source, const char *destination, const int shouldDebug) { static void copyDir(const char *source, const char *destination, const char **rsyncArgs, const int rsyncArgsNumber, const int shouldDebug) {
debug("Backuping... source: %s and destination: %s", source, destination); debug("Backuping... source: %s and destination: %s", source, destination);
pid_t pid = fork(); pid_t pid = fork();
@@ -78,16 +78,16 @@ void copyDir(const char *source, const char *destination, const int shouldDebug)
if (pid == 0) { if (pid == 0) {
// Child process: execute rsync // Child process: execute rsync
char *args[] = { // (TODO LATER) char **args = malloc((4 + rsyncArgsNumber)*sizeof(char*));
"rsync", args[0] = "rsync";
"-Lqah", // archive, follow links, human-readable // (TODO LATER) add a way to get verbose (-v) without it going on top of ncurses for (int i = 0; i < rsyncArgsNumber; i++) {
"--progress", // show progress args[i+1] = (char *)rsyncArgs[i];
"--update", // only update if newer if (i == rsyncArgsNumber-1) { // last loop
(char *)source, args[i+2] = (char*)source;
(char *)destination, args[i+3] = (char*)destination;
NULL args[i+4] = NULL; // execvp expect last arg to be NULL
}; }
}
execvp("rsync", args); execvp("rsync", args);
// If execvp returns, there was an error // If execvp returns, there was an error
error(1, "program", "execvp() failed"); error(1, "program", "execvp() failed");
@@ -141,14 +141,15 @@ void initAppFilesAndDirs(const char *home, const int shouldDebug) {
" \"backup\": {\n" " \"backup\": {\n"
" \"enable\": false,\n" " \"enable\": false,\n"
" \"directory\": \"/path/to/backup\",\n" " \"directory\": \"/path/to/backup\",\n"
" \"interval\": \"weekly\"\n" " \"interval\": \"weekly\",\n"
" \"rsyncArgs\": [\"-Lqah\", \"--update\"]\n"
" }\n" " }\n"
"}\n"); "}\n");
fclose(w); fclose(w);
} }
void handleBackups(const char *pathOfVaults, const char *pathOfBackup, const char *homeDir, const int interval, const int shouldDebug) { void handleBackups(const char *pathOfVaults, const char *pathOfBackup, const char *homeDir, const int interval, const char **rsyncArguments, const int rsyncArgumentsNumber, const int shouldDebug) {
int shouldBackup = 0; int shouldBackup = 0;
time_t now = time(NULL); time_t now = time(NULL);
debug("Time since epoch is %ld", (long)now); debug("Time since epoch is %ld", (long)now);
@@ -194,7 +195,7 @@ void handleBackups(const char *pathOfVaults, const char *pathOfBackup, const cha
} }
if (shouldBackup) { if (shouldBackup) {
copyDir(pathOfVaults, pathOfBackup, shouldDebug); copyDir(pathOfVaults, pathOfBackup, rsyncArguments, rsyncArgumentsNumber, shouldDebug);
} }
} }
+3 -2
View File
@@ -76,6 +76,7 @@ int openEditor(char *path, char *editor, int render, int shouldJumpToEndOfFile,
// you should not forgot to free this string as it is in the heap. // you should not forgot to free this string as it is in the heap.
char *getFormatedTime(char *format, int shouldDebug); char *getFormatedTime(char *format, int shouldDebug);
/* Caclulates if we need to do another backup (by reading ~/.cache/NoteWrapper/backupTime.txt. /* Caclulates if we need to do another backup (by reading ~/.cache/NoteWrapper/backupTime.txt.
If need launches in the background rsync to do the backuping.*/ If need launches in the background rsync to do the backuping.
void handleBackups(const char *pathOfVaults, const char *pathOfBackup, const char *homeDir, const int interval, const int shouldDebug); rsyncArgs is the array of arguments to be passed to rsync. Do not inclue destination or source. It will be added in the function.*/
void handleBackups(const char *pathOfVaults, const char *pathOfBackup, const char *homeDir, const int interval, const char **rsyncArgs, const int rsyncArgsNumber, const int shouldDebug);
#endif #endif
BIN
View File
Binary file not shown.