From eb715f59b7791749a8d792ae2eff7bfe54e4ee8e Mon Sep 17 00:00:00 2001 From: casjay Date: Mon, 18 May 2026 15:38:13 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20Update=20configuration=20files?= =?UTF-8?q?=20=F0=9F=94=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AI.md CLAUDE.md Dockerfile .env.scripts IDEA.md README.md rootfs/root/docker/setup/00-init.sh rootfs/root/docker/setup/01-system.sh rootfs/root/docker/setup/02-packages.sh rootfs/root/docker/setup/03-files.sh rootfs/root/docker/setup/06-post.sh rootfs/root/docker/setup/07-cleanup.sh rootfs/usr/local/bin/entrypoint.sh rootfs/usr/local/etc/docker/functions/entrypoint.sh rootfs/usr/local/etc/docker/init.d/09-mariadb.sh rootfs/usr/local/etc/docker/init.d/99-ampache.sh TODO.AI.md --- .env.scripts | 6 +- AI.md | 86 ++ CLAUDE.md | 396 +--------- Dockerfile | 18 +- IDEA.md | 3 + README.md | 31 +- TODO.AI.md | 34 + rootfs/root/docker/setup/00-init.sh | 43 +- rootfs/root/docker/setup/01-system.sh | 43 +- rootfs/root/docker/setup/02-packages.sh | 43 +- rootfs/root/docker/setup/03-files.sh | 43 +- rootfs/root/docker/setup/06-post.sh | 43 +- rootfs/root/docker/setup/07-cleanup.sh | 46 +- rootfs/usr/local/bin/entrypoint.sh | 43 +- .../local/etc/docker/functions/entrypoint.sh | 535 +++++++------ .../usr/local/etc/docker/init.d/09-mariadb.sh | 734 +++++++++++++----- .../usr/local/etc/docker/init.d/99-ampache.sh | 729 +++++++++++++---- 17 files changed, 1711 insertions(+), 1165 deletions(-) create mode 100644 AI.md create mode 100644 IDEA.md create mode 100644 TODO.AI.md diff --git a/.env.scripts b/.env.scripts index 5ce9da7..747385d 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:10 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..b279729 --- /dev/null +++ b/AI.md @@ -0,0 +1,86 @@ +# How this image is built and wired + +## Base image and tooling + +Built from `casjaysdev/alpine:latest` via a multi-stage Dockerfile (build stage → `FROM scratch` final). `tini` is the PID 1 supervisor; `gosu` provides privilege dropping. Package management is handled by `pkmgr` (auto-detects `apk`). + +## Package set + +All packages come from Alpine's `apk` package manager. Key groups: + +- **Apache 2**: `apache2 apache2-ctl apache2-utils apache2-ssl apache2-proxy apache2-http2 apache2-brotli apache2-icons apache2-error` +- **PHP 8.4**: `php84 php84-fpm` plus all modules Ampache requires (pdo, pdo_mysql, mysqli, mysqlnd, session, intl, curl, simplexml, xml, xmlreader, xmlwriter, dom, mbstring, iconv, tokenizer, fileinfo, openssl, phar, gd, zip, bz2, gmp, exif, opcache, pecl-redis, ctype) +- **MariaDB**: `mariadb mariadb-client mariadb-server-utils` +- **Utilities**: `bash tini curl wget unzip tar gzip tzdata ca-certificates pwgen` + +## Build-time setup flow (`rootfs/root/docker/setup/`) + +| Script | Role | +|--------|------| +| `00-init.sh` | Clears `template-files/{data,config,defaults}` staging dirs | +| `01-system.sh` | Stub (Alpine repos are already configured by the base image) | +| `02-packages.sh` | Stub (no post-install compile steps; prebuilt Ampache zip needs no composer/npm) | +| `03-files.sh` | Auto-installs `rootfs/tmp/etc/*` → `/etc/*` and stages copies under `template-files/config/` | +| `04-users.sh` | Defensive creation of `apache:apache` and `mysql:mysql` system accounts | +| `05-custom.sh` | **Core setup**: wipes distro defaults under `/etc/{apache2,php84,my.cnf.d}/*`, copies our optimized configs from `/tmp/etc/`, then downloads and unpacks the Ampache prebuilt zip to `/usr/local/share/ampache/` | +| `06-post.sh` | Stub | +| `07-cleanup.sh` | Stub | + +## Config wipe-and-replace + +`05-custom.sh` performs the canonical wipe-and-replace for all three config trees: + +1. Preserve `apache2/mime.types` and `apache2/magic` (not shipped in our `rootfs/tmp/etc/apache2/`) +2. `rm -Rf /etc/{apache2,php84,my.cnf.d}/*` +3. `cp -Rf /tmp/etc/{apache2,php84,my.cnf.d}/. /etc/{apache2,php84,my.cnf.d}/` +4. Copy resulting `/etc/` trees to `template-files/config/` for runtime seeding + +## Runtime init.d scripts + +Two init.d scripts run in numeric order: + +### `09-mariadb.sh` +- `SERVICE_NAME="mariadb"`, `EXEC_CMD_BIN='mariadbd'` +- Runs as `mysql:mysql`; datadir `/data/db/mariadb`; socket `/run/mysqld/mysqld.sock` +- `IS_DATABASE_SERVICE="yes"`, `DATABASE_SERVICE_TYPE="mariadb"` +- `__run_pre_execute_checks`: initializes the datadir with `mariadb-install-db` if `ibdata1` is missing +- `__post_execute`: waits for the socket, then creates the `ampache` database, `ampache` user (random password), grants privileges, and sets the root password + +### `99-ampache.sh` +- `SERVICE_NAME="ampache"`, `EXEC_CMD_BIN='/usr/local/etc/docker/bin/start-ampache'` +- `IS_WEB_SERVER="yes"`, `USES_DATABASE_SERVICE="yes"`, `DATABASE_SERVICE_TYPE="mariadb"` +- `SERVICE_USER="apache"`, `SERVICE_GROUP="apache"` +- `WWW_ROOT_DIR="/usr/local/share/ampache/public"`, `ETC_DIR="/etc/apache2"`, `CONF_DIR="/config/apache2"` +- `ADDITIONAL_CONFIG_DIRS="/config/php84 /config/ampache"` +- `__execute_prerun`: creates runtime dirs (`/run/apache2 /run/php-fpm /tmp/php-sessions /data/logs/{apache2,php-fpm}`), chowns them to `apache:apache`; symlinks `ampache.cfg.php` between `/usr/local/share/ampache/config/` and `/config/ampache/` once install.php writes it +- `__run_pre_execute_checks`: waits up to 30 s for the MariaDB socket; validates `httpd -t` apache config syntax +- `__update_conf_files`: replaces the `REPLACE_TZ` token in `/etc/php84/php.ini` with `$TZ` +- `__post_execute`: mirrors `ampache.cfg.php` out to `/config/ampache/` and creates the symlink if install.php has written it + +### `start-ampache` wrapper +`EXEC_CMD_BIN` points to `/usr/local/etc/docker/bin/start-ampache`, which: +1. Starts `php-fpm84` in the background (waits up to 10 s for `/run/php-fpm/php-fpm.sock`) +2. Exec's `httpd -D FOREGROUND -f /etc/apache2/httpd.conf` (becomes the process the framework monitors) + +## Config paths + +| Component | Config file | User-editable at | +|-----------|-------------|-----------------| +| Apache main | `/etc/apache2/httpd.conf` | `/config/apache2/httpd.conf` | +| Apache ampache vhost | `/etc/apache2/conf.d/ampache.conf` | `/config/apache2/conf.d/ampache.conf` | +| Apache MPM tuning | `/etc/apache2/conf.d/mpm.conf` | `/config/apache2/conf.d/mpm.conf` | +| User vhosts | `IncludeOptional /config/apache2/vhosts.d/*.conf` | `/config/apache2/vhosts.d/` | +| PHP runtime | `/etc/php84/php.ini` | `/config/php84/php.ini` | +| PHP-FPM global | `/etc/php84/php-fpm.conf` | `/config/php84/php-fpm.conf` | +| PHP-FPM pool | `/etc/php84/php-fpm.d/www.conf` | `/config/php84/php-fpm.d/www.conf` | +| MariaDB server | `/etc/my.cnf.d/mariadb-server.cnf` | `/config/my.cnf.d/mariadb-server.cnf` | +| Ampache app config | `/usr/local/share/ampache/config/ampache.cfg.php` | `/config/ampache/ampache.cfg.php` (symlinked) | + +## Volume layout + +- `/config` — all user-editable configs (seeded on first run from `template-files/config/`) +- `/data` — MariaDB datadir (`/data/db/mariadb`), logs (`/data/logs/`), media library if mounted + +## Port + +- `80` (HTTP); `443` available if SSL is enabled via `/config/enable/ssl` diff --git a/CLAUDE.md b/CLAUDE.md index e83d101..6c009b6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,395 +1 @@ -# casjaysdevdocker repo template spec - -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. - -- 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. - ---- - -## 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 AI.md and IDEA.md for context. Follow ~/.claude/CLAUDE.md and the org-level spec at /root/Projects/github/casjaysdevdocker/.github/AI.md for org conventions. diff --git a/Dockerfile b/Dockerfile index 578f7e2..0f18417 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # Docker image for ampache using the alpine template ARG IMAGE_NAME="ampache" ARG PHP_SERVER="ampache" -ARG BUILD_DATE="202605091200" +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,7 @@ 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; \ + [ -f "/root/.profile" ] || touch "/root/.profile"; \ 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 "" @@ -148,6 +137,7 @@ RUN echo "Custom Settings"; \ $SHELL_OPTS; \ echo "" + RUN echo "Setting up users and scripts "; \ $SHELL_OPTS; \ if [ -f "/root/docker/setup/04-users.sh" ];then echo "Running the users script";/root/docker/setup/04-users.sh||{ echo "Failed to execute /root/docker/setup/04-users.sh" >&2 && exit 10; };echo "Done running the users script";fi; \ diff --git a/IDEA.md b/IDEA.md new file mode 100644 index 0000000..794c861 --- /dev/null +++ b/IDEA.md @@ -0,0 +1,3 @@ +# What this image is + +A self-contained Docker image for [Ampache](https://ampache.org/), the open-source web-based music streaming server. The image bundles the full application stack in a single Alpine Linux container: Apache 2 as the web server, PHP 8.4 via PHP-FPM for application execution, MariaDB as the relational database, and the Ampache PHP application itself pre-installed under `/usr/local/share/ampache`. On first run, navigating to `http://localhost:80/` lands on the Ampache web installer (`install.php`), which provisions the database and creates the initial admin account. After installation, users can catalog and stream their music libraries, manage users and playlists, and connect media players via Ampache's API or DLNA/UPnP capabilities. diff --git a/README.md b/README.md index d34348d..22e8759 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## 👋 Welcome to ampache 🚀 -ampache README +A self-contained Docker image for [Ampache](https://ampache.org/), the open-source web-based music streaming server. Bundles Apache 2, PHP 8.4 via PHP-FPM, MariaDB, and Ampache itself. First run opens the Ampache web installer at `http://localhost:80/`. ## Install my system scripts @@ -54,6 +54,35 @@ services: restart: always ``` +## Environment variables + +| Variable | Default | Description | +|----------|---------|-------------| +| `TZ` | `America/New_York` | Container timezone (sets PHP date.timezone) | +| `MARIADB_ROOT_USER_NAME` | `root` | MariaDB root username | +| `MARIADB_ROOT_PASS_WORD` | `random` | MariaDB root password (auto-generated if `random`) | +| `MARIADB_USER_NAME` | `ampache` | MariaDB application username | +| `MARIADB_USER_PASS_WORD` | `random` | MariaDB application password (auto-generated if `random`) | +| `DATABASE_CREATE` | `ampache` | MariaDB database name to create | +| `HOSTNAME` | `ampache` | Container hostname used in Apache vhost | +| `DEBUGGER` | _(unset)_ | Set to `on` to enable bash `set -x` debugging | + +Passwords generated on first run are saved to `/config/secure/auth/`. + +## Volumes + +| Path | Purpose | +|------|---------| +| `/config` | All user-editable config files (Apache 2, PHP 8.4, MariaDB, Ampache) | +| `/data` | MariaDB data (`/data/db/mariadb`), logs (`/data/logs/`), and media library | + +## Ports + +| Port | Protocol | Description | +|------|----------|-------------| +| `80` | HTTP | Ampache web UI and API | +| `443` | HTTPS | Available when SSL is enabled via `/config/enable/ssl` | + ## Get source files ```shell diff --git a/TODO.AI.md b/TODO.AI.md new file mode 100644 index 0000000..fb1077c --- /dev/null +++ b/TODO.AI.md @@ -0,0 +1,34 @@ +# TODO — ampache migration + +Living list of what still needs doing. Remove items only when actually complete. + +## Completed this pass + +- [x] `Dockerfile` — updated `BUILD_DATE` to `202605131434`; prerequisites RUN changed to `true`; "Creating and editing system files" block stripped of inline APK repos management +- [x] `.env.scripts` — migrated to canonical 2026 header; all repo-specific values preserved +- [x] `CLAUDE.md` — replaced full TEMPLATE.md content with minimal per-repo pointer +- [x] `IDEA.md` — created: one-paragraph description of the image +- [x] `AI.md` — created: comprehensive technical description of how the image is built and wired +- [x] `README.md` — replaced old dockermgr-style README with user-facing docs (what it is, docker run, docker-compose, env vars table, volumes table, ports table) +- [x] `rootfs/usr/local/bin/entrypoint.sh` — copied from example; updated `CONTAINER_NAME` and description to `ampache` +- [x] `rootfs/usr/local/bin/pkmgr` — copied verbatim from example +- [x] `rootfs/usr/local/etc/docker/functions/entrypoint.sh` — copied verbatim from example +- [x] `rootfs/root/docker/setup/00-init.sh` — copied from example (canonical 2026 header) +- [x] `rootfs/root/docker/setup/01-system.sh` — copied from example (stub) +- [x] `rootfs/root/docker/setup/02-packages.sh` — copied from example (stub) +- [x] `rootfs/root/docker/setup/03-files.sh` — copied from example (canonical header) +- [x] `rootfs/root/docker/setup/06-post.sh` — copied from example (stub) +- [x] `rootfs/root/docker/setup/07-cleanup.sh` — copied from example (stub) +- [x] `rootfs/root/docker/setup/04-users.sh` — preserved (service-specific apache/mysql user creation) +- [x] `rootfs/root/docker/setup/05-custom.sh` — preserved (wipe-and-replace + Ampache zip download) +- [x] `rootfs/usr/local/etc/docker/init.d/09-mariadb.sh` — updated to canonical pattern (ERR trap handler, `__trap_err_handler`, canonical header, `SERVICE_USES_PID`) +- [x] `rootfs/usr/local/etc/docker/init.d/99-ampache.sh` — updated to canonical pattern (same as above) + +## Outstanding + +- [ ] Build verification — run `buildx` against the repo and confirm the image builds clean with all packages installable +- [ ] Runtime smoke test — start the container, verify MariaDB starts and the Ampache installer loads at `http://localhost:80/` +- [ ] `PLAN.md` — update `BUILD_DATE` field and mark completed steps; currently has stale 202503 date +- [ ] Confirm Ampache version in `05-custom.sh` — `ampache-7.9.3_all_php8.4.zip` was current at time of writing; bump when a new release is available +- [ ] SSL config — verify `/config/enable/ssl` toggle works with the Apache vhost in `conf.d/ampache.conf` +- [ ] `template-files/config/` seeding — verify all three config trees (apache2, php84, my.cnf.d) are correctly staged under `rootfs/usr/local/share/template-files/config/` by `05-custom.sh` diff --git a/rootfs/root/docker/setup/00-init.sh b/rootfs/root/docker/setup/00-init.sh index 4b5dcf5..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 : 202502050828-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 d88ad01..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 : 202502050828-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 542f872..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 : 202502050828-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/06-post.sh b/rootfs/root/docker/setup/06-post.sh index a2f32c6..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 : 202502050828-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 2933c15..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 : 202502050828-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 c671962..94860c2 100755 --- a/rootfs/usr/local/bin/entrypoint.sh +++ b/rootfs/usr/local/bin/entrypoint.sh @@ -1,13 +1,13 @@ #!/usr/bin/env bash # shellcheck shell=bash # - - - - - - - - - - - - - - - - - - - - - - - - - -##@Version : 202602061352-git +##@Version : 202605052024-git # @@Author : Jason Hempstead # @@Contact : jason@casjaysdev.pro # @@License : WTFPL # @@ReadME : entrypoint.sh --help # @@Copyright : Copyright: (c) 2026 Jason Hempstead, Casjays Developments -# @@Created : Tuesday, May 05, 2026 14:38 EDT +# @@Created : Wednesday, May 13, 2026 14:31 EDT # @@File : entrypoint.sh # @@Description : Entrypoint file for ampache # @@Changelog : New script @@ -25,7 +25,13 @@ trap 'retVal=$?;[ "$SERVICE_IS_RUNNING" != "yes" ] && [ -f "$SERVICE_PID_FILE" ] # - - - - - - - - - - - - - - - - - - - - - - - - - # 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 -o pipefail -x$DEBUGGER_OPTIONS && export DEBUGGER="on" || set -o pipefail +if [ "$DEBUGGER" = "on" ] || [ -f "/config/.debug" ]; then + echo "Enabling debugging" + set -o pipefail -x$DEBUGGER_OPTIONS + export DEBUGGER="on" +else + set -o pipefail +fi # - - - - - - - - - - - - - - - - - - - - - - - - - PATH="/usr/local/etc/docker/bin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin" # - - - - - - - - - - - - - - - - - - - - - - - - - @@ -87,8 +93,8 @@ SERVICE_UID="${SERVICE_UID:-0}" SERVICE_GID="${SERVICE_GID:-0}" # - - - - - - - - - - - - - - - - - - - - - - - - - # User and group in which the service switches to - IE: nginx,apache,mysql,postgres -#SERVICE_USER="${SERVICE_USER:-ampache}" # execute command as another user -#SERVICE_GROUP="${SERVICE_GROUP:-ampache}" # Set the service group +#SERVICE_USER="${SERVICE_USER:-example}" # execute command as another user +#SERVICE_GROUP="${SERVICE_GROUP:-example}" # Set the service group # - - - - - - - - - - - - - - - - - - - - - - - - - # Secondary ports # specifiy other ports @@ -357,7 +363,7 @@ if [ "$ENTRYPOINT_FIRST_RUN" != "no" ]; then fi # - - - - - - - - - - - - - - - - - - - - - - - - - if [ -f "/etc/hostname" ]; then - if [ -n "$(type -P hostname 2>/dev/null)" ]; then + if command -v hostname &>/dev/null; then hostname -F "/etc/hostname" 2>/dev/null || true else HOSTNAME="$(<"/etc/hostname")" 2>/dev/null || true @@ -372,7 +378,7 @@ if [ "$ENTRYPOINT_FIRST_RUN" != "no" ]; then # - - - - - - - - - - - - - - - - - - - - - - - - - # import resolv.conf file into container if [ "$CUSTOM_DNS" != "yes" ] && [ -f "/usr/local/etc/resolv.conf" ] && [ "$UPDATE_FILE_RESOLV" = "yes" ]; then - cat "/usr/local/etc/resolv.conf" >"/etc/resolv.conf" 2>/dev/null || true + cp -f "/usr/local/etc/resolv.conf" "/etc/resolv.conf" 2>/dev/null || true fi # - - - - - - - - - - - - - - - - - - - - - - - - - if [ -n "$HOME" ] && [ -d "/usr/local/etc/skel" ]; then @@ -383,12 +389,13 @@ if [ "$ENTRYPOINT_FIRST_RUN" != "no" ]; then # - - - - - - - - - - - - - - - - - - - - - - - - - fi # - - - - - - - - - - - - - - - - - - - - - - - - - -# Delete any .gitkeep files +# Delete any .gitkeep files (bash * does not match dotfiles by default, +# so the explicit /.gitkeep path is required at each depth) if [ -d "/data" ]; then - rm -Rf "/data/.gitkeep" "/data"/*/*.gitkeep 2>/dev/null || true + rm -Rf "/data/.gitkeep" "/data"/*/.gitkeep 2>/dev/null || true fi if [ -d "/config" ]; then - rm -Rf "/config/.gitkeep" "/config"/*/*.gitkeep 2>/dev/null || true + rm -Rf "/config/.gitkeep" "/config"/*/.gitkeep 2>/dev/null || true fi if [ -f "/usr/local/bin/.gitkeep" ]; then rm -Rf "/usr/local/bin/.gitkeep" 2>/dev/null || true @@ -442,7 +449,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" @@ -451,12 +458,12 @@ if [ -f "$ENTRYPOINT_PID_FILE" ]; then # PID file exists but process is dead - this is a restart START_SERVICES="yes" # Clean any stale PID files on restart - rm -f /run/__start_init_scripts.pid /run/init.d/*.pid /run/*.pid 2>/dev/null || true + rm -f /run/.start_init_scripts.pid /run/init.d/*.pid /run/*.pid 2>/dev/null || true fi else START_SERVICES=yes # Clean any stale PID files on first run - rm -f /run/__start_init_scripts.pid /run/init.d/*.pid /run/*.pid 2>/dev/null || true + rm -f /run/.start_init_scripts.pid /run/init.d/*.pid /run/*.pid 2>/dev/null || true fi # - - - - - - - - - - - - - - - - - - - - - - - - - [ "$ENTRYPOINT_MESSAGE" = "yes" ] && __printf_space "40" "The containers ip address is:" "$CONTAINER_IP4_ADDRESS" @@ -581,13 +588,13 @@ healthcheck) services="$(echo "${SERVICES_LIST//,/ }")" healthMessage="Everything seems to be running" [ "$healthEnabled" = "yes" ] || exit 0 - if [ -d "/run/healthcheck" ] && [ "$(ls -A "/run/healthcheck" | wc -l)" -ne 0 ]; then + if [ -d "/run/healthcheck" ] && ! __is_dir_empty "/run/healthcheck"; then for service in /run/healthcheck/*; do name="${service##*/}" services+="$name " done fi - services="$(echo "$services" | tr ' ' '\n' | sort -u | grep -v '^$')" + services="$(printf '%s\n' $services | sort -u | grep -v '^$')" for proc in $services; do if [ -n "$proc" ]; then if ! __pgrep "$proc"; then @@ -597,7 +604,7 @@ healthcheck) fi done for port in $ports; do - if [ -n "$(type -P netstat)" ] && [ -n "$port" ]; then + if command -v netstat &>/dev/null && [ -n "$port" ]; then if ! netstat -taupln | grep -q ":$port "; then echo "$port isn't open" >&2 healthStatus=$((healthStatus + 1)) @@ -621,14 +628,14 @@ healthcheck) # show open ports ports) shift 1 - ports="$(__netstat -taupln | awk -F ' ' '{print $4}' | awk -F ':' '{print $2}' | sort --unique --version-sort | grep -v '^$' | grep '^' || echo '')" + ports="$(__netstat -taupln 2>/dev/null | awk '{ split($4, a, ":"); if (a[2] != "") print a[2] }' | sort -uV)" [ -n "$ports" ] && printf '%s\n%s\n' "The following are servers:" "$ports" | tr '\n' ' ' exit $? ;; # show running processes procs) shift 1 - ps="$(__ps axco command | grep -vE 'COMMAND|grep|ps' | sort -u || grep '^' || echo '')" + ps="$(__ps axco command 2>/dev/null | grep -vE '^(COMMAND|grep|ps)$' | sort -u)" [ -n "$ps" ] && printf '%s\n%s\n' "Found the following processes" "$ps" | tr '\n' ' ' exit $? ;; 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/09-mariadb.sh b/rootfs/usr/local/etc/docker/init.d/09-mariadb.sh index 666a6c7..3b727e0 100755 --- a/rootfs/usr/local/etc/docker/init.d/09-mariadb.sh +++ b/rootfs/usr/local/etc/docker/init.d/09-mariadb.sh @@ -1,39 +1,118 @@ #!/usr/bin/env bash # shellcheck shell=bash -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# casjaysdevdocker/ampache - mariadb init.d (runs before 99-ampache.sh) -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# shellcheck disable=SC1003,SC2016,SC2031,SC2120,SC2155,SC2199,SC2317 -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -trap 'retVal=$?;[ "$SERVICE_IS_RUNNING" != "yes" ] && [ -f "$SERVICE_PID_FILE" ] && rm -Rf "$SERVICE_PID_FILE";exit $retVal' SIGINT SIGTERM EXIT -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -[ -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" +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202605131434-git +# @@Author : Jason Hempstead +# @@Contact : jason@casjaysdev.pro +# @@License : WTFPL +# @@ReadME : 09-mariadb.sh --help +# @@Copyright : Copyright: (c) 2026 Jason Hempstead, Casjays Developments +# @@Created : Wednesday, May 13, 2026 14:34 EDT +# @@File : 09-mariadb.sh +# @@Description : mariadb init.d script for casjaysdevdocker/ampache +# @@Changelog : New script +# @@TODO : Better documentation +# @@Other : +# @@Resource : +# @@Terminal App : no +# @@sudo/root : no +# @@Template : other/start-service +# - - - - - - - - - - - - - - - - - - - - - - - - - +# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329 +# - - - - - - - - - - - - - - - - - - - - - - - - - +set -e +# - - - - - - - - - - - - - - - - - - - - - - - - - +# run trap command on exit +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="mariadb" +SCRIPT_NAME="${SCRIPT_FILE##*/}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Function to exit appropriately based on context __script_exit() { - local exit_code="${1:-0}" - if [ "${BASH_SOURCE[0]}" != "${0}" ]; then return "$exit_code"; else 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)" -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 +# - - - - - - - - - - - - - - - - - - - - - - - - - +# 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 +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Script to execute START_SCRIPT="/usr/local/etc/docker/exec/$SERVICE_NAME" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Reset environment before executing service RESET_ENV="no" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Set webroot WWW_ROOT_DIR="/usr/local/share/ampache/public" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Default predefined variables DATA_DIR="/data/db/mariadb" CONF_DIR="/config/my.cnf.d" ETC_DIR="/etc/my.cnf.d" @@ -42,151 +121,214 @@ TMP_DIR="/tmp/mysql" RUN_DIR="/run/mysqld" LOG_DIR="/data/logs/mariadb" WORK_DIR="" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# port which service is listening on SERVICE_PORT="3306" +# - - - - - - - - - - - - - - - - - - - - - - - - - RUNAS_USER="root" SERVICE_USER="mysql" SERVICE_GROUP="mysql" +# - - - - - - - - - - - - - - - - - - - - - - - - - RANDOM_PASS_USER="" RANDOM_PASS_ROOT="" SERVICE_UID="0" SERVICE_GID="0" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# execute command variables - keep single quotes; variables will be expanded later EXEC_CMD_BIN='mariadbd' EXEC_CMD_ARGS='--user=$SERVICE_USER --datadir=$DATABASE_DIR --socket=/run/mysqld/mysqld.sock' EXEC_PRE_SCRIPT='' +# Set to 'no' for configuration services (no daemon process), leave blank for actual services +SERVICE_USES_PID='' +# - - - - - - - - - - - - - - - - - - - - - - - - - IS_WEB_SERVER="no" IS_DATABASE_SERVICE="yes" USES_DATABASE_SERVICE="no" DATABASE_SERVICE_TYPE="mariadb" +# - - - - - - - - - - - - - - - - - - - - - - - - - PRE_EXEC_MESSAGE="" POST_EXECUTE_WAIT_TIME="1" +# - - - - - - - - - - - - - - - - - - - - - - - - - PATH="$PATH:." +# - - - - - - - - - - - - - - - - - - - - - - - - - IP4_ADDRESS="$(__get_ip4)" IP6_ADDRESS="$(__get_ip6)" +# - - - - - - - - - - - - - - - - - - - - - - - - - ROOT_FILE_PREFIX="/config/secure/auth/root" USER_FILE_PREFIX="/config/secure/auth/user" +# - - - - - - - - - - - - - - - - - - - - - - - - - root_user_name="${MARIADB_ROOT_USER_NAME:-root}" root_user_pass="${MARIADB_ROOT_PASS_WORD:-random}" user_name="${MARIADB_USER_NAME:-ampache}" user_pass="${MARIADB_USER_PASS_WORD:-random}" DATABASE_CREATE="${DATABASE_CREATE:-ampache}" -[ -f "/config/env/mariadb.script.sh" ] && . "/config/env/mariadb.script.sh" -[ -f "/config/env/mariadb.sh" ] && . "/config/env/mariadb.sh" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Load variables from config +if [ -f "/config/env/mariadb.script.sh" ]; then + . "/config/env/mariadb.script.sh" +fi +if [ -f "/config/env/mariadb.sh" ]; then + . "/config/env/mariadb.sh" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - 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="" CMD_ENV="" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Custom functions + +# - - - - - - - - - - - - - - - - - - - - - - - - - __run_precopy() { - local hostname=${HOSTNAME} - if builtin type -t __run_precopy_local | grep -q 'function'; then __run_precopy_local; fi + local hostname=${HOSTNAME} + if [ ! -d "/run/healthcheck" ]; then + mkdir -p "/run/healthcheck" + fi + if builtin type -t __run_precopy_local | grep -q 'function'; then + __run_precopy_local + fi } +# - - - - - - - - - - - - - - - - - - - - - - - - - __execute_prerun() { - local hostname=${HOSTNAME} - mkdir -p /run/mysqld /data/db/mariadb /data/logs/mariadb - chown -Rf mysql:mysql /run/mysqld /data/db/mariadb /data/logs/mariadb 2>/dev/null || true - if builtin type -t __execute_prerun_local | grep -q 'function'; then __execute_prerun_local; fi + local hostname=${HOSTNAME} + mkdir -p /run/mysqld /data/db/mariadb /data/logs/mariadb + chown -Rf mysql:mysql /run/mysqld /data/db/mariadb /data/logs/mariadb 2>/dev/null || true + if builtin type -t __execute_prerun_local | grep -q 'function'; then + __execute_prerun_local + fi } +# - - - - - - - - - - - - - - - - - - - - - - - - - __run_pre_execute_checks() { - local exitStatus=0 - local pre_execute_checks_MessageST="Running preexecute check for $SERVICE_NAME" - local pre_execute_checks_MessageEnd="Finished preexecute check for $SERVICE_NAME" - __banner "$pre_execute_checks_MessageST" - { - if [ ! -d "$DATABASE_DIR" ] || [ ! -f "$DATABASE_DIR/ibdata1" ] && [ ! -d "$DATABASE_DIR/mysql" ]; then - rm -Rf "${DATABASE_DIR:?}"/* - mkdir -p "$DATABASE_DIR" - chown -Rf $SERVICE_USER:$SERVICE_GROUP "$DATABASE_DIR" - mariadb-install-db --datadir=$DATABASE_DIR --user=$SERVICE_USER --auth-root-authentication-method=normal 2>/dev/null || \ - mysql_install_db --datadir=$DATABASE_DIR --user=$SERVICE_USER 2>/dev/null - fi - } - exitStatus=$? - __banner "$pre_execute_checks_MessageEnd: Status $exitStatus" - 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 - if builtin type -t __run_pre_execute_checks_local | grep -q 'function'; then __run_pre_execute_checks_local; fi - return $exitStatus + local exitStatus=0 + local pre_execute_checks_MessageST="Running preexecute check for $SERVICE_NAME" + local pre_execute_checks_MessageEnd="Finished preexecute check for $SERVICE_NAME" + __banner "$pre_execute_checks_MessageST" + { + if [ ! -d "$DATABASE_DIR" ] || [ ! -f "$DATABASE_DIR/ibdata1" ] && [ ! -d "$DATABASE_DIR/mysql" ]; then + rm -Rf "${DATABASE_DIR:?}"/* + mkdir -p "$DATABASE_DIR" + chown -Rf $SERVICE_USER:$SERVICE_GROUP "$DATABASE_DIR" + mariadb-install-db --datadir=$DATABASE_DIR --user=$SERVICE_USER --auth-root-authentication-method=normal 2>/dev/null || \ + mysql_install_db --datadir=$DATABASE_DIR --user=$SERVICE_USER 2>/dev/null + fi + } + exitStatus=$? + __banner "$pre_execute_checks_MessageEnd: Status $exitStatus" + 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 + if builtin type -t __run_pre_execute_checks_local | grep -q 'function'; then + __run_pre_execute_checks_local + fi + return $exitStatus } +# - - - - - - - - - - - - - - - - - - - - - - - - - __update_conf_files() { - local exitCode=0 - local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" - if builtin type -t __update_conf_files_local | grep -q 'function'; then __update_conf_files_local; fi - return $exitCode + local exitCode=0 + local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" + if builtin type -t __update_conf_files_local | grep -q 'function'; then + __update_conf_files_local + fi + return $exitCode } +# - - - - - - - - - - - - - - - - - - - - - - - - - __pre_execute() { - local exitCode=0 - sleep 5 - if builtin type -t __pre_execute_local | grep -q 'function'; then __pre_execute_local; fi - return $exitCode + local exitCode=0 + local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" + sleep 5 + unset sysname + if builtin type -t __pre_execute_local | grep -q 'function'; then + __pre_execute_local + fi + return $exitCode } +# - - - - - - - - - - - - - - - - - - - - - - - - - __post_execute() { - local pid="" - local retVal=0 - local ctime=${POST_EXECUTE_WAIT_TIME:-1} - local waitTime=$((ctime * 60)) - local postMessageST="Running post commands for $SERVICE_NAME" - local postMessageEnd="Finished post commands for $SERVICE_NAME" - local DATABASE_ROOT_PASSWORD="${root_user_pass:-$(__random_password)}" - local db_root_user="${MYSQL_ROOT_USER_NAME:-root}" - echo "$DATABASE_ROOT_PASSWORD" >"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_pass" 2>/dev/null || true - sleep $waitTime - ( - __banner "$postMessageST" - # Wait for socket - local i=0 - while [ ! -S /run/mysqld/mysqld.sock ] && [ $i -lt 30 ]; do sleep 1; i=$((i+1)); done - if [ -f "$CONF_DIR/init.sh" ]; then bash -c "$CONF_DIR/init.sh"; fi - if [ -n "$DATABASE_CREATE" ]; then - mariadb -v -u $db_root_user <"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_pass" 2>/dev/null || true + sleep $waitTime + ( + __banner "$postMessageST" + # Wait for socket + local i=0 + while [ ! -S /run/mysqld/mysqld.sock ] && [ $i -lt 30 ]; do sleep 1; i=$((i+1)); done + if [ -f "$CONF_DIR/init.sh" ]; then bash -c "$CONF_DIR/init.sh"; fi + if [ -n "$DATABASE_CREATE" ]; then + mariadb -v -u $db_root_user <"/dev/stderr" | tee -p -a "/data/logs/init.txt" & - pid=$! - if builtin type -t __post_execute_local | grep -q 'function'; then __post_execute_local; fi - return $retVal + __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 + if builtin type -t __post_execute_local | grep -q 'function'; then + __post_execute_local + fi + return $retVal } +# - - - - - - - - - - - - - - - - - - - - - - - - - __pre_message() { - local exitCode=0 - [ -n "$PRE_EXEC_MESSAGE" ] && eval echo "$PRE_EXEC_MESSAGE" - if builtin type -t __pre_message_local | grep -q 'function'; then __pre_message_local; fi - return $exitCode + local exitCode=0 + if [ -n "$PRE_EXEC_MESSAGE" ]; then + eval echo "$PRE_EXEC_MESSAGE" + fi + if builtin type -t __pre_message_local | grep -q 'function'; then + __pre_message_local + fi + return $exitCode } +# - - - - - - - - - - - - - - - - - - - - - - - - - __update_ssl_conf() { - local exitCode=0 - if builtin type -t __update_ssl_conf_local | grep -q 'function'; then __update_ssl_conf_local; fi - return $exitCode + local exitCode=0 + local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" + if builtin type -t __update_ssl_conf_local | grep -q 'function'; then + __update_ssl_conf_local + fi + 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 +# - - - - - - - - - - - - - - - - - - - - - - - - - # Generated by 09-mariadb.sh - edit to override defaults #root_user_name="root" #root_user_pass="random" @@ -194,125 +336,281 @@ __create_service_env() { #user_pass="random" #DATABASE_CREATE="ampache" 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 } +# - - - - - - - - - - - - - - - - - - - - - - - - - __run_start_script() { - local runExitCode=0 - local workdir="$(eval echo "${WORK_DIR:-}")" - local cmd="$(eval echo "${EXEC_CMD_BIN:-}")" - local args="$(eval echo "${EXEC_CMD_ARGS:-}")" - local name="$(eval echo "${EXEC_CMD_NAME:-}")" - local pre="$(eval echo "${EXEC_PRE_SCRIPT:-}")" - local extra_env="$(eval echo "${CMD_ENV//,/ }")" - local lc_type="$(eval echo "${LANG:-${LC_ALL:-$LC_CTYPE}}")" - local home="$(eval echo "${workdir//\/root/\/tmp\/docker}")" - local path="$(eval echo "$PATH")" - local message="$(eval echo "")" - local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$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 - if [ ! -x "$cmd" ]; then echo "$name is not a valid executable"; return 2; fi - if __proc_check "$name" || __proc_check "$cmd"; then echo "$name is already running" >&2; return 0; fi - [ -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="" - export cmd_exec="$cmd $args" - message="Starting service: $name $args" - [ -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" - execute_command="$(__trim "$su_exec $cmd_exec")" - if [ ! -f "$START_SCRIPT" ]; then - cat <"$START_SCRIPT" + local runExitCode=0 + local workdir="$(eval echo "${WORK_DIR:-}")" + local cmd="$(eval echo "${EXEC_CMD_BIN:-}")" + local args="$(eval echo "${EXEC_CMD_ARGS:-}")" + local name="$(eval echo "${EXEC_CMD_NAME:-}")" + local pre="$(eval echo "${EXEC_PRE_SCRIPT:-}")" + local extra_env="$(eval echo "${CMD_ENV//,/ }")" + local lc_type="$(eval echo "${LANG:-${LC_ALL:-$LC_CTYPE}}")" + local home="$(eval echo "${workdir//\/root/\/tmp\/docker}")" + local path="$(eval echo "$PATH")" + 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 + if [ ! -x "$cmd" ]; then + __log_error "$name is not a valid executable" + return 2 + fi + if __proc_check "$name" || __proc_check "$cmd"; then + __log_debug "Service $name is already running" + return 0 + else + 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" + execute_command="$(__trim "$su_exec $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} 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 -exit \$retVal -EOF - fi - [ -x "$START_SCRIPT" ] || chmod 755 -Rf "$START_SCRIPT" - [ "$CONTAINER_INIT" = "yes" ] || eval sh -c "$START_SCRIPT" - runExitCode=$? - fi - return $runExitCode -} -__run_secure_function() { - local filesperms - for filesperms in "${USER_FILE_PREFIX}"/* "${ROOT_FILE_PREFIX}"/*; do - [ -e "$filesperms" ] && { chmod -Rf 600 "$filesperms"; chown -Rf $SERVICE_USER:$SERVICE_USER "$filesperms" 2>/dev/null; } - done 2>/dev/null - unset filesperms -} -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -__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 -EXEC_CMD_NAME="$(basename -- "$EXEC_CMD_BIN")" -SERVICE_PID_FILE="/run/init.d/$EXEC_CMD_NAME.pid" -SERVICE_PID_NUMBER="$(__pgrep)" -EXEC_CMD_BIN="$(type -P "$EXEC_CMD_BIN" || echo "$EXEC_CMD_BIN")" -EXEC_PRE_SCRIPT="$(type -P "$EXEC_PRE_SCRIPT" || echo "$EXEC_PRE_SCRIPT")" -__check_service "$1" && SERVICE_IS_RUNNING=yes -[ -d "$LOG_DIR" ] || mkdir -p "$LOG_DIR" -[ -d "$RUN_DIR" ] || mkdir -p "$RUN_DIR" -[ -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}" -if [ "$IS_DATABASE_SERVICE" = "yes" ]; then - 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}}" - [ -n "$DATABASE_PASS_NORMAL" ] && [ ! -f "${USER_FILE_PREFIX}/db_pass_user" ] && echo "$DATABASE_PASS_NORMAL" >"${USER_FILE_PREFIX}/db_pass_user" - [ -n "$DATABASE_PASS_ROOT" ] && [ ! -f "${ROOT_FILE_PREFIX}/db_pass_root" ] && echo "$DATABASE_PASS_ROOT" >"${ROOT_FILE_PREFIX}/db_pass_root" +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 + 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 +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__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 +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Allow ENV_ variable - Import env file +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="${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 +# - - - - - - - - - - - - - - - - - - - - - - - - - +if __check_service "$1"; then + SERVICE_IS_RUNNING=yes +else + SERVICE_IS_RUNNING="no" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +if [ ! -d "$LOG_DIR" ]; then + mkdir -p "$LOG_DIR" +fi +if [ ! -d "$RUN_DIR" ]; then + mkdir -p "$RUN_DIR" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +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 +# - - - - - - - - - - - - - - - - - - - - - - - - - +# 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" ]; 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="${DATABASE_DIR_MARIADB:-/data/db/mariadb}" DATABASE_BASE_DIR="$DATABASE_DIR" -[ -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" ] && . "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" -[ "$user_pass" = "random" ] && user_pass="$(__random_password ${RANDOM_PASS_USER:-16})" -[ "$root_user_pass" = "random" ] && root_user_pass="$(__random_password ${RANDOM_PASS_ROOT:-16})" -[ -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" -[ -d "$LOG_DIR" ] || mkdir -p "$LOG_DIR" -[ -d "$RUN_DIR" ] || mkdir -p "$RUN_DIR" -__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")" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Allow variables via imports - Overwrite existing +if [ -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" ]; then + . "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +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 +# - - - - - - - - - - - - - - - - - - - - - - - - - +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 +# - - - - - - - - - - - - - - - - - - - - - - - - - +if [ ! -d "$LOG_DIR" ]; then + mkdir -p "$LOG_DIR" +fi +if [ ! -d "$RUN_DIR" ]; then + mkdir -p "$RUN_DIR" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +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 +# - - - - - - - - - - - - - - - - - - - - - - - - - sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" +# - - - - - - - - - - - - - - - - - - - - - - - - - __create_service_env __init_config_etc __execute_prerun @@ -328,7 +626,7 @@ __update_ssl_certs __run_secure_function __run_precopy 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 __initialize_replace_variables "$ETC_DIR" "$CONF_DIR" "$ADDITIONAL_CONFIG_DIRS" "$WWW_ROOT_DIR" __initialize_database @@ -339,9 +637,23 @@ __run_pre_execute_checks 2>/dev/stderr | tee -a -p "/data/logs/entrypoint.log" " __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 +# - - - - - - - - - - - - - - - - - - - - - - - - - __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 +# - - - - - - - - - - - - - - - - - - - - - - - - - +# ex: ts=2 sw=2 et filetype=sh +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/etc/docker/init.d/99-ampache.sh b/rootfs/usr/local/etc/docker/init.d/99-ampache.sh index 202ed44..d02fa27 100755 --- a/rootfs/usr/local/etc/docker/init.d/99-ampache.sh +++ b/rootfs/usr/local/etc/docker/init.d/99-ampache.sh @@ -1,38 +1,118 @@ #!/usr/bin/env bash # shellcheck shell=bash -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# casjaysdevdocker/ampache - apache + php-fpm init.d (runs after 09-mariadb.sh) -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# shellcheck disable=SC1003,SC2016,SC2031,SC2120,SC2155,SC2199,SC2317 -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -trap 'retVal=$?;[ "$SERVICE_IS_RUNNING" != "yes" ] && [ -f "$SERVICE_PID_FILE" ] && rm -Rf "$SERVICE_PID_FILE";exit $retVal' SIGINT SIGTERM EXIT -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -[ -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" +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202605131434-git +# @@Author : Jason Hempstead +# @@Contact : jason@casjaysdev.pro +# @@License : WTFPL +# @@ReadME : 99-ampache.sh --help +# @@Copyright : Copyright: (c) 2026 Jason Hempstead, Casjays Developments +# @@Created : Wednesday, May 13, 2026 14:34 EDT +# @@File : 99-ampache.sh +# @@Description : apache + php-fpm init.d script for casjaysdevdocker/ampache +# @@Changelog : New script +# @@TODO : Better documentation +# @@Other : +# @@Resource : +# @@Terminal App : no +# @@sudo/root : no +# @@Template : other/start-service +# - - - - - - - - - - - - - - - - - - - - - - - - - +# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329 +# - - - - - - - - - - - - - - - - - - - - - - - - - +set -e +# - - - - - - - - - - - - - - - - - - - - - - - - - +# run trap command on exit +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="ampache" +SCRIPT_NAME="${SCRIPT_FILE##*/}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Function to exit appropriately based on context __script_exit() { - local exit_code="${1:-0}" - if [ "${BASH_SOURCE[0]}" != "${0}" ]; then return "$exit_code"; else 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)" -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 +# - - - - - - - - - - - - - - - - - - - - - - - - - +# 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 +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Script to execute START_SCRIPT="/usr/local/etc/docker/exec/$SERVICE_NAME" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Reset environment before executing service RESET_ENV="no" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Set webroot WWW_ROOT_DIR="/usr/local/share/ampache/public" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Default predefined variables DATA_DIR="/data/ampache" CONF_DIR="/config/apache2" ETC_DIR="/etc/apache2" @@ -41,213 +121,524 @@ TMP_DIR="/tmp/ampache" RUN_DIR="/run/apache2" LOG_DIR="/data/logs/apache2" WORK_DIR="" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# port which service is listening on SERVICE_PORT="80" +# - - - - - - - - - - - - - - - - - - - - - - - - - RUNAS_USER="root" SERVICE_USER="apache" SERVICE_GROUP="apache" +# - - - - - - - - - - - - - - - - - - - - - - - - - RANDOM_PASS_USER="" RANDOM_PASS_ROOT="" SERVICE_UID="0" SERVICE_GID="0" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# execute command variables - keep single quotes; variables will be expanded later EXEC_CMD_BIN='/usr/local/etc/docker/bin/start-ampache' EXEC_CMD_ARGS='' EXEC_PRE_SCRIPT='' +# Set to 'no' for configuration services (no daemon process), leave blank for actual services +SERVICE_USES_PID='' +# - - - - - - - - - - - - - - - - - - - - - - - - - IS_WEB_SERVER="yes" IS_DATABASE_SERVICE="no" USES_DATABASE_SERVICE="yes" DATABASE_SERVICE_TYPE="mariadb" +# - - - - - - - - - - - - - - - - - - - - - - - - - PRE_EXEC_MESSAGE="Open http://localhost:${SERVICE_PORT:-80}/ to run the Ampache web installer." POST_EXECUTE_WAIT_TIME="1" +# - - - - - - - - - - - - - - - - - - - - - - - - - PATH="$PATH:." +# - - - - - - - - - - - - - - - - - - - - - - - - - IP4_ADDRESS="$(__get_ip4)" IP6_ADDRESS="$(__get_ip6)" +# - - - - - - - - - - - - - - - - - - - - - - - - - ROOT_FILE_PREFIX="/config/secure/auth/root" USER_FILE_PREFIX="/config/secure/auth/user" +# - - - - - - - - - - - - - - - - - - - - - - - - - root_user_name="${AMPACHE_ROOT_USER_NAME:-}" root_user_pass="${AMPACHE_ROOT_PASS_WORD:-}" user_name="${AMPACHE_USER_NAME:-}" user_pass="${AMPACHE_USER_PASS_WORD:-}" -[ -f "/config/env/ampache.script.sh" ] && . "/config/env/ampache.script.sh" -[ -f "/config/env/ampache.sh" ] && . "/config/env/ampache.sh" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Load variables from config +if [ -f "/config/env/ampache.script.sh" ]; then + . "/config/env/ampache.script.sh" +fi +if [ -f "/config/env/ampache.sh" ]; then + . "/config/env/ampache.sh" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - ADD_APPLICATION_FILES="" ADD_APPLICATION_DIRS="/usr/local/share/ampache /usr/local/share/ampache/config /tmp/php-sessions" APPLICATION_FILES="$LOG_DIR/$SERVICE_NAME.log" APPLICATION_DIRS="$ETC_DIR $CONF_DIR $LOG_DIR $TMP_DIR $RUN_DIR $VAR_DIR /run/php-fpm /data/logs/php-fpm" ADDITIONAL_CONFIG_DIRS="/config/php84 /config/ampache" CMD_ENV="" -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Custom functions + +# - - - - - - - - - - - - - - - - - - - - - - - - - __run_precopy() { - local hostname=${HOSTNAME} - if builtin type -t __run_precopy_local | grep -q 'function'; then __run_precopy_local; fi + local hostname=${HOSTNAME} + if [ ! -d "/run/healthcheck" ]; then + mkdir -p "/run/healthcheck" + fi + if builtin type -t __run_precopy_local | grep -q 'function'; then + __run_precopy_local + fi } +# - - - - - - - - - - - - - - - - - - - - - - - - - __execute_prerun() { - local hostname=${HOSTNAME} - # Ensure runtime dirs - mkdir -p /run/apache2 /run/php-fpm /tmp/php-sessions \ - /data/logs/apache2 /data/logs/php-fpm /data/ampache - chown -Rf apache:apache /run/apache2 /run/php-fpm /tmp/php-sessions \ - /data/logs/apache2 /data/logs/php-fpm 2>/dev/null || true - # Ampache writable dirs - if [ -d /usr/local/share/ampache ]; then - mkdir -p /usr/local/share/ampache/config - chown -Rf apache:apache /usr/local/share/ampache/config 2>/dev/null || true - # Live ampache.cfg.php is mirrored out to /config/ampache/ once install.php writes it. - if [ -f /usr/local/share/ampache/config/ampache.cfg.php ] && [ ! -L /usr/local/share/ampache/config/ampache.cfg.php ]; then - cp -f /usr/local/share/ampache/config/ampache.cfg.php /config/ampache/ampache.cfg.php 2>/dev/null || true - ln -sf /config/ampache/ampache.cfg.php /usr/local/share/ampache/config/ampache.cfg.php - elif [ -f /config/ampache/ampache.cfg.php ] && [ ! -e /usr/local/share/ampache/config/ampache.cfg.php ]; then - ln -sf /config/ampache/ampache.cfg.php /usr/local/share/ampache/config/ampache.cfg.php - fi - fi - if builtin type -t __execute_prerun_local | grep -q 'function'; then __execute_prerun_local; fi + local hostname=${HOSTNAME} + # Ensure runtime dirs + mkdir -p /run/apache2 /run/php-fpm /tmp/php-sessions \ + /data/logs/apache2 /data/logs/php-fpm /data/ampache + chown -Rf apache:apache /run/apache2 /run/php-fpm /tmp/php-sessions \ + /data/logs/apache2 /data/logs/php-fpm 2>/dev/null || true + # Ampache writable dirs + if [ -d /usr/local/share/ampache ]; then + mkdir -p /usr/local/share/ampache/config + chown -Rf apache:apache /usr/local/share/ampache/config 2>/dev/null || true + # Live ampache.cfg.php is mirrored out to /config/ampache/ once install.php writes it. + if [ -f /usr/local/share/ampache/config/ampache.cfg.php ] && [ ! -L /usr/local/share/ampache/config/ampache.cfg.php ]; then + cp -f /usr/local/share/ampache/config/ampache.cfg.php /config/ampache/ampache.cfg.php 2>/dev/null || true + ln -sf /config/ampache/ampache.cfg.php /usr/local/share/ampache/config/ampache.cfg.php + elif [ -f /config/ampache/ampache.cfg.php ] && [ ! -e /usr/local/share/ampache/config/ampache.cfg.php ]; then + ln -sf /config/ampache/ampache.cfg.php /usr/local/share/ampache/config/ampache.cfg.php + fi + fi + if builtin type -t __execute_prerun_local | grep -q 'function'; then + __execute_prerun_local + fi } +# - - - - - - - - - - - - - - - - - - - - - - - - - __run_pre_execute_checks() { - local exitStatus=0 - __banner "Running preexecute check for $SERVICE_NAME" - # Wait briefly for mariadb socket - local i=0 - while [ ! -S /run/mysqld/mysqld.sock ] && [ $i -lt 30 ]; do sleep 1; i=$((i+1)); done - if [ ! -S /run/mysqld/mysqld.sock ]; then - echo "Warning: mariadb socket not found after 30s; ampache install.php will need it before continuing" >&2 - fi - # Validate apache config syntax - httpd -t -f /etc/apache2/httpd.conf 2>&1 | head -20 || exitStatus=$? - __banner "Finished preexecute check for $SERVICE_NAME: Status $exitStatus" - 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 - if builtin type -t __run_pre_execute_checks_local | grep -q 'function'; then __run_pre_execute_checks_local; fi - return $exitStatus + local exitStatus=0 + local pre_execute_checks_MessageST="Running preexecute check for $SERVICE_NAME" + local pre_execute_checks_MessageEnd="Finished preexecute check for $SERVICE_NAME" + __banner "$pre_execute_checks_MessageST" + { + # Wait briefly for mariadb socket + local i=0 + while [ ! -S /run/mysqld/mysqld.sock ] && [ $i -lt 30 ]; do sleep 1; i=$((i+1)); done + if [ ! -S /run/mysqld/mysqld.sock ]; then + echo "Warning: mariadb socket not found after 30s; ampache install.php will need it before continuing" >&2 + fi + # Validate apache config syntax + httpd -t -f /etc/apache2/httpd.conf 2>&1 | head -20 || exitStatus=$? + } + exitStatus=$? + __banner "$pre_execute_checks_MessageEnd: Status $exitStatus" + 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 + if builtin type -t __run_pre_execute_checks_local | grep -q 'function'; then + __run_pre_execute_checks_local + fi + return $exitStatus } +# - - - - - - - - - - - - - - - - - - - - - - - - - __update_conf_files() { - local exitCode=0 - local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" - __replace "REPLACE_TZ" "${TZ:-UTC}" "/etc/php84/php.ini" - if builtin type -t __update_conf_files_local | grep -q 'function'; then __update_conf_files_local; fi - return $exitCode + local exitCode=0 + local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" + __replace "REPLACE_TZ" "${TZ:-UTC}" "/etc/php84/php.ini" + if builtin type -t __update_conf_files_local | grep -q 'function'; then + __update_conf_files_local + fi + return $exitCode } +# - - - - - - - - - - - - - - - - - - - - - - - - - __pre_execute() { - local exitCode=0 - sleep 5 - if builtin type -t __pre_execute_local | grep -q 'function'; then __pre_execute_local; fi - return $exitCode + local exitCode=0 + local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" + unset sysname + sleep 5 + if builtin type -t __pre_execute_local | grep -q 'function'; then + __pre_execute_local + fi + return $exitCode } +# - - - - - - - - - - - - - - - - - - - - - - - - - __post_execute() { - local pid="" - local retVal=0 - local ctime=${POST_EXECUTE_WAIT_TIME:-1} - local waitTime=$((ctime * 60)) - sleep $waitTime - ( - __banner "Running post commands for $SERVICE_NAME" - # Mirror live ampache.cfg.php out to /config once install.php has written it - if [ -f /usr/local/share/ampache/config/ampache.cfg.php ] && [ ! -L /usr/local/share/ampache/config/ampache.cfg.php ]; then - cp -f /usr/local/share/ampache/config/ampache.cfg.php /config/ampache/ampache.cfg.php - ln -sf /config/ampache/ampache.cfg.php /usr/local/share/ampache/config/ampache.cfg.php - fi - __banner "Finished post commands for $SERVICE_NAME: Status $retVal" - ) 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt" & - pid=$! - if builtin type -t __post_execute_local | grep -q 'function'; then __post_execute_local; fi - return $retVal + local pid="" + local retVal=0 + local ctime=${POST_EXECUTE_WAIT_TIME:-1} + local waitTime=$((ctime * 60)) + local postMessageST="Running post commands for $SERVICE_NAME" + local postMessageEnd="Finished post commands for $SERVICE_NAME" + sleep $waitTime + ( + __banner "$postMessageST" + # Mirror live ampache.cfg.php out to /config once install.php has written it + if [ -f /usr/local/share/ampache/config/ampache.cfg.php ] && [ ! -L /usr/local/share/ampache/config/ampache.cfg.php ]; then + cp -f /usr/local/share/ampache/config/ampache.cfg.php /config/ampache/ampache.cfg.php + ln -sf /config/ampache/ampache.cfg.php /usr/local/share/ampache/config/ampache.cfg.php + fi + __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 + if builtin type -t __post_execute_local | grep -q 'function'; then + __post_execute_local + fi + return $retVal } +# - - - - - - - - - - - - - - - - - - - - - - - - - __pre_message() { - local exitCode=0 - [ -n "$PRE_EXEC_MESSAGE" ] && eval echo "$PRE_EXEC_MESSAGE" - if builtin type -t __pre_message_local | grep -q 'function'; then __pre_message_local; fi - return $exitCode + local exitCode=0 + if [ -n "$PRE_EXEC_MESSAGE" ]; then + eval echo "$PRE_EXEC_MESSAGE" + fi + if builtin type -t __pre_message_local | grep -q 'function'; then + __pre_message_local + fi + return $exitCode } +# - - - - - - - - - - - - - - - - - - - - - - - - - __update_ssl_conf() { - local exitCode=0 - if builtin type -t __update_ssl_conf_local | grep -q 'function'; then __update_ssl_conf_local; fi - return $exitCode + local exitCode=0 + local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" + if builtin type -t __update_ssl_conf_local | grep -q 'function'; then + __update_ssl_conf_local + fi + 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 +# - - - - - - - - - - - - - - - - - - - - - - - - - # Generated by 99-ampache.sh - edit to override defaults #user_name="" #user_pass="" 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 } +# - - - - - - - - - - - - - - - - - - - - - - - - - __run_start_script() { - local runExitCode=0 - local cmd="$(eval echo "${EXEC_CMD_BIN:-}")" - local args="$(eval echo "${EXEC_CMD_ARGS:-}")" - local name="$(eval echo "${EXEC_CMD_NAME:-}")" - local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" - [ -f "$CONF_DIR/$SERVICE_NAME.exec_cmd.sh" ] && . "$CONF_DIR/$SERVICE_NAME.exec_cmd.sh" - if [ ! -x "$cmd" ]; then echo "$cmd is not executable" >&2; return 2; fi - if __proc_check "httpd"; then echo "httpd already running" >&2; return 0; fi - echo "Starting $cmd $args" | tee -a -p "/data/logs/init.txt" - su_cmd touch "$SERVICE_PID_FILE" - if [ ! -f "$START_SCRIPT" ]; then - cat <"$START_SCRIPT" + local runExitCode=0 + local workdir="$(eval echo "${WORK_DIR:-}")" + local cmd="$(eval echo "${EXEC_CMD_BIN:-}")" + local args="$(eval echo "${EXEC_CMD_ARGS:-}")" + local name="$(eval echo "${EXEC_CMD_NAME:-}")" + local pre="$(eval echo "${EXEC_PRE_SCRIPT:-}")" + local extra_env="$(eval echo "${CMD_ENV//,/ }")" + local lc_type="$(eval echo "${LANG:-${LC_ALL:-$LC_CTYPE}}")" + local home="$(eval echo "${workdir//\/root/\/tmp\/docker}")" + local path="$(eval echo "$PATH")" + 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 + if [ ! -x "$cmd" ]; then + __log_error "$name is not a valid executable" + return 2 + fi + if __proc_check "$name" || __proc_check "$cmd"; then + __log_debug "Service $name is already running" + return 0 + else + 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" -$cmd $args 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 3 -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 $cmd $args" >&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 - [ -x "$START_SCRIPT" ] || chmod 755 -Rf "$START_SCRIPT" - [ "$CONTAINER_INIT" = "yes" ] || eval sh -c "$START_SCRIPT" - runExitCode=$? - return $runExitCode + fi + else + if [ ! -f "$START_SCRIPT" ]; then + execute_command="$(__trim "$su_exec $cmd_exec")" + cat <"$START_SCRIPT" +#!/usr/bin/env bash +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" +LOG_DIR="$LOG_DIR" +execute_command="$execute_command" +\$execute_command 2>>"/dev/stderr" >>"\$LOG_DIR/\$SERVICE_NAME.log" & +execPid=\$! +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 + 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 } +# - - - - - - - - - - - - - - - - - - - - - - - - - __run_secure_function() { - local filesperms - for filesperms in "${USER_FILE_PREFIX}"/* "${ROOT_FILE_PREFIX}"/*; do - [ -e "$filesperms" ] && { chmod -Rf 600 "$filesperms"; chown -Rf $SERVICE_USER:$SERVICE_USER "$filesperms" 2>/dev/null; } - done 2>/dev/null - 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 } -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -__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" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Allow ENV_ variable - Import env file +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 -EXEC_CMD_NAME="$(basename -- "$EXEC_CMD_BIN")" +# application specific +EXEC_CMD_NAME="${EXEC_CMD_BIN##*/}" SERVICE_PID_FILE="/run/init.d/$EXEC_CMD_NAME.pid" -SERVICE_PID_NUMBER="$(__pgrep)" -__check_service "$1" && SERVICE_IS_RUNNING=yes -[ -d "$LOG_DIR" ] || mkdir -p "$LOG_DIR" -[ -d "$RUN_DIR" ] || mkdir -p "$RUN_DIR" -[ -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" -[ -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" ] && . "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" +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 +# - - - - - - - - - - - - - - - - - - - - - - - - - +if __check_service "$1"; then + SERVICE_IS_RUNNING=yes +else + SERVICE_IS_RUNNING="no" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +if [ ! -d "$LOG_DIR" ]; then + mkdir -p "$LOG_DIR" +fi +if [ ! -d "$RUN_DIR" ]; then + mkdir -p "$RUN_DIR" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +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" ]; 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="${DATABASE_DIR_MARIADB:-/data/db/mariadb}" +DATABASE_BASE_DIR="$DATABASE_DIR" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Allow variables via imports - Overwrite existing +if [ -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" ]; then + . "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +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 +# - - - - - - - - - - - - - - - - - - - - - - - - - +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 +# - - - - - - - - - - - - - - - - - - - - - - - - - +if [ ! -d "$LOG_DIR" ]; then + mkdir -p "$LOG_DIR" +fi +if [ ! -d "$RUN_DIR" ]; then + mkdir -p "$RUN_DIR" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +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 +# - - - - - - - - - - - - - - - - - - - - - - - - - sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" +# - - - - - - - - - - - - - - - - - - - - - - - - - __create_service_env __init_config_etc __execute_prerun @@ -257,14 +648,16 @@ __setup_directories __switch_to_user __init_working_dir __pre_message +__initialize_db_users __update_ssl_conf __update_ssl_certs __run_secure_function __run_precopy 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 __initialize_replace_variables "$ETC_DIR" "$CONF_DIR" "$ADDITIONAL_CONFIG_DIRS" "$WWW_ROOT_DIR" +__initialize_database __update_conf_files __pre_execute __fix_permissions "$SERVICE_USER" "$SERVICE_GROUP" @@ -272,9 +665,23 @@ __run_pre_execute_checks 2>/dev/stderr | tee -a -p "/data/logs/entrypoint.log" " __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 +# - - - - - - - - - - - - - - - - - - - - - - - - - __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 +# - - - - - - - - - - - - - - - - - - - - - - - - - +# ex: ts=2 sw=2 et filetype=sh +# - - - - - - - - - - - - - - - - - - - - - - - - -