diff --git a/.env.scripts b/.env.scripts index 9181484..04e0d58 100644 --- a/.env.scripts +++ b/.env.scripts @@ -1,10 +1,10 @@ # - - - - - - - - - - - - - - - - - - - - - - - - - -##@Version : 202509161146-git +##@Version : 202605131434-git # @@Author : CasjaysDev # @@Contact : CasjaysDev # @@License : MIT -# @@Copyright : Copyright 2025 CasjaysDev -# @@Created : Tue Sep 16 11:46:20 AM EDT 2025 +# @@Copyright : Copyright 2026 CasjaysDev +# @@Created : Wed May 13 02:34:14 PM EDT 2026 # @@File : .env.scripts # @@Description : Variables for gen-dockerfile and buildx scripts # @@Changelog : newScript diff --git a/AI.md b/AI.md new file mode 100644 index 0000000..aa43ac1 --- /dev/null +++ b/AI.md @@ -0,0 +1,55 @@ +# aria2 — THE HOW + +## Build flow + +Multi-stage Alpine Dockerfile (`casjaysdev/alpine` base → `FROM scratch` final). + +1. **Package install**: `pkmgr install aria2 bash tini curl wget tzdata ca-certificates unzip jq pwgen nginx` installs all components in one layer. +2. **Setup scripts** (`rootfs/root/docker/setup/`): `03-files.sh` auto-installs everything under `rootfs/tmp/` into the image (`/etc/aria2/`, `/etc/nginx/`, `/usr/local/etc/docker/bin/`, etc.). `05-custom.sh` performs the wipe-and-replace — removes distro defaults from `/etc/aria2/` and `/etc/nginx/`, installs our optimized configs, and unpacks the pre-bundled AriaNg zip from `rootfs/tmp/ariang-src/AriaNg-*.zip` into `/usr/local/share/ariang/`. +3. **AriaNg pre-bundle**: GitHub SSL is blocked inside the buildx sandbox on this host, so the AriaNg zip must be downloaded on the host first and placed at `rootfs/tmp/ariang-src/AriaNg-1.3.13.zip` (gitignored) before running `buildx`. +4. **Final stage**: `FROM scratch` + `COPY --from=build /. /` produces a minimal image with tini as PID 1. + +## Runtime boot chain + +``` +tini → /usr/local/bin/entrypoint.sh → /usr/local/etc/docker/init.d/00-aria2c.sh → /usr/local/etc/docker/bin/start-aria2 +``` + +- `entrypoint.sh` seeds `/config/` and `/data/` on first run (via `__initialize_config_dir` / `__initialize_data_dir`), then calls `__start_init_scripts` which sources and executes `init.d/00-aria2c.sh`. +- `00-aria2c.sh` sources `functions/entrypoint.sh`, runs hook functions (`__run_pre_execute_checks` → `tracker.sh` to refresh BT trackers; `__update_conf_files` → token substitution: `REPLACE_RPC_PORT`, `REPLACE_SERVER_ADDR`, optional `rpc-secret` toggle, DHT port, log path, file-allocation, AriaNg config overlay), then calls the framework's `__run_start_script`. +- `start-aria2` backgrounds `aria2c --conf-path=/config/aria2/aria2.conf`, waits for port 6800 to open, then `exec`s `nginx -c /config/nginx/nginx.conf -g 'daemon off;'` as the foreground process (becomes PID adopted by tini). + +## Key paths + +| Path | Role | +|---|---| +| `/usr/bin/aria2c` | Download daemon binary | +| `/usr/sbin/nginx` | HTTP server binary | +| `/usr/local/share/ariang/` | AriaNg static files (index.html, JS, CSS) | +| `/usr/local/etc/docker/bin/start-aria2` | Wrapper: backgrounds aria2c, foregrounds nginx | +| `/usr/local/etc/docker/init.d/00-aria2c.sh` | Init.d script — wires up the service | +| `/usr/local/bin/tracker.sh` | P3TERX BT tracker updater | +| `/config/aria2/aria2.conf` | User-editable aria2c config (seeded from `rootfs/tmp/etc/aria2/aria2.conf`) | +| `/config/nginx/nginx.conf` | User-editable nginx config (seeded from `rootfs/tmp/etc/nginx/nginx.conf`) | +| `/data/downloads/aria2/` | Download destination | +| `/data/logs/aria2/aria2.log` | aria2c log | +| `/data/logs/nginx/` | nginx access + error logs | + +## Config token substitution (00-aria2c.sh `__update_conf_files`) + +Tokens in `/config/aria2/aria2.conf` replaced at each container start: + +| Token | Replaced with | +|---|---| +| `REPLACE_RPC_PORT` | `${RPC_PORT:-6800}` | +| `REPLACE_SERVER_ADDR` | Container IPv4 (via `__get_ip4`) | +| `rpc-secret=REPLACE_RPC_SECRET` | Commented out unless `RPC_SECRET` env var is set | +| `dht-listen-port=.*` | `dht-listen-port=6888` | +| `log=.*` | `log=/data/logs/aria2/aria2.log` | +| `file-allocation=.*` | `file-allocation=prealloc` | + +The AriaNg client config (`/config/aria2/aria-ng.config.js`) is also overlaid onto the bundled `js/aria-ng-*.min.js` so the UI auto-connects to the local RPC endpoint without user configuration. + +## Single init.d design + +The framework's `__start_init_scripts` only reliably runs the first `init.d/*.sh`. Two separate scripts (`00-aria2c.sh` + `zz-nginx.sh`) would only start aria2c. The resolution is a single init.d entry (`00-aria2c.sh`) pointing at the `start-aria2` wrapper script which manages both processes. diff --git a/CLAUDE.md b/CLAUDE.md index e83d101..e2465c7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,395 +1,7 @@ -# casjaysdevdocker repo template spec +# aria2 — agent context -This file is the **canonical spec** for what a properly-set-up `casjaysdevdocker/` container repo looks like. It is the source of truth for migrations, audits, and new repos. +Read `AI.md` and `IDEA.md` in this directory for service intent and build architecture. -- Untracked: this file lives at the repos root, not in any individual repo's git tree. -- Per-repo: each repo gets `/CLAUDE.md` (a copy of this file) and `/PLAN.md` (the concrete plan for that specific service stack), both committed to the repo. -- Authority: `~/.claude/CLAUDE.md` (52 numbered global rules) is the base. This file extends it for the docker-image work. Existing repo files are *input*, never authoritative — the repos are mostly unfinished. +Follow `/root/Projects/github/casjaysdevdocker/.github/AI.md` for org-wide conventions (Dockerfile structure, init.d contract, wipe-and-replace config flow, shared vs per-repo file rules). ---- - -## 1. What a repo is - -Each repo builds **one self-contained Docker image** for the service named after the repo. The image: - -- Targets `linux/amd64` and `linux/arm64` via `buildx`. -- Boots via `tini` → `entrypoint.sh` → init.d service scripts → long-running service. -- Stores user-modifiable config under `/config/` (volume). -- Stores runtime data, logs, DB files under `/data` (volume). -- Ships a single, **highly-optimized** config in `rootfs/tmp/etc//` that replaces the distro defaults at build time. -- Provides sane defaults: first-run with no env vars works for the common case. - -App-style repos (ampache, wordpress, navidrome, …) ship the **whole stack** the app needs: the app itself at `/usr/local/share/`, a webserver (apache or nginx) to serve it, php-fpm if PHP-based, and a database (mariadb/postgres) if the app needs one. DB-server repos (mariadb, postgres, mongodb, …) ship the DB **plus** apache + php-fpm + the canonical web admin UI (phpmyadmin for mariadb/mysql; pgAdmin/phpPgAdmin for postgres; mongo-express for mongodb; etc.). - -Inferred intent from repo name examples: - -| Repo | What it is | -|-----------------|-------------------------------------------------------------------------------------------------------------------------| -| `nginx` | nginx webserver; PHP-FPM upstream on `:9000`; CGI/Lua/etc via `nginx-mod-*` packages | -| `apache`/`httpd`| apache2 webserver + php-fpm; mod_rewrite/proxy/ssl/etc | -| `cherokee` | cherokee webserver with **CGI handlers for Ruby, Perl, Python** + **full PHP support** | -| `lighttpd` | lighttpd webserver + php-fpm/cgi | -| `caddy` | Caddy webserver (reverse-proxy/auto-TLS) | -| `traefik` | Traefik edge router | -| `mariadb` | mariadb-server + apache + php-fpm + **phpmyadmin** at `/usr/local/share/phpmyadmin` | -| `mysql` | mysql + apache + php-fpm + phpmyadmin | -| `postgres` | postgresql + apache + php-fpm + **phpPgAdmin/pgAdmin** at `/usr/local/share/phppgadmin` | -| `mongodb` | mongodb + apache + php-fpm + mongo-express or comparable web UI | -| `couchdb` | couchdb (built-in Fauxton UI) | -| `redis`/`valkey`| key-value store; CLI tools | -| `ampache` | apache + php-fpm + mariadb + ampache app at `/usr/local/share/ampache`; serves the music UI on `:80` | -| `wordpress` | apache + php-fpm + mariadb + wordpress at `/usr/local/share/wordpress` | -| `nextcloud` | apache + php-fpm + mariadb + nextcloud at `/usr/local/share/nextcloud` | -| `gitea`/`forgejo`| the binary, sqlite by default | -| `bind` | bind9 DNS server | -| `tor` | tor daemon | -| `ssl-ca` | a self-signed CA + `openssl`/`certbot` tooling | - -**Always cross-check intent and packages against:** -- **Distro docs for file paths**: Alpine docs for `/etc/` layout (and `pkgs.alpinelinux.org` for available package names); Alma/Rocky docs for `/etc/httpd` (rhel-family path). -- **Project docs for config content**: `nginx.org` for `nginx.conf` directives, `httpd.apache.org` for `httpd.conf`, `mariadb.com` for `my.cnf`, etc. -- **Upstream Docker images**: when available, `docker pull /:latest` and inspect (`docker history`, `docker run --rm -it ... sh`) to confirm canonical install paths and config locations. **Always `docker rmi` to clean up after.** - -Never invent a package name or a config option. `WebFetch`/`WebSearch`/`docker pull` to verify. - ---- - -## 2. File inventory (every repo) - -``` -/ -├── CLAUDE.md # copy of TEMPLATE.md, committed; agent reads this when working in this repo -├── PLAN.md # this repo's concrete plan: packages, configs, init.d behavior, success criteria -├── README.md # user-facing install/run docs -├── LICENSE.md # MIT (per global rule 32) or per-repo as appropriate -├── Dockerfile # multi-stage, alpine-based by default (rhel for systemd-only repos) -├── .env.scripts # buildx wrapper config (registry, push, pull, packages list) -├── .dockerignore -├── .gitattributes -├── .gitignore -├── .gitea/workflows/docker.yaml # gitea CI workflow -├── Jenkinsfile # optional, if the repo had one -└── rootfs/ # everything under here is COPYed to / in the build - ├── usr/local/bin/ - │ ├── entrypoint.sh # SHARED template, only the description + CONTAINER_NAME line are repo-specific - │ └── pkmgr # SHARED template (apt/dnf/apk auto-detect wrapper) - ├── usr/local/etc/docker/ - │ ├── functions/entrypoint.sh # framework functions sourced by entrypoint.sh and 99-.sh - │ └── init.d/ - │ └── 99-.sh # PER-REPO; defines SERVICE_NAME, ETC_DIR, CONF_DIR, EXEC_CMD_BIN/ARGS, hooks - ├── usr/local/share/ - │ ├── / # for app-style repos: the actual app code (e.g., ampache, wordpress) - │ ├── phpmyadmin/ # for mariadb/mysql repos - │ ├── phppgadmin/ # for postgres repos - │ ├── httpd/default/ # default webroot (used when no app) - │ └── template-files/ - │ ├── config/ # templates copied to /config// on first run by __initialize_config_dir - │ ├── data/ # templates copied to /data// on first run - │ └── defaults/ # default fallbacks - ├── tmp/etc// # PER-REPO optimized configs; copied to /etc// at build time (see §4) - ├── tmp/bin/ # optional; auto-installed to /usr/local/bin/ at build time - ├── tmp/var/ # optional; auto-installed to /var/ at build time - └── root/docker/setup/ # PER-REPO build-time scripts (see §3) - ├── 00-init.sh - ├── 01-system.sh - ├── 02-packages.sh - ├── 03-files.sh - ├── 04-users.sh - ├── 05-custom.sh # ← service-specific config wipe-and-replace lives here - ├── 06-post.sh - └── 07-cleanup.sh -``` - -**SHARED vs PER-REPO** (load-bearing distinction — getting this wrong breaks repos): - -- **SHARED** (safe to overwrite from the upstream template): `rootfs/usr/local/bin/entrypoint.sh` (only the description + `CONTAINER_NAME=""` change per repo), `rootfs/usr/local/bin/pkmgr`, `rootfs/usr/local/etc/docker/functions/entrypoint.sh`. -- **PER-REPO** (never overwrite from a template — read first; preserve service-specific logic): every script under `rootfs/root/docker/setup/`, `rootfs/usr/local/etc/docker/init.d/*`, everything under `rootfs/tmp/`, everything under `rootfs/usr/local/share//`. - ---- - -## 3. Build-time setup script flow - -`Dockerfile` runs `00-init.sh` → … → `07-cleanup.sh` interleaved with package install. Order and contract: - -| Script | When it runs | What it does | -|------------------|-----------------------------------------------|----------------------------------------------------------------------------------------------------| -| `00-init.sh` | Right after `mkdir`s before anything else | Sanity setup; usually empty | -| `01-system.sh` | After apk repos are configured | System-level tweaks (extra repos, timezone, non-package OS config) | -| `02-packages.sh` | After `pkmgr install $PACK_LIST` | Per-service post-install tweaks (e.g., compile a module, install a pip/npm package, fetch the app) | -| `03-files.sh` | After packages are installed | **Auto-installs `rootfs/tmp/{bin,var,etc,data}/*`** into `/usr/local/bin/`, `/var/`, `/etc/`, and the `template-files/` staging dirs. Most repos use the canonical version verbatim. | -| `04-users.sh` | After files are placed | Create system users/groups the service needs (e.g., `nginx`, `mysql`, `apache`) | -| `05-custom.sh` | After users | **Service-specific config wipe-and-replace** (see §4). Also: clone wwwroot templates, fetch app source, etc. | -| `06-post.sh` | After custom | Late tweaks (permissions, symlinks) | -| `07-cleanup.sh` | Last | Per-service cache cleanup beyond the Dockerfile's generic cleanup | - -The Dockerfile's own RUN steps already do generic cleanup (`pkmgr clean`, `rm -Rf /usr/share/doc/*`, etc.); the per-script `07-cleanup.sh` only handles service-specific files. - ---- - -## 4. The wipe-and-replace config flow - -The most important pattern in this template. Goal: the running container's `/etc//` contains **only** our optimized config, never distro defaults. - -**Build time:** -1. Service package install (e.g., `apk add nginx`) creates distro defaults under `/etc//` (e.g., `/etc/nginx/{nginx.conf, conf.d/, modules-enabled/, http.d/, mime.types, …}`). -2. `03-files.sh` copies `rootfs/tmp/etc//*` → `/etc//*` (overlay only) **and** stages a copy at `/usr/local/share/template-files/config//` for runtime seeding. -3. `05-custom.sh` performs the **wipe-and-replace** (the canonical idiom): - ```sh - if [ -d "/tmp/etc/" ]; then - # preserve distro-shipped files we need (e.g., mime.types when not in tmp/etc/) - # then wipe defaults - rm -Rf "/etc/"/* - cp -Rf "/tmp/etc//." "/etc//" - fi - ``` - For services that auto-discover sub-confs, our `.conf` ends with an **optional** include like `include /config//vhosts.d/*.conf;` (nginx) or `IncludeOptional /config//conf.d/*.conf` (apache) so an empty include dir doesn't crash startup. - -**Runtime (entrypoint + 99-.sh):** -1. `entrypoint.sh` calls `__initialize_default_templates` / `__initialize_config_dir` / `__initialize_data_dir` which copy `template-files/{defaults,config,data}//*` → `/config//` and `/data//` **only when those target dirs are not already initialized** (via `/config/.docker_has_run` and `/data/.docker_has_run` markers). -2. `99-.sh` calls `__initialize_system_etc "$CONF_DIR"` which symlinks/copies the user-editable `/config//` → the service's expected runtime path (`/etc//` for system services; `/usr/local/share//config/` for app-stack repos). -3. `99-.sh` also ensures runtime dirs exist: `vhosts.d/`, `conf.d/`, `ssl/`, `secure/auth/`, log dirs under `/data/logs//`. -4. Service starts pointing at `/etc//.conf` (or equivalent), which transitively reads from `/config//`. - -Net effect: end users edit files under `/config//` (volume); the service picks them up; rebuilds and restarts don't trample user changes. - -**Anti-patterns:** -- Letting distro defaults survive into the running image (didn't wipe `/etc//*`). -- Hardcoding paths in our config that point inside `/etc//` instead of `/config//` for things users should customize. -- Copying `template-files/config//*` into `/config//` unconditionally on every container start (clobbers user edits) — always gate with the init markers. -- Using a non-optional `include` for `vhosts.d/` (kills the service when the dir is empty on first run). - ---- - -## 5. Dockerfile structure - -Multi-stage. Build stage installs packages and runs setup scripts; final stage is `FROM scratch` and `COPY --from=build /. /` for a minimal final image. Exception: containers needing systemd as PID 1 (e.g., blueonyx) are single-stage with `CMD ["/sbin/init"]`. - -Required ARGs in the **header** (preserve per-repo values during migration): - -```dockerfile -ARG IMAGE_NAME="" -ARG PHP_SERVER="" # often same as IMAGE_NAME -ARG BUILD_DATE="" # auto-bumped by gen-dockerfile / CI -ARG LANGUAGE="en_US.UTF-8" -ARG TIMEZONE="America/New_York" -ARG WWW_ROOT_DIR="/usr/local/share/httpd/default" -ARG DEFAULT_FILE_DIR="/usr/local/share/template-files" -ARG DEFAULT_DATA_DIR="/usr/local/share/template-files/data" -ARG DEFAULT_CONF_DIR="/usr/local/share/template-files/config" -ARG DEFAULT_TEMPLATE_DIR="/usr/local/share/template-files/defaults" -ARG PATH="/usr/local/etc/docker/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" -ARG USER="root" -ARG SHELL_OPTS="set -e -o pipefail" -ARG SERVICE_PORT="" -ARG EXPOSE_PORTS="" -ARG PHP_VERSION="" -ARG NODE_VERSION="system" -ARG NODE_MANAGER="system" -ARG IMAGE_REPO="/" -ARG IMAGE_VERSION="latest" -ARG CONTAINER_VERSION="" # "USE_DATE" if buildx should auto-add a date tag -ARG PULL_URL="casjaysdev/alpine" # or "alpine", "almalinux/10-init", etc. -ARG DISTRO_VERSION="${IMAGE_VERSION}" -ARG BUILD_VERSION="${BUILD_DATE}" -``` - -`PACK_LIST` lives in the build stage and is the **single most repo-specific value** — it must be complete and accurate for the service stack: - -```dockerfile -ARG PACK_LIST="" -``` - -Build-stage RUN order (alpine): - -1. `COPY ./rootfs/. /` (early, so setup scripts and `/tmp/etc/` are available before package install) -2. `RUN pkmgr update; pkmgr install bash` -3. `RUN` install bash + symlink `/bin/sh` → `bash` (Alpine ships busybox sh) -4. `ENV SHELL="/bin/bash"; SHELL [ "/bin/bash", "-c" ]` -5. `COPY --from=gosu /usr/local/bin/gosu /usr/local/bin/gosu` -6. `RUN` initialize: `mkdir -p` template dirs + `00-init.sh` -7. `RUN` system: rewrite `/etc/apk/repositories` for the right distro version; `apk update && apk upgrade` + `01-system.sh` -8. `RUN` pre-package commands (usually empty) -9. `RUN` install packages from `${PACK_LIST}` via `pkmgr install` -10. `RUN` `02-packages.sh` -11. `COPY ./Dockerfile /root/docker/Dockerfile` (so the image carries its own build recipe) -12. `RUN` updating system files: timezone, nsswitch, php symlinks, .bashrc, `03-files.sh` -13. `RUN` Custom Settings (usually empty placeholder) -14. `RUN` users + `04-users.sh` -15. `RUN` user init (placeholder) -16. `RUN` OS Settings (placeholder) -17. `RUN` Custom Applications (placeholder) -18. `RUN` `05-custom.sh` -19. `RUN` final commands + `06-post.sh` -20. `RUN` cleanup (generic) + `07-cleanup.sh` -21. `RUN echo "Init done"` - -Final stage (`FROM scratch`): - -- ARGs re-declared (scratch needs them); ENVs set; standard LABEL block (URLs, vendor, revision = `${GIT_COMMIT}`); `COPY --from=build /. /`; `VOLUME [ "/config","/data" ]`; `EXPOSE ${SERVICE_PORT} ${ENV_PORTS}`; `STOPSIGNAL SIGRTMIN+3`; `ENTRYPOINT [ "tini", "-p", "SIGTERM", "--", "/usr/local/bin/entrypoint.sh" ]`; `HEALTHCHECK ... CMD [ "/usr/local/bin/entrypoint.sh", "healthcheck" ]`. - -Distro variants: -- **alpine** (default for ~all repos) -- **rhel/almalinux** (for repos that need RHEL packages or systemd) — generated via `gen-dockerfile --dir rhel`. Almost all are still single-stage with `CMD ["/sbin/init"]`. - -Generic Dockerfile bug fixes to apply when migrating any repo (these are upstream gen-dockerfile bugs): -- Missing space before `]`: `[ "$SH_CMD" != "/bin/sh"]` → `[ "$SH_CMD" != "/bin/sh" ]` -- Blank line inside the "Creating and editing system files" RUN block (after `$SHELL_OPTS; \`) — remove the blank line; line continuation is broken otherwise. -- Unindented `echo ""` in the "Custom Settings" and "Custom Applications" RUN blocks — re-indent to ` echo ""`. - ---- - -## 6. .env.scripts fields - -The buildx wrapper (`/usr/local/bin/buildx`) reads `.env.scripts`. Required fields (current names — older field names are deprecated): - -```sh -ENV_DOCKERFILE="Dockerfile" -ENV_REGISTRY_REPO="" # was ENV_IMAGE_NAME -ENV_USE_TEMPLATE="alpine" # or "almalinux", "debian", "ubuntu" -ENV_REGISTRY_ORG="" # was ENV_ORG_NAME; must match the org in ENV_REGISTRY_PUSH -ENV_VENDOR="CasjaysDev" -ENV_AUTHOR="CasjaysDev" -ENV_MAINTAINER="CasjaysDev " -ENV_GIT_REPO_URL="https://github.com//" -ENV_REGISTRY_URL="https://docker.io" # full URL, not bare "docker.io" -ENV_REGISTRY_PUSH="/" # was ENV_IMAGE_PUSH -ENV_IMAGE_TAG="latest" -ENV_ADD_TAGS="" # "USE_DATE" to auto-add YYMM tag -ENV_ADD_IMAGE_PUSH="" -ENV_PULL_URL="" # e.g. "casjaysdev/alpine", "alpine", "almalinux/10-init" -ENV_DISTRO_TAG="${IMAGE_VERSION}" -ENV_PLATFORMS="linux/amd64,linux/arm64" # only emit when overriding the default both-archs -SERVICE_PORT="" -EXPOSE_PORTS="" -LANG_VERSION="" -PHP_VERSION="" -NODE_VERSION="system" -NODE_MANAGER="system" -WWW_ROOT_DIR="/usr/local/share/httpd/default" -DEFAULT_FILE_DIR="/usr/local/share/template-files" -DEFAULT_DATA_DIR="/usr/local/share/template-files/data" -DEFAULT_CONF_DIR="/usr/local/share/template-files/config" -DEFAULT_TEMPLATE_DIR="/usr/local/share/template-files/defaults" -ENV_PACKAGES="" -``` - -`ENV_PACKAGES` and Dockerfile `PACK_LIST` must stay in sync. Single-space separation, no double spaces. - ---- - -## 7. init.d/99-.sh contract - -Each repo's primary init.d script (named `99-.sh` for late ordering, or `09-.sh`/etc. when ordering matters relative to other init.d entries — e.g., php-fpm starts before nginx) defines repo-specific state and calls framework functions defined in `rootfs/usr/local/etc/docker/functions/entrypoint.sh`. Required variable assignments at the top (use the nginx 99-nginx.sh as the reference structure): - -```sh -SERVICE_NAME="" -DATA_DIR="/data/" -CONF_DIR="/config/" -ETC_DIR="/etc/" # or /usr/local/share//config for app-stack repos -TMP_DIR="/tmp/" -RUN_DIR="/run/" -LOG_DIR="/data/logs/" -SERVICE_PORT="" -SERVICE_USER="" # the daemon's run-as user -SERVICE_GROUP="" -EXEC_CMD_BIN='' # e.g., 'nginx', 'mysqld', 'httpd' -EXEC_CMD_ARGS='' # e.g., '-c $ETC_DIR/nginx.conf' -IS_WEB_SERVER="yes|no" -IS_DATABASE_SERVICE="yes|no" -USES_DATABASE_SERVICE="yes|no" -DATABASE_SERVICE_TYPE="" -ADDITIONAL_CONFIG_DIRS="" # extra /config subdirs to seed/symlink -APPLICATION_FILES="..." -APPLICATION_DIRS="$ETC_DIR $CONF_DIR $LOG_DIR $TMP_DIR $RUN_DIR $VAR_DIR" -``` - -Repo-customizable hooks (override the `_local` variants — the framework calls them at the right time): - -- `__run_precopy_local` — before any /config copy -- `__execute_prerun_local` — pre-execution setup -- `__run_pre_execute_checks_local` — final preflight checks -- `__update_conf_files_local` — token replacement in `/etc//*` (use `__replace`/`__find_replace`) -- `__pre_execute_local` — last-mile actions -- `__post_execute_local` — actions in background after service start -- `__pre_message_local` — pre-launch banner -- `__update_ssl_conf_local` — repo-specific SSL handling - ---- - -## 8. Per-repo CLAUDE.md and PLAN.md - -When working on a repo, the agent should: - -1. `cd ` -2. Read `CLAUDE.md` (this file's content, copied) for the spec. -3. Read `PLAN.md` for repo-specific decisions. -4. Read every existing file in the repo before editing it (rule 8). -5. When uncertain about a package/path/option, `WebFetch` the relevant docs (distro for paths, project for content). Never invent. - -`PLAN.md` template (commit this in each repo): - -```markdown -# migration plan - -## Service intent - - -## Service stack -- : ; canonical config at -- : ... - -## Packages (PACK_LIST / ENV_PACKAGES) - - -## Configs to ship in rootfs/tmp/etc/ -- /etc//: ; -- ... - -## /config// layout (user-editable) -- -> symlinked to -- vhosts.d/ -> include /config//vhosts.d/*.conf (optional) - -## init.d/99-.sh -- SERVICE_NAME, EXEC_CMD_BIN, EXEC_CMD_ARGS -- IS_WEB_SERVER / IS_DATABASE_SERVICE / USES_DATABASE_SERVICE -- Repo-specific hooks needed: __update_conf_files_local (replace XYZ), ... - -## 05-custom.sh additions -- Wipe /etc//* and copy from /tmp/etc//. -- Fetch if not present -- Other service-specific install steps - -## Verification (success criteria) -- buildx run Dockerfile succeeds for linux/amd64 + linux/arm64 -- docker run -d -p : ... starts cleanly; logs show no errors -- curl -fsS http://localhost:/ returns the expected response -- /config// is seeded on first run; editing a file there changes service behavior on restart -- (DB repos) connecting with the right CLI client succeeds -- (optional) compared against upstream image (`docker pull :latest && docker history :latest`); upstream image deleted (`docker rmi`) after verification -``` - ---- - -## 9. Migration workflow per repo - -1. Create `/CLAUDE.md` = copy of this `TEMPLATE.md`. -2. Read existing files; assemble the PLAN.md. -3. **Read each file before changing it** (no batch templating). Apply only the changes that PLAN.md identifies. -4. `cd && rm -f .build_failed && buildx run Dockerfile` — fix any build error before moving on. -5. Smoke-test: `docker run --rm -d --name test- -p : /:latest`; wait for healthcheck; `curl` the health/main endpoint; `docker exec` and inspect `/config//`; stop and remove. -6. Commit `CLAUDE.md` and `PLAN.md` to the repo (do NOT commit code changes unless the user has asked — global rule about commits applies). -7. Move to next repo with **no carry-over**: spawn a fresh subagent; do not load prior repo's context. - ---- - -## 10. Anti-patterns (never do) - -- Overwriting `rootfs/root/docker/setup/*.sh` from a generic template — these are per-repo. -- Overwriting `rootfs/usr/local/etc/docker/init.d/*.sh` from a template — per-repo. -- Overwriting `rootfs/tmp/etc//*` — per-repo. -- Overwriting `rootfs/usr/local/share//*` — per-repo (the actual application code). -- Inventing package names, config keys, or service paths — verify with distro/project docs. -- Hardcoding secrets, tokens, internal hostnames (rule 39: every repo is public). -- Skipping the wipe-and-replace step (leaves distro defaults active alongside our config). -- Using a non-optional include for vhosts.d / conf.d (empty dir crashes the service). -- Calling a repo "done" because `buildx` was green; "done" requires the smoke-test passing. +Read `PLAN.md` for repo-specific decisions (packages, configs, init.d hooks, success criteria). diff --git a/Dockerfile b/Dockerfile index 6b6962e..f43fc1a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # Docker image for aria2 using the alpine template ARG IMAGE_NAME="aria2" ARG PHP_SERVER="aria2" -ARG BUILD_DATE="202605101200" +ARG BUILD_DATE="202605131434" ARG LANGUAGE="en_US.UTF-8" ARG TIMEZONE="America/New_York" ARG WWW_ROOT_DIR="/usr/local/share/httpd/default" @@ -76,13 +76,7 @@ RUN set -e; \ RUN set -e; \ echo "Setting up prerequisites"; \ - apk --no-cache add bash; \ - SH_CMD="$(which sh 2>/dev/null||command -v sh 2>/dev/null)"; \ - BASH_CMD="$(which bash 2>/dev/null||command -v bash 2>/dev/null)"; \ - [ -x "$BASH_CMD" ] && symlink "$BASH_CMD" "/bin/sh" || true; \ - [ -x "$BASH_CMD" ] && symlink "$BASH_CMD" "/usr/bin/sh" || true; \ - [ -x "$BASH_CMD" ] && [ "$SH_CMD" != "/bin/sh" ] && symlink "$BASH_CMD" "$SH_CMD" || true; \ - [ -n "$BASH_CMD" ] && sed -i 's|root:x:.*|root:x:0:0:root:/root:'$BASH_CMD'|g' "/etc/passwd" || true + true ENV SHELL="/bin/bash" SHELL [ "/bin/bash", "-c" ] @@ -97,12 +91,6 @@ RUN echo "Initializing the system"; \ RUN echo "Creating and editing system files "; \ $SHELL_OPTS; \ - rm -Rf "/etc/apk/repositories"; \ - [ "$DISTRO_VERSION" = "latest" ] && DISTRO_VERSION="edge";[ "$DISTRO_VERSION" = "edge" ] || DISTRO_VERSION="v${DISTRO_VERSION}"; \ - echo "http://dl-cdn.alpinelinux.org/alpine/${DISTRO_VERSION}/main" >>"/etc/apk/repositories"; \ - echo "http://dl-cdn.alpinelinux.org/alpine/${DISTRO_VERSION}/community" >>"/etc/apk/repositories"; \ - if [ "${DISTRO_VERSION}" = "edge" ]; then echo "http://dl-cdn.alpinelinux.org/alpine/${DISTRO_VERSION}/testing" >>"/etc/apk/repositories";fi; \ - apk update; apk upgrade --no-cache; \ if [ -f "/root/docker/setup/01-system.sh" ];then echo "Running the system script";/root/docker/setup/01-system.sh||{ echo "Failed to execute /root/docker/setup/01-system.sh" >&2 && exit 10; };echo "Done running the system script";fi; \ echo "" diff --git a/IDEA.md b/IDEA.md new file mode 100644 index 0000000..156d7f8 --- /dev/null +++ b/IDEA.md @@ -0,0 +1,3 @@ +# aria2 — THE WHAT + +A single Alpine-based Docker image that provides a complete, self-hosted download solution: **aria2c** handles multi-protocol downloads (HTTP/HTTPS, FTP, SFTP, BitTorrent, Metalink) via a JSON-RPC daemon on port 6800, while **AriaNg** (a pure-static web UI bundled at build time) is served by **nginx** on port 80, which also reverse-proxies `/jsonrpc` and `/rpc` to aria2c so end users interact with a single port. BitTorrent peer traffic uses port 6888. The design is zero-config on first run: the container seeds `/config/aria2/aria2.conf` and `/config/nginx/nginx.conf` from baked-in optimized defaults, a `tracker.sh` helper refreshes the BitTorrent tracker list at each startup, and users who want RPC authentication simply set `RPC_SECRET` in the environment. diff --git a/README.md b/README.md index 0a73331..7341b19 100644 --- a/README.md +++ b/README.md @@ -1,79 +1,101 @@ -## 👋 Welcome to aria2 🚀 +## 👋 Welcome to aria2 🚀 -aria2 README - - -## Install my system scripts +A self-contained Docker image running **aria2c** (multi-protocol download daemon) with the **AriaNg** web UI served by **nginx**. Supports HTTP/HTTPS, FTP, BitTorrent, Metalink, and WebSocket RPC. + +--- + +## 🚀 Quick start ```shell - sudo bash -c "$(curl -q -LSsf "https://github.com/systemmgr/installer/raw/main/install.sh")" - sudo systemmgr --config && sudo systemmgr install scripts -``` - -## Automatic install/update - -```shell -dockermgr update aria2 -``` - -## Install and run container - -```shell -dockerHome="/var/lib/srv/$USER/docker/casjaysdevdocker/aria2/aria2/latest/rootfs" -mkdir -p "/var/lib/srv/$USER/docker/aria2/rootfs" -git clone "https://github.com/dockermgr/aria2" "$HOME/.local/share/CasjaysDev/dockermgr/aria2" -cp -Rfva "$HOME/.local/share/CasjaysDev/dockermgr/aria2/rootfs/." "$dockerHome/" docker run -d \ ---restart always \ ---privileged \ ---name casjaysdevdocker-aria2-latest \ ---hostname aria2 \ --e TZ=${TIMEZONE:-America/New_York} \ --v "$dockerHome/data:/data:z" \ --v "$dockerHome/config:/config:z" \ --p 80:80 \ -casjaysdevdocker/aria2:latest + --restart always \ + --name casjaysdevdocker-aria2 \ + --hostname aria2 \ + -e TZ=${TIMEZONE:-America/New_York} \ + -v /srv/docker/aria2/config:/config:z \ + -v /srv/docker/aria2/data:/data:z \ + -p 80:80 \ + -p 6800:6800 \ + -p 6888:6888 \ + casjaysdevdocker/aria2:latest ``` - -## via docker-compose - + +Open `http://localhost` to access the AriaNg web interface. + +--- + +## 🐳 docker-compose + ```yaml version: "2" services: - ProjectName: - image: casjaysdevdocker/aria2 + aria2: + image: casjaysdevdocker/aria2:latest container_name: casjaysdevdocker-aria2 + hostname: aria2 + restart: always environment: - TZ=America/New_York - - HOSTNAME=aria2 volumes: - - "/var/lib/srv/$USER/docker/casjaysdevdocker/aria2/aria2/latest/rootfs/data:/data:z" - - "/var/lib/srv/$USER/docker/casjaysdevdocker/aria2/aria2/latest/rootfs/config:/config:z" + - /srv/docker/aria2/config:/config:z + - /srv/docker/aria2/data:/data:z ports: - - 80:80 - restart: always + - 80:80 # AriaNg web UI + proxied RPC + - 6800:6800 # aria2c direct JSON-RPC / WebSocket + - 6888:6888 # BitTorrent peer / DHT ``` - -## Get source files - -```shell -dockermgr download src casjaysdevdocker/aria2 -``` - -OR - + +--- + +## 🔧 Environment variables + +| Variable | Default | Description | +|---|---|---| +| `TZ` | `America/New_York` | Container timezone | +| `RPC_PORT` | `6800` | aria2c RPC listen port | +| `RPC_SECRET` | _(unset)_ | aria2c RPC secret token (blank = no auth) | +| `CUSTOM_TRACKER_URL` | _(unset)_ | URL to fetch fresh BT tracker list (P3TERX format) | + +--- + +## 📁 Volumes + +| Path | Purpose | +|---|---| +| `/config` | User-editable config — `aria2/aria2.conf`, `aria2/aria2.session`, `nginx/nginx.conf`, AriaNg client config | +| `/data` | Downloads at `/data/downloads/aria2/`; logs at `/data/logs/{aria2,nginx}/` | + +Seeded on first run from the image defaults. Edit `/config/aria2/aria2.conf` to tune aria2c; restart the container to apply. + +--- + +## 🌐 Ports + +| Port | Protocol | Purpose | +|---|---|---| +| `80` | TCP | AriaNg web UI (nginx); also proxies `/jsonrpc` and `/rpc` to aria2c | +| `6800` | TCP | aria2c JSON-RPC / WebSocket (direct, bypasses nginx) | +| `6888` | TCP/UDP | BitTorrent peer connections and DHT | + +--- + +## 🔨 Build from source + ```shell git clone "https://github.com/casjaysdevdocker/aria2" "$HOME/Projects/github/casjaysdevdocker/aria2" -``` - -## Build container - -```shell cd "$HOME/Projects/github/casjaysdevdocker/aria2" -buildx + +# pre-bundle AriaNg (required before buildx — GitHub SSL is blocked inside the sandbox) +mkdir -p rootfs/tmp/ariang-src +curl -fsSL -o rootfs/tmp/ariang-src/AriaNg-1.3.13.zip \ + https://github.com/mayswind/AriaNg/releases/download/1.3.13/AriaNg-1.3.13.zip + +buildx ``` - -## Authors - -🤖 casjay: [Github](https://github.com/casjay) 🤖 -⛵ casjaysdevdocker: [Github](https://github.com/casjaysdevdocker) [Docker](https://hub.docker.com/u/casjaysdevdocker) ⛵ + +--- + +## 👤 Authors + +🤖 casjay: [Github](https://github.com/casjay) 🤖 +⛵ casjaysdevdocker: [Github](https://github.com/casjaysdevdocker) [Docker](https://hub.docker.com/u/casjaysdevdocker) ⛵ diff --git a/TODO.AI.md b/TODO.AI.md new file mode 100644 index 0000000..47c70d5 --- /dev/null +++ b/TODO.AI.md @@ -0,0 +1,23 @@ +# aria2 — TODO (AI living list) + +## Done +- [x] Dockerfile: BUILD_DATE → 202605131434, prerequisites RUN → `true`, removed inline APK repo setup from "Creating and editing system files" RUN +- [x] .env.scripts: header updated to 2026, all aria2-specific values preserved +- [x] entrypoint.sh: UUOC fix (cat → bash builtin), CONTAINER_NAME="aria2" already correct +- [x] pkmgr: copied verbatim from canonical template +- [x] functions/entrypoint.sh: copied verbatim from canonical template (1724 lines) +- [x] Setup scripts 00-04, 06-07: copied from canonical template +- [x] 05-custom.sh: preserved (AriaNg install + wipe-and-replace logic) +- [x] init.d/00-aria2c.sh: full canonical rewrite (04-example.sh pattern, aria2-specific hooks preserved) +- [x] README.md: user-facing install/run docs with ports, volumes, env vars +- [x] IDEA.md: one-paragraph service intent +- [x] AI.md: build flow, runtime chain, key paths, token substitution table +- [x] CLAUDE.md: minimal agent context pointer +- [x] PLAN.md: already complete from earlier migration work +- [x] bash -n validation: all modified scripts pass syntax check + +## Pending +- [ ] Smoke test: `docker run` + curl RPC + curl AriaNg UI (requires buildx to run first) +- [ ] Pre-bundle AriaNg zip on host: `mkdir -p rootfs/tmp/ariang-src && curl -fsSL -o rootfs/tmp/ariang-src/AriaNg-1.3.13.zip https://github.com/mayswind/AriaNg/releases/download/1.3.13/AriaNg-1.3.13.zip` +- [ ] buildx: `cd /root/Projects/github/casjaysdevdocker/aria2 && buildx` +- [ ] gitcommit when smoke test passes diff --git a/rootfs/root/docker/setup/00-init.sh b/rootfs/root/docker/setup/00-init.sh index 9835570..99e88df 100755 --- a/rootfs/root/docker/setup/00-init.sh +++ b/rootfs/root/docker/setup/00-init.sh @@ -1,40 +1,45 @@ #!/usr/bin/env bash -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -##@Version : 202505131551-git +# shellcheck shell=bash +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202605131431-git # @@Author : CasjaysDev # @@Contact : CasjaysDev # @@License : MIT -# @@ReadME : -# @@Copyright : Copyright 2023 CasjaysDev -# @@Created : Mon Aug 28 06:48:42 PM EDT 2023 +# @@Copyright : Copyright 2026 CasjaysDev +# @@Created : Wed May 13 02:31:25 PM EDT 2026 # @@File : 00-init.sh # @@Description : script to run init -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# shellcheck shell=bash -# shellcheck disable=SC2016 -# shellcheck disable=SC2031 -# shellcheck disable=SC2120 -# shellcheck disable=SC2155 -# shellcheck disable=SC2199 -# shellcheck disable=SC2317 -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# @@Changelog : newScript +# @@TODO : Refactor code +# @@Other : N/A +# @@Resource : N/A +# @@Terminal App : yes +# @@sudo/root : yes +# @@Template : templates/dockerfiles/init_scripts/00-init.sh +# - - - - - - - - - - - - - - - - - - - - - - - - - +# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329 +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set bash options set -o pipefail [ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set env variables exitCode=0 -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Predefined actions if [ -d "/usr/local/share/template-files/data" ]; then rm -Rf "/usr/local/share/template-files/data"/*; fi if [ -d "/usr/local/share/template-files/config" ]; then rm -Rf "/usr/local/share/template-files/config"/*; fi if [ -d "/usr/local/share/template-files/defaults" ]; then rm -Rf "/usr/local/share/template-files/defaults"/*; fi -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Main script -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set the exit code #exitCode=$? -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - exit $exitCode +# - - - - - - - - - - - - - - - - - - - - - - - - - +# ex: ts=2 sw=2 et filetype=sh +# - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/rootfs/root/docker/setup/01-system.sh b/rootfs/root/docker/setup/01-system.sh index 1585472..c7cae6f 100755 --- a/rootfs/root/docker/setup/01-system.sh +++ b/rootfs/root/docker/setup/01-system.sh @@ -1,38 +1,43 @@ #!/usr/bin/env bash -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -##@Version : 202505131551-git +# shellcheck shell=bash +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202605131431-git # @@Author : CasjaysDev # @@Contact : CasjaysDev # @@License : MIT -# @@ReadME : -# @@Copyright : Copyright 2023 CasjaysDev -# @@Created : Mon Aug 28 06:48:42 PM EDT 2023 +# @@Copyright : Copyright 2026 CasjaysDev +# @@Created : Wed May 13 02:31:25 PM EDT 2026 # @@File : 01-system.sh # @@Description : script to run system -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# shellcheck shell=bash -# shellcheck disable=SC2016 -# shellcheck disable=SC2031 -# shellcheck disable=SC2120 -# shellcheck disable=SC2155 -# shellcheck disable=SC2199 -# shellcheck disable=SC2317 -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# @@Changelog : newScript +# @@TODO : Refactor code +# @@Other : N/A +# @@Resource : N/A +# @@Terminal App : yes +# @@sudo/root : yes +# @@Template : templates/dockerfiles/init_scripts/01-system.sh +# - - - - - - - - - - - - - - - - - - - - - - - - - +# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329 +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set bash options set -o pipefail [ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set env variables exitCode=0 -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Predefined actions -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Main script -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set the exit code #exitCode=$? -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - exit $exitCode +# - - - - - - - - - - - - - - - - - - - - - - - - - +# ex: ts=2 sw=2 et filetype=sh +# - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/rootfs/root/docker/setup/02-packages.sh b/rootfs/root/docker/setup/02-packages.sh index 3309e06..58c3443 100755 --- a/rootfs/root/docker/setup/02-packages.sh +++ b/rootfs/root/docker/setup/02-packages.sh @@ -1,38 +1,43 @@ #!/usr/bin/env bash -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -##@Version : 202505131551-git +# shellcheck shell=bash +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202605131431-git # @@Author : CasjaysDev # @@Contact : CasjaysDev # @@License : MIT -# @@ReadME : -# @@Copyright : Copyright 2023 CasjaysDev -# @@Created : Mon Aug 28 06:48:42 PM EDT 2023 +# @@Copyright : Copyright 2026 CasjaysDev +# @@Created : Wed May 13 02:31:25 PM EDT 2026 # @@File : 02-packages.sh # @@Description : script to run packages -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# shellcheck shell=bash -# shellcheck disable=SC2016 -# shellcheck disable=SC2031 -# shellcheck disable=SC2120 -# shellcheck disable=SC2155 -# shellcheck disable=SC2199 -# shellcheck disable=SC2317 -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# @@Changelog : newScript +# @@TODO : Refactor code +# @@Other : N/A +# @@Resource : N/A +# @@Terminal App : yes +# @@sudo/root : yes +# @@Template : templates/dockerfiles/init_scripts/02-packages.sh +# - - - - - - - - - - - - - - - - - - - - - - - - - +# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329 +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set bash options set -o pipefail [ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set env variables exitCode=0 -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Predefined actions -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Main script -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set the exit code #exitCode=$? -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - exit $exitCode +# - - - - - - - - - - - - - - - - - - - - - - - - - +# ex: ts=2 sw=2 et filetype=sh +# - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/rootfs/root/docker/setup/03-files.sh b/rootfs/root/docker/setup/03-files.sh index ed8bb0e..5823f67 100755 --- a/rootfs/root/docker/setup/03-files.sh +++ b/rootfs/root/docker/setup/03-files.sh @@ -1,31 +1,32 @@ #!/usr/bin/env bash -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -##@Version : 202408270903-git +# shellcheck shell=bash +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202605131431-git # @@Author : CasjaysDev # @@Contact : CasjaysDev # @@License : MIT -# @@ReadME : -# @@Copyright : Copyright 2023 CasjaysDev -# @@Created : Mon Aug 28 06:48:42 PM EDT 2023 +# @@Copyright : Copyright 2026 CasjaysDev +# @@Created : Wed May 13 02:31:25 PM EDT 2026 # @@File : 03-files.sh # @@Description : script to run files -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# shellcheck shell=bash -# shellcheck disable=SC2016 -# shellcheck disable=SC2031 -# shellcheck disable=SC2120 -# shellcheck disable=SC2155 -# shellcheck disable=SC2199 -# shellcheck disable=SC2317 -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# @@Changelog : newScript +# @@TODO : Refactor code +# @@Other : N/A +# @@Resource : N/A +# @@Terminal App : yes +# @@sudo/root : yes +# @@Template : templates/dockerfiles/init_scripts/03-files.sh +# - - - - - - - - - - - - - - - - - - - - - - - - - +# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329 +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set bash options set -o pipefail [ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set env variables exitCode=0 -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Predefined actions if [ -d "/tmp/bin" ]; then mkdir -p "/usr/local/bin" @@ -79,11 +80,15 @@ if [ -d "/tmp/data" ]; then done fi unset data -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Main script -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set the exit code #exitCode=$? -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - exit $exitCode +# - - - - - - - - - - - - - - - - - - - - - - - - - +# ex: ts=2 sw=2 et filetype=sh +# - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/rootfs/root/docker/setup/04-users.sh b/rootfs/root/docker/setup/04-users.sh index 6d2390a..ff375ca 100755 --- a/rootfs/root/docker/setup/04-users.sh +++ b/rootfs/root/docker/setup/04-users.sh @@ -1,38 +1,43 @@ #!/usr/bin/env bash -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -##@Version : 202505131551-git +# shellcheck shell=bash +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202605131431-git # @@Author : CasjaysDev # @@Contact : CasjaysDev # @@License : MIT -# @@ReadME : -# @@Copyright : Copyright 2023 CasjaysDev -# @@Created : Mon Aug 28 06:48:42 PM EDT 2023 +# @@Copyright : Copyright 2026 CasjaysDev +# @@Created : Wed May 13 02:31:26 PM EDT 2026 # @@File : 04-users.sh # @@Description : script to run users -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# shellcheck shell=bash -# shellcheck disable=SC2016 -# shellcheck disable=SC2031 -# shellcheck disable=SC2120 -# shellcheck disable=SC2155 -# shellcheck disable=SC2199 -# shellcheck disable=SC2317 -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# @@Changelog : newScript +# @@TODO : Refactor code +# @@Other : N/A +# @@Resource : N/A +# @@Terminal App : yes +# @@sudo/root : yes +# @@Template : templates/dockerfiles/init_scripts/04-users.sh +# - - - - - - - - - - - - - - - - - - - - - - - - - +# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329 +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set bash options set -o pipefail [ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set env variables exitCode=0 -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Predefined actions -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Main script -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set the exit code #exitCode=$? -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - exit $exitCode +# - - - - - - - - - - - - - - - - - - - - - - - - - +# ex: ts=2 sw=2 et filetype=sh +# - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/rootfs/root/docker/setup/06-post.sh b/rootfs/root/docker/setup/06-post.sh index 704bbfb..a0c32c6 100755 --- a/rootfs/root/docker/setup/06-post.sh +++ b/rootfs/root/docker/setup/06-post.sh @@ -1,38 +1,43 @@ #!/usr/bin/env bash -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -##@Version : 202505131551-git +# shellcheck shell=bash +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202605131431-git # @@Author : CasjaysDev # @@Contact : CasjaysDev # @@License : MIT -# @@ReadME : -# @@Copyright : Copyright 2023 CasjaysDev -# @@Created : Mon Aug 28 06:48:42 PM EDT 2023 +# @@Copyright : Copyright 2026 CasjaysDev +# @@Created : Wed May 13 02:31:26 PM EDT 2026 # @@File : 06-post.sh # @@Description : script to run post -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# shellcheck shell=bash -# shellcheck disable=SC2016 -# shellcheck disable=SC2031 -# shellcheck disable=SC2120 -# shellcheck disable=SC2155 -# shellcheck disable=SC2199 -# shellcheck disable=SC2317 -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# @@Changelog : newScript +# @@TODO : Refactor code +# @@Other : N/A +# @@Resource : N/A +# @@Terminal App : yes +# @@sudo/root : yes +# @@Template : templates/dockerfiles/init_scripts/06-post.sh +# - - - - - - - - - - - - - - - - - - - - - - - - - +# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329 +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set bash options set -o pipefail [ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set env variables exitCode=0 -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Predefined actions -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Main script -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set the exit code #exitCode=$? -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - exit $exitCode +# - - - - - - - - - - - - - - - - - - - - - - - - - +# ex: ts=2 sw=2 et filetype=sh +# - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/rootfs/root/docker/setup/07-cleanup.sh b/rootfs/root/docker/setup/07-cleanup.sh index 7191087..23b9272 100755 --- a/rootfs/root/docker/setup/07-cleanup.sh +++ b/rootfs/root/docker/setup/07-cleanup.sh @@ -1,39 +1,47 @@ #!/usr/bin/env bash -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -##@Version : 202505131551-git +# shellcheck shell=bash +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202605131431-git # @@Author : CasjaysDev # @@Contact : CasjaysDev # @@License : MIT -# @@ReadME : -# @@Copyright : Copyright 2023 CasjaysDev -# @@Created : Mon Aug 28 06:48:42 PM EDT 2023 +# @@Copyright : Copyright 2026 CasjaysDev +# @@Created : Wed May 13 02:31:26 PM EDT 2026 # @@File : 07-cleanup.sh # @@Description : script to run cleanup -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# shellcheck shell=bash -# shellcheck disable=SC2016 -# shellcheck disable=SC2031 -# shellcheck disable=SC2120 -# shellcheck disable=SC2155 -# shellcheck disable=SC2199 -# shellcheck disable=SC2317 -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# @@Changelog : newScript +# @@TODO : Refactor code +# @@Other : N/A +# @@Resource : N/A +# @@Terminal App : yes +# @@sudo/root : yes +# @@Template : templates/dockerfiles/init_scripts/07-cleanup.sh +# - - - - - - - - - - - - - - - - - - - - - - - - - +# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329 +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set bash options set -o pipefail [ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Load functions +__find_and_remove() { [ -z "$1" ] || find "${2:-/etc}" -iname "$1" -exec rm -Rf {} \; 2>/dev/null; } +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set env variables exitCode=0 -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Predefined actions if [ -d "/tmp" ]; then rm -Rf "/tmp"/*; fi if [ -d "$HOME/.cache" ]; then rm -Rf "$HOME/.cache"; fi -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Main script -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set the exit code #exitCode=$? -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - exit $exitCode +# - - - - - - - - - - - - - - - - - - - - - - - - - +# ex: ts=2 sw=2 et filetype=sh +# - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/rootfs/usr/local/bin/entrypoint.sh b/rootfs/usr/local/bin/entrypoint.sh index 16ffdad..e9652aa 100755 --- a/rootfs/usr/local/bin/entrypoint.sh +++ b/rootfs/usr/local/bin/entrypoint.sh @@ -442,7 +442,7 @@ fi # if no pid assume container restart - clean stale files on restart if [ -f "$ENTRYPOINT_PID_FILE" ]; then # Check if the PID in the file is still running - entrypoint_pid=$(cat "$ENTRYPOINT_PID_FILE" 2>/dev/null || echo "") + entrypoint_pid=$(<"$ENTRYPOINT_PID_FILE") 2>/dev/null if [ -n "$entrypoint_pid" ] && kill -0 "$entrypoint_pid" 2>/dev/null; then # Process is still running, don't restart services START_SERVICES="no" diff --git a/rootfs/usr/local/etc/docker/functions/entrypoint.sh b/rootfs/usr/local/etc/docker/functions/entrypoint.sh index 9b8c550..e5c74eb 100644 --- a/rootfs/usr/local/etc/docker/functions/entrypoint.sh +++ b/rootfs/usr/local/etc/docker/functions/entrypoint.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # shellcheck shell=bash # - - - - - - - - - - - - - - - - - - - - - - - - - -##@Version : 202511301145-git +##@Version : 202605051922-git # @@Author : Jason Hempstead # @@Contact : git-admin@casjaysdev.pro # @@License : LICENSE.md @@ -31,7 +31,20 @@ else set -o pipefail fi # - - - - - - - - - - - - - - - - - - - - - - - - - -__remove_extra_spaces() { sed 's/\( \)*/\1/g;s|^ ||g'; } +__remove_extra_spaces() { sed -E 's/ +/ /g; s|^ ||'; } +# - - - - - - - - - - - - - - - - - - - - - - - - - +__log_debug() { + [ "$DEBUGGER" = "on" ] && echo "[DEBUG] $*" >&2 +} +__log_info() { + echo "[INFO] $*" +} +__log_warn() { + echo "[WARN] $*" >&2 +} +__log_error() { + echo "[ERROR] $*" >&2 +} # - - - - - - - - - - - - - - - - - - - - - - - - - __printf_space() { local pad=$(printf '%0.1s' " "{1..60}) @@ -47,185 +60,137 @@ __printf_space() { # - - - - - - - - - - - - - - - - - - - - - - - - - __mkdir() { if [ -n "$1" ]; then - mkdir -p "$@" 2>/dev/null || true + if ! mkdir -p "$@" 2>/dev/null; then + [ "$DEBUGGER" = "on" ] && echo "Warning: Failed to create directory: $*" >&2 + return 1 + fi fi + return 0 } __rm() { if [ -n "$1" ] && [ -e "$1" ]; then - rm -Rf "${1:?}" 2>/dev/null || true - fi -} -__grep_test() { - if grep -sh "$1" "$2" 2>/dev/null | grep -qwF "${3:-$1}"; then - return 0 - else - return 1 - fi -} -__netstat() { - if [ -f "$(type -P netstat 2>/dev/null)" ]; then - netstat "$@" 2>/dev/null - else - return 10 - fi -} -__cd() { - if [ ! -d "$1" ]; then - mkdir -p "$1" 2>/dev/null || return 1 - fi - builtin cd "$1" || return 1 -} -__is_in_file() { - if [ -e "$2" ] && grep -Rsq "$1" "$2" 2>/dev/null; then - return 0 - else - return 1 - fi -} -__curl() { - if curl -q -sfI --max-time 3 -k -o /dev/null "$@" 2>/dev/null; then - return 0 - else - return 10 - fi -} -__find() { - if find "$1" -mindepth 1 -type ${2:-f,d} 2>/dev/null | grep '.'; then - return 0 - else - return 10 - fi -} -__pcheck() { - if [ -n "$(which pgrep 2>/dev/null)" ] && pgrep -x "$1" &>/dev/null; then - return 0 - else - return 10 - fi -} -__file_exists_with_content() { - if [ -n "$1" ] && [ -f "$1" ] && [ -s "$1" ]; then - return 0 - else - return 2 - fi -} -__sed() { - if sed -i 's|'$1'|'$2'|g' "$3" 2>/dev/null; then - return 0 - elif sed -i "s|$1|$2|g" "$3" 2>/dev/null; then - return 0 - else - return 0 - fi -} -__ps() { - if [ -f "$(type -P ps 2>/dev/null)" ]; then - if ps "$@" 2>/dev/null | sed 's|:||g' | grep -Fw " ${1:-$SERVICE_NAME}$"; then - return 0 - else - return 10 - fi - else - return 10 - fi -} -__is_dir_empty() { - if [ -n "$1" ]; then - if [ "$(ls -A "$1" 2>/dev/null | wc -l)" -eq 0 ]; then - return 0 - else + if ! rm -Rf "${1:?}" 2>/dev/null; then + [ "$DEBUGGER" = "on" ] && echo "Warning: Failed to remove: $1" >&2 return 1 fi - else - return 1 fi + return 0 +} +__grep_test() { grep -sh "$1" "$2" 2>/dev/null | grep -qwF "${3:-$1}"; } +__netstat() { + command -v netstat &>/dev/null || { + [ "$DEBUGGER" = "on" ] && echo "Warning: netstat command not found" >&2 + return 10 + } + netstat "$@" 2>/dev/null +} +__cd() { + [ -d "$1" ] || mkdir -p "$1" 2>/dev/null || return 1 + builtin cd "$1" || return 1 +} +__is_in_file() { [ -e "$2" ] && grep -Rsq "$1" "$2" 2>/dev/null; } +__curl() { curl -q -sfI --max-time 3 -k -o /dev/null "$@" 2>/dev/null || return 10; } +__find() { + local result + result=$(find "$1" -mindepth 1 -type "${2:-f,d}" 2>/dev/null) + [ -n "$result" ] || return 10 + printf '%s\n' "$result" +} +__pcheck() { + command -v pgrep &>/dev/null && pgrep -x "$1" &>/dev/null || return 10 +} +__file_exists_with_content() { [ -n "$1" ] && [ -f "$1" ] && [ -s "$1" ] || return 2; } +__sed() { sed -i "s|$1|$2|g" "$3" 2>/dev/null || return 1; } +__ps() { + command -v ps &>/dev/null || return 10 + ps "$@" 2>/dev/null | sed 's|:||g' | grep -Fw " ${1:-$SERVICE_NAME}$" || return 10 +} +__is_dir_empty() { + [ -n "$1" ] && [ -d "$1" ] || return 1 + [ -z "$(ls -A "$1" 2>/dev/null)" ] } __get_ip6() { - local ip6 - ip6="$(ip a 2>/dev/null | grep -w 'inet6' | awk '{print $2}' | grep -vE '^::1|^fe' | sed 's|/.*||g' | head -n1 | grep '.')" - if [ -n "$ip6" ]; then - echo "$ip6" - else - echo '' - fi + ip a 2>/dev/null | awk '/^[[:space:]]*inet6 / { + split($2, a, "/"); ip = a[1] + if (ip !~ /^::1$/ && ip !~ /^fe/) { print ip; exit } + }' } __get_ip4() { local ip4 - ip4="$(ip a 2>/dev/null | grep -w 'inet' | awk '{print $2}' | grep -vE '^127.0.0' | sed 's|/.*||g' | head -n1 | grep '.')" - if [ -n "$ip4" ]; then - echo "$ip4" - else - echo '127.0.0.1' - fi + ip4=$(ip a 2>/dev/null | awk '/^[[:space:]]*inet / { + split($2, a, "/"); ip = a[1] + if (ip !~ /^127\.0\.0/) { print ip; exit } + }') + echo "${ip4:-127.0.0.1}" } __find_and_remove() { find "${2:-/etc}" -iname "$1" -exec rm -Rfv {} \; 2>/dev/null || true } # - - - - - - - - - - - - - - - - - - - - - - - - - __pgrep() { - local count=3 - local srvc="${1:-SERVICE_NAME}" + local srvc="$1" count=3 + [ -z "$srvc" ] && return 10 while [ $count -ge 0 ]; do - # Use exact process name matching, not full command line search - pgrep -x "$srvc" >/dev/null 2>&1 && return 0 - sleep 1 + pgrep -x "$srvc" &>/dev/null && return 0 + pgrep -f "$srvc" &>/dev/null && return 0 + ps -ef 2>/dev/null | grep -v 'grep' | grep -qw "$srvc" && return 0 + [ $count -gt 0 ] && sleep 1 count=$((count - 1)) done return 10 } # - - - - - - - - - - - - - - - - - - - - - - - - - __find_file_relative() { - if [ ! -e "$1" ]; then - return 0 - fi - find "$1"/* -not -path '*env/*' -not -path '.git*' -type f 2>/dev/null | sed 's|'$1'/||g' | sort -u | grep -v '^$' | grep '.' || true + [ -e "$1" ] || return 0 + find "$1"/* -not -path '*env/*' -not -path '.git*' -type f 2>/dev/null \ + | sort -u \ + | sed "s|^$1/||" || true } # - - - - - - - - - - - - - - - - - - - - - - - - - __find_directory_relative() { - if [ ! -d "$1" ]; then - return 0 - fi - find "$1"/* -not -path '*env/*' -not -path '.git*' -type d 2>/dev/null | sed 's|'$1'/||g' | sort -u | grep -v '^$' | grep '.' || true + [ -d "$1" ] || return 0 + find "$1"/* -not -path '*env/*' -not -path '.git*' -type d 2>/dev/null \ + | sort -u \ + | sed "s|^$1/||" || true } # - - - - - - - - - - - - - - - - - - - - - - - - - -__pid_exists() { - local result="" - result="$(ps -ax --no-header 2>/dev/null | sed 's/^[[:space:]]*//g' | awk -F' ' '{print $1}' | sed 's|:||g' | grep '[0-9]' | sort -uV | grep "^$1$" 2>/dev/null || echo '')" - if [ -n "$result" ]; then - return 0 - else - return 1 - fi -} +__pid_exists() { [ -n "$1" ] && [ -d "/proc/$1" ]; } __is_running() { - local result="" - result="$(ps -eo args --no-header 2>/dev/null | awk '{print $1,$2,$3}' | sed 's|:||g' | sort -u | grep -vE 'grep|COMMAND|awk|tee|ps|sed|sort|tail' | grep "$1" | grep "${2:-^}" 2>/dev/null || echo '')" - if [ -n "$result" ]; then - return 0 + local pat="$1" + [ -n "$2" ] && pat="$pat.*$2" + if command -v pgrep &>/dev/null; then + pgrep -f "$pat" &>/dev/null else - return 1 + ps -eo args 2>/dev/null | grep -v grep | grep -Eq "$pat" fi } __get_pid() { - local result="" - result="$(ps -ax --no-header 2>/dev/null | sed 's/^[[:space:]]*//g;s|;||g;s|:||g' | awk '{print $1,$5}' | sed 's|:||g' | grep "$1$" | grep -v 'grep' | awk -F' ' '{print $1}' | grep '[0-9]' | sort -uV | head -n1 | grep '.' 2>/dev/null || echo '')" - if [ -n "$result" ]; then - echo "$result" - return 0 - else + if [ -z "$1" ]; then + [ "$DEBUGGER" = "on" ] && echo "Warning: __get_pid called without process name" >&2 return 1 fi + local pid + pid=$(pgrep -x "$1" 2>/dev/null | head -n1) + if [ -n "$pid" ]; then + echo "$pid" + return 0 + fi + [ "$DEBUGGER" = "on" ] && echo "Debug: No PID found for process: $1" >&2 + return 1 } # - - - - - - - - - - - - - - - - - - - - - - - - - -__format_variables() { printf '%s\n' "${@//,/ }" | tr ' ' '\n' | sort -RVu | grep -v '^$' | tr '\n' ' ' | __clean_variables | grep '.' || return 0; } +__format_variables() { + local input="${*//,/ }" + [ -z "$input" ] && return 0 + printf '%s\n' $input | sort -Ru | tr '\n' ' ' +} # - - - - - - - - - - - - - - - - - - - - - - - - - __clean_variables() { local var="$*" - var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters - var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters - var="$(printf '%s\n' "$var" | sed 's/\( \)*/\1/g;s|^ ||g')" - printf '%s' "$var" | grep -v '^$' + var="${var#"${var%%[![:space:]]*}"}" + var="${var%"${var##*[![:space:]]}"}" + while [[ 202605051922-gitar == *" "* ]]; do var="${var// / }"; done + [ -n "202605051922-gitar" ] && printf '%s' "$var" } # - - - - - - - - - - - - - - - - - - - - - - - - - __no_exit() { @@ -235,7 +200,17 @@ __no_exit() { local failed_services="" local failure_count=0 - [ -f "/run/.no_exit.pid" ] && return 0 + # only return early if the recorded PID is still alive; a leftover + # pid file from a prior container life (docker restart) would otherwise + # cause us to exit instead of entering the monitor loop. + if [ -f "/run/.no_exit.pid" ]; then + local no_exit_pid + no_exit_pid=$(<"/run/.no_exit.pid") 2>/dev/null + if [ -n "$no_exit_pid" ] && kill -0 "$no_exit_pid" 2>/dev/null; then + return 0 + fi + rm -f /run/.no_exit.pid 2>/dev/null || true + fi exec bash -c " trap 'echo \"Container shutdown requested\"; rm -f /run/.no_exit.pid /run/*.pid; exit 0' TERM INT @@ -270,10 +245,10 @@ __no_exit() { # - - - - - - - - - - - - - - - - - - - - - - - - - __trim() { local var="${*//;/ }" - var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters - var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters - var="$(echo "$var" | __remove_extra_spaces | sed "s| |; |g;s|;$| |g" | __remove_extra_spaces)" - printf '%s' "$var" | sed 's|;||g' | grep -v '^$' + var="${var#"${var%%[![:space:]]*}"}" + var="${var%"${var##*[![:space:]]}"}" + while [[ 202605051922-gitar == *" "* ]]; do var="${var// / }"; done + [ -n "202605051922-gitar" ] && printf '%s' "$var" } # - - - - - - - - - - - - - - - - - - - - - - - - - __banner() { @@ -295,21 +270,25 @@ __service_banner() { printf '# - - - %s %-*s %s - - - #\n' "$icon" "$text_width" "$full_message" "$icon" } # - - - - - - - - - - - - - - - - - - - - - - - - - -__find_php_bin() { find -L '/usr'/*bin -maxdepth 4 -name 'php-fpm*' 2>/dev/null | head -n1 | grep '.' || echo ''; } -__find_php_ini() { find -L '/etc' -maxdepth 4 -name 'php.ini' 2>/dev/null | head -n1 | sed 's|/php.ini||g' | grep '.' || echo ''; } +__find_php_bin() { find -L '/usr'/*bin -maxdepth 4 -name 'php-fpm*' 2>/dev/null | head -n1; } +__find_php_ini() { + local f + f=$(find -L '/etc' -maxdepth 4 -name 'php.ini' 2>/dev/null | head -n1) + [ -n "$f" ] && printf '%s\n' "${f%/php.ini}" +} # - - - - - - - - - - - - - - - - - - - - - - - - - -__find_nginx_conf() { find -L '/etc' -maxdepth 4 -name 'nginx.conf' 2>/dev/null | head -n1 | grep '.' || echo ''; } -__find_caddy_conf() { find -L '/etc' -maxdepth 4 -type f -iname 'caddy.conf' 2>/dev/null | head -n1 | grep '.' || echo ''; } -__find_lighttpd_conf() { find -L '/etc' -maxdepth 4 -type f -iname 'lighttpd.conf' 2>/dev/null | head -n1 | grep '.' || echo ''; } -__find_cherokee_conf() { find -L '/etc' -maxdepth 4 -type f -iname 'cherokee.conf' 2>/dev/null | head -n1 | grep '.' || echo ''; } -__find_httpd_conf() { find -L '/etc' -maxdepth 4 -type f -iname 'httpd.conf' -o -iname 'apache2.conf' 2>/dev/null | head -n1 | grep '.' || echo ''; } +__find_nginx_conf() { find -L '/etc' -maxdepth 4 -name 'nginx.conf' 2>/dev/null | head -n1; } +__find_caddy_conf() { find -L '/etc' -maxdepth 4 -type f -iname 'caddy.conf' 2>/dev/null | head -n1; } +__find_lighttpd_conf() { find -L '/etc' -maxdepth 4 -type f -iname 'lighttpd.conf' 2>/dev/null | head -n1; } +__find_cherokee_conf() { find -L '/etc' -maxdepth 4 -type f -iname 'cherokee.conf' 2>/dev/null | head -n1; } +__find_httpd_conf() { find -L '/etc' -maxdepth 4 -type f -iname 'httpd.conf' -o -iname 'apache2.conf' 2>/dev/null | head -n1; } # - - - - - - - - - - - - - - - - - - - - - - - - - -__find_mysql_conf() { find -L '/etc' -maxdepth 4 -type f -name 'my.cnf' 2>/dev/null | head -n1 | grep '.' || echo ''; } -__find_pgsql_conf() { find -L '/var/lib' '/etc' -maxdepth 8 -type f -name 'postgresql.conf' 2>/dev/null | head -n1 | grep '.' || echo ''; } +__find_mysql_conf() { find -L '/etc' -maxdepth 4 -type f -name 'my.cnf' 2>/dev/null | head -n1; } +__find_pgsql_conf() { find -L '/var/lib' '/etc' -maxdepth 8 -type f -name 'postgresql.conf' 2>/dev/null | head -n1; } __find_couchdb_conf() { return; } __find_mongodb_conf() { return; } # - - - - - - - - - - - - - - - - - - - - - - - - - -__random_password() { cat "/dev/urandom" | tr -dc '0-9a-zA-Z' | head -c${1:-16} && echo ""; } +__random_password() { tr -dc '0-9a-zA-Z' < /dev/urandom | head -c${1:-16} && echo ""; } # - - - - - - - - - - - - - - - - - - - - - - - - - __init_working_dir() { local service_name="$SERVICE_NAME" # get service name @@ -472,7 +451,8 @@ __display_user_info() { # - - - - - - - - - - - - - - - - - - - - - - - - - __init_config_etc() { local copy="no" - local name="$(find "/etc/$SERVICE_NAME" -maxdepth 0 2>/dev/null | head -n1)" + local name="" + [ -e "/etc/$SERVICE_NAME" ] && name="/etc/$SERVICE_NAME" local etc_dir="${ETC_DIR:-/etc/$name}" local conf_dir="${CONF_DIR:-/config/$name}" __is_dir_empty "$conf_dir" && copy=yes @@ -614,7 +594,7 @@ __cron() { fi [ $# -eq 0 ] && echo "Usage: cron [interval] [command]" && exit 1 local command="$*" - local bin="$(basename "${CRON_NAME:-$1}")" + local bin="${CRON_NAME:-$1}"; bin="${bin##*/}" [ -d "/run/cron" ] || mkdir -p "/run/cron" echo "$pid" >"/run/cron/$bin.pid" echo "$command" >"/run/cron/$bin.run" @@ -640,8 +620,8 @@ __find_replace() { # - - - - - - - - - - - - - - - - - - - - - - - - - # /config > /etc __copy_templates() { - local from="$1" to="$2" - is_link="$(ls -la "$dest" 2>/dev/null | awk '{print $NF}')" + local from="$1" to="$2" is_link="" + [ -L "$to" ] && is_link="$(readlink "$to")" [ "$from" != "$is_link" ] || return 0 if [ -e "$from" ] && __is_dir_empty "$to"; then __file_copy "$from" "$to" @@ -651,16 +631,18 @@ __copy_templates() { # /config/file > /etc/file __symlink() { local from="$1" to="$2" - if [ -e "$to" ]; then - [ -e "$from" ] && __rm "$from" - ln -sf "$to" "$from" && echo "Created symlink to $from > $to" - fi + [ -e "$to" ] || return 0 + [ "$from" = "$to" ] && return 0 + __rm "$from" + [ -d "${from%/*}" ] || mkdir -p "${from%/*}" 2>/dev/null + ln -sf "$to" "$from" && echo "Created symlink to $from > $to" } # - - - - - - - - - - - - - - - - - - - - - - - - - __file_copy() { local from="$1" local dest="$2" - is_link="$(ls -la "$dest" 2>/dev/null | awk '{print $NF}')" + local is_link="" + [ -L "$dest" ] && is_link="$(readlink "$dest")" if [ "$from" != "$is_link" ]; then if [ -n "$from" ] && [ -e "$from" ] && [ -n "$dest" ]; then if [ -d "$from" ]; then @@ -757,20 +739,40 @@ __fix_permissions() { fi } # - - - - - - - - - - - - - - - - - - - - - - - - - -__get_gid() { grep "^$1:" /etc/group 2>/dev/null | awk -F ':' '{print $3}' || return 1; } -__get_uid() { grep "^$1:" /etc/passwd 2>/dev/null | awk -F ':' '{print $3}' || return 1; } -__check_for_uid() { cat "/etc/passwd" 2>/dev/null | awk -F ':' '{print $3}' | sort -u | grep -q "^$1$" 2>/dev/null || return 1; } -__check_for_guid() { cat "/etc/group" 2>/dev/null | awk -F ':' '{print $3}' | sort -u | grep -q "^$1$" 2>/dev/null || return 1; } -__check_for_user() { cat "/etc/passwd" 2>/dev/null | awk -F ':' '{print $1}' | sort -u | grep -q "^$1$" 2>/dev/null || return 1; } -__check_for_group() { cat "/etc/group" 2>/dev/null | awk -F ':' '{print $1}' | sort -u | grep -q "^$1$" 2>/dev/null || return 1; } +__get_gid() { awk -F: -v n="$1" '$1==n {print $3; found=1; exit} END {exit !found}' /etc/group 2>/dev/null; } +__get_uid() { awk -F: -v n="$1" '$1==n {print $3; found=1; exit} END {exit !found}' /etc/passwd 2>/dev/null; } +__check_for_uid() { awk -F: -v n="$1" '$3==n {found=1; exit} END {exit !found}' /etc/passwd 2>/dev/null; } +__check_for_guid() { awk -F: -v n="$1" '$3==n {found=1; exit} END {exit !found}' /etc/group 2>/dev/null; } +__check_for_user() { awk -F: -v n="$1" '$1==n {found=1; exit} END {exit !found}' /etc/passwd 2>/dev/null; } +__check_for_group() { awk -F: -v n="$1" '$1==n {found=1; exit} END {exit !found}' /etc/group 2>/dev/null; } # - - - - - - - - - - - - - - - - - - - - - - - - - # check if process is already running __proc_check() { - cmd_bin="$(type -P "${1:-$EXEC_CMD_BIN}")" - cmd_name="$(basename "${cmd_bin:-$EXEC_CMD_NAME}")" - if __pgrep "$cmd_bin" || __pgrep "$cmd_name"; then + # Skip process check for one-shot/configuration services + if [ "$SERVICE_USES_PID" = "no" ]; then + return 1 + fi + local cmd_bin cmd_name check_result + cmd_bin="$(type -P "${1:-$EXEC_CMD_BIN}" 2>/dev/null || echo "${1:-$EXEC_CMD_BIN}")" + cmd_name="${cmd_bin:-${1:-$EXEC_CMD_NAME}}"; cmd_name="${cmd_name##*/}" + if [ -z "$cmd_name" ] || [ "$cmd_name" = "." ]; then + return 1 + fi + check_result=1 + if [ -n "$cmd_bin" ] && __pgrep "$cmd_bin" 2>/dev/null; then + check_result=0 + elif [ -n "$cmd_name" ] && __pgrep "$cmd_name" 2>/dev/null; then + check_result=0 + elif [ -f "$SERVICE_PID_FILE" ]; then + local pid_from_file + pid_from_file=$(<"$SERVICE_PID_FILE") 2>/dev/null + if [ -n "$pid_from_file" ] && kill -0 "$pid_from_file" 2>/dev/null; then + check_result=0 + fi + fi + if [ $check_result -eq 0 ]; then SERVICE_IS_RUNNING="yes" - touch "$SERVICE_PID_FILE" + touch "$SERVICE_PID_FILE" 2>/dev/null || true return 0 else return 1 @@ -824,11 +826,11 @@ __create_service_user() { return 0 fi # Validate user/group name format (alphanumeric, underscore, hyphen; must start with letter or underscore) - if [ -n "$create_user" ] && ! echo "$create_user" | grep -qE '^[a-z_][a-z0-9_-]*$'; then + if [ -n "$create_user" ] && [[ ! "$create_user" =~ ^[a-z_][a-z0-9_-]*$ ]]; then echo "Error: Invalid username format '$create_user' - must start with letter/underscore, contain only lowercase alphanumeric, underscore, or hyphen" >&2 return 1 fi - if [ -n "$create_group" ] && ! echo "$create_group" | grep -qE '^[a-z_][a-z0-9_-]*$'; then + if [ -n "$create_group" ] && [[ ! "$create_group" =~ ^[a-z_][a-z0-9_-]*$ ]]; then echo "Error: Invalid group name format '$create_group' - must start with letter/underscore, contain only lowercase alphanumeric, underscore, or hyphen" >&2 return 1 fi @@ -858,11 +860,11 @@ __create_service_user() { create_gid="$random_id" fi # Validate UID/GID are numeric and within valid range - if ! echo "$create_uid" | grep -qE '^[0-9]+$' || [ "$create_uid" -lt 1 ] || [ "$create_uid" -gt 65534 ]; then + if [[ ! "$create_uid" =~ ^[0-9]+$ ]] || [ "$create_uid" -lt 1 ] || [ "$create_uid" -gt 65534 ]; then echo "Error: Invalid UID '$create_uid' - must be a number between 1 and 65534" >&2 return 1 fi - if ! echo "$create_gid" | grep -qE '^[0-9]+$' || [ "$create_gid" -lt 1 ] || [ "$create_gid" -gt 65534 ]; then + if [[ ! "$create_gid" =~ ^[0-9]+$ ]] || [ "$create_gid" -lt 1 ] || [ "$create_gid" -gt 65534 ]; then echo "Error: Invalid GID '$create_gid' - must be a number between 1 and 65534" >&2 return 1 fi @@ -947,9 +949,7 @@ __create_env_file() { dir="$(dirname "$create_env")" [ -d "$dir" ] || mkdir -p "$dir" if [ -n "$create_env" ] && [ ! -f "$create_env" ]; then - cat </dev/null -$(<"$sample_file") -EOF + cp -f "$sample_file" "$create_env" fi [ -f "$create_env" ] || envStatus=$((1 + envStatus)) done @@ -958,17 +958,17 @@ EOF } # - - - - - - - - - - - - - - - - - - - - - - - - - __exec_command() { - local bin="" local arg=("$@") - local exitCode="0" + local exitCode=0 local cmdExec="${arg:-}" local pre_exec="--login -c" - local shell="$(type -P bash 2>/dev/null || type -P dash 2>/dev/null || type -P ash 2>/dev/null || type -P sh 2>/dev/null)" - bin="$(echo "${arg[*]}" | tr ' ' '\n' | grep -v '^$' | head -n1 | sed 's| ||g' || echo 'bash')" + local shell bin prog + shell=$(type -P bash || type -P dash || type -P ash || type -P sh) 2>/dev/null + bin="${arg[0]:-bash}" prog="$(type -P "$bin" 2>/dev/null || echo "$bin")" - if type -t $bin >/dev/null 2>&1; then + if type -t "$bin" &>/dev/null; then echo "${exec_message:-Executing command: $cmdExec}" - eval $shell $pre_exec "$cmdExec" || exitCode=1 + eval "$shell" $pre_exec "$cmdExec" exitCode=$? elif [ -f "$prog" ]; then echo "$prog is not executable" @@ -997,7 +997,9 @@ __start_init_scripts() { local critical_failures="0" local pidFile="/run/.start_init_scripts.pid" local init_dir="${1:-/usr/local/etc/docker/init.d}" - local init_count="$(ls -A "$init_dir"/* 2>/dev/null | grep -v '\.sample' | wc -l)" + local init_files=("$init_dir"/*.sh) + local init_count=0 + [ -e "${init_files[0]}" ] && init_count=${#init_files[@]} local exit_on_failure="${EXIT_ON_SERVICE_FAILURE:-true}" # Clean stale PID files from previous runs @@ -1013,7 +1015,10 @@ __start_init_scripts() { while :; do echo "Running: $(date)" >"/data/logs/init/keep_alive" && sleep 3600; done & else if [ -d "$init_dir" ]; then - [ -f "$init_dir/service.sample" ] && __rm "$init_dir"/*.sample + local sample + for sample in "$init_dir"/*.sample; do + [ -e "$sample" ] && __rm "$sample" + done chmod -Rf 755 "$init_dir"/*.sh echo "🚀 Starting container services initialization" @@ -1025,9 +1030,9 @@ __start_init_scripts() { for init in "$init_dir"/*.sh; do if [ -x "$init" ]; then touch "$pidFile" - name="$(basename "$init")" - service="$(printf '%s' "$name" | sed 's/^[^-]*-//;s|.sh$||g')" - __service_banner "🔧" "Executing service script:" "$(basename "$init")" + name="${init##*/}" + service="${name#*-}"; service="${service%.sh}" + __service_banner "🔧" "Executing service script:" "${init##*/}" # Execute the init script and capture the exit code if source "$init"; then # Check if service was disabled first @@ -1044,52 +1049,48 @@ __start_init_scripts() { sleep 1 # Check for service success indicators local expected_pid_file="/run/init.d/$service.pid" + set +e + # Check if this is a configuration service (no daemon process expected) if [ "$SERVICE_USES_PID" = "no" ]; then - # Service doesn't use PID files - check if expected PID file exists or assume success - if [ -f "$expected_pid_file" ]; then - retPID="$(cat "$expected_pid_file" 2>/dev/null || echo "0")" - initStatus="0" - __service_banner "✅" "Service $service started successfully -" "PID file" - else - initStatus="0" - __service_banner "✅" "Service $service started successfully -" "no PID tracking" - fi + # Configuration service - no daemon process expected + initStatus="0" + __service_banner "✅" "Service $service completed successfully -" "configuration service" else # Service uses PID tracking - verify actual running processes - set +e # Temporarily disable exit on error retPID="" - # First, try to find actual running process with various name patterns - for name_variant in "$service" "${service}84" "${service}d" "$(echo "$service" | sed 's/-//g')" "$(echo "$service" | tr -d '-')"; do + local found_process="" + # Try multiple name variants to find the process + for name_variant in "$service" "${service}84" "${service}d" "${service//-/}"; do if [ -z "$retPID" ]; then retPID=$(__get_pid "$name_variant" 2>/dev/null || echo "") - [ -n "$retPID" ] && found_process="$name_variant" && break + if [ -n "$retPID" ] && [ "$retPID" != "0" ]; then + found_process="$name_variant" + break + fi fi done - set -e # Re-enable exit on error if [ -n "$retPID" ] && [ "$retPID" != "0" ]; then # Found actual running process initStatus="0" __service_banner "✅" "Service $service started successfully -" "PID: ${retPID} ($found_process)" elif [ -f "$expected_pid_file" ]; then # No running process but PID file exists - verify PID is valid - file_pid="$(cat "$expected_pid_file" 2>/dev/null || echo "")" + file_pid=$(<"$expected_pid_file") 2>/dev/null if [ -n "$file_pid" ] && kill -0 "$file_pid" 2>/dev/null; then initStatus="0" __service_banner "✅" "Service $service started successfully -" "PID: $file_pid (from file)" - elif [ -n "$file_pid" ]; then - initStatus="1" - critical_failures=$((critical_failures + 1)) - __service_banner "⚠️" "Service $service has stale PID file -" "process $file_pid not running" else + # PID file exists but process isn't running - treat as warning, not failure initStatus="0" - __service_banner "✅" "Service $service completed initialization -" "no process tracking" + __service_banner "⚠️" "Service $service may not be running -" "no process found (non-critical)" fi else - # No process and no PID file - this is likely a configuration-only service + # No process and no PID file - likely a configuration-only service initStatus="0" __service_banner "✅" "Service $service completed successfully -" "configuration service" fi fi + set -e fi else initStatus="1" @@ -1102,15 +1103,19 @@ __start_init_scripts() { done # Summary + echo "" if [ $critical_failures -gt 0 ]; then - echo "⚠️ Warning: $critical_failures service(s) failed to start" - if [ "$exit_on_failure" = "true" ] && [ $critical_failures -ge 1 ]; then - echo "❌ Exiting due to critical service failures" + echo "⚠️ Warning: $critical_failures critical service(s) reported failures" + if [ "$exit_on_failure" = "true" ] && [ $critical_failures -ge 2 ]; then + echo "❌ Exiting due to multiple critical service failures (threshold: 2)" return 1 + else + echo "ℹ️ Continuing with $critical_failures failure(s) - container may still be functional" fi else - echo "✅ All services started successfully" + echo "✅ All service initializations completed successfully" fi + echo "" fi fi @@ -1129,14 +1134,14 @@ __setup_mta() { local local_hostname="${FULL_DOMAIN_NAME:-}" local account_user="${SERVER_ADMIN//@*/}" local account_domain="${EMAIL_DOMAIN//*@/}" - echo "$EMAIL_RELAY" | grep '[0-9][0-9]' || relay_port="465" + [[ $EMAIL_RELAY == *[0-9][0-9]* ]] || relay_port="465" ################# sSMTP relay setup - if [ -n "$(type -P 'ssmtp')" ]; then + if command -v ssmtp &>/dev/null; then [ -d "/config/ssmtp" ] || mkdir -p "/config/ssmtp" [ -f "/etc/ssmtp/ssmtp.conf" ] && __rm "/etc/ssmtp/ssmtp.conf" symlink_files="$(__find_file_relative "/config/ssmtp")" if [ ! -f "/config/ssmtp/ssmtp.conf" ]; then - cat </dev/null + cat >"/config/ssmtp/ssmtp.conf" </dev/null; then [ -d "/etc/postfix" ] || mkdir -p "/etc/postfix" [ -d "/config/postfix" ] || mkdir -p "/config/postfix" [ -f "/etc/postfix/main.cf" ] && __rm "/etc/postfix/main.cf" symlink_files="$(__find_file_relative "/config/postfix")" if [ ! -f "/config/postfix/main.cf" ]; then - cat </dev/null + cat >"/config/postfix/main.cf" </dev/null | sed 's|'/config/'||g' | sort -u | grep -v '^$' | grep '.' || false)" - directories="$(find "$conf_dir"/* -not -path '*/env/*' -type d 2>/dev/null | sed 's|'/config/'||g' | sort -u | grep -v '^$' | grep '.' || false)" + files=$(find "$conf_dir"/* -not -path '*/env/*' -type f 2>/dev/null | sort -u | sed 's|/config/||') + directories=$(find "$conf_dir"/* -not -path '*/env/*' -type d 2>/dev/null | sort -u | sed 's|/config/||') echo "Copying config files to system: $conf_dir > /etc/${conf_dir//\/config\//}" if [ -n "$directories" ]; then for d in $directories; do @@ -1356,7 +1361,7 @@ __initialize_custom_bin_dir() { echo "Setting up bin $SET_USR_BIN > $LOCAL_BIN_DIR" for create_bin_template in $SET_USR_BIN; do if [ -n "$create_bin_template" ]; then - create_bin_name="$(basename "$create_bin_template")" + create_bin_name="${create_bin_template##*/}" if [ -e "$create_bin_template" ]; then ln -sf "$create_bin_template" "$LOCAL_BIN_DIR/$create_bin_name" fi @@ -1367,51 +1372,85 @@ __initialize_custom_bin_dir() { } # - - - - - - - - - - - - - - - - - - - - - - - - - __initialize_default_templates() { + local errors=0 if [ -n "$DEFAULT_TEMPLATE_DIR" ]; then if [ "$CONFIG_DIR_INITIALIZED" = "false" ] && [ -d "/config" ]; then - echo "Copying default config files $DEFAULT_TEMPLATE_DIR > /config" + __log_info "Copying default config files $DEFAULT_TEMPLATE_DIR > /config" + if [ ! -d "$DEFAULT_TEMPLATE_DIR" ]; then + __log_warn "Template directory not found: $DEFAULT_TEMPLATE_DIR" + return 0 + fi for create_config_template in "$DEFAULT_TEMPLATE_DIR"/*; do - if [ -n "$create_config_template" ]; then - create_template_name="$(basename "$create_config_template")" + if [ -e "$create_config_template" ]; then + create_template_name="${create_config_template##*/}" if [ -d "$create_config_template" ]; then - mkdir -p "/config/$create_template_name/" - __is_dir_empty "/config/$create_template_name" && cp -Rf "$create_config_template/." "/config/$create_template_name/" 2>/dev/null - elif [ -e "$create_config_template" ]; then - [ -e "/config/$create_template_name" ] || cp -Rf "$create_config_template" "/config/$create_template_name" 2>/dev/null + mkdir -p "/config/$create_template_name/" || errors=$((errors + 1)) + if __is_dir_empty "/config/$create_template_name"; then + if ! cp -Rf "$create_config_template/." "/config/$create_template_name/" 2>/dev/null; then + __log_warn "Failed to copy template directory: $create_template_name" + errors=$((errors + 1)) + fi + fi + elif [ -f "$create_config_template" ]; then + if [ ! -e "/config/$create_template_name" ]; then + if ! cp -Rf "$create_config_template" "/config/$create_template_name" 2>/dev/null; then + __log_warn "Failed to copy template file: $create_template_name" + errors=$((errors + 1)) + fi + fi fi fi done unset create_config_template create_template_name + __log_debug "Template initialization completed with $errors errors" fi fi + return 0 } # - - - - - - - - - - - - - - - - - - - - - - - - - __initialize_config_dir() { + local errors=0 if [ -n "$DEFAULT_CONF_DIR" ]; then if [ "$CONFIG_DIR_INITIALIZED" = "false" ] && [ -d "/config" ]; then - echo "Copying custom config files: $DEFAULT_CONF_DIR > /config" + __log_info "Copying custom config files: $DEFAULT_CONF_DIR > /config" + if [ ! -d "$DEFAULT_CONF_DIR" ]; then + __log_warn "Config directory not found: $DEFAULT_CONF_DIR" + return 0 + fi for create_config_template in "$DEFAULT_CONF_DIR"/*; do - create_config_name="$(basename "$create_config_template")" - if [ -n "$create_config_template" ]; then + if [ -e "$create_config_template" ]; then + create_config_name="${create_config_template##*/}" if [ -d "$create_config_template" ]; then - mkdir -p "/config/$create_config_name" - __is_dir_empty "/config/$create_config_name" && cp -Rf "$create_config_template/." "/config/$create_config_name/" 2>/dev/null - elif [ -e "$create_config_template" ]; then - [ -e "/config/$create_config_name" ] || cp -Rf "$create_config_template" "/config/$create_config_name" 2>/dev/null + mkdir -p "/config/$create_config_name" || errors=$((errors + 1)) + if __is_dir_empty "/config/$create_config_name"; then + if ! cp -Rf "$create_config_template/." "/config/$create_config_name/" 2>/dev/null; then + __log_warn "Failed to copy config directory: $create_config_name" + errors=$((errors + 1)) + fi + fi + elif [ -f "$create_config_template" ]; then + if [ ! -e "/config/$create_config_name" ]; then + if ! cp -Rf "$create_config_template" "/config/$create_config_name" 2>/dev/null; then + __log_warn "Failed to copy config file: $create_config_name" + errors=$((errors + 1)) + fi + fi fi fi done unset create_config_template create_config_name + __log_debug "Config initialization completed with $errors errors" fi fi + return 0 } # - - - - - - - - - - - - - - - - - - - - - - - - - __initialize_data_dir() { if [ -d "/data" ]; then if [ "$DATA_DIR_INITIALIZED" = "false" ] && [ -n "$DEFAULT_DATA_DIR" ]; then - echo "Copying data files $DEFAULT_DATA_DIR > /data" + __log_info "Copying data files $DEFAULT_DATA_DIR > /data" for create_data_template in "$DEFAULT_DATA_DIR"/*; do - create_data_name="$(basename "$create_data_template")" + create_data_name="${create_data_template##*/}" if [ -n "$create_data_template" ]; then if [ -d "$create_data_template" ]; then mkdir -p "/data/$create_data_name" @@ -1447,11 +1486,11 @@ __is_htdocs_mounted() { WWW_ROOT_DIR="${WWW_ROOT_DIR:-/data/htdocs}" [ -n "$ENV_WWW_ROOT_DIR" ] && WWW_ROOT_DIR="$ENV_WWW_ROOT_DIR" if [ -n "$IMPORT_FROM_GIT" ]; then - if ! echo "$IMPORT_FROM_GIT" | grep -qE 'https://|http://|git://|ssh://'; then + if [[ ! "$IMPORT_FROM_GIT" =~ (https://|http://|git://|ssh://) ]]; then unset IMPORT_FROM_GIT fi fi - if [ -n "$IMPORT_FROM_GIT" ] && [ "$(command -v "git" 2>/dev/null)" ]; then + if [ -n "$IMPORT_FROM_GIT" ] && command -v git &>/dev/null; then if __is_dir_empty "$WWW_ROOT_DIR"; then echo "Importing project from $IMPORT_FROM_GIT to $WWW_ROOT_DIR" git clone -q "$IMPORT_FROM_GIT" "$WWW_ROOT_DIR" @@ -1507,7 +1546,7 @@ __start_php_dev_server() { find "/usr/local/share/httpd" -type f -not -path '.git*' -iname '*.php' -exec sed -i 's|[<].*SERVER_ADDR.*[>]|'${CONTAINER_IP4_ADDRESS:-127.0.0.1}'|g' {} \; 2>/dev/null php -S 0.0.0.0:$PHP_DEV_SERVER_PORT -t "/usr/local/share/httpd" fi - if ! echo "$1" | grep -q "^/usr/local/share/httpd"; then + if [[ "$1" != "/usr/local/share/httpd"* ]]; then find "$1" -type f -not -path '.git*' -iname '*.php' -exec sed -i 's|[<].*SERVER_ADDR.*[>]|'${CONTAINER_IP4_ADDRESS:-127.0.0.1}'|g' {} \; 2>/dev/null php -S 0.0.0.0:$PHP_DEV_SERVER_PORT -t "$1" fi @@ -1528,16 +1567,16 @@ __switch_to_user() { if [ "$switch_user" = "root" ]; then su_exec="" su_cmd() { eval "$@" || return 1; } - elif [ "$(builtin type -P gosu)" ]; then + elif command -v gosu &>/dev/null; then su_exec="gosu $switch_user" su_cmd() { $su_exec "$@" || return 1; } - elif [ "$(builtin type -P runuser)" ]; then + elif command -v runuser &>/dev/null; then su_exec="runuser -u $switch_user" su_cmd() { $su_exec "$@" || return 1; } - elif [ "$(builtin type -P sudo)" ]; then + elif command -v sudo &>/dev/null; then su_exec="sudo -u $switch_user" su_cmd() { $su_exec "$@" || return 1; } - elif [ "$(builtin type -P su)" ]; then + elif command -v su &>/dev/null; then su_exec="su -s /bin/sh - $switch_user" su_cmd() { $su_exec -c "$@" || return 1; } else diff --git a/rootfs/usr/local/etc/docker/init.d/00-aria2c.sh b/rootfs/usr/local/etc/docker/init.d/00-aria2c.sh index 7cad5f2..ba07e86 100644 --- a/rootfs/usr/local/etc/docker/init.d/00-aria2c.sh +++ b/rootfs/usr/local/etc/docker/init.d/00-aria2c.sh @@ -1,15 +1,15 @@ #!/usr/bin/env bash # shellcheck shell=bash -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -##@Version : 202505131559-git +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202605131434-git # @@Author : Jason Hempstead # @@Contact : jason@casjaysdev.pro -# @@License : LICENSE.md +# @@License : WTFPL # @@ReadME : 00-aria2c.sh --help -# @@Copyright : Copyright: (c) 2025 Jason Hempstead, Casjays Developments -# @@Created : Tuesday, May 13, 2025 15:59 EDT +# @@Copyright : Copyright: (c) 2026 Jason Hempstead, Casjays Developments +# @@Created : Wednesday, May 13, 2026 14:34 EDT # @@File : 00-aria2c.sh -# @@Description : +# @@Description : Init script for aria2c download manager + nginx/AriaNg frontend # @@Changelog : New script # @@TODO : Better documentation # @@Other : @@ -17,726 +17,981 @@ # @@Terminal App : no # @@sudo/root : no # @@Template : other/start-service -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# shellcheck disable=SC1003,SC2016,SC2031,SC2120,SC2155,SC2199,SC2317 -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - +# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329 +# - - - - - - - - - - - - - - - - - - - - - - - - - +set -e +# - - - - - - - - - - - - - - - - - - - - - - - - - # run trap command on exit -trap 'retVal=$?;[ "$SERVICE_IS_RUNNING" != "yes" ] && [ -f "$SERVICE_PID_FILE" ] && rm -Rf "$SERVICE_PID_FILE";exit $retVal' SIGINT SIGTERM EXIT -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# setup debugging - https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html -[ -f "/config/.debug" ] && [ -z "$DEBUGGER_OPTIONS" ] && export DEBUGGER_OPTIONS="$(<"/config/.debug")" || DEBUGGER_OPTIONS="${DEBUGGER_OPTIONS:-}" -{ [ "$DEBUGGER" = "on" ] || [ -f "/config/.debug" ]; } && echo "Enabling debugging" && set -xo pipefail -x$DEBUGGER_OPTIONS && export DEBUGGER="on" || set -o pipefail -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -export PATH="/usr/local/etc/docker/bin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +trap '__trap_err_handler' ERR +trap 'retVal=$?;if [ "$SERVICE_IS_RUNNING" != "yes" ] && [ -f "$SERVICE_PID_FILE" ]; then rm -Rf "$SERVICE_PID_FILE"; fi;exit $retVal' SIGINT SIGTERM SIGPWR +# - - - - - - - - - - - - - - - - - - - - - - - - - +# ERR trap handler - smart about critical vs non-critical errors +__trap_err_handler() { + local retVal=$? + local command="$BASH_COMMAND" + # Ignore SIGPIPE and user interrupts + [ $retVal -eq 130 ] || [ $retVal -eq 141 ] && return $retVal + # Non-critical: file operations, text processing, user/group operations + if [[ "$command" =~ (mkdir|touch|chmod|chown|chgrp|ln|cp|mv|rm|echo|printf|cat|tee|sed|awk|grep|find|sort|uniq|adduser|addgroup|usermod|groupmod|id|getent) ]]; then + return 0 + fi + # Non-critical: conditional checks that might fail + if [[ "$command" =~ (test|\[|\[\[|kill -0|pgrep|pidof|ps) ]]; then + return 0 + fi + # Critical error - but only fail if service hasn't started yet + if [ "$SERVICE_IS_RUNNING" != "yes" ]; then + echo "Critical error (exit $retVal): $command" >&2 + kill -TERM 1 2>/dev/null || exit $retVal + fi + return 0 +} +# - - - - - - - - - - - - - - - - - - - - - - - - - SCRIPT_FILE="$0" SERVICE_NAME="aria2c" +SCRIPT_NAME="${SCRIPT_FILE##*/}" +# - - - - - - - - - - - - - - - - - - - - - - - - - # Function to exit appropriately based on context __script_exit() { - local exit_code="${1:-0}" - if [ "${BASH_SOURCE[0]}" != "${0}" ]; then - # Script is being sourced - use return - return "$exit_code" - else - # Script is being executed - use exit - exit "$exit_code" - fi + local exit_code="${1:-0}" + if [ "${BASH_SOURCE[0]}" != "${0}" ]; then + # Script is being sourced - use return + return "$exit_code" + else + # Script is being executed - use exit + exit "$exit_code" + fi } -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -SCRIPT_NAME="$(basename -- "$SCRIPT_FILE" 2>/dev/null)" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# exit if __start_init_scripts function hasn't been Initialized -if [ ! -f "/run/.start_init_scripts.pid" ]; then - echo "__start_init_scripts function hasn't been Initialized" >&2 - SERVICE_IS_RUNNING="no" - __script_exit 1 +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Exit if service is disabled +if [ -n "$ARIA2C_ENABLED" ]; then + if [ "$ARIA2C_ENABLED" != "yes" ]; then + export SERVICE_DISABLED="$SERVICE_NAME" + __script_exit 0 + fi fi -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - +# setup debugging - https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html +[ -f "/config/.debug" ] && [ -z "$DEBUGGER_OPTIONS" ] && export DEBUGGER_OPTIONS="$(<"/config/.debug")" || DEBUGGER_OPTIONS="${DEBUGGER_OPTIONS:-}" +if [ "$DEBUGGER" = "on" ] || [ -f "/config/.debug" ]; then + echo "Enabling debugging" + set -xo pipefail -x$DEBUGGER_OPTIONS + export DEBUGGER="on" +else + set -o pipefail +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +export PATH="/usr/local/etc/docker/bin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin" +# - - - - - - - - - - - - - - - - - - - - - - - - - # import the functions file if [ -f "/usr/local/etc/docker/functions/entrypoint.sh" ]; then - . "/usr/local/etc/docker/functions/entrypoint.sh" + . "/usr/local/etc/docker/functions/entrypoint.sh" fi -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # import variables for set_env in "/root/env.sh" "/usr/local/etc/docker/env"/*.sh "/config/env"/*.sh; do - [ -f "$set_env" ] && . "$set_env" + if [ -f "$set_env" ]; then + . "$set_env" + fi done -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - +# exit if __start_init_scripts function hasn't been Initialized +if [ ! -f "/run/.start_init_scripts.pid" ]; then + echo "__start_init_scripts function hasn't been Initialized" >&2 + SERVICE_IS_RUNNING="no" + __script_exit 1 +fi +# Clean up any stale PID file for this service on startup +if [ -n "$SERVICE_NAME" ] && [ -f "/run/init.d/$SERVICE_NAME.pid" ]; then + old_pid=$(<"/run/init.d/$SERVICE_NAME.pid") 2>/dev/null + if [ -n "$old_pid" ] && ! kill -0 "$old_pid" 2>/dev/null; then + echo "Removing stale PID file for $SERVICE_NAME" + rm -f "/run/init.d/$SERVICE_NAME.pid" + fi +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - # Custom functions -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Script to execute START_SCRIPT="/usr/local/etc/docker/exec/$SERVICE_NAME" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Reset environment before executing service RESET_ENV="no" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# Set webroot +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Set webroot - AriaNg web UI WWW_ROOT_DIR="/usr/local/share/ariang" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Default predefined variables -DATA_DIR="/data/aria2" # set data directory -CONF_DIR="/config/aria2" # set config directory -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# set data directory +DATA_DIR="/data/aria2" +# set config directory +CONF_DIR="/config/aria2" +# - - - - - - - - - - - - - - - - - - - - - - - - - # set the containers etc directory ETC_DIR="/etc/aria2" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # set the var dir VAR_DIR="" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -TMP_DIR="/tmp/aria2" # set the temp dir -RUN_DIR="/run/aria2" # set scripts pid dir -LOG_DIR="/data/logs/aria2" # set log directory -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - +# set the temp dir +TMP_DIR="/tmp/aria2" +# set scripts pid dir +RUN_DIR="/run/aria2" +# set log directory +LOG_DIR="/data/logs/aria2" +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set the working dir WORK_DIR="" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# port which service is listening on +# - - - - - - - - - - - - - - - - - - - - - - - - - +# port which service is listening on (aria2c RPC port) SERVICE_PORT="6800" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # User to use to launch service - IE: postgres -RUNAS_USER="root" # normally root -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# normally root +RUNAS_USER="root" +# - - - - - - - - - - - - - - - - - - - - - - - - - # User and group in which the service switches to - IE: nginx,apache,mysql,postgres -#SERVICE_USER="aria2c" # execute command as another user -#SERVICE_GROUP="aria2c" # Set the service group -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# execute command as another user +#SERVICE_USER="aria2c" +# Set the service group +#SERVICE_GROUP="aria2c" +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set password length RANDOM_PASS_USER="" RANDOM_PASS_ROOT="" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set user and group ID -#SERVICE_UID="0" # set the user id -#SERVICE_GID="0" # set the group id -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# set the user id +SERVICE_UID="0" +# set the group id +SERVICE_GID="0" +# - - - - - - - - - - - - - - - - - - - - - - - - - # execute command variables - keep single quotes variables will be expanded later -EXEC_CMD_BIN='/usr/local/etc/docker/bin/start-aria2' # wrapper: bg aria2c, exec nginx -EXEC_CMD_ARGS='' # wrapper takes no args -EXEC_PRE_SCRIPT='' # execute script before -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# wrapper: launches aria2c in background then execs nginx in foreground +EXEC_CMD_BIN='/usr/local/etc/docker/bin/start-aria2' +# command arguments +EXEC_CMD_ARGS='' +# execute script before +EXEC_PRE_SCRIPT='' +# Set to 'yes' so PID sentinel is tracked +SERVICE_USES_PID='yes' +# - - - - - - - - - - - - - - - - - - - - - - - - - # Is this service a web server IS_WEB_SERVER="no" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Is this service a database server IS_DATABASE_SERVICE="no" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Does this service use a database server USES_DATABASE_SERVICE="no" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# Set defualt type - [custom,sqlite,redis,postgres,mariadb,mysql,couchdb,mongodb,supabase] +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Set default type - [custom,sqlite,redis,postgres,mariadb,mysql,couchdb,mongodb,supabase] DATABASE_SERVICE_TYPE="sqlite" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Show message before execute PRE_EXEC_MESSAGE="" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set the wait time to execute __post_execute function - minutes POST_EXECUTE_WAIT_TIME="1" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Update path var PATH="$PATH:." -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Lets get containers ip address IP4_ADDRESS="$(__get_ip4)" IP6_ADDRESS="$(__get_ip6)" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Where to save passwords to -ROOT_FILE_PREFIX="/config/secure/auth/root" # directory to save username/password for root user -USER_FILE_PREFIX="/config/secure/auth/user" # directory to save username/password for normal user -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# directory to save username/password for root user +ROOT_FILE_PREFIX="/config/secure/auth/root" +# directory to save username/password for normal user +USER_FILE_PREFIX="/config/secure/auth/user" +# - - - - - - - - - - - - - - - - - - - - - - - - - # root/admin user info password/random] -root_user_name="${ARIA2C_ROOT_USER_NAME:-}" # root user name -root_user_pass="${ARIA2C_ROOT_PASS_WORD:-}" # root user password -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# root user name +root_user_name="${ARIA2C_ROOT_USER_NAME:-}" +# root user password +root_user_pass="${ARIA2C_ROOT_PASS_WORD:-}" +# - - - - - - - - - - - - - - - - - - - - - - - - - # Normal user info [password/random] -user_name="${ARIA2C_USER_NAME:-}" # normal user name -user_pass="${ARIA2C_USER_PASS_WORD:-}" # normal user password -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# normal user name +user_name="${ARIA2C_USER_NAME:-}" +# normal user password +user_pass="${ARIA2C_USER_PASS_WORD:-}" +# - - - - - - - - - - - - - - - - - - - - - - - - - # Load variables from config -[ -f "/config/env/aria2c.script.sh" ] && . "/config/env/aria2c.script.sh" # Generated by my dockermgr script -[ -f "/config/env/aria2c.sh" ] && . "/config/env/aria2c.sh" # Overwrite the variabes -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Generated by my dockermgr script +if [ -f "/config/env/aria2c.script.sh" ]; then + . "/config/env/aria2c.script.sh" +fi +# Overwrite the variables +if [ -f "/config/env/aria2c.sh" ]; then + . "/config/env/aria2c.sh" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - # Additional predefined variables -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Additional variables -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# Specifiy custom directories to be created +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Specify custom directories to be created ADD_APPLICATION_FILES="" ADD_APPLICATION_DIRS="" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - APPLICATION_FILES="$LOG_DIR/$SERVICE_NAME.log" -APPLICATION_DIRS="$ETC_DIR $CONF_DIR $LOG_DIR $TMP_DIR $RUN_DIR $VAR_DIR" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# Additional config dirs - will be Copied to /etc/$name +APPLICATION_DIRS="$ETC_DIR $CONF_DIR $DATA_DIR $LOG_DIR $TMP_DIR $RUN_DIR $VAR_DIR" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Additional config dirs - will be copied to /etc/$name ADDITIONAL_CONFIG_DIRS="" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # define variables that need to be loaded into the service - escape quotes - var=\"value\",other=\"test\" CMD_ENV="" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Overwrite based on file/directory -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Per Application Variables or imports -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Custom commands to run before copying to /config __run_precopy() { - # Define environment - local hostname=${HOSTNAME} - [ -d "/run/healthcheck" ] || mkdir -p "/run/healthcheck" - # Define actions/commands + # Define environment + local hostname=${HOSTNAME} + if [ ! -d "/run/healthcheck" ]; then + mkdir -p "/run/healthcheck" + fi + # Define actions/commands - # allow custom functions - if builtin type -t __run_precopy_local | grep -q 'function'; then __run_precopy_local; fi + # allow custom functions + if builtin type -t __run_precopy_local | grep -q 'function'; then + __run_precopy_local + fi } -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Custom prerun functions - IE setup WWW_ROOT_DIR __execute_prerun() { - # Define environment - local hostname=${HOSTNAME} - # Define actions/commands + # Define environment + local hostname=${HOSTNAME} + # Define actions/commands - # allow custom functions - if builtin type -t __execute_prerun_local | grep -q 'function'; then __execute_prerun_local; fi + # allow custom functions + if builtin type -t __execute_prerun_local | grep -q 'function'; then + __execute_prerun_local + fi } -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Run any pre-execution checks __run_pre_execute_checks() { - # Set variables - local exitStatus=0 - local pre_execute_checks_MessageST="Running preexecute check for $SERVICE_NAME" # message to show at start - local pre_execute_checks_MessageEnd="Finished preexecute check for $SERVICE_NAME" # message to show at completion - __banner "$pre_execute_checks_MessageST" - # Put command to execute in parentheses - { - echo "--------------------[BitTorrent Trackers]--------------------" - /usr/local/bin/tracker.sh "$CONF_DIR/aria2.conf" "$CUSTOM_TRACKER_URL" | tee "$LOG_DIR/trackers.log" >/dev/null - echo "-----------------[End of Trackers Scripts]--------------------" - true - } - exitStatus=$? - __banner "$pre_execute_checks_MessageEnd: Status $exitStatus" + # Set variables + local exitStatus=0 + # message to show at start + local pre_execute_checks_MessageST="Running preexecute check for $SERVICE_NAME" + # message to show at completion + local pre_execute_checks_MessageEnd="Finished preexecute check for $SERVICE_NAME" + __banner "$pre_execute_checks_MessageST" + # Put command to execute in parentheses + { + echo "--------------------[BitTorrent Trackers]--------------------" + /usr/local/bin/tracker.sh "$CONF_DIR/aria2.conf" "$CUSTOM_TRACKER_URL" | tee "$LOG_DIR/trackers.log" >/dev/null + echo "-----------------[End of Trackers Scripts]--------------------" + true + } + exitStatus=$? + __banner "$pre_execute_checks_MessageEnd: Status $exitStatus" - # show exit message - if [ $exitStatus -ne 0 ]; then - echo "The pre-execution check has failed" >&2 - [ -f "$SERVICE_PID_FILE" ] && rm -Rf "$SERVICE_PID_FILE" - __script_exit 1 - fi - # allow custom functions - if builtin type -t __run_pre_execute_checks_local | grep -q 'function'; then __run_pre_execute_checks_local; fi - # exit function - return $exitStatus + # show exit message + if [ $exitStatus -ne 0 ]; then + echo "The pre-execution check has failed" >&2 + if [ -f "$SERVICE_PID_FILE" ]; then + rm -Rf "$SERVICE_PID_FILE" + fi + __script_exit 1 + fi + # allow custom functions + if builtin type -t __run_pre_execute_checks_local | grep -q 'function'; then + __run_pre_execute_checks_local + fi + # exit function + return $exitStatus } -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # use this function to update config files - IE: change port __update_conf_files() { - local exitCode=0 # default exit code - local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" # set hostname - local get_data_dir="$(grep -Rs 'dir=' "/config/aria2/aria2.conf" | awk -F'=' '{print $2}')" - local get_config="$(find "$WWW_ROOT_DIR/js" -name 'aria-ng-*.min.js' | grep -v 'f1dd57abb9.min' | head -n1)" - local get_session_file="$(grep -Rs 'aria2.session' "/config/aria2/aria2.conf" | awk -F'=' '{print $2}' | head -n1)" - local rpc_port="${RPC_PORT:-${RPC_LISTEN:-6800}}" - local dht_port="$DHT_LISTEN_PORT" - local secret_rpc_base64="" - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # delete files - #__rm "" + # default exit code + local exitCode=0 + # set hostname + local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" + local get_data_dir + local get_config + local get_session_file + local rpc_port="${RPC_PORT:-${RPC_LISTEN:-6800}}" + local dht_port="$DHT_LISTEN_PORT" + local secret_rpc_base64="" + get_data_dir="$(grep -Rs 'dir=' "/config/aria2/aria2.conf" | awk -F'=' '{print $2}')" + get_config="$(find "$WWW_ROOT_DIR/js" -name 'aria-ng-*.min.js' 2>/dev/null | grep -v 'f1dd57abb9.min' | head -n1 || true)" + get_session_file="$(grep -Rs 'aria2.session' "/config/aria2/aria2.conf" | awk -F'=' '{print $2}' | head -n1)" + # - - - - - - - - - - - - - - - - - - - - - - - - - + # delete files + #__rm "" - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # custom commands + # - - - - - - - - - - - - - - - - - - - - - - - - - + # custom commands - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # replace variables - __replace "REPLACE_RPC_PORT" "$rpc_port" "$CONF_DIR/aria2.conf" - __replace "REPLACE_SERVER_ADDR" "$CONTAINER_IP4_ADDRESS" "$CONF_DIR/aria-ng.config.js" - # if [ -n "$RPC_SECRET" ]; then - # echo "Changing rpc secret to $RPC_SECRET" - # secret_secret_rpc_base64="$(echo -n "$RPC_SECRET" | base64 -w 0)" - # if grep -sq "rpc-secret=" "$CONF_DIR/aria2.conf"; then - # __replace "#rpc-secret=" "rpc-secret=" "$CONF_DIR/aria2.conf" - # __replace "REPLACE_RPC_SECRET" "$RPC_SECRET" "$CONF_DIR/aria2.conf" - # echo "Setting $secret_rpc_base64 in $CONF_DIR/aria-ng.config.js" - # __replace "REPLACE_RPC_SECRET" "$secret_rpc_base64" "$CONF_DIR/aria-ng.config.js" - # else - # echo "rpc-secret=$RPC_SECRET" >>"$CONF_DIR/aria2.conf" - # fi - # else - __replace "rpc-secret=" "#rpc-secret=" "$CONF_DIR/aria2.conf" - __replace "REPLACE_RPC_SECRET" "" "$CONF_DIR/aria-ng.config.js" - # fi - if [ -n "$dht_port" ]; then - sed -i "s@^\(listen-port=\).*@\1$dht_port@" "$CONF_DIR/aria2.conf" - sed -i "s@^\(dht-listen-port=\).*@\1$dht_port@" "$CONF_DIR/aria2.conf" - fi - sed -i "s@\(move-log=\).*@\1$LOG_DIR/move.log@" "$CONF_DIR/aria2.conf" - sed -i "s@\(upload-log=\).*@\1$LOG_DIR/upload.log@" "$CONF_DIR/aria2.conf" - if [ -n "$FILE_ALLOCATION" ]; then - sed -i "s@^\(file-allocation=\).*@\1${FILE_ALLOCATION}@" "$CONF_DIR/aria2.conf" - fi - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # define actions - [ -n "$get_session_file" ] && touch "$get_session_file" - if [ -n "$get_data_dir" ]; then - [ -d "$get_data_dir" ] || mkdir -p "$get_data_dir" - fi - if [ -f "$CONF_DIR/aria-ng.config.js" ]; then - if [ -n "$get_config" ]; then - rm -Rf "$get_config" - cp -Rf "$CONF_DIR/aria-ng.config.js" "$get_config" - fi - cp -Rf "$CONF_DIR/aria-ng.config.js" "$WWW_ROOT_DIR/js/aria-ng-f1dd57abb9.min.js" - fi - # allow custom functions - if builtin type -t __update_conf_files_local | grep -q 'function'; then __update_conf_files_local; fi - # exit function - return $exitCode + # - - - - - - - - - - - - - - - - - - - - - - - - - + # replace variables + __replace "REPLACE_RPC_PORT" "$rpc_port" "$CONF_DIR/aria2.conf" + __replace "REPLACE_SERVER_ADDR" "$CONTAINER_IP4_ADDRESS" "$CONF_DIR/aria-ng.config.js" + # if [ -n "$RPC_SECRET" ]; then + # echo "Changing rpc secret to $RPC_SECRET" + # secret_rpc_base64="$(printf '%s' "$RPC_SECRET" | base64 -w 0)" + # if grep -sq "rpc-secret=" "$CONF_DIR/aria2.conf"; then + # __replace "#rpc-secret=" "rpc-secret=" "$CONF_DIR/aria2.conf" + # __replace "REPLACE_RPC_SECRET" "$RPC_SECRET" "$CONF_DIR/aria2.conf" + # echo "Setting $secret_rpc_base64 in $CONF_DIR/aria-ng.config.js" + # __replace "REPLACE_RPC_SECRET" "$secret_rpc_base64" "$CONF_DIR/aria-ng.config.js" + # else + # echo "rpc-secret=$RPC_SECRET" >>"$CONF_DIR/aria2.conf" + # fi + # else + __replace "rpc-secret=" "#rpc-secret=" "$CONF_DIR/aria2.conf" + __replace "REPLACE_RPC_SECRET" "" "$CONF_DIR/aria-ng.config.js" + # fi + if [ -n "$dht_port" ]; then + sed -i "s@^\(listen-port=\).*@\1$dht_port@" "$CONF_DIR/aria2.conf" + sed -i "s@^\(dht-listen-port=\).*@\1$dht_port@" "$CONF_DIR/aria2.conf" + fi + sed -i "s@\(move-log=\).*@\1$LOG_DIR/move.log@" "$CONF_DIR/aria2.conf" + sed -i "s@\(upload-log=\).*@\1$LOG_DIR/upload.log@" "$CONF_DIR/aria2.conf" + if [ -n "$FILE_ALLOCATION" ]; then + sed -i "s@^\(file-allocation=\).*@\1${FILE_ALLOCATION}@" "$CONF_DIR/aria2.conf" + fi + # - - - - - - - - - - - - - - - - - - - - - - - - - + # define actions + [ -n "$get_session_file" ] && touch "$get_session_file" + if [ -n "$get_data_dir" ]; then + [ -d "$get_data_dir" ] || mkdir -p "$get_data_dir" + fi + if [ -f "$CONF_DIR/aria-ng.config.js" ]; then + if [ -n "$get_config" ]; then + rm -Rf "$get_config" + cp -Rf "$CONF_DIR/aria-ng.config.js" "$get_config" + fi + cp -Rf "$CONF_DIR/aria-ng.config.js" "$WWW_ROOT_DIR/js/aria-ng-f1dd57abb9.min.js" + fi + # allow custom functions + if builtin type -t __update_conf_files_local | grep -q 'function'; then + __update_conf_files_local + fi + # exit function + return $exitCode } -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # function to run before executing __pre_execute() { - local exitCode=0 # default exit code - local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" # set hostname - # execute if directories is empty - # __is_dir_empty "$CONF_DIR" && true - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # define actions to run after copying to /config + # default exit code + local exitCode=0 + # set hostname + local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" + # execute if directories is empty + # __is_dir_empty "$CONF_DIR" && true + # - - - - - - - - - - - - - - - - - - - - - - - - - + # define actions to run after copying to /config - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # unset unneeded variables - unset sysname - # Lets wait a few seconds before continuing - sleep 5 - # allow custom functions - if builtin type -t __pre_execute_local | grep -q 'function'; then __pre_execute_local; fi - # exit function - return $exitCode + # - - - - - - - - - - - - - - - - - - - - - - - - - + # unset unneeded variables + unset sysname + # Lets wait a few seconds before continuing + sleep 5 + # allow custom functions + if builtin type -t __pre_execute_local | grep -q 'function'; then + __pre_execute_local + fi + # exit function + return $exitCode } -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # function to run after executing __post_execute() { - local pid="" # init pid var - local retVal=0 # set default exit code - local ctime=${POST_EXECUTE_WAIT_TIME:-1} # how long to wait before executing - local waitTime=$((ctime * 60)) # convert minutes to seconds - local postMessageST="Running post commands for $SERVICE_NAME" # message to show at start - local postMessageEnd="Finished post commands for $SERVICE_NAME" # message to show at completion - # wait - sleep $waitTime - # execute commands after waiting - ( - # show message - __banner "$postMessageST" - # commands to execute - sleep 5 - # show exit message - __banner "$postMessageEnd: Status $retVal" - ) 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt" & - pid=$! - ps ax | awk '{print $1}' | grep -v grep | grep -q "$execPid$" && retVal=0 || retVal=10 - # allow custom functions - if builtin type -t __post_execute_local | grep -q 'function'; then __post_execute_local; fi - # exit function - return $retVal + # init pid var + local pid="" + # set default exit code + local retVal=0 + # how long to wait before executing + local ctime=${POST_EXECUTE_WAIT_TIME:-1} + # convert minutes to seconds + local waitTime=$((ctime * 60)) + # message to show at start + local postMessageST="Running post commands for $SERVICE_NAME" + # message to show at completion + local postMessageEnd="Finished post commands for $SERVICE_NAME" + # wait + sleep $waitTime + # execute commands after waiting + ( + # show message + __banner "$postMessageST" + # commands to execute + sleep 5 + # show exit message + __banner "$postMessageEnd: Status $retVal" + ) 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt" & + pid=$! + if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then + retVal=0 + else + retVal=10 + fi + # allow custom functions + if builtin type -t __post_execute_local | grep -q 'function'; then + __post_execute_local + fi + # exit function + return $retVal } -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # use this function to update config files - IE: change port __pre_message() { - local exitCode=0 - [ -n "$PRE_EXEC_MESSAGE" ] && eval echo "$PRE_EXEC_MESSAGE" - # execute commands + local exitCode=0 + if [ -n "$PRE_EXEC_MESSAGE" ]; then + eval echo "$PRE_EXEC_MESSAGE" + fi + # execute commands - # allow custom functions - if builtin type -t __pre_message_local | grep -q 'function'; then __pre_message_local; fi - # exit function - return $exitCode + # allow custom functions + if builtin type -t __pre_message_local | grep -q 'function'; then + __pre_message_local + fi + # exit function + return $exitCode } -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # use this function to setup ssl support __update_ssl_conf() { - local exitCode=0 - local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" # set hostname - # execute commands + local exitCode=0 + local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" + # execute commands - # allow custom functions - if builtin type -t __update_ssl_conf_local | grep -q 'function'; then __update_ssl_conf_local; fi - # set exitCode - return $exitCode + # allow custom functions + if builtin type -t __update_ssl_conf_local | grep -q 'function'; then + __update_ssl_conf_local + fi + # set exitCode + return $exitCode } -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - __create_service_env() { - local exitCode=0 - if [ ! -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" ]; then - cat </dev/null -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + local exitCode=0 + if [ ! -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" ]; then + cat </dev/null +# - - - - - - - - - - - - - - - - - - - - - - - - - # root/admin user info [password/random] #ENV_ROOT_USER_NAME="${ENV_ROOT_USER_NAME:-$ARIA2C_ROOT_USER_NAME}" # root user name #ENV_ROOT_USER_PASS="${ENV_ROOT_USER_NAME:-$ARIA2C_ROOT_PASS_WORD}" # root user password -#root_user_name="${ENV_ROOT_USER_NAME:-$root_user_name}" # -#root_user_pass="${ENV_ROOT_USER_PASS:-$root_user_pass}" # -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +#root_user_name="${ENV_ROOT_USER_NAME:-$root_user_name}" # +#root_user_pass="${ENV_ROOT_USER_PASS:-$root_user_pass}" # +# - - - - - - - - - - - - - - - - - - - - - - - - - #Normal user info [password/random] #ENV_USER_NAME="${ENV_USER_NAME:-$ARIA2C_USER_NAME}" # #ENV_USER_PASS="${ENV_USER_PASS:-$ARIA2C_USER_PASS_WORD}" # -#user_name="${ENV_USER_NAME:-$user_name}" # normal user name -#user_pass="${ENV_USER_PASS:-$user_pass}" # normal user password +#user_name="${ENV_USER_NAME:-$user_name}" # normal user name +#user_pass="${ENV_USER_PASS:-$user_pass}" # normal user password EOF - fi - if [ ! -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh" ]; then - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - __run_precopy_local() { true; } - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - __execute_prerun_local() { true; } - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - __run_pre_execute_checks_local() { true; } - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - __update_conf_files_local() { true; } - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - __pre_execute_local() { true; } - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - __post_execute_local() { true; } - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - __pre_message_local() { true; } - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - __update_ssl_conf_local() { true; } - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fi - __file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" || exitCode=$((exitCode + 1)) - __file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh" || exitCode=$((exitCode + 1)) - return $exitCode + fi + if [ ! -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh" ]; then + # - - - - - - - - - - - - - - - - - - - - - - - - - + __run_precopy_local() { true; } + # - - - - - - - - - - - - - - - - - - - - - - - - - + __execute_prerun_local() { true; } + # - - - - - - - - - - - - - - - - - - - - - - - - - + __run_pre_execute_checks_local() { true; } + # - - - - - - - - - - - - - - - - - - - - - - - - - + __update_conf_files_local() { true; } + # - - - - - - - - - - - - - - - - - - - - - - - - - + __pre_execute_local() { true; } + # - - - - - - - - - - - - - - - - - - - - - - - - - + __post_execute_local() { true; } + # - - - - - - - - - - - - - - - - - - - - - - - - - + __pre_message_local() { true; } + # - - - - - - - - - - - - - - - - - - - - - - - - - + __update_ssl_conf_local() { true; } + # - - - - - - - - - - - - - - - - - - - - - - - - - + fi + if ! __file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh"; then + exitCode=$((exitCode + 1)) + fi + if ! __file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh"; then + exitCode=$((exitCode + 1)) + fi + return $exitCode } -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # script to start server __run_start_script() { - local runExitCode=0 - local workdir="$(eval echo "${WORK_DIR:-}")" # expand variables - local cmd="$(eval echo "${EXEC_CMD_BIN:-}")" # expand variables - local args="$(eval echo "${EXEC_CMD_ARGS:-}")" # expand variables - local name="$(eval echo "${EXEC_CMD_NAME:-}")" # expand variables - local pre="$(eval echo "${EXEC_PRE_SCRIPT:-}")" # expand variables - local extra_env="$(eval echo "${CMD_ENV//,/ }")" # expand variables - local lc_type="$(eval echo "${LANG:-${LC_ALL:-$LC_CTYPE}}")" # expand variables - local home="$(eval echo "${workdir//\/root/\/tmp\/docker}")" # expand variables - local path="$(eval echo "$PATH")" # expand variables - local message="$(eval echo "")" # expand variables - local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" # set hostname - [ -f "$CONF_DIR/$SERVICE_NAME.exec_cmd.sh" ] && . "$CONF_DIR/$SERVICE_NAME.exec_cmd.sh" - # - if [ -z "$cmd" ]; then - __post_execute 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt" - retVal=$? - echo "Initializing $SCRIPT_NAME has completed" - __script_exit $retVal - else - # ensure the command exists - if [ ! -x "$cmd" ]; then - echo "$name is not a valid executable" - return 2 - fi - # check and exit if already running - if __proc_check "$name" || __proc_check "$cmd"; then - echo "$name is already running" >&2 - return 0 - else - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # show message if env exists - if [ -n "$cmd" ]; then - [ -n "$SERVICE_USER" ] && echo "Setting up $cmd to run as $SERVICE_USER" || SERVICE_USER="root" - [ -n "$SERVICE_PORT" ] && echo "$name will be running on port $SERVICE_PORT" || SERVICE_PORT="" - fi - if [ -n "$pre" ] && [ -n "$(command -v "$pre" 2>/dev/null)" ]; then - export cmd_exec="$pre $cmd $args" - message="Starting service: $name $args through $pre" - else - export cmd_exec="$cmd $args" - message="Starting service: $name $args" - fi - [ -n "$su_exec" ] && echo "using $su_exec" | tee -a -p "/data/logs/init.txt" - echo "$message" | tee -a -p "/data/logs/init.txt" - su_cmd touch "$SERVICE_PID_FILE" - if [ "$RESET_ENV" = "yes" ]; then - env_command="$(echo "env -i HOME=\"$home\" LC_CTYPE=\"$lc_type\" PATH=\"$path\" HOSTNAME=\"$sysname\" USER=\"${SERVICE_USER:-$RUNAS_USER}\" $extra_env")" - execute_command="$(__trim "$su_exec $env_command $cmd_exec")" - if [ ! -f "$START_SCRIPT" ]; then - cat <"$START_SCRIPT" + local runExitCode=0 + # expand variables + local workdir="$(eval echo "${WORK_DIR:-}")" + # expand variables + local cmd="$(eval echo "${EXEC_CMD_BIN:-}")" + # expand variables + local args="$(eval echo "${EXEC_CMD_ARGS:-}")" + # expand variables + local name="$(eval echo "${EXEC_CMD_NAME:-}")" + # expand variables + local pre="$(eval echo "${EXEC_PRE_SCRIPT:-}")" + # expand variables + local extra_env="$(eval echo "${CMD_ENV//,/ }")" + # expand variables + local lc_type="$(eval echo "${LANG:-${LC_ALL:-$LC_CTYPE}}")" + # expand variables + local home="$(eval echo "${workdir//\/root/\/tmp\/docker}")" + # expand variables + local path="$(eval echo "$PATH")" + # expand variables + local message="$(eval echo "")" + local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" + if [ -f "$CONF_DIR/$SERVICE_NAME.exec_cmd.sh" ]; then + . "$CONF_DIR/$SERVICE_NAME.exec_cmd.sh" + fi + # + if [ -z "$cmd" ]; then + __post_execute 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt" + retVal=$? + __log_info "Initialization of $SCRIPT_NAME has completed" + __script_exit $retVal + else + # ensure the command exists + if [ ! -x "$cmd" ]; then + __log_error "$name is not a valid executable" + return 2 + fi + # check and exit if already running (respects SERVICE_USES_PID in __proc_check) + if __proc_check "$name" || __proc_check "$cmd"; then + __log_debug "Service $name is already running" + return 0 + else + # - - - - - - - - - - - - - - - - - - - - - - - - - + # show message if env exists + if [ -n "$cmd" ]; then + if [ -n "$SERVICE_USER" ]; then + __log_info "Setting up $cmd to run as $SERVICE_USER" + else + SERVICE_USER="root" + fi + if [ -n "$SERVICE_PORT" ]; then + __log_info "$name will be running on port $SERVICE_PORT" + else + SERVICE_PORT="" + fi + fi + if [ -n "$pre" ] && command -v "$pre" &>/dev/null; then + export cmd_exec="$pre $cmd $args" + message="Starting service: $name $args through $pre" + else + export cmd_exec="$cmd $args" + message="Starting service: $name $args" + fi + if [ -n "$su_exec" ]; then + __log_debug "Using $su_exec" | tee -a -p "/data/logs/init.txt" + fi + __log_info "$message" | tee -a -p "/data/logs/init.txt" + su_cmd touch "$SERVICE_PID_FILE" + if [ "$RESET_ENV" = "yes" ]; then + env_command="$(echo "env -i HOME=\"$home\" LC_CTYPE=\"$lc_type\" PATH=\"$path\" HOSTNAME=\"$sysname\" USER=\"${SERVICE_USER:-$RUNAS_USER}\" $extra_env")" + execute_command="$(__trim "$su_exec $env_command $cmd_exec")" + if [ ! -f "$START_SCRIPT" ]; then + cat <"$START_SCRIPT" #!/usr/bin/env bash -trap 'exitCode=\$?;if [ \$exitCode -ne 0 ] && [ -f "\$SERVICE_PID_FILE" ]; then rm -Rf "\$SERVICE_PID_FILE"; fi; exit \$exitCode' EXIT +trap 'exitCode=\$?;[ \$exitCode -ne 0 ] && [ -f "\$SERVICE_PID_FILE" ] && rm -Rf "\$SERVICE_PID_FILE";exit \$exitCode' EXIT # set -Eeo pipefail # Setting up $cmd to run as ${SERVICE_USER:-root} with env retVal=10 cmd="$cmd" +args="$args" SERVICE_NAME="$SERVICE_NAME" SERVICE_PID_FILE="$SERVICE_PID_FILE" -$execute_command 2>"/dev/stderr" >>"$LOG_DIR/$SERVICE_NAME.log" & +LOG_DIR="$LOG_DIR" +execute_command="$execute_command" +\$execute_command 2>"/dev/stderr" >>"\$LOG_DIR/\$SERVICE_NAME.log" & execPid=\$! -sleep 2 -checkPID="\$(ps ax | awk '{print \$1}' | grep -v grep | grep "\$execPid$" || false)" -[ -n "\$execPid" ] && [ -n "\$checkPID" ] && echo "\$execPid" >"\$SERVICE_PID_FILE" && retVal=0 || retVal=10 -[ "\$retVal" = 0 ] && echo "\$cmd has been started" && printf '%s\n' "\$SERVICE_NAME: \$execPid" >"/run/healthcheck/\$SERVICE_NAME" || echo "Failed to start $execute_command" >&2 +sleep 1 +if [ -n "\$execPid" ] && kill -0 "\$execPid" 2>/dev/null; then + echo "\$execPid" >"\$SERVICE_PID_FILE" + retVal=0 + printf '%s\n' "\$SERVICE_NAME: \$execPid" >"/run/healthcheck/\$SERVICE_NAME" +else + retVal=10 + echo "Failed to start $execute_command" >&2 +fi exit \$retVal EOF - fi - else - if [ ! -f "$START_SCRIPT" ]; then - execute_command="$(__trim "$su_exec $cmd_exec")" - cat <"$START_SCRIPT" + fi + else + if [ ! -f "$START_SCRIPT" ]; then + execute_command="$(__trim "$su_exec $cmd_exec")" + cat <"$START_SCRIPT" #!/usr/bin/env bash -trap 'exitCode=\$?;if [ \$exitCode -ne 0 ] && [ -f "\$SERVICE_PID_FILE" ]; then rm -Rf "\$SERVICE_PID_FILE"; fi; exit \$exitCode' EXIT +trap 'exitCode=\$?;[ \$exitCode -ne 0 ] && [ -f "\$SERVICE_PID_FILE" ] && rm -Rf "\$SERVICE_PID_FILE";exit \$exitCode' EXIT # set -Eeo pipefail # Setting up $cmd to run as ${SERVICE_USER:-root} retVal=10 cmd="$cmd" +args="$args" SERVICE_NAME="$SERVICE_NAME" SERVICE_PID_FILE="$SERVICE_PID_FILE" -$execute_command 2>>"/dev/stderr" >>"$LOG_DIR/$SERVICE_NAME.log" & +LOG_DIR="$LOG_DIR" +execute_command="$execute_command" +\$execute_command 2>>"/dev/stderr" >>"\$LOG_DIR/\$SERVICE_NAME.log" & execPid=\$! -sleep 2 -checkPID="\$(ps ax | awk '{print \$1}' | grep -v grep | grep "\$execPid$" || false)" -[ -n "\$execPid" ] && [ -n "\$checkPID" ] && echo "\$execPid" >"\$SERVICE_PID_FILE" && retVal=0 || retVal=10 -[ "\$retVal" = 0 ] && echo "\$cmd has been started" || echo "Failed to start $execute_command" >&2 >&2 +sleep 1 +if [ -n "\$execPid" ] && kill -0 "\$execPid" 2>/dev/null; then + echo "\$execPid" >"\$SERVICE_PID_FILE" + retVal=0 +else + retVal=10 + echo "Failed to start $execute_command" >&2 +fi exit \$retVal EOF - fi - fi - fi - [ -x "$START_SCRIPT" ] || chmod 755 -Rf "$START_SCRIPT" - [ "$CONTAINER_INIT" = "yes" ] || eval sh -c "$START_SCRIPT" - runExitCode=$? - fi - return $runExitCode + fi + fi + fi + if [ ! -x "$START_SCRIPT" ]; then + chmod 755 -Rf "$START_SCRIPT" + fi + if [ "$CONTAINER_INIT" != "yes" ]; then + eval sh -c "$START_SCRIPT" + runExitCode=$? + fi + fi + return $runExitCode } -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # username and password actions __run_secure_function() { - local filesperms - if [ -n "$user_name" ] || [ -n "$user_pass" ]; then - for filesperms in "${USER_FILE_PREFIX}"/*; do - if [ -e "$filesperms" ]; then - chmod -Rf 600 "$filesperms" - chown -Rf $SERVICE_USER:$SERVICE_USER "$filesperms" 2>/dev/null - fi - done 2>/dev/null | tee -p -a "/data/logs/init.txt" - fi - if [ -n "$root_user_name" ] || [ -n "$root_user_pass" ]; then - for filesperms in "${ROOT_FILE_PREFIX}"/*; do - if [ -e "$filesperms" ]; then - chmod -Rf 600 "$filesperms" - chown -Rf $SERVICE_USER:$SERVICE_USER "$filesperms" 2>/dev/null - fi - done 2>/dev/null | tee -p -a "/data/logs/init.txt" - fi - unset filesperms + local filesperms + if [ -n "$user_name" ] || [ -n "$user_pass" ]; then + for filesperms in "${USER_FILE_PREFIX}"/*; do + if [ -e "$filesperms" ]; then + chmod -Rf 600 "$filesperms" + chown -Rf $SERVICE_USER:$SERVICE_USER "$filesperms" 2>/dev/null + fi + done 2>/dev/null | tee -p -a "/data/logs/init.txt" + fi + if [ -n "$root_user_name" ] || [ -n "$root_user_pass" ]; then + for filesperms in "${ROOT_FILE_PREFIX}"/*; do + if [ -e "$filesperms" ]; then + chmod -Rf 600 "$filesperms" + chown -Rf $SERVICE_USER:$SERVICE_USER "$filesperms" 2>/dev/null + fi + done 2>/dev/null | tee -p -a "/data/logs/init.txt" + fi + unset filesperms } -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Allow ENV_ variable - Import env file -__file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" && . "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" -__file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh" && . "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -SERVICE_EXIT_CODE=0 # default exit code +if __file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh"; then + . "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" +fi +if __file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh"; then + . "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +# default exit code +SERVICE_EXIT_CODE=0 # application specific -EXEC_CMD_NAME="$(basename -- "$EXEC_CMD_BIN")" # set the binary name -SERVICE_PID_FILE="/run/init.d/$EXEC_CMD_NAME.pid" # set the pid file location -SERVICE_PID_NUMBER="$(__pgrep)" # check if running -EXEC_CMD_BIN="$(type -P "$EXEC_CMD_BIN" || echo "$EXEC_CMD_BIN")" # set full path -EXEC_PRE_SCRIPT="$(type -P "$EXEC_PRE_SCRIPT" || echo "$EXEC_PRE_SCRIPT")" # set full path -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +EXEC_CMD_NAME="${EXEC_CMD_BIN##*/}" +SERVICE_PID_FILE="/run/init.d/$EXEC_CMD_NAME.pid" +SERVICE_PID_NUMBER="$(__pgrep "$EXEC_CMD_NAME" 2>/dev/null || echo '')" +_resolved="$(type -P "$EXEC_CMD_BIN" 2>/dev/null)" +[ -n "$_resolved" ] && EXEC_CMD_BIN="$_resolved" +_resolved="$(type -P "$EXEC_PRE_SCRIPT" 2>/dev/null)" +[ -n "$_resolved" ] && EXEC_PRE_SCRIPT="$_resolved" +unset _resolved +# - - - - - - - - - - - - - - - - - - - - - - - - - # Only run check -__check_service "$1" && SERVICE_IS_RUNNING=yes -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +if __check_service "$1"; then + SERVICE_IS_RUNNING=yes +else + SERVICE_IS_RUNNING="no" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - # ensure needed directories exists -[ -d "$LOG_DIR" ] || mkdir -p "$LOG_DIR" -[ -d "$RUN_DIR" ] || mkdir -p "$RUN_DIR" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +if [ ! -d "$LOG_DIR" ]; then + mkdir -p "$LOG_DIR" +fi +if [ ! -d "$RUN_DIR" ]; then + mkdir -p "$RUN_DIR" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - # create auth directories -[ -n "$USER_FILE_PREFIX" ] && { [ -d "$USER_FILE_PREFIX" ] || mkdir -p "$USER_FILE_PREFIX"; } -[ -n "$ROOT_FILE_PREFIX" ] && { [ -d "$ROOT_FILE_PREFIX" ] || mkdir -p "$ROOT_FILE_PREFIX"; } -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -[ -n "$RUNAS_USER" ] || RUNAS_USER="root" -[ -n "$SERVICE_USER" ] || SERVICE_USER="$RUNAS_USER" -[ -n "$SERVICE_GROUP" ] || SERVICE_GROUP="${SERVICE_USER:-$RUNAS_USER}" -[ "$IS_WEB_SERVER" = "yes" ] && RESET_ENV="yes" && __is_htdocs_mounted -[ "$IS_WEB_SERVER" = "yes" ] && [ -z "$SERVICE_PORT" ] && SERVICE_PORT="80" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +if [ -n "$USER_FILE_PREFIX" ]; then + if [ ! -d "$USER_FILE_PREFIX" ]; then + mkdir -p "$USER_FILE_PREFIX" + fi +fi +if [ -n "$ROOT_FILE_PREFIX" ]; then + if [ ! -d "$ROOT_FILE_PREFIX" ]; then + mkdir -p "$ROOT_FILE_PREFIX" + fi +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +if [ -z "$RUNAS_USER" ]; then + RUNAS_USER="root" +fi +if [ -z "$SERVICE_USER" ]; then + SERVICE_USER="$RUNAS_USER" +fi +if [ -z "$SERVICE_GROUP" ]; then + SERVICE_GROUP="${SERVICE_USER:-$RUNAS_USER}" +fi +if [ "$IS_WEB_SERVER" = "yes" ]; then + RESET_ENV="yes" + __is_htdocs_mounted +fi +if [ "$IS_WEB_SERVER" = "yes" ] && [ -z "$SERVICE_PORT" ]; then + SERVICE_PORT="80" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - # Database env if [ "$IS_DATABASE_SERVICE" = "yes" ] || [ "$USES_DATABASE_SERVICE" = "yes" ]; then - RESET_ENV="no" - DATABASE_CREATE="${ENV_DATABASE_CREATE:-$DATABASE_CREATE}" - DATABASE_USER_NORMAL="${ENV_DATABASE_USER:-${DATABASE_USER_NORMAL:-$user_name}}" - DATABASE_PASS_NORMAL="${ENV_DATABASE_PASSWORD:-${DATABASE_PASS_NORMAL:-$user_pass}}" - DATABASE_USER_ROOT="${ENV_DATABASE_ROOT_USER:-${DATABASE_USER_ROOT:-$root_user_name}}" - DATABASE_PASS_ROOT="${ENV_DATABASE_ROOT_PASSWORD:-${DATABASE_PASS_ROOT:-$root_user_pass}}" - if [ -n "$DATABASE_PASS_NORMAL" ] && [ ! -f "${USER_FILE_PREFIX}/db_pass_user" ]; then - echo "$DATABASE_PASS_NORMAL" >"${USER_FILE_PREFIX}/db_pass_user" - fi - if [ -n "$DATABASE_PASS_ROOT" ] && [ ! -f "${ROOT_FILE_PREFIX}/db_pass_root" ]; then - echo "$DATABASE_PASS_ROOT" >"${ROOT_FILE_PREFIX}/db_pass_root" - fi + RESET_ENV="no" + DATABASE_CREATE="${ENV_DATABASE_CREATE:-$DATABASE_CREATE}" + DATABASE_USER_NORMAL="${ENV_DATABASE_USER:-${DATABASE_USER_NORMAL:-$user_name}}" + DATABASE_PASS_NORMAL="${ENV_DATABASE_PASSWORD:-${DATABASE_PASS_NORMAL:-$user_pass}}" + DATABASE_USER_ROOT="${ENV_DATABASE_ROOT_USER:-${DATABASE_USER_ROOT:-$root_user_name}}" + DATABASE_PASS_ROOT="${ENV_DATABASE_ROOT_PASSWORD:-${DATABASE_PASS_ROOT:-$root_user_pass}}" + if [ -n "$DATABASE_PASS_NORMAL" ]; then + if [ ! -f "${USER_FILE_PREFIX}/db_pass_user" ]; then + echo "$DATABASE_PASS_NORMAL" >"${USER_FILE_PREFIX}/db_pass_user" + fi + fi + if [ -n "$DATABASE_PASS_ROOT" ]; then + if [ ! -f "${ROOT_FILE_PREFIX}/db_pass_root" ]; then + echo "$DATABASE_PASS_ROOT" >"${ROOT_FILE_PREFIX}/db_pass_root" + fi + fi fi -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # [DATABASE_DIR_[SQLITE,REDIS,POSTGRES,MARIADB,COUCHDB,MONGODB,SUPABASE]] if [ "$DATABASE_SERVICE_TYPE" = "custom" ]; then - DATABASE_DIR="${DATABASE_DIR_CUSTOM:-/data/db/custom}" - DATABASE_BASE_DIR="${DATABASE_DIR_CUSTOM:-/data/db/custom}" - DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_CUSTOM:-/usr/local/share/httpd/admin/databases}" - [ -d "$DATABASE_ADMIN_WWW_ROOT" ] && SERVER_ADMIN_URL="${SERVER_ADMIN_URL_CUSTOM:-/admin/dbadmin}" + DATABASE_DIR="${DATABASE_DIR_CUSTOM:-/data/db/custom}" + DATABASE_BASE_DIR="${DATABASE_DIR_CUSTOM:-/data/db/custom}" + DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_CUSTOM:-/usr/local/share/httpd/admin/databases}" + if [ -d "$DATABASE_ADMIN_WWW_ROOT" ]; then + SERVER_ADMIN_URL="${SERVER_ADMIN_URL_CUSTOM:-/admin/dbadmin}" + fi elif [ "$SERVICE_NAME" = "redis" ] || [ "$DATABASE_SERVICE_TYPE" = "redis" ]; then - DATABASE_DIR="${DATABASE_DIR_REDIS:-/data/db/redis}" - DATABASE_BASE_DIR="${DATABASE_DIR_REDIS:-/data/db/redis}" - DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_REDIS:-/usr/local/share/httpd/admin/redis}" - [ -d "$DATABASE_ADMIN_WWW_ROOT" ] && SERVER_ADMIN_URL="${SERVER_ADMIN_URL_REDIS:-/admin/redis}" + DATABASE_DIR="${DATABASE_DIR_REDIS:-/data/db/redis}" + DATABASE_BASE_DIR="${DATABASE_DIR_REDIS:-/data/db/redis}" + DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_REDIS:-/usr/local/share/httpd/admin/redis}" + if [ -d "$DATABASE_ADMIN_WWW_ROOT" ]; then + SERVER_ADMIN_URL="${SERVER_ADMIN_URL_REDIS:-/admin/redis}" + fi elif [ "$SERVICE_NAME" = "postgres" ] || [ "$DATABASE_SERVICE_TYPE" = "postgres" ]; then - DATABASE_DIR="${DATABASE_DIR_POSTGRES:-/data/db/postgres}" - DATABASE_BASE_DIR="${DATABASE_DIR_POSTGRES:-/data/db/postgres}" - DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_POSTGRES:-/usr/local/share/httpd/admin/postgres}" - [ -d "$DATABASE_ADMIN_WWW_ROOT" ] && SERVER_ADMIN_URL="${SERVER_ADMIN_URL_POSTGRES:-/admin/postgres}" + DATABASE_DIR="${DATABASE_DIR_POSTGRES:-/data/db/postgres}" + DATABASE_BASE_DIR="${DATABASE_DIR_POSTGRES:-/data/db/postgres}" + DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_POSTGRES:-/usr/local/share/httpd/admin/postgres}" + if [ -d "$DATABASE_ADMIN_WWW_ROOT" ]; then + SERVER_ADMIN_URL="${SERVER_ADMIN_URL_POSTGRES:-/admin/postgres}" + fi elif [ "$SERVICE_NAME" = "mariadb" ] || [ "$DATABASE_SERVICE_TYPE" = "mariadb" ]; then - DATABASE_DIR="${DATABASE_DIR_MARIADB:-/data/db/mariadb}" - DATABASE_BASE_DIR="${DATABASE_DIR_MARIADB:-/data/db/mariadb}" - DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_MARIADB:-/usr/local/share/httpd/admin/mysql}" - [ -d "$DATABASE_ADMIN_WWW_ROOT" ] && SERVER_ADMIN_URL="${SERVER_ADMIN_URL_MARIADB:-/admin/mysql}" + DATABASE_DIR="${DATABASE_DIR_MARIADB:-/data/db/mariadb}" + DATABASE_BASE_DIR="${DATABASE_DIR_MARIADB:-/data/db/mariadb}" + DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_MARIADB:-/usr/local/share/httpd/admin/mysql}" + if [ -d "$DATABASE_ADMIN_WWW_ROOT" ]; then + SERVER_ADMIN_URL="${SERVER_ADMIN_URL_MARIADB:-/admin/mysql}" + fi elif [ "$SERVICE_NAME" = "mysql" ] || [ "$DATABASE_SERVICE_TYPE" = "mysql" ]; then - DATABASE_DIR="${DATABASE_DIR_MYSQL:-/data/db/mysql}" - DATABASE_BASE_DIR="${DATABASE_DIR_MYSQL:-/data/db/mysql}" - DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_MYSQL:-/usr/local/share/httpd/admin/mysql}" - [ -d "$DATABASE_ADMIN_WWW_ROOT" ] && SERVER_ADMIN_URL="${SERVER_ADMIN_URL_MYSQL:-/admin/mysql}" + DATABASE_DIR="${DATABASE_DIR_MYSQL:-/data/db/mysql}" + DATABASE_BASE_DIR="${DATABASE_DIR_MYSQL:-/data/db/mysql}" + DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_MYSQL:-/usr/local/share/httpd/admin/mysql}" + if [ -d "$DATABASE_ADMIN_WWW_ROOT" ]; then + SERVER_ADMIN_URL="${SERVER_ADMIN_URL_MYSQL:-/admin/mysql}" + fi elif [ "$SERVICE_NAME" = "couchdb" ] || [ "$DATABASE_SERVICE_TYPE" = "couchdb" ]; then - DATABASE_DIR="${DATABASE_DIR_COUCHDB:-/data/db/couchdb}" - DATABASE_BASE_DIR="${DATABASE_DIR_COUCHDB:-/data/db/couchdb}" - DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_COUCHDB:-/usr/local/share/httpd/admin/couchdb}" - [ -d "$DATABASE_ADMIN_WWW_ROOT" ] && SERVER_ADMIN_URL="${SERVER_ADMIN_URL_COUCHDB:-/admin/couchdb}" + DATABASE_DIR="${DATABASE_DIR_COUCHDB:-/data/db/couchdb}" + DATABASE_BASE_DIR="${DATABASE_DIR_COUCHDB:-/data/db/couchdb}" + DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_COUCHDB:-/usr/local/share/httpd/admin/couchdb}" + if [ -d "$DATABASE_ADMIN_WWW_ROOT" ]; then + SERVER_ADMIN_URL="${SERVER_ADMIN_URL_COUCHDB:-/admin/couchdb}" + fi elif [ "$SERVICE_NAME" = "mongodb" ] || [ "$DATABASE_SERVICE_TYPE" = "mongodb" ]; then - DATABASE_DIR="${DATABASE_DIR_MONGODB:-/data/db/mongodb}" - DATABASE_BASE_DIR="${DATABASE_DIR_MONGODB:-/data/db/mongodb}" - DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_MONGODB:-/usr/local/share/httpd/admin/mongodb}" - [ -d "$DATABASE_ADMIN_WWW_ROOT" ] && SERVER_ADMIN_URL="${SERVER_ADMIN_URL_MONGODB:-/admin/mongodb}" + DATABASE_DIR="${DATABASE_DIR_MONGODB:-/data/db/mongodb}" + DATABASE_BASE_DIR="${DATABASE_DIR_MONGODB:-/data/db/mongodb}" + DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_MONGODB:-/usr/local/share/httpd/admin/mongodb}" + if [ -d "$DATABASE_ADMIN_WWW_ROOT" ]; then + SERVER_ADMIN_URL="${SERVER_ADMIN_URL_MONGODB:-/admin/mongodb}" + fi elif [ "$SERVICE_NAME" = "supabase" ] || [ "$DATABASE_SERVICE_TYPE" = "supabase" ]; then - DATABASE_DIR="${DATABASE_DIR_SUPABASE:-/data/db/supabase}" - DATABASE_BASE_DIR="${DATABASE_DIR_SUPABASE:-/data/db/supabase}" - DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_SUPABASE:-/usr/local/share/httpd/admin/supabase}" - [ -d "$DATABASE_ADMIN_WWW_ROOT" ] && SERVER_ADMIN_URL="${SERVER_ADMIN_URL_SUPBASE:-/admin/supabase}" + DATABASE_DIR="${DATABASE_DIR_SUPABASE:-/data/db/supabase}" + DATABASE_BASE_DIR="${DATABASE_DIR_SUPABASE:-/data/db/supabase}" + DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_SUPABASE:-/usr/local/share/httpd/admin/supabase}" + if [ -d "$DATABASE_ADMIN_WWW_ROOT" ]; then + SERVER_ADMIN_URL="${SERVER_ADMIN_URL_SUPBASE:-/admin/supabase}" + fi elif [ "$SERVICE_NAME" = "sqlite" ] || [ "$DATABASE_SERVICE_TYPE" = "sqlite" ]; then - DATABASE_DIR="${DATABASE_DIR_SQLITE:-/data/db/sqlite}/$SERVER_NAME" - DATABASE_BASE_DIR="${DATABASE_DIR_SQLITE:-/data/db/sqlite}/$SERVER_NAME" - DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_SQLITE:-/usr/local/share/httpd/admin/sqlite}" - [ -d "$DATABASE_ADMIN_WWW_ROOT" ] && SERVER_ADMIN_URL="${SERVER_ADMIN_URL_SQLITE:-/admin/sqlite}" - [ -d "$DATABASE_DIR" ] || mkdir -p "$DATABASE_DIR" - chmod 777 "$DATABASE_DIR" + DATABASE_DIR="${DATABASE_DIR_SQLITE:-/data/db/sqlite}/$SERVER_NAME" + DATABASE_BASE_DIR="${DATABASE_DIR_SQLITE:-/data/db/sqlite}/$SERVER_NAME" + DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_SQLITE:-/usr/local/share/httpd/admin/sqlite}" + if [ -d "$DATABASE_ADMIN_WWW_ROOT" ]; then + SERVER_ADMIN_URL="${SERVER_ADMIN_URL_SQLITE:-/admin/sqlite}" + fi + if [ ! -d "$DATABASE_DIR" ]; then + mkdir -p "$DATABASE_DIR" + fi + chmod 777 "$DATABASE_DIR" fi -[ -n "$DATABASE_ADMIN_WWW_ROOT" ] && { [ ! -d "$DATABASE_ADMIN_WWW_ROOT" ] || mkdir -p "${DATABASE_ADMIN_WWW_ROOT}"; } -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +if [ -n "$DATABASE_ADMIN_WWW_ROOT" ]; then + if [ ! -d "$DATABASE_ADMIN_WWW_ROOT" ]; then + mkdir -p "${DATABASE_ADMIN_WWW_ROOT}" + fi +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - # Allow variables via imports - Overwrite existing -[ -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" ] && . "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +if [ -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" ]; then + . "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - # set password to random if variable is random -[ "$user_pass" = "random" ] && user_pass="$(__random_password ${RANDOM_PASS_USER:-16})" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -[ "$root_user_pass" = "random" ] && root_user_pass="$(__random_password ${RANDOM_PASS_ROOT:-16})" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +if [ "$user_pass" = "random" ]; then + user_pass="$(__random_password ${RANDOM_PASS_USER:-16})" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +if [ "$root_user_pass" = "random" ]; then + root_user_pass="$(__random_password ${RANDOM_PASS_ROOT:-16})" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - # Allow setting initial users and passwords via environment and save to file -[ -n "$user_name" ] && echo "$user_name" >"${USER_FILE_PREFIX}/${SERVICE_NAME}_name" -[ -n "$user_pass" ] && echo "$user_pass" >"${USER_FILE_PREFIX}/${SERVICE_NAME}_pass" -[ -n "$root_user_name" ] && echo "$root_user_name" >"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_name" -[ -n "$root_user_pass" ] && echo "$root_user_pass" >"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_pass" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +if [ -n "$user_name" ]; then + echo "$user_name" >"${USER_FILE_PREFIX}/${SERVICE_NAME}_name" +fi +if [ -n "$user_pass" ]; then + echo "$user_pass" >"${USER_FILE_PREFIX}/${SERVICE_NAME}_pass" +fi +if [ -n "$root_user_name" ]; then + echo "$root_user_name" >"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_name" +fi +if [ -n "$root_user_pass" ]; then + echo "$root_user_pass" >"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_pass" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - # create needed dirs -[ -d "$LOG_DIR" ] || mkdir -p "$LOG_DIR" -[ -d "$RUN_DIR" ] || mkdir -p "$RUN_DIR" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +if [ ! -d "$LOG_DIR" ]; then + mkdir -p "$LOG_DIR" +fi +if [ ! -d "$RUN_DIR" ]; then + mkdir -p "$RUN_DIR" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - # Allow per init script usernames and passwords -__file_exists_with_content "${USER_FILE_PREFIX}/${SERVICE_NAME}_name" && user_name="$(<"${USER_FILE_PREFIX}/${SERVICE_NAME}_name")" -__file_exists_with_content "${USER_FILE_PREFIX}/${SERVICE_NAME}_pass" && user_pass="$(<"${USER_FILE_PREFIX}/${SERVICE_NAME}_pass")" -__file_exists_with_content "${ROOT_FILE_PREFIX}/${SERVICE_NAME}_name" && root_user_name="$(<"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_name")" -__file_exists_with_content "${ROOT_FILE_PREFIX}/${SERVICE_NAME}_pass" && root_user_pass="$(<"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_pass")" -__file_exists_with_content "${USER_FILE_PREFIX}/db_pass_user" && DATABASE_PASS_NORMAL="$(<"${USER_FILE_PREFIX}/db_pass_user")" -__file_exists_with_content "${ROOT_FILE_PREFIX}/db_pass_root" && DATABASE_PASS_ROOT="$(<"${ROOT_FILE_PREFIX}/db_pass_root")" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +if __file_exists_with_content "${USER_FILE_PREFIX}/${SERVICE_NAME}_name"; then + user_name="$(<"${USER_FILE_PREFIX}/${SERVICE_NAME}_name")" +fi +if __file_exists_with_content "${USER_FILE_PREFIX}/${SERVICE_NAME}_pass"; then + user_pass="$(<"${USER_FILE_PREFIX}/${SERVICE_NAME}_pass")" +fi +if __file_exists_with_content "${ROOT_FILE_PREFIX}/${SERVICE_NAME}_name"; then + root_user_name="$(<"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_name")" +fi +if __file_exists_with_content "${ROOT_FILE_PREFIX}/${SERVICE_NAME}_pass"; then + root_user_pass="$(<"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_pass")" +fi +if __file_exists_with_content "${USER_FILE_PREFIX}/db_pass_user"; then + DATABASE_PASS_NORMAL="$(<"${USER_FILE_PREFIX}/db_pass_user")" +fi +if __file_exists_with_content "${ROOT_FILE_PREFIX}/db_pass_root"; then + DATABASE_PASS_ROOT="$(<"${ROOT_FILE_PREFIX}/db_pass_root")" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - # set hostname for script sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - __create_service_env -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Setup /config directories __init_config_etc -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # pre-run function __execute_prerun -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # create user if needed __create_service_user "$SERVICE_USER" "$SERVICE_GROUP" "${WORK_DIR:-/home/$SERVICE_USER}" "${SERVICE_UID:-}" "${SERVICE_GID:-}" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Modify user if needed __set_user_group_id $SERVICE_USER ${SERVICE_UID:-} ${SERVICE_GID:-} -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Create base directories __setup_directories -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # set switch user command __switch_to_user -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Initialize the home/working dir __init_working_dir -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # show init message __pre_message -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # __initialize_db_users -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Initialize ssl __update_ssl_conf __update_ssl_certs -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set permissions in ${USER_FILE_PREFIX} and ${ROOT_FILE_PREFIX} __run_secure_function -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - __run_precopy -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Copy /config to /etc for config_2_etc in $CONF_DIR $ADDITIONAL_CONFIG_DIRS; do - __initialize_system_etc "$config_2_etc" 2>/dev/stderr | tee -p -a "/data/logs/init.txt" + __initialize_system_etc "$config_2_etc" 2>/dev/stderr | tee -p -a "/data/logs/init.txt" done -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Replace variables __initialize_replace_variables "$ETC_DIR" "$CONF_DIR" "$ADDITIONAL_CONFIG_DIRS" "$WWW_ROOT_DIR" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # __initialize_database -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Updating config files __update_conf_files -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # run the pre execute commands __pre_execute -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # Set permissions __fix_permissions "$SERVICE_USER" "$SERVICE_GROUP" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # __run_pre_execute_checks 2>/dev/stderr | tee -a -p "/data/logs/entrypoint.log" "/data/logs/init.txt" || return 20 -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - __run_start_script 2>>/dev/stderr | tee -p -a "/data/logs/entrypoint.log" errorCode=$? if [ -n "$EXEC_CMD_BIN" ]; then - if [ "$errorCode" -eq 0 ]; then - SERVICE_EXIT_CODE=0 - SERVICE_IS_RUNNING="yes" - else - SERVICE_EXIT_CODE=$errorCode - SERVICE_IS_RUNNING="${SERVICE_IS_RUNNING:-no}" - [ -s "$SERVICE_PID_FILE" ] || rm -Rf "$SERVICE_PID_FILE" - fi - SERVICE_EXIT_CODE=0 + if [ "$errorCode" -eq 0 ]; then + SERVICE_EXIT_CODE=0 + SERVICE_IS_RUNNING="yes" + else + SERVICE_EXIT_CODE=$errorCode + SERVICE_IS_RUNNING="${SERVICE_IS_RUNNING:-no}" + if [ ! -s "$SERVICE_PID_FILE" ]; then + rm -Rf "$SERVICE_PID_FILE" + fi + fi + SERVICE_EXIT_CODE=0 fi -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - # start the post execute function in background __post_execute 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt" & -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -__banner "Initializing of $SERVICE_NAME has completed with statusCode: $SERVICE_EXIT_CODE" | tee -p -a "/data/logs/entrypoint.log" "/data/logs/init.txt" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - __script_exit $SERVICE_EXIT_CODE