From fc00423f48f009e77e83b3396a6cd505d18f1ead Mon Sep 17 00:00:00 2001 From: Volodymyr Kolesnykov Date: Sat, 1 Jun 2024 08:00:26 +0300 Subject: [PATCH] refactor(cron): support Debian and Ubuntu --- features/src/cron/bbsuid.c | 107 ++++++++++++++++++++ features/src/cron/devcontainer-feature.json | 4 +- features/src/cron/install.sh | 68 +++++++++++-- features/src/cron/service-run | 2 +- 4 files changed, 169 insertions(+), 12 deletions(-) create mode 100644 features/src/cron/bbsuid.c diff --git a/features/src/cron/bbsuid.c b/features/src/cron/bbsuid.c new file mode 100644 index 00000000..24d0d7d3 --- /dev/null +++ b/features/src/cron/bbsuid.c @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2008 Natanael Copa + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. See http://www.gnu.org/ for details. + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#define BBSUID_PATH "/bin/bbsuid" + +const static char * applets[] = { + "/bin/mount", + "/bin/umount", + "/bin/su", + "/usr/bin/crontab", + "/usr/bin/passwd", + "/usr/bin/traceroute", + "/usr/bin/traceroute6", + "/usr/bin/vlock", + NULL +}; + + +static const char *applet_from_path(const char *str) +{ + const char *p = strrchr(str, '/'); + if (p == NULL) + p = str; + else + p++; + return p; +} + +static int is_valid_applet(const char *str) +{ + int i; + for (i = 0; applets[i] != NULL; i++) { + const char *a = applet_from_path(applets[i]); + if (strcmp(applet_from_path(str), a) == 0) + return 1; + } + return 0; +} + +int exec_busybox(const char *app, int argc, char **argv) +{ + char **newargv = malloc((argc + 2) * sizeof(char *)); + int i; + newargv[0] = "/bin/busybox"; + newargv[1] = (char *)app; + for (i = 1; i < argc; i++) + newargv[i+1] = argv[i]; + newargv[argc+1] = NULL; + execv(newargv[0], newargv); + perror(newargv[0]); + free(newargv); + return 1; +} + +static int install_links(void) +{ + int i, r = 0; + /* we don't want others than root to install the symlinks */ + if (getuid() != 0) + errx(1, "Only root can install symlinks"); + + for (i = 0; applets[i] != NULL; i++) { + const char *a = applets[i]; + struct stat st; + if (lstat(a, &st) == 0 && S_ISLNK(st.st_mode)) + unlink(a); + if (symlink(BBSUID_PATH, a) < 0) + r++; + } + + return r; +} + +int main(int argc, char **argv) +{ + const char *app = applet_from_path(argv[0]); + + if (strcmp(app, "bbsuid") == 0) { + if (argc == 2 && strcmp(argv[1], "--install") == 0) + return install_links(); + errx(1, "Use --install to install symlinks"); + } + + if (is_valid_applet(app)) + return exec_busybox(app, argc, argv); + + errx(1, "%s is not a valid applet", app); + return 1; +} + diff --git a/features/src/cron/devcontainer-feature.json b/features/src/cron/devcontainer-feature.json index 39351da7..61605842 100644 --- a/features/src/cron/devcontainer-feature.json +++ b/features/src/cron/devcontainer-feature.json @@ -2,11 +2,11 @@ "id": "cron", "name": "Cron", "description": "Enables cron in the Dev Environment", - "version": "1.0.3", + "version": "1.1.0", "options": { "enabled": { "type": "boolean", - "default": false, + "default": true, "description": "Enable cron" }, "run_wp_cron": { diff --git a/features/src/cron/install.sh b/features/src/cron/install.sh index c0c8d33e..fc2de040 100755 --- a/features/src/cron/install.sh +++ b/features/src/cron/install.sh @@ -9,23 +9,73 @@ if [ "$(id -u || true)" -ne 0 ]; then exit 1 fi +: "${_REMOTE_USER:?"_REMOTE_USER is required"}" + if [ "${ENABLED:-}" = 'true' ]; then echo '(*) Installing cron...' - apk add --no-cache busybox-suid + + # shellcheck source=/dev/null + . /etc/os-release + : "${ID:=}" + : "${ID_LIKE:=${ID}}" + + case "${ID_LIKE}" in + "debian") + # In Ubuntu Noble, cron now depends on systemd. We need to install busybox-static and use it as crond/crontab to avoid garbage in the system. + PACKAGES_NOREMOVE="" + PACKAGES="" + if [ ! -f /usr/bin/busybox ]; then + PACKAGES_NOREMOVE="${PACKAGES_NOREMOVE} busybox-static" + fi + + if ! dpkg -s libc6-dev >/dev/null 2>&1; then + PACKAGES="${PACKAGES} libc6-dev" + fi + + if ! hash cc >/dev/null 2>&1; then + PACKAGES="${PACKAGES} tcc" + fi + + if [ -n "${PACKAGES}" ] || [ -n "${PACKAGES_NOREMOVE}" ]; then + apt-get update + # shellcheck disable=SC2086 + apt-get install -y --no-install-recommends ${PACKAGES} ${PACKAGES_NOREMOVE} + fi + + cc -O2 bbsuid.c -o /usr/local/bin/bbsuid + + if [ -n "${PACKAGES}" ]; then + # shellcheck disable=SC2086 + apt-get purge -y --auto-remove ${PACKAGES} + fi + + apt-get clean + rm -rf /var/lib/apt/lists/* + + chown root:root /usr/local/bin/bbsuid + chmod 04111 /usr/local/bin/bbsuid + ln -s /usr/local/bin/bbsuid /usr/bin/crontab + ln -s /usr/bin/busybox /usr/sbin/crond + install -D -d -m 0755 -o root -g root /var/spool/cron/crontabs + ;; + + "alpine") + apk add --no-cache busybox-suid + ;; + + *) + echo "(!) Unsupported distribution: ${ID}" + exit 1 + ;; + esac install -D -m 0755 -o root -g root service-run /etc/sv/cron/run install -d -m 0755 -o root -g root /etc/service - install -m 0755 -o root -g root wp-cron.sh /usr/local/bin/wp-cron.sh ln -sf /etc/sv/cron /etc/service/cron if [ "${RUN_WP_CRON:-}" = 'true' ] && [ -n "${WP_CRON_SCHEDULE:-}" ]; then - if [ -z "${_REMOTE_USER}" ] || [ "${_REMOTE_USER}" = "root" ]; then - WEB_USER=www-data - else - WEB_USER="${_REMOTE_USER}" - fi - - echo "${WP_CRON_SCHEDULE} /usr/bin/flock -n /tmp/wp-cron.lock /usr/local/bin/wp-cron.sh" | crontab -u "${WEB_USER}" - + install -m 0755 -o root -g root wp-cron.sh /usr/local/bin/wp-cron.sh + echo "${WP_CRON_SCHEDULE} /usr/bin/flock -n /tmp/wp-cron.lock /usr/local/bin/wp-cron.sh" | crontab -u "${_REMOTE_USER}" - fi echo 'Done!' diff --git a/features/src/cron/service-run b/features/src/cron/service-run index a98983d6..a40cb9c8 100755 --- a/features/src/cron/service-run +++ b/features/src/cron/service-run @@ -2,4 +2,4 @@ exec 2>&1 -/usr/sbin/crond -f -d 8 -L /var/log/cron.log +exec /usr/sbin/crond -f -l 8