mirror of https://github.com/sfeakes/AqualinkD.git
246 lines
6.6 KiB
C
246 lines
6.6 KiB
C
/*
|
|
* Copyright (c) 2017 Shaun Feakes - All rights reserved
|
|
*
|
|
* You may use redistribute and/or modify this code under the terms of
|
|
* the GNU General Public License version 2 as published by the
|
|
* Free Software Foundation. For the terms of this license,
|
|
* see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* You are free to use this software under the terms of the GNU General
|
|
* Public License, but WITHOUT ANY WARRANTY; without even the implied
|
|
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
* See the GNU General Public License for more details.
|
|
*
|
|
* https://github.com/sfeakes/aqualinkd
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/statvfs.h>
|
|
#include <sys/wait.h>
|
|
|
|
#include "aqualink.h"
|
|
#include "aq_scheduler.h"
|
|
|
|
bool remount_root_ro(bool readonly)
|
|
{
|
|
|
|
#ifdef AQ_CONTAINER
|
|
// In container this is pointless
|
|
return false;
|
|
#endif
|
|
|
|
if (readonly)
|
|
{
|
|
LOG(AQUA_LOG, LOG_INFO, "reMounting root RO\n");
|
|
mount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
struct statvfs fsinfo;
|
|
statvfs("/", &fsinfo);
|
|
if ((fsinfo.f_flag & ST_RDONLY) == 0) // We are readwrite, ignore
|
|
return false;
|
|
|
|
LOG(AQUA_LOG, LOG_INFO, "reMounting root RW\n");
|
|
mount(NULL, "/", NULL, MS_REMOUNT, NULL);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
FILE *aq_open_file(char *filename, bool *ro_root, bool *created_file)
|
|
{
|
|
FILE *fp;
|
|
|
|
*ro_root = remount_root_ro(false);
|
|
|
|
if (access(filename, F_OK) == 0)
|
|
{
|
|
*created_file = true;
|
|
}
|
|
|
|
fp = fopen(filename, "w");
|
|
if (fp == NULL)
|
|
{
|
|
remount_root_ro(*ro_root);
|
|
}
|
|
|
|
return fp;
|
|
}
|
|
|
|
bool aq_close_file(FILE *file, bool ro_root)
|
|
{
|
|
if (file != NULL)
|
|
fclose(file);
|
|
|
|
return remount_root_ro(ro_root);
|
|
}
|
|
|
|
#define BUFFER_SIZE 4096
|
|
|
|
bool copy_file(const char *source_path, const char *destination_path)
|
|
{
|
|
|
|
bool ro_root = remount_root_ro(false);
|
|
|
|
FILE *source_file = fopen(source_path, "rb");
|
|
if (source_file == NULL)
|
|
{
|
|
LOG(AQUA_LOG, LOG_ERR, "Error opening source file: %s\n", source_path);
|
|
remount_root_ro(ro_root);
|
|
return false;
|
|
}
|
|
|
|
FILE *destination_file = fopen(destination_path, "wb");
|
|
if (destination_file == NULL)
|
|
{
|
|
LOG(AQUA_LOG, LOG_ERR, "Error opening source file: %s\n", destination_path);
|
|
fclose(source_file);
|
|
remount_root_ro(ro_root);
|
|
return false;
|
|
}
|
|
|
|
char buffer[BUFFER_SIZE];
|
|
size_t bytes_read;
|
|
|
|
while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, source_file)) > 0)
|
|
{
|
|
if (fwrite(buffer, 1, bytes_read, destination_file) != bytes_read)
|
|
{
|
|
LOG(AQUA_LOG, LOG_ERR, "Error writing to destination file: %s\n", destination_path);
|
|
fclose(source_file);
|
|
fclose(destination_file);
|
|
remount_root_ro(ro_root);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (ferror(source_file))
|
|
{
|
|
LOG(AQUA_LOG, LOG_ERR, "Error reading from source: %s\n", source_path);
|
|
fclose(source_file);
|
|
fclose(destination_file);
|
|
remount_root_ro(ro_root);
|
|
return false;
|
|
}
|
|
|
|
fclose(source_file);
|
|
fclose(destination_file);
|
|
remount_root_ro(ro_root);
|
|
return true;
|
|
}
|
|
|
|
bool run_aqualinkd_upgrade(bool onlycheck)
|
|
{
|
|
int pipe_curl_to_bash[2];
|
|
pid_t pid_curl, pid_bash;
|
|
//char *curl_args[] = {"curl", "-fsSl", "http://tiger/scratch/remote_install.sh", NULL};
|
|
char *curl_args[] = {"curl", "-fsSl", "-H", "Accept: application/vnd.github.raw", "https://api.github.com/repos/AqualinkD/AqualinkD/contents/release/remote_install.sh", NULL};
|
|
char *bash_args[] = {"bash", "-s", "--", "check", NULL};
|
|
int status_curl, status_bash;
|
|
|
|
if (!onlycheck) {
|
|
bash_args[3] = NULL;
|
|
}
|
|
|
|
if (pipe(pipe_curl_to_bash) == -1)
|
|
{
|
|
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, opening pipe");
|
|
return false;
|
|
}
|
|
|
|
// Fork for curl
|
|
pid_curl = fork();
|
|
if (pid_curl == -1)
|
|
{
|
|
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, fork (curl)");
|
|
return false;
|
|
}
|
|
|
|
if (pid_curl == 0)
|
|
{ // Child process (curl)
|
|
close(pipe_curl_to_bash[0]);
|
|
dup2(pipe_curl_to_bash[1], STDOUT_FILENO);
|
|
close(pipe_curl_to_bash[1]);
|
|
execvp("curl", curl_args);
|
|
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, execvp (curl)");
|
|
return false;
|
|
}
|
|
|
|
// Fork for bash
|
|
pid_bash = fork();
|
|
if (pid_bash == -1)
|
|
{
|
|
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, fork (bash)");
|
|
return false;
|
|
}
|
|
|
|
if (pid_bash == 0)
|
|
{ // Child process (bash)
|
|
close(pipe_curl_to_bash[1]);
|
|
dup2(pipe_curl_to_bash[0], STDIN_FILENO);
|
|
close(pipe_curl_to_bash[0]);
|
|
execvp("bash", bash_args);
|
|
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, execvp (bash)");
|
|
return false;
|
|
}
|
|
|
|
// Parent process
|
|
close(pipe_curl_to_bash[0]);
|
|
close(pipe_curl_to_bash[1]);
|
|
|
|
// Wait for curl and get its exit status
|
|
if (waitpid(pid_curl, &status_curl, 0) == -1)
|
|
{
|
|
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, waitpid (curl)");
|
|
return false;
|
|
}
|
|
|
|
// Wait for bash and get its exit status
|
|
if (waitpid(pid_bash, &status_bash, 0) == -1)
|
|
{
|
|
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, waitpid (bash)");
|
|
return false;
|
|
}
|
|
|
|
// Check the exit status of curl
|
|
if (WIFEXITED(status_curl))
|
|
{
|
|
//printf("curl exited with status: %d\n", WEXITSTATUS(status_curl));
|
|
if (WEXITSTATUS(status_curl) != 0) {
|
|
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, curl exited with status: %d\n", WEXITSTATUS(status_curl));
|
|
return false;
|
|
}
|
|
}
|
|
else if (WIFSIGNALED(status_curl))
|
|
{
|
|
//printf("curl terminated by signal: %d\n", WTERMSIG(status_curl));
|
|
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, curl terminated by signal: %d\n", WTERMSIG(status_curl));
|
|
return false;
|
|
}
|
|
|
|
// Check the exit status of bash
|
|
if (WIFEXITED(status_bash))
|
|
{
|
|
//printf("bash exited with status: %d\n", WEXITSTATUS(status_bash));
|
|
if (WEXITSTATUS(status_bash) != 0) {
|
|
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, bash exited with status: %d\n", WEXITSTATUS(status_bash));
|
|
return false;
|
|
}
|
|
}
|
|
else if (WIFSIGNALED(status_bash))
|
|
{
|
|
//printf("bash terminated by signal: %d\n", WTERMSIG(status_bash));
|
|
LOG(AQUA_LOG, LOG_ERR,"Upgrade error, bash terminated by signal: %d\n", WTERMSIG(status_bash));
|
|
return false;
|
|
}
|
|
|
|
//printf("Command execution complete.\n");
|
|
LOG(AQUA_LOG, LOG_NOTICE, "AqualinkD is upgrading!");
|
|
return true;
|
|
} |