Compare commits

..

3 commits
rust ... master

Author SHA1 Message Date
55d29e84dc
Fix dependency installation in workflow
All checks were successful
Build / build-and-test (pull_request) Successful in 27s
2024-08-14 21:19:35 -06:00
54a9b3e71b
fixup! Add Forgejo workflow
Some checks failed
Build / build-and-test (pull_request) Failing after 7s
2024-08-14 19:25:14 -06:00
2b322cbef2
Add Forgejo workflow
Some checks failed
Build / build-and-test (pull_request) Failing after 10s
2024-08-14 19:10:56 -06:00
22 changed files with 1639 additions and 32 deletions

View file

@ -0,0 +1,24 @@
name: Build
on: pull_request
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Dependencies
run: |
sudo apt-get update
sudo apt-get install -y cmake \
make \
gcc \
g++ \
autoconf \
libtool \
libcurl4-openssl-dev \
libssl-dev \
libjson-c-dev
- name: Build
run: |
cmake -DPIHELPER_EXECUTABLE=BOOL:ON -B build
cmake --build build

8
.gitignore vendored
View file

@ -1,3 +1,5 @@
# Added by cargo
/target
build/
*.o
tags
*.swp
deps/

29
CMakeLists.txt Normal file
View file

@ -0,0 +1,29 @@
# Copyright © 2019, 2020 William Brawner.
#
# This file is part of PiHelper.
#
# PiHelper is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# PiHelper is distributed in the hope that it will be useful,
# 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.
#
# You should have received a copy of the GNU General Public License
# along with PiHelper. If not, see <https://www.gnu.org/licenses/>.
cmake_minimum_required (VERSION 3.10.2)
project(
pihelper
VERSION 0.1.0
LANGUAGES C
)
add_subdirectory(src)
add_subdirectory(doc)

7
Cargo.lock generated
View file

@ -1,7 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "pihelper"
version = "0.1.0"

View file

@ -1,14 +0,0 @@
[package]
name = "pihelper"
version = "0.1.0"
edition = "2021"
[[bin]]
name = "pihelper"
[lib]
name = "pihelper"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

3
doc/CMakeLists.txt Normal file
View file

@ -0,0 +1,3 @@
if(PIHELPER_EXECUTABLE)
install(FILES pihelper.1 DESTINATION "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/man/man1")
endif()

84
doc/pihelper.1 Normal file
View file

@ -0,0 +1,84 @@
.TH PIHELPER 1 2020-01-10 "PiHelper 0.1.0"
.SH NAME
pihelper \- enable, disable, or view the status of a Pi-hole
.SH SYNOPSIS
.B pihelper [
.I options
]
.SH DESCRIPTION
Pihelper is a command-line utility used to enable, disable, or view the status of a given Pi-hole. It supports using alternative configuration files in order to manage multiple Pi-holes.
.SH OPTIONS
.IP "-c, --configure"
.RS
Create (or replace) the pihelper configuration.
.RE
.IP "-d, --disable <seconds>"
.RS
Disable the Pi-hole for a given number of seconds.
.br
.br
If no argument is passed, disable the Pi-hole permanently.
.RE
.IP "-e, --enable"
.RS
Enable the Pi-hole.
.RE
.IP "-f, --file <file>"
.RS
Use the given configuration file.
.RE
.IP "-h, --help"
.RS
Display the help message.
.RE
.IP "-q, --quiet"
.RS
Suppress all output.
.RE
.IP "-v, --verbose"
.RS
Print additional output.
.RE
.SH EXIT STATUS
The exit status for
.B pihelper
is dependent upon the status of the Pi-hole.
.IP \-1
.B pihelper
was unable to connect to the Pi-hole.
.IP 0
The Pi-hole is enabled
.IP 1
The Pi-hole is disabled.
.SH FILES
.IP ~/.config/pihelper.conf
The default configuration file.
.SH EXAMPLES
Print the status of the Pi-hole:
.PP
.RS
pihelper
.RE
.PP
Enable the Pi-hole:
.PP
.RS
pihelper -e
.RE
.PP
Disable the Pi-hole permanently:
.PP
.RS
pihelper -d
.RE
.PP
Disable the Pi-hole for 5 minutes:
.PP
.RS
pihelper -d300
.SH AUTHOR
Originally written by William Brawner <me@wbrawner.com>
.SH COPYRIGHT
Copyright (c) 2019-2020 William Brawner
.PP
PiHelper is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

184
scripts/build-android Executable file
View file

@ -0,0 +1,184 @@
#!/usr/bin/env bash
# Configure the following variables according to your needs
NDK_VERSION="21.1.6352462"
OPENSSL_TAG_VERSION="OpenSSL_1_1_1g "
CURL_TAG_VERSION="curl-7_78_0"
JSONC_TAG_VERSION="master"
ANDROID_ARCHS="arm arm64 x86 x86_64"
NDK=$HOME/Android/Sdk/ndk/$NDK_VERSION
MIN_SDK_VERSION=23 # Can't go any lower unfortunately. See the cURL docs for more info.
TARGET_SDK_VERSION=29
# Edit below at your own risk
get_abi() {
case $1 in
"arm")
echo -n "armeabi-v7a"
;;
"arm64")
echo -n "arm64-v8a"
;;
"x86")
echo -n "x86"
;;
"x86_64")
echo -n "x86_64"
;;
esac
}
make_openssl() {
test -d openssl || git clone --branch $OPENSSL_TAG_VERSION https://github.com/openssl/openssl.git
for ARCH in $ANDROID_ARCHS; do
(
export PREFIX="$BUILD_DIR/android/$ARCH"
mkdir -p "$PREFIX"
cd openssl
git checkout $OPENSSL_TAG_VERSION
make clean
export ANDROID_NDK_HOME=$NDK
export ANDROID_NDK_ROOT=$NDK
export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$ANDROID_NDK_HOME/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin:$PATH
./Configure \
--prefix="$PREFIX" \
-D__ANDROID_API__=$TARGET_SDK_VERSION \
no-shared \
android-$ARCH
make -j24 install_dev
)
done
}
make_curl() {
test -d curl || git clone --branch $CURL_TAG_VERSION https://github.com/curl/curl.git
for ARCH in $ANDROID_ARCHS; do
(
export PREFIX="$BUILD_DIR/android/$ARCH"
mkdir -p "$PREFIX"
cd curl
git checkout $CURL_TAG_VERSION
test -f configure || autoreconf -fi
export HOST_TAG=linux-x86_64
export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/$HOST_TAG
case $ARCH in
"arm")
export CURL_ARCH="arm-linux-androideabi"
export CLANG="armv7a-linux-androideabi"
;;
"arm64")
export CURL_ARCH="aarch64-linux-android"
export CLANG=$CURL_ARCH
;;
"x86")
export CURL_ARCH="i686-linux-android"
export CLANG=$CURL_ARCH
;;
"x86_64")
export CURL_ARCH="x86_64-linux-android"
export CLANG=$CURL_ARCH
;;
esac
export AR=$TOOLCHAIN/bin/$CURL_ARCH-ar
export AS=$TOOLCHAIN/bin/$CURL_ARCH-as
export CC=$TOOLCHAIN/bin/${CLANG}${MIN_SDK_VERSION}-clang
export CXX=$TOOLCHAIN/bin/${CLANG}${MIN_SDK_VERSION}-clang++
export LD=$TOOLCHAIN/bin/$CURL_ARCH-ld
export RANLIB=$TOOLCHAIN/bin/$CURL_ARCH-ranlib
export STRIP=$TOOLCHAIN/bin/$CURL_ARCH-strip
make clean
./configure --prefix="$PREFIX" \
--host $CURL_ARCH \
--with-pic \
--disable-shared \
--with-ssl="$PREFIX"
make -j24 install
)
done
}
make_jsonc() {
test -d json-c || git clone --branch $JSONC_TAG_VERSION https://github.com/json-c/json-c.git
for ARCH in $ANDROID_ARCHS; do
(
export PREFIX="$BUILD_DIR/android/$ARCH"
mkdir -p "$PREFIX"
cd json-c
git checkout $JSONC_TAG_VERSION
test -d $ARCH && rm -rf $ARCH
mkdir $ARCH
pushd $ARCH
export ABI="$(get_abi $ARCH)"
cmake \
-DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=$ABI \
-DANDROID_NATIVE_API_LEVEL=$MIN_SDK_VERSION \
-DCMAKE_INSTALL_PREFIX=$PREFIX \
-DBUILD_SHARED_LIBS=OFF \
-DBUILD_STATIC_LIBS=ON \
..
make -j24
make install
)
done
}
make_pihelper() {
for ARCH in $ANDROID_ARCHS; do
(
export PREFIX="$BUILD_DIR/android/$ARCH"
mkdir -p "$PREFIX"
cd "$BUILD_DIR"
test -d $ARCH && rm -rf $ARCH
mkdir $ARCH
pushd $ARCH
cmake \
-DCMAKE_FIND_ROOT_PATH=$PREFIX \
-DCMAKE_INCLUDE_PATH=$PREFIX/include \
-DCMAKE_PREFIX_PATH=$PREFIX \
-DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=$ABI \
-DANDROID_NATIVE_API_LEVEL=$MIN_SDK_VERSION \
-DCMAKE_INSTALL_PREFIX=$PREFIX \
-DPIHELPER_SHARED=OFF \
-DPIHELPER_STATIC=ON \
-DPIHELPER_DEV=ON \
../..
make -j24
make install
)
done
}
package() {
for ARCH in $ANDROID_ARCHS; do
(
export ABI="$(get_abi $ARCH)"
cd $BUILD_DIR/android
cp -r $ARCH/include .
mv $ARCH/lib/*.a $ARCH/lib/*.la $ARCH/
rm -rf $ARCH/{bin,lib,include,share}
if [ "$ARCH" != "$ABI" ]; then
mv $ARCH $ABI
fi
)
done
}
(
if [ "$(dirname $0)" == "." ]; then
cd ..
fi
test -d deps || mkdir deps
export BUILD_DIR="$PWD/build"
test -d "$BUILD_DIR" || mkdir -p "$BUILD_DIR"
cd deps
make_openssl
make_curl
make_jsonc
make_pihelper
package
)

201
scripts/build-ios Executable file
View file

@ -0,0 +1,201 @@
#!/usr/bin/env bash
set -ex
# Configure the following variables according to your needs
OPENSSL_TAG_VERSION="OpenSSL_1_1_1g "
CURL_TAG_VERSION="master "
JSONC_TAG_VERSION="master"
IOS_MIN_VERSION="13.0"
# Edit below at your own risk
XCODE_ROOT="$(xcode-select -p)/Platforms"
VARIANTS="Simulator OS"
get_toolchain() {
(
cd deps
test -d ios-cmake || git clone https://github.com/cristeab/ios-cmake.git
)
}
make_openssl() {
(
cd deps
test -d openssl || git clone --branch $OPENSSL_TAG_VERSION https://github.com/openssl/openssl.git
for VARIANT in $VARIANTS; do
(
export PREFIX="$BUILD_DIR/ios/$VARIANT"
#export PLATFORM="${XCODE_ROOT}/iPhone${VARIANT}.platform"
#export SDK="${PLATFORM}/Developer/SDKs/iPhone${VARIANT}.sdk"
mkdir -p "$PREFIX"
cd openssl
git checkout $OPENSSL_TAG_VERSION
make clean
#export CC=clang
#export PATH="${XCODE_ROOT}/../Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin:$PATH"
#export CROSS_TOP=${PLATFORM}/Developer
#export CROSS_SDK="iPhone${VARIANT}.sdk"
case $VARIANT in
OS)
export TARGET=ios64-xcrun
;;
Simulator)
export TARGET=iossimulator-xcrun
;;
esac
./Configure \
--prefix="$PREFIX" \
no-dso \
no-hw \
no-engine \
no-shared \
$TARGET
make -j $(sysctl -n hw.logicalcpu_max)
make install_dev
)
done
)
}
make_curl() {
(
cd deps
test -d curl || git clone --branch $CURL_TAG_VERSION https://github.com/curl/curl.git
for VARIANT in $VARIANTS; do
(
export PREFIX="$BUILD_DIR/ios/$VARIANT"
export PLATFORM="${XCODE_ROOT}/iPhone${VARIANT}.platform"
export SDK="${PLATFORM}/Developer/SDKs/iPhone${VARIANT}.sdk"
case $VARIANT in
OS)
export ARCH=arm64
export HOST=arm-apple-darwin
break;;
Simulator)
export ARCH=x86_64
export HOST=x86_64-apple-darwin
break;;
esac
export CPPFLAGS="-DCURL_BUILD_IOS"
export CFLAGS="-arch ${ARCH} -pipe -Os -gdwarf-2 -isysroot ${SDK} -miphoneos-version-min=${IOS_MIN_VERSION} -fembed-bitcode"
export LDFLAGS="-arch ${ARCH} -isysroot ${SDK}"
mkdir -p "$PREFIX"
cd curl
git checkout $CURL_TAG_VERSION
test -f configure || ./buildconf
make clean
./configure \
--disable-shared \
--without-zlib \
--enable-static \
--enable-ipv6 \
--host="${HOST}" \
--with-darwinssl \
--prefix=${PREFIX}
#--with-ssl="$PREFIX" \
make -j $(sysctl -n hw.logicalcpu_max)
make install
)
done
)
}
make_jsonc() {
(
cd deps
test -d json-c || git clone --branch $JSONC_TAG_VERSION https://github.com/json-c/json-c.git
for VARIANT in $VARIANTS; do
(
export PLATFORM="${XCODE_ROOT}/iPhone${VARIANT}.platform"
export SDK="${PLATFORM}/Developer/SDKs/iPhone${VARIANT}.sdk"
export PREFIX="$BUILD_DIR/ios/$VARIANT"
mkdir -p "$PREFIX"
cd json-c
git checkout $JSONC_TAG_VERSION
if [ -d $VARIANT ]; then
rm -rf $VARIANT
fi
mkdir $VARIANT
pushd $VARIANT
cmake \
-DCMAKE_FIND_ROOT_PATH=$PREFIX \
-DCMAKE_INCLUDE_PATH=$PREFIX/include \
-DCMAKE_PREFIX_PATH="${PREFIX};${SDK}/usr" \
-DCMAKE_IOS_DEVELOPER_ROOT="$PLATFORM" \
-DCMAKE_IOS_SDK_ROOT="$SDK" \
-DIOS_PLATFORM=$(echo $VARIANT | tr a-z A-Z) \
-DCMAKE_TOOLCHAIN_FILE=../../ios-cmake/toolchain/iOS.cmake \
-DCMAKE_INSTALL_PREFIX=$PREFIX \
-DBUILD_SHARED_LIBS=OFF \
-DBUILD_STATIC_LIBS=ON \
..
make -j $(sysctl -n hw.logicalcpu_max)
make install
)
done
)
}
make_pihelper() {
for VARIANT in $VARIANTS; do
(
export PLATFORM="${XCODE_ROOT}/iPhone${VARIANT}.platform"
export SDK="${PLATFORM}/Developer/SDKs/iPhone${VARIANT}.sdk"
export PREFIX="$BUILD_DIR/ios/$VARIANT"
mkdir -p "$PREFIX"
pushd build
if [ -d $VARIANT ]; then
rm -rf $VARIANT
fi
mkdir $VARIANT
pushd $VARIANT
cmake \
-DCMAKE_FIND_ROOT_PATH=$PREFIX \
-DCMAKE_INCLUDE_PATH=$PREFIX/include \
-DCMAKE_PREFIX_PATH="${PREFIX};${SDK}/usr" \
-DCMAKE_IOS_DEVELOPER_ROOT="$PLATFORM" \
-DCMAKE_IOS_SDK_ROOT="$SDK" \
-DIOS_PLATFORM=$(echo $VARIANT | tr a-z A-Z) \
-DCMAKE_TOOLCHAIN_FILE=../../deps/ios-cmake/toolchain/iOS.cmake \
-DCMAKE_INSTALL_PREFIX=$PREFIX \
-DPIHELPER_DEV=ON \
-DPIHELPER_SHARED=OFF \
-DPIHELPER_STATIC=ON \
../..
make -j $(sysctl -n hw.logicalcpu_max)
make install
)
done
}
package() {
cd $BUILD_DIR/ios
cp -r OS/include .
for LIB in json-c curl ssl crypto pihelper; do
(
lipo -create \
OS/lib/lib${LIB}.a \
Simulator/lib/lib${LIB}.a \
-output lib${LIB}.dylib
)
done
}
(
if [ "$(dirname $0)" == "." ]; then
cd ..
fi
test -d deps || mkdir deps
export BUILD_DIR="$PWD/build"
test -d "$BUILD_DIR" || mkdir -p "$BUILD_DIR"
get_toolchain
make_openssl
#make_curl
#make_jsonc
#make_pihelper
package
)

145
src/CMakeLists.txt Normal file
View file

@ -0,0 +1,145 @@
# Copyright © 2019, 2020 William Brawner.
#
# This file is part of PiHelper.
#
# PiHelper is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# PiHelper is distributed in the hope that it will be useful,
# 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.
#
# You should have received a copy of the GNU General Public License
# along with PiHelper. If not, see <https://www.gnu.org/licenses/>.
include(GNUInstallDirs)
set(PIHELPER_SOURCES
pihelper.c
log.c
network.c
config.c
)
include_directories(/usr/local/include ${CMAKE_INCLUDE_PATH})
if (NOT TARGET CURL)
find_library(
CURL
NAMES curl libcurl
PATHS /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /lib
)
if (NOT CURL)
message(SEND_ERROR "Did not find curl")
endif()
endif()
if (NOT TARGET JSONC)
find_library(
JSONC
NAMES json-c libjson-c
PATHS /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /lib
)
if (NOT JSONC)
message(SEND_ERROR "Did not find json-c")
endif()
endif()
if (NOT TARGET CRYPTO)
find_library(
CRYPTO
NAMES crypto libcrypto
PATHS /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /lib
)
if (NOT CRYPTO)
message(SEND_ERROR "Did not find OpenSSL")
endif()
endif()
if (NOT TARGET OPENSSL)
find_library(
OPENSSL
NAMES ssl libssl
PATHS /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /lib
)
if (NOT OPENSSL)
message(SEND_ERROR "Did not find OpenSSL")
endif()
endif()
option(PIHELPER_STATIC "Build Pi-Helper as a static library" ON)
option(PIHELPER_SHARED "Build Pi-Helper as a shared library" OFF)
option(PIHELPER_EXECUTABLE "Build Pi-Helper as an executable" OFF)
option(PIHELPER_DEV "Install Pi-Helper header files for development" OFF)
option(PIHELPER_RPM "Apply custom config for building RPM packages" OFF)
if (PIHELPER_STATIC)
add_library(libpihelperstatic STATIC
${PIHELPER_SOURCES}
)
set_target_properties(libpihelperstatic PROPERTIES OUTPUT_NAME "pihelper"
VERSION ${PROJECT_VERSION}
)
if (PIHELPER_DEV)
set_target_properties(libpihelperstatic PROPERTIES PUBLIC_HEADER pihelper.h)
endif()
target_link_libraries(libpihelperstatic ${CURL}
${JSONC}
${CRYPTO}
${OPENSSL}
)
install(TARGETS libpihelperstatic
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
endif()
if (PIHELPER_SHARED OR PIHELPER_EXECUTABLE)
add_library(libpihelpershared SHARED
${PIHELPER_SOURCES}
)
set_target_properties(libpihelpershared PROPERTIES
OUTPUT_NAME "pihelper"
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
)
message("shared major version: ${PROJECT_VERSION_MAJOR}")
if (PIHELPER_DEV)
set_target_properties(libpihelpershared PROPERTIES PUBLIC_HEADER pihelper.h)
endif()
target_link_libraries(libpihelpershared ${CURL}
${JSONC}
${CRYPTO}
${OPENSSL}
)
install(TARGETS libpihelpershared
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
endif()
if (PIHELPER_EXECUTABLE)
if (NOT PIHELPER_RPM)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH};${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR})
endif()
add_executable(pihelper
cli.c
)
target_link_libraries(pihelper libpihelpershared
${CURL}
${JSONC}
${CRYPTO}
${OPENSSL}
)
install(TARGETS pihelper
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
endif()

187
src/cli.c Normal file
View file

@ -0,0 +1,187 @@
/**
* Copyright © 2019, 2020 William Brawner.
*
* This file is part of PiHelper.
*
* PiHelper is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PiHelper is distributed in the hope that it will be useful,
* 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.
*
* You should have received a copy of the GNU General Public License
* along with PiHelper. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "cli.h"
#include "log.h"
static char * DEFAULT_CONFIG_PATH = "/.config/pihelper.conf";
int main(int argc, char ** argv) {
bool configure = false, enable = false;
char * disable = NULL;
char * config_path = NULL;
char ch;
while ((ch = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
switch(ch) {
case 'c':
configure = true;
break;
case 'd':
if (optarg != NULL) {
disable = malloc(strlen(optarg) + 1);
strncpy(disable, optarg, strlen(optarg));
disable[strlen(optarg)] = '\0';
} else {
disable = malloc(1);
disable[0] = '\0';
}
break;
case 'e':
enable = true;
break;
case 'f':
if (optarg == NULL) break;
if (strstr(optarg, "/") != optarg) {
// This is a relative path, prepend the current working directory
char * cwd = getcwd(NULL, 0);
int full_path_len = strlen(cwd) + 1 + strlen(optarg) + 1;
config_path = malloc(full_path_len);
strncpy(config_path, cwd, strlen(cwd));
config_path[strlen(cwd)] = '/';
strncpy(&(config_path[strlen(cwd) + 1]), optarg, strlen(optarg));
config_path[full_path_len - 1] = '\0';
free(cwd);
} else {
// This is an absolute path, copy as-is
config_path = malloc(strlen(optarg) + 1);
strncpy(config_path, optarg, strlen(optarg));
config_path[strlen(optarg)] = '\0';
}
break;
case 'q':
pihelper_set_log_level(PIHELPER_LOG_DISABLED);
break;
case 'v':
pihelper_set_log_level(PIHELPER_LOG_DEBUG);
break;
case 'h':
default:
print_usage();
return PIHELPER_OPERATION_FAILED;
}
}
if (config_path == NULL) {
char * home_dir = getenv("HOME");
int path_len = strlen(home_dir) + strlen(DEFAULT_CONFIG_PATH);
config_path = malloc(path_len + 1);
sprintf(config_path, "%s%s", home_dir, DEFAULT_CONFIG_PATH);
config_path[path_len] = '\0';
}
if (access(config_path, F_OK)) {
char * user_input = malloc(4);
// Intentionally using printf here to ensure that this is always printed
printf("No Pi-Helper configuration found. Would you like to create it now? [Y/n] ");
fgets(user_input, 3, stdin);
user_input[3] = '\0';
write_log(PIHELPER_LOG_DEBUG, "User's input: %s", user_input);
if (strstr(user_input, "\n") == user_input
|| strstr(user_input, "Y") == user_input
|| strstr(user_input, "y") == user_input
) {
configure = true;
free(user_input);
} else {
free(config_path);
free(user_input);
return 1;
}
} else {
write_log(PIHELPER_LOG_DEBUG, "Using config file at: %s", config_path);
}
pihole_config * config;
if (configure) {
write_log(PIHELPER_LOG_DEBUG, "Configuring PiHelper");
config = configure_pihole(config_path);
} else {
write_log(PIHELPER_LOG_DEBUG, "Reading existing PiHelper config");
config = pihelper_read_config(config_path);
}
int status;
if (config == NULL) {
write_log(PIHELPER_LOG_ERROR, "Failed to parse Pi-Helper config at %s", config_path);
status = PIHELPER_OPERATION_FAILED;
} else if (enable && disable != NULL) {
print_usage();
status = PIHELPER_OPERATION_FAILED;
} else if (enable) {
status = pihelper_enable_pihole(config);
} else if (disable != NULL) {
status = pihelper_disable_pihole(config, disable);
free(disable);
} else {
status = pihelper_get_status(config);
}
char * status_message = NULL;
if (status == PIHELPER_ENABLED) {
status_message = "enabled";
} else if (status == PIHELPER_DISABLED) {
status_message = "disabled";
}
if (status_message != NULL) {
write_log(PIHELPER_LOG_INFO, "Pi-hole status: %s", status_message);
}
free(config_path);
pihelper_free_config(config);
return status;
}
void print_usage() {
printf("Usage: pihelper [options]\n");
printf(" -c, --configure Configure Pi-Helper\n");
printf(" -d, --disable <duration> Disable the Pi-hole for a given duration, or permanently if empty\n");
printf(" -e, --enable Enable the Pi-hole\n");
printf(" -f, --file <config-file> Use the given config file instead of the default\n");
printf(" -h, --help Display this message\n");
printf(" -q, --quiet Don't print anything\n");
printf(" -v, --verbose Print debug logs\n");
}
pihole_config * configure_pihole(char * config_path) {
if (access(config_path, F_OK) == 0) {
// TODO: Check if file is accessible for read/write (not just if it exists)
write_log(PIHELPER_LOG_WARN, "WARNING: The config file already exists. Continuing will overwrite any existing configuration.\n");
}
pihole_config * config = pihelper_new_config();
printf("Enter the hostname or ip address for your pi-hole: ");
char * host = calloc(1, 257);
fgets(host, 256, stdin);
host[256] = '\0';
write_log(PIHELPER_LOG_DEBUG, "User entered \"%s\" for host", host);
pihelper_config_set_host(config, host);
free(host);
char * raw_pass = getpass("Enter the api key or web password for your pi-hole: ");
if (strlen(raw_pass) != 64) {
pihelper_config_set_password(config, raw_pass);
} else {
pihelper_config_set_api_key(config, raw_pass);
}
free(raw_pass);
// TODO: Make an authenticated request to verify that the credentials are valid and save the config
pihelper_save_config(config, config_path);
return config;
}

37
src/cli.h Normal file
View file

@ -0,0 +1,37 @@
/**
* Copyright © 2019, 2020 William Brawner.
*
* This file is part of PiHelper.
*
* PiHelper is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PiHelper is distributed in the hope that it will be useful,
* 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.
*
* You should have received a copy of the GNU General Public License
* along with PiHelper. If not, see <https://www.gnu.org/licenses/>.
*/
#include <getopt.h>
#include "pihelper.h"
static char * shortopts = "cd::ef:hqv";
static struct option longopts[] = {
{ "configure", no_argument, NULL, 'c' },
{ "disable", optional_argument, NULL, 'd' },
{ "enable", no_argument, NULL, 'e' },
{ "file", required_argument, NULL, 'f' },
{ "help", no_argument, NULL, 'h' },
{ "quiet", no_argument, NULL, 'q' },
{ "verbose", no_argument, NULL, 'v' }
};
void print_usage();
pihole_config * configure_pihole(char * config_path);

171
src/config.c Normal file
View file

@ -0,0 +1,171 @@
/**
* Copyright © 2019, 2020 William Brawner.
*
* This file is part of PiHelper.
*
* PiHelper is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PiHelper is distributed in the hope that it will be useful,
* 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.
*
* You should have received a copy of the GNU General Public License
* along with PiHelper. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <limits.h>
#include <pwd.h>
#include <unistd.h>
#include "config.h"
int mkdirs(char * path) {
char * curPos = strstr(path, "/") + 1;
char parents[strlen(path)];
int retval = 0;
while (curPos != NULL) {
snprintf(parents, strlen(path) - strlen(curPos) + 1, "%s", path);
curPos = strstr(curPos + 1, "/");
if (access(parents, F_OK)) {
if ((retval = mkdir(parents, 0755)) != 0) {
return retval;
}
}
}
return retval;
}
int save_config(pihole_config * config, char * config_path) {
if (mkdirs(config_path)) {
perror(config_path);
return 1;
}
FILE * config_file = fopen(config_path, "w");
int config_len = strlen(config->host) + strlen(config->api_key) + 16;
char config_string[config_len + 1];
snprintf(config_string, config_len, "host=%s\napi-key=%s\n", config->host, config->api_key);
config_string[config_len + 1] = '\0';
fputs(config_string, config_file);
fclose(config_file);
return 0;
}
/*
* Calculate the hash of the password
*/
static char * hash_string (char * raw_string) {
unsigned char bytes[SHA256_DIGEST_LENGTH];
SHA256((unsigned char *) raw_string, strlen(raw_string), bytes);
char * hash = malloc(MAX_PIHOLE_API_KEY + 1);
int i;
for(i = 0; i < SHA256_DIGEST_LENGTH; i++) {
sprintf(hash + (i * 2), "%02x", bytes[i]);
}
hash[MAX_PIHOLE_API_KEY] = '\0';
return hash;
}
pihole_config * read_config(char * config_path) {
if (access(config_path, F_OK)) {
write_log(PIHELPER_LOG_ERROR, "The specified config file doesn't exist: %s", config_path);
return NULL;
}
FILE * config_file = fopen(config_path, "r");
char * host = calloc(1, _POSIX_HOST_NAME_MAX + 7);
fgets(host, _POSIX_HOST_NAME_MAX + 7, config_file);
if (strstr(host, "host=") == NULL || strlen(host) < 7) {
write_log(PIHELPER_LOG_DEBUG, "Config file contains invalid host: %s", host);
write_log(PIHELPER_LOG_ERROR, "Invalid config file");
fclose(config_file);
return NULL;
}
pihole_config * config = pihole_config_new();
config_set_host(config, host + 5);
free(host);
char * api_key = calloc(1, 74);
fgets(api_key, 74, config_file);
fclose(config_file);
if (strstr(api_key, "api-key=") == NULL
|| strlen(api_key) < 9) {
write_log(PIHELPER_LOG_DEBUG, "Config file contains invalid api key: %s", api_key);
write_log(PIHELPER_LOG_WARN, "The config file is missing a valid API key. Authenticated operations won't work.");
free(api_key);
fclose(config_file);
return config;
}
config_set_api_key(config, api_key + 8);
free(api_key);
write_log(PIHELPER_LOG_DEBUG, "Using host %s and api key %s", config->host, config->api_key);
return config;
}
pihole_config * pihole_config_new() {
pihole_config * config;
if ((config = malloc(sizeof(pihole_config))) == NULL) {
write_log(PIHELPER_LOG_ERROR, "Failed to allocate memory for config");
free_config(config);
return NULL;
}
if ((config->host = calloc(1, _POSIX_HOST_NAME_MAX + 1)) == NULL) {
write_log(PIHELPER_LOG_ERROR, "Failed to allocate memory for config host");
free_config(config);
return NULL;
}
if ((config->api_key = calloc(1, MAX_PIHOLE_API_KEY + 1)) == NULL) {
write_log(PIHELPER_LOG_ERROR, "Failed to allocate memory for config API key");
free_config(config);
return NULL;
}
config->host[_POSIX_HOST_NAME_MAX] = '\0';
config->api_key[MAX_PIHOLE_API_KEY] = '\0';
return config;
}
void config_set_host(pihole_config * config, char * host) {
strncpy(config->host, host, _POSIX_HOST_NAME_MAX);
config->host[_POSIX_HOST_NAME_MAX] = '\0';
trim_string(config->host);
}
void config_set_password(pihole_config * config, char * password) {
trim_string(password);
// This is definitely not an API key, so hash it
// The Pi-hole hashes twice so we do the same here
char * first = hash_string(password);
char * hash = hash_string(first);
free(first);
config_set_api_key(config, hash);
free(hash);
}
void config_set_api_key(pihole_config * config, char * api_key) {
strncpy(config->api_key, api_key, MAX_PIHOLE_API_KEY);
config->api_key[MAX_PIHOLE_API_KEY] = '\0';
trim_string(config->api_key);
}
static void trim_string(char * raw_str) {
char * newline = strstr(raw_str, "\n");
if (newline != NULL) {
raw_str[strlen(raw_str) - strlen(newline)] = '\0';
}
}
void free_config(pihole_config * config) {
if (config == NULL) return;
if (config->host != NULL) {
free(config->host);
}
if (config->api_key != NULL) {
free(config->api_key);
}
free(config);
}

43
src/config.h Normal file
View file

@ -0,0 +1,43 @@
/**
* Copyright © 2019, 2020 William Brawner.
*
* This file is part of PiHelper.
*
* PiHelper is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PiHelper is distributed in the hope that it will be useful,
* 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.
*
* You should have received a copy of the GNU General Public License
* along with PiHelper. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef PIHELPER_CONFIG
#define PIHELPER_CONFIG
#include <openssl/sha.h>
#include "log.h"
#include "pihelper.h"
#define MAX_PIHOLE_API_KEY 64
int save_config(pihole_config * config, char * config_path);
pihole_config * read_config(char * config_path);
pihole_config * pihole_config_new();
void config_set_host(pihole_config * config, char * host);
void config_set_password(pihole_config * config, char * password);
void config_set_api_key(pihole_config * config, char * api_key);
void free_config(pihole_config * config);
static void trim_string(char * raw_str);
#endif

View file

@ -1,3 +0,0 @@
pub fn hello() {
println!("Hello world!");
}

47
src/log.c Normal file
View file

@ -0,0 +1,47 @@
/**
* Copyright © 2019, 2020 William Brawner.
*
* This file is part of PiHelper.
*
* PiHelper is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PiHelper is distributed in the hope that it will be useful,
* 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.
*
* You should have received a copy of the GNU General Public License
* along with PiHelper. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "log.h"
#include "pihelper.h"
int LOG_LEVEL = 2; // Default to info logs
void set_log_level(int level) {
LOG_LEVEL = level;
}
void write_log(int level, char * format, ...) {
if (level > LOG_LEVEL) return;
va_list args;
va_start(args, format);
int format_len = strlen(format);
char * new_format = malloc(format_len + 2);
memcpy(new_format, format, format_len);
new_format[format_len] = '\n';
new_format[format_len + 1] = '\0';
FILE *stream = level < PIHELPER_LOG_INFO ? stderr : stdout;
vfprintf(stream, new_format, args);
va_end(args);
free(new_format);
}

26
src/log.h Normal file
View file

@ -0,0 +1,26 @@
/**
* Copyright © 2019, 2020 William Brawner.
*
* This file is part of PiHelper.
*
* PiHelper is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PiHelper is distributed in the hope that it will be useful,
* 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.
*
* You should have received a copy of the GNU General Public License
* along with PiHelper. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef PIHELPER_LOG
#define PIHELPER_LOG
extern int LOG_LEVEL;
void set_log_level(int level);
void write_log(int level, char * format, ...);
#endif

View file

@ -1,5 +0,0 @@
use pihelper::hello;
fn main() {
hello();
}

185
src/network.c Normal file
View file

@ -0,0 +1,185 @@
/**
* Copyright © 2019, 2020 William Brawner.
*
* This file is part of PiHelper.
*
* PiHelper is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PiHelper is distributed in the hope that it will be useful,
* 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.
*
* You should have received a copy of the GNU General Public License
* along with PiHelper. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include <json-c/json_object.h>
#include <json-c/json_tokener.h>
#include "config.h"
#include "log.h"
#include "network.h"
int get_status(pihole_config * config) {
write_log(PIHELPER_LOG_DEBUG, "Getting Pi-hole status…");
char * formatted_host = prepend_scheme(config->host);
char * response = get(formatted_host);
free(formatted_host);
if (response == NULL) {
write_log(PIHELPER_LOG_ERROR, "Failed to retrieve status for Pi-hole at %s\n", config->host);
return PIHELPER_OPERATION_FAILED;
} else {
int status = parse_status(response);
free(response);
return status;
}
}
int enable_pihole(pihole_config * config) {
write_log(PIHELPER_LOG_DEBUG, "Enabling Pi-hole…");
char * formatted_host = prepend_scheme(config->host);
append_query_parameter(&formatted_host, AUTH_QUERY, config->api_key);
append_query_parameter(&formatted_host, ENABLE_QUERY, NULL);
char * response = get(formatted_host);
free(formatted_host);
if (response == NULL) {
return PIHELPER_OPERATION_FAILED;
} else {
int status = parse_status(response);
free(response);
return status;
}
}
int disable_pihole(pihole_config * config, char * duration) {
if (*duration == '\0') {
write_log(PIHELPER_LOG_DEBUG, "Disabling Pi-hole permanently…");
} else {
write_log(PIHELPER_LOG_DEBUG, "Disabling Pi-hole for %s seconds…", duration);
}
char * formatted_host = prepend_scheme(config->host);
append_query_parameter(&formatted_host, AUTH_QUERY, config->api_key);
append_query_parameter(&formatted_host, DISABLE_QUERY, duration);
char * response = get(formatted_host);
free(formatted_host);
if (response == NULL) {
return PIHELPER_OPERATION_FAILED;
} else {
int status = parse_status(response);
free(response);
return status;
}
}
/**
* Used to handle curl data callbacks
*/
static size_t receive_data(char *ptr, size_t size, size_t nmemb, void *userdata) {
size_t realsize = size * nmemb;
http_response * response = (http_response *) userdata;
char * next = realloc(response->body, response->size + realsize + 1);
response->body = next;
memcpy(&(response->body[response->size]), ptr, realsize);
response->size += realsize;
response->body[response->size] = '\0';
return realsize;
}
/**
* Used to make a GET request to a given endpoint
*/
static char * get(char endpoint[]) {
http_response response;
response.body = malloc(1);
response.size = 0;
curl_global_init(CURL_GLOBAL_ALL);
CURL * curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, endpoint);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receive_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
if (LOG_LEVEL == PIHELPER_LOG_DEBUG) {
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
}
int res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if (res == CURLE_OK) {
return response.body;
} else {
free(response.body);
return NULL;
}
}
/**
* Given a potentially unformatted host (missing scheme), prepends the scheme (http://) to the host. Note
* that the caller is responsible for freeing the memory allocated by this method.
* @return a pointer to the host with the scheme prepended, or the given pointer if the host is already
* properly formatted.
*/
static char * prepend_scheme(char * raw_host) {
if (raw_host == NULL) return NULL;
char * formatted_host;
if (strstr(raw_host, HTTP_SCHEME) != raw_host
&& strstr(raw_host, HTTPS_SCHEME) != raw_host) {
formatted_host = malloc(URL_FORMAT_LEN + strlen(raw_host));
sprintf(formatted_host, URL_FORMAT, raw_host);
} else {
formatted_host = malloc(strlen(raw_host));
strcpy(formatted_host, raw_host);
}
return formatted_host;
}
static int parse_status(char * raw_json) {
json_tokener *tok = json_tokener_new();
json_object *jobj = NULL;
int stringlen = 0;
int retval = PIHELPER_OPERATION_FAILED;
enum json_tokener_error jerr;
do {
stringlen = strlen(raw_json);
jobj = json_tokener_parse_ex(tok, raw_json, stringlen);
} while ((jerr = json_tokener_get_error(tok)) == json_tokener_continue);
if (jerr != json_tokener_success) {
write_log(PIHELPER_LOG_ERROR, "Failed to parse JSON: %s", json_tokener_error_desc(jerr));
json_tokener_free(tok);
return retval;
}
write_log(PIHELPER_LOG_DEBUG, "%s", json_object_to_json_string_ext(jobj, JSON_C_TO_STRING_PRETTY));
json_object *status;
const char * status_string;
if (json_object_object_get_ex(jobj, "status", &status) == 1
&& (status_string = json_object_get_string(status)) != NULL) {
if (strstr(status_string, "enabled") == status_string) {
retval = PIHELPER_ENABLED;
} else if (strstr(status_string, "disabled") == status_string) {
retval = PIHELPER_DISABLED;
}
} else {
write_log(PIHELPER_LOG_DEBUG, "Unable to parse response: %s", raw_json);
}
json_tokener_free(tok);
json_object_put(jobj);
return retval;
}
static void append_query_parameter(char ** host, char * key, char * value) {
char separator = strstr(*host, "?") ? '&' : '?';
int host_len = strlen(*host);
int new_len = host_len + 1 + strlen(key) + 1;
if (value) {
// Add another byte for the '='
new_len += strlen(value) + 1;
}
*host = realloc(*host, new_len);
char * format = value ? "%c%s=%s" : "%c%s";
sprintf(&((*host)[host_len]), format, separator, key, value);
(*host)[strlen(*host)] = '\0';
}

68
src/network.h Normal file
View file

@ -0,0 +1,68 @@
/**
* Copyright © 2019, 2020 William Brawner.
*
* This file is part of PiHelper.
*
* PiHelper is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PiHelper is distributed in the hope that it will be useful,
* 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.
*
* You should have received a copy of the GNU General Public License
* along with PiHelper. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef PIHELPER_NETWORK
#define PIHELPER_NETWORK
#define URL_FORMAT "http://%s/admin/api.php"
#define URL_FORMAT_LEN 22
#define AUTH_QUERY "auth"
#define ENABLE_QUERY "enable"
#define DISABLE_QUERY "disable"
#define HTTP_SCHEME "http://"
#define HTTPS_SCHEME "https://"
typedef struct {
size_t size;
char * body;
} http_response;
typedef struct {
size_t domains_being_blocked;
size_t dns_queries_today;
size_t ads_blocked_today;
double ads_percentage_today;
size_t unique_domains;
size_t queries_forwarded;
size_t queries_cached;
size_t clients_ever_seen;
size_t unique_clients;
size_t dns_queries_all_types;
size_t reply_NODATA;
size_t reply_NXDOMAIN;
size_t reply_CNAME;
size_t reply_IP;
size_t privacy_level;
char * status;
} pihole_status;
int get_status(pihole_config * config);
int enable_pihole(pihole_config * config);
int disable_pihole(pihole_config * config, char * duration);
static char * get(char endpoint[]);
static int parse_status(char * raw_json);
static void append_query_parameter(char ** host, char * key, char * value);
static char * prepend_scheme(char * raw_host);
#endif

67
src/pihelper.c Normal file
View file

@ -0,0 +1,67 @@
/**
* Copyright © 2019, 2020 William Brawner.
*
* This file is part of PiHelper.
*
* PiHelper is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PiHelper is distributed in the hope that it will be useful,
* 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.
*
* You should have received a copy of the GNU General Public License
* along with PiHelper. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "log.h"
#include "network.h"
#include "pihelper.h"
int pihelper_get_status(pihole_config * config) {
return get_status(config);
}
int pihelper_enable_pihole(pihole_config * config) {
return enable_pihole(config);
}
int pihelper_disable_pihole(pihole_config * config, char * duration) {
return disable_pihole(config, duration);
}
void pihelper_set_log_level(int level) {
set_log_level(level);
}
pihole_config * pihelper_new_config() {
return pihole_config_new();
}
void pihelper_config_set_host(pihole_config * config, char * host) {
config_set_host(config, host);
}
void pihelper_config_set_password(pihole_config * config, char * password) {
config_set_password(config, password);
}
void pihelper_config_set_api_key(pihole_config * config, char * api_key) {
config_set_api_key(config, api_key);
}
pihole_config * pihelper_read_config(char * config_path) {
return read_config(config_path);
}
int pihelper_save_config(pihole_config * config, char * config_path) {
save_config(config, config_path);
}
void pihelper_free_config(pihole_config * config) {
free_config(config);
}

133
src/pihelper.h Normal file
View file

@ -0,0 +1,133 @@
/**
* Copyright © 2019, 2020 William Brawner.
*
* This file is part of PiHelper.
*
* PiHelper is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PiHelper is distributed in the hope that it will be useful,
* 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.
*
* You should have received a copy of the GNU General Public License
* along with PiHelper. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef PIHELPER
#define PIHELPER
/**
* Use this with pihelper_set_log_level() to disable logging
*/
#define PIHELPER_LOG_DISABLED -1
/**
* Use this with pihelper_set_log_level() to only log error messages
*/
#define PIHELPER_LOG_ERROR 0
/**
* Use this with pihelper_set_log_level() to log error and warning messages
*/
#define PIHELPER_LOG_WARN 1
/**
* Use this with pihelper_set_log_level() to log error, warning, and info messages
*/
#define PIHELPER_LOG_INFO 2
/**
* Use this with pihelper_set_log_level() to print all log messages
*/
#define PIHELPER_LOG_DEBUG 3
/**
* The return code used when a Pi-hole operation fails
*/
#define PIHELPER_OPERATION_FAILED -1
/**
* The return code used to denote that the Pi-hole is enabled
*/
#define PIHELPER_ENABLED 0
/**
* The return code used to denote that the Pi-hole is disabled
*/
#define PIHELPER_DISABLED 1
typedef struct {
char * host;
char * api_key;
} pihole_config;
/**
* Call this to change the logging level with one of the PIHELPER_LOG_* constants
*/
void pihelper_set_log_level(int level);
/**
* Retrieve the status of the pi-hole. This method does not require an API key to succeed.
* @return PIHELPER_OPERATION_FAILED on failure, or either PIHELPER_ENABLED or PIHELPER_DISABLED
*/
int pihelper_get_status(pihole_config * config);
/**
* Enable the pi-hole. This method requires a valid API key to succeed.
* @return PIHELPER_OPERATION_FAILED on failure, or either PIHELPER_ENABLED or PIHELPER_DISABLED
*/
int pihelper_enable_pihole(pihole_config * config);
/**
* Disable the pi-hole. This method requires a valid API key to succeed.
* @return PIHELPER_OPERATION_FAILED on failure, or either PIHELPER_ENABLED or PIHELPER_DISABLED
*/
int pihelper_disable_pihole(pihole_config * config, char * duration);
/**
* Create a new pihole_config object. The pointer returned here should be passed to pihelper_free_config()
* when it is no longer needed;
* @return A pointer to a pihole_config object or NULL if the system doesn't have enough memory
*/
pihole_config * pihelper_new_config();
/**
* Sets the host for a given config. The memory will be copied, so you can free your copy once it's been
* passed to the config object.
*/
void pihelper_config_set_host(pihole_config * config, char * host);
/**
* Sets the password for a given config. The password will be hashed and converted to an API key. Call this
* if you don't already have the API key, otherwise call pihelper_config_set_api_key(). The memory will be
* copied, so you can free your copy once it's been passed to the config object.
*/
void pihelper_config_set_password(pihole_config * config, char * password);
/**
* Sets the API key for a given config. The API key is a 64-character double SHA256 hash of the password. If
* you don't have this, call pihelper_config_set_password() instead. The memory will be copied, so you can
* free your copy once it's been passed to the config object.
*/
void pihelper_config_set_api_key(pihole_config * config, char * api_key);
/**
* Read the PiHelper config from a file at the given path.
*/
pihole_config * pihelper_read_config(char * config_path);
/**
* Save the PiHelper config to a file at the given path.
*/
int pihelper_save_config(pihole_config * config, char * config_path);
/**
* Clean up all memory associated with a pihole_config object.
*/
void pihelper_free_config(pihole_config * config);
#endif