🔧 Update configuration files 🔧
All checks were successful
ampache / release-ampache (push) Successful in 21m48s

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
This commit is contained in:
casjay
2026-05-18 15:38:13 -04:00
parent c07f970f14
commit eb715f59b7
17 changed files with 1711 additions and 1165 deletions

View File

@@ -1,10 +1,10 @@
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
##@Version : 202509161146-git ##@Version : 202605131434-git
# @@Author : CasjaysDev # @@Author : CasjaysDev
# @@Contact : CasjaysDev <docker-admin@casjaysdev.pro> # @@Contact : CasjaysDev <docker-admin@casjaysdev.pro>
# @@License : MIT # @@License : MIT
# @@Copyright : Copyright 2025 CasjaysDev # @@Copyright : Copyright 2026 CasjaysDev
# @@Created : Tue Sep 16 11:46:10 AM EDT 2025 # @@Created : Wed May 13 02:34:14 PM EDT 2026
# @@File : .env.scripts # @@File : .env.scripts
# @@Description : Variables for gen-dockerfile and buildx scripts # @@Description : Variables for gen-dockerfile and buildx scripts
# @@Changelog : newScript # @@Changelog : newScript

86
AI.md Normal file
View File

@@ -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`

396
CLAUDE.md
View File

@@ -1,395 +1 @@
# casjaysdevdocker repo template spec 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.
This file is the **canonical spec** for what a properly-set-up `casjaysdevdocker/<repo>` 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 `<repo>/CLAUDE.md` (a copy of this file) and `<repo>/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/<svc>` (volume).
- Stores runtime data, logs, DB files under `/data` (volume).
- Ships a single, **highly-optimized** config in `rootfs/tmp/etc/<svc>/` 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/<app>`, 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/<svc>` 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 <upstream>/<image>: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)
```
<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-<svc>.sh
│ └── init.d/
│ └── 99-<svc>.sh # PER-REPO; defines SERVICE_NAME, ETC_DIR, CONF_DIR, EXEC_CMD_BIN/ARGS, hooks
├── usr/local/share/
│ ├── <app>/ # 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/<svc>/ on first run by __initialize_config_dir
│ ├── data/ # templates copied to /data/<svc>/ on first run
│ └── defaults/ # default fallbacks
├── tmp/etc/<svc>/ # PER-REPO optimized configs; copied to /etc/<svc>/ 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="<svc>"` 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/<app>/`.
---
## 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/<svc>/` contains **only** our optimized config, never distro defaults.
**Build time:**
1. Service package install (e.g., `apk add nginx`) creates distro defaults under `/etc/<svc>/` (e.g., `/etc/nginx/{nginx.conf, conf.d/, modules-enabled/, http.d/, mime.types, …}`).
2. `03-files.sh` copies `rootfs/tmp/etc/<svc>/*``/etc/<svc>/*` (overlay only) **and** stages a copy at `/usr/local/share/template-files/config/<svc>/` for runtime seeding.
3. `05-custom.sh` performs the **wipe-and-replace** (the canonical idiom):
```sh
if [ -d "/tmp/etc/<svc>" ]; then
# preserve distro-shipped files we need (e.g., mime.types when not in tmp/etc/)
# then wipe defaults
rm -Rf "/etc/<svc>"/*
cp -Rf "/tmp/etc/<svc>/." "/etc/<svc>/"
fi
```
For services that auto-discover sub-confs, our `<svc>.conf` ends with an **optional** include like `include /config/<svc>/vhosts.d/*.conf;` (nginx) or `IncludeOptional /config/<svc>/conf.d/*.conf` (apache) so an empty include dir doesn't crash startup.
**Runtime (entrypoint + 99-<svc>.sh):**
1. `entrypoint.sh` calls `__initialize_default_templates` / `__initialize_config_dir` / `__initialize_data_dir` which copy `template-files/{defaults,config,data}/<svc>/*``/config/<svc>/` and `/data/<svc>/` **only when those target dirs are not already initialized** (via `/config/.docker_has_run` and `/data/.docker_has_run` markers).
2. `99-<svc>.sh` calls `__initialize_system_etc "$CONF_DIR"` which symlinks/copies the user-editable `/config/<svc>/<file>` → the service's expected runtime path (`/etc/<svc>/<file>` for system services; `/usr/local/share/<app>/config/<file>` for app-stack repos).
3. `99-<svc>.sh` also ensures runtime dirs exist: `vhosts.d/`, `conf.d/`, `ssl/`, `secure/auth/`, log dirs under `/data/logs/<svc>/`.
4. Service starts pointing at `/etc/<svc>/<svc>.conf` (or equivalent), which transitively reads from `/config/<svc>/`.
Net effect: end users edit files under `/config/<svc>/` (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/<svc>/*`).
- Hardcoding paths in our config that point inside `/etc/<svc>/` instead of `/config/<svc>/` for things users should customize.
- Copying `template-files/config/<svc>/*` into `/config/<svc>/` 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="<repo>"
ARG PHP_SERVER="<repo>" # often same as IMAGE_NAME
ARG BUILD_DATE="<YYYYMMDDHHMM>" # 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="<primary port for healthcheck/EXPOSE>"
ARG EXPOSE_PORTS="<additional space-separated ports>"
ARG PHP_VERSION="<php82|php83|php84|system|none>"
ARG NODE_VERSION="system"
ARG NODE_MANAGER="system"
ARG IMAGE_REPO="<org>/<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="<all packages this stack needs, space-separated, trailing space>"
```
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 <tmp> 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="<repo>" # was ENV_IMAGE_NAME
ENV_USE_TEMPLATE="alpine" # or "almalinux", "debian", "ubuntu"
ENV_REGISTRY_ORG="<casjaysdevdocker | casjaysdev>" # was ENV_ORG_NAME; must match the org in ENV_REGISTRY_PUSH
ENV_VENDOR="CasjaysDev"
ENV_AUTHOR="CasjaysDev"
ENV_MAINTAINER="CasjaysDev <docker-admin@casjaysdev.pro>"
ENV_GIT_REPO_URL="https://github.com/<org>/<repo>"
ENV_REGISTRY_URL="https://docker.io" # full URL, not bare "docker.io"
ENV_REGISTRY_PUSH="<org>/<repo>" # 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="<base image>" # 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="<primary>"
EXPOSE_PORTS="<extra ports space-separated>"
LANG_VERSION=""
PHP_VERSION="<system|php82|php83|php84|none>"
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="<single-space-separated package list — must mirror PACK_LIST in Dockerfile>"
```
`ENV_PACKAGES` and Dockerfile `PACK_LIST` must stay in sync. Single-space separation, no double spaces.
---
## 7. init.d/99-<svc>.sh contract
Each repo's primary init.d script (named `99-<svc>.sh` for late ordering, or `09-<svc>.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="<svc>"
DATA_DIR="/data/<svc>"
CONF_DIR="/config/<svc>"
ETC_DIR="/etc/<svc>" # or /usr/local/share/<app>/config for app-stack repos
TMP_DIR="/tmp/<svc>"
RUN_DIR="/run/<svc>"
LOG_DIR="/data/logs/<svc>"
SERVICE_PORT="<primary>"
SERVICE_USER="<svc>" # the daemon's run-as user
SERVICE_GROUP="<svc>"
EXEC_CMD_BIN='<binary>' # e.g., 'nginx', 'mysqld', 'httpd'
EXEC_CMD_ARGS='<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="<sqlite|redis|postgres|mariadb|mysql|couchdb|mongodb|supabase|custom>"
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/<svc>/*` (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 <repo>`
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
# <repo> migration plan
## Service intent
<one paragraph: what this image provides, who runs it, primary user-facing port>
## Service stack
- <component 1>: <package(s)>; canonical config at <path>
- <component 2>: ...
## Packages (PACK_LIST / ENV_PACKAGES)
<list, sourced from pkgs.alpinelinux.org, with one-line justification each>
## Configs to ship in rootfs/tmp/etc/
- /etc/<svc>/<file>: <source: which project's docs>; <key tunings applied>
- ...
## /config/<svc>/ layout (user-editable)
- <file> -> symlinked to <runtime path>
- vhosts.d/ -> include /config/<svc>/vhosts.d/*.conf (optional)
## init.d/99-<svc>.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/<svc>/* and copy from /tmp/etc/<svc>/.
- Fetch <app source> if not present
- Other service-specific install steps
## Verification (success criteria)
- buildx run Dockerfile succeeds for linux/amd64 + linux/arm64
- docker run -d -p <port>:<port> ... starts cleanly; logs show no errors
- curl -fsS http://localhost:<port>/<healthpath> returns the expected response
- /config/<svc>/ 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 <upstream>:latest && docker history <upstream>:latest`); upstream image deleted (`docker rmi`) after verification
```
---
## 9. Migration workflow per repo
1. Create `<repo>/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 <repo> && rm -f .build_failed && buildx run Dockerfile` — fix any build error before moving on.
5. Smoke-test: `docker run --rm -d --name test-<svc> -p <port>:<port> <org>/<repo>:latest`; wait for healthcheck; `curl` the health/main endpoint; `docker exec` and inspect `/config/<svc>/`; 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/<svc>/*` — per-repo.
- Overwriting `rootfs/usr/local/share/<app>/*` — 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.

View File

@@ -1,7 +1,7 @@
# Docker image for ampache using the alpine template # Docker image for ampache using the alpine template
ARG IMAGE_NAME="ampache" ARG IMAGE_NAME="ampache"
ARG PHP_SERVER="ampache" ARG PHP_SERVER="ampache"
ARG BUILD_DATE="202605091200" ARG BUILD_DATE="202605131434"
ARG LANGUAGE="en_US.UTF-8" ARG LANGUAGE="en_US.UTF-8"
ARG TIMEZONE="America/New_York" ARG TIMEZONE="America/New_York"
ARG WWW_ROOT_DIR="/usr/local/share/httpd/default" ARG WWW_ROOT_DIR="/usr/local/share/httpd/default"
@@ -76,13 +76,7 @@ RUN set -e; \
RUN set -e; \ RUN set -e; \
echo "Setting up prerequisites"; \ echo "Setting up prerequisites"; \
apk --no-cache add bash; \ true
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
ENV SHELL="/bin/bash" ENV SHELL="/bin/bash"
SHELL [ "/bin/bash", "-c" ] SHELL [ "/bin/bash", "-c" ]
@@ -97,12 +91,7 @@ RUN echo "Initializing the system"; \
RUN echo "Creating and editing system files "; \ RUN echo "Creating and editing system files "; \
$SHELL_OPTS; \ $SHELL_OPTS; \
rm -Rf "/etc/apk/repositories"; \ [ -f "/root/.profile" ] || touch "/root/.profile"; \
[ "$DISTRO_VERSION" = "latest" ] && DISTRO_VERSION="edge";[ "$DISTRO_VERSION" = "edge" ] || DISTRO_VERSION="v${DISTRO_VERSION}"; \
echo "http://dl-cdn.alpinelinux.org/alpine/${DISTRO_VERSION}/main" >>"/etc/apk/repositories"; \
echo "http://dl-cdn.alpinelinux.org/alpine/${DISTRO_VERSION}/community" >>"/etc/apk/repositories"; \
if [ "${DISTRO_VERSION}" = "edge" ]; then echo "http://dl-cdn.alpinelinux.org/alpine/${DISTRO_VERSION}/testing" >>"/etc/apk/repositories";fi; \
apk update; apk upgrade --no-cache; \
if [ -f "/root/docker/setup/01-system.sh" ];then echo "Running the system script";/root/docker/setup/01-system.sh||{ echo "Failed to execute /root/docker/setup/01-system.sh" >&2 && exit 10; };echo "Done running the system script";fi; \ 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 "" echo ""
@@ -148,6 +137,7 @@ RUN echo "Custom Settings"; \
$SHELL_OPTS; \ $SHELL_OPTS; \
echo "" echo ""
RUN echo "Setting up users and scripts "; \ RUN echo "Setting up users and scripts "; \
$SHELL_OPTS; \ $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; \ 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; \

3
IDEA.md Normal file
View File

@@ -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.

View File

@@ -1,6 +1,6 @@
## 👋 Welcome to ampache 🚀 ## 👋 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 ## Install my system scripts
@@ -54,6 +54,35 @@ services:
restart: always 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 ## Get source files
```shell ```shell

34
TODO.AI.md Normal file
View File

@@ -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`

View File

@@ -1,40 +1,45 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # shellcheck shell=bash
##@Version : 202502050828-git # - - - - - - - - - - - - - - - - - - - - - - - - -
##@Version : 202605131431-git
# @@Author : CasjaysDev # @@Author : CasjaysDev
# @@Contact : CasjaysDev <docker-admin@casjaysdev.pro> # @@Contact : CasjaysDev <docker-admin@casjaysdev.pro>
# @@License : MIT # @@License : MIT
# @@ReadME : # @@Copyright : Copyright 2026 CasjaysDev
# @@Copyright : Copyright 2023 CasjaysDev # @@Created : Wed May 13 02:31:25 PM EDT 2026
# @@Created : Mon Aug 28 06:48:42 PM EDT 2023
# @@File : 00-init.sh # @@File : 00-init.sh
# @@Description : script to run init # @@Description : script to run init
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # @@Changelog : newScript
# shellcheck shell=bash # @@TODO : Refactor code
# shellcheck disable=SC2016 # @@Other : N/A
# shellcheck disable=SC2031 # @@Resource : N/A
# shellcheck disable=SC2120 # @@Terminal App : yes
# shellcheck disable=SC2155 # @@sudo/root : yes
# shellcheck disable=SC2199 # @@Template : templates/dockerfiles/init_scripts/00-init.sh
# shellcheck disable=SC2317 # - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
# - - - - - - - - - - - - - - - - - - - - - - - - -
# Set bash options # Set bash options
set -o pipefail set -o pipefail
[ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS [ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Set env variables # Set env variables
exitCode=0 exitCode=0
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Predefined actions # 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/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/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 if [ -d "/usr/local/share/template-files/defaults" ]; then rm -Rf "/usr/local/share/template-files/defaults"/*; fi
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Main script # Main script
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Set the exit code # Set the exit code
#exitCode=$? #exitCode=$?
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
exit $exitCode exit $exitCode
# - - - - - - - - - - - - - - - - - - - - - - - - -
# ex: ts=2 sw=2 et filetype=sh
# - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@@ -1,38 +1,43 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # shellcheck shell=bash
##@Version : 202502050828-git # - - - - - - - - - - - - - - - - - - - - - - - - -
##@Version : 202605131431-git
# @@Author : CasjaysDev # @@Author : CasjaysDev
# @@Contact : CasjaysDev <docker-admin@casjaysdev.pro> # @@Contact : CasjaysDev <docker-admin@casjaysdev.pro>
# @@License : MIT # @@License : MIT
# @@ReadME : # @@Copyright : Copyright 2026 CasjaysDev
# @@Copyright : Copyright 2023 CasjaysDev # @@Created : Wed May 13 02:31:25 PM EDT 2026
# @@Created : Mon Aug 28 06:48:42 PM EDT 2023
# @@File : 01-system.sh # @@File : 01-system.sh
# @@Description : script to run system # @@Description : script to run system
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # @@Changelog : newScript
# shellcheck shell=bash # @@TODO : Refactor code
# shellcheck disable=SC2016 # @@Other : N/A
# shellcheck disable=SC2031 # @@Resource : N/A
# shellcheck disable=SC2120 # @@Terminal App : yes
# shellcheck disable=SC2155 # @@sudo/root : yes
# shellcheck disable=SC2199 # @@Template : templates/dockerfiles/init_scripts/01-system.sh
# shellcheck disable=SC2317 # - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
# - - - - - - - - - - - - - - - - - - - - - - - - -
# Set bash options # Set bash options
set -o pipefail set -o pipefail
[ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS [ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Set env variables # Set env variables
exitCode=0 exitCode=0
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Predefined actions # Predefined actions
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Main script # Main script
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Set the exit code # Set the exit code
#exitCode=$? #exitCode=$?
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
exit $exitCode exit $exitCode
# - - - - - - - - - - - - - - - - - - - - - - - - -
# ex: ts=2 sw=2 et filetype=sh
# - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@@ -1,38 +1,43 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # shellcheck shell=bash
##@Version : 202502050828-git # - - - - - - - - - - - - - - - - - - - - - - - - -
##@Version : 202605131431-git
# @@Author : CasjaysDev # @@Author : CasjaysDev
# @@Contact : CasjaysDev <docker-admin@casjaysdev.pro> # @@Contact : CasjaysDev <docker-admin@casjaysdev.pro>
# @@License : MIT # @@License : MIT
# @@ReadME : # @@Copyright : Copyright 2026 CasjaysDev
# @@Copyright : Copyright 2023 CasjaysDev # @@Created : Wed May 13 02:31:25 PM EDT 2026
# @@Created : Mon Aug 28 06:48:42 PM EDT 2023
# @@File : 02-packages.sh # @@File : 02-packages.sh
# @@Description : script to run packages # @@Description : script to run packages
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # @@Changelog : newScript
# shellcheck shell=bash # @@TODO : Refactor code
# shellcheck disable=SC2016 # @@Other : N/A
# shellcheck disable=SC2031 # @@Resource : N/A
# shellcheck disable=SC2120 # @@Terminal App : yes
# shellcheck disable=SC2155 # @@sudo/root : yes
# shellcheck disable=SC2199 # @@Template : templates/dockerfiles/init_scripts/02-packages.sh
# shellcheck disable=SC2317 # - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
# - - - - - - - - - - - - - - - - - - - - - - - - -
# Set bash options # Set bash options
set -o pipefail set -o pipefail
[ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS [ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Set env variables # Set env variables
exitCode=0 exitCode=0
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Predefined actions # Predefined actions
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Main script # Main script
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Set the exit code # Set the exit code
#exitCode=$? #exitCode=$?
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
exit $exitCode exit $exitCode
# - - - - - - - - - - - - - - - - - - - - - - - - -
# ex: ts=2 sw=2 et filetype=sh
# - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@@ -1,31 +1,32 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # shellcheck shell=bash
##@Version : 202408270903-git # - - - - - - - - - - - - - - - - - - - - - - - - -
##@Version : 202605131431-git
# @@Author : CasjaysDev # @@Author : CasjaysDev
# @@Contact : CasjaysDev <docker-admin@casjaysdev.pro> # @@Contact : CasjaysDev <docker-admin@casjaysdev.pro>
# @@License : MIT # @@License : MIT
# @@ReadME : # @@Copyright : Copyright 2026 CasjaysDev
# @@Copyright : Copyright 2023 CasjaysDev # @@Created : Wed May 13 02:31:25 PM EDT 2026
# @@Created : Mon Aug 28 06:48:42 PM EDT 2023
# @@File : 03-files.sh # @@File : 03-files.sh
# @@Description : script to run files # @@Description : script to run files
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # @@Changelog : newScript
# shellcheck shell=bash # @@TODO : Refactor code
# shellcheck disable=SC2016 # @@Other : N/A
# shellcheck disable=SC2031 # @@Resource : N/A
# shellcheck disable=SC2120 # @@Terminal App : yes
# shellcheck disable=SC2155 # @@sudo/root : yes
# shellcheck disable=SC2199 # @@Template : templates/dockerfiles/init_scripts/03-files.sh
# shellcheck disable=SC2317 # - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
# - - - - - - - - - - - - - - - - - - - - - - - - -
# Set bash options # Set bash options
set -o pipefail set -o pipefail
[ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS [ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Set env variables # Set env variables
exitCode=0 exitCode=0
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Predefined actions # Predefined actions
if [ -d "/tmp/bin" ]; then if [ -d "/tmp/bin" ]; then
mkdir -p "/usr/local/bin" mkdir -p "/usr/local/bin"
@@ -79,11 +80,15 @@ if [ -d "/tmp/data" ]; then
done done
fi fi
unset data unset data
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Main script # Main script
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Set the exit code # Set the exit code
#exitCode=$? #exitCode=$?
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
exit $exitCode exit $exitCode
# - - - - - - - - - - - - - - - - - - - - - - - - -
# ex: ts=2 sw=2 et filetype=sh
# - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@@ -1,38 +1,43 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # shellcheck shell=bash
##@Version : 202502050828-git # - - - - - - - - - - - - - - - - - - - - - - - - -
##@Version : 202605131431-git
# @@Author : CasjaysDev # @@Author : CasjaysDev
# @@Contact : CasjaysDev <docker-admin@casjaysdev.pro> # @@Contact : CasjaysDev <docker-admin@casjaysdev.pro>
# @@License : MIT # @@License : MIT
# @@ReadME : # @@Copyright : Copyright 2026 CasjaysDev
# @@Copyright : Copyright 2023 CasjaysDev # @@Created : Wed May 13 02:31:26 PM EDT 2026
# @@Created : Mon Aug 28 06:48:42 PM EDT 2023
# @@File : 06-post.sh # @@File : 06-post.sh
# @@Description : script to run post # @@Description : script to run post
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # @@Changelog : newScript
# shellcheck shell=bash # @@TODO : Refactor code
# shellcheck disable=SC2016 # @@Other : N/A
# shellcheck disable=SC2031 # @@Resource : N/A
# shellcheck disable=SC2120 # @@Terminal App : yes
# shellcheck disable=SC2155 # @@sudo/root : yes
# shellcheck disable=SC2199 # @@Template : templates/dockerfiles/init_scripts/06-post.sh
# shellcheck disable=SC2317 # - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
# - - - - - - - - - - - - - - - - - - - - - - - - -
# Set bash options # Set bash options
set -o pipefail set -o pipefail
[ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS [ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Set env variables # Set env variables
exitCode=0 exitCode=0
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Predefined actions # Predefined actions
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Main script # Main script
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Set the exit code # Set the exit code
#exitCode=$? #exitCode=$?
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
exit $exitCode exit $exitCode
# - - - - - - - - - - - - - - - - - - - - - - - - -
# ex: ts=2 sw=2 et filetype=sh
# - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@@ -1,39 +1,47 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # shellcheck shell=bash
##@Version : 202502050828-git # - - - - - - - - - - - - - - - - - - - - - - - - -
##@Version : 202605131431-git
# @@Author : CasjaysDev # @@Author : CasjaysDev
# @@Contact : CasjaysDev <docker-admin@casjaysdev.pro> # @@Contact : CasjaysDev <docker-admin@casjaysdev.pro>
# @@License : MIT # @@License : MIT
# @@ReadME : # @@Copyright : Copyright 2026 CasjaysDev
# @@Copyright : Copyright 2023 CasjaysDev # @@Created : Wed May 13 02:31:26 PM EDT 2026
# @@Created : Mon Aug 28 06:48:42 PM EDT 2023
# @@File : 07-cleanup.sh # @@File : 07-cleanup.sh
# @@Description : script to run cleanup # @@Description : script to run cleanup
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # @@Changelog : newScript
# shellcheck shell=bash # @@TODO : Refactor code
# shellcheck disable=SC2016 # @@Other : N/A
# shellcheck disable=SC2031 # @@Resource : N/A
# shellcheck disable=SC2120 # @@Terminal App : yes
# shellcheck disable=SC2155 # @@sudo/root : yes
# shellcheck disable=SC2199 # @@Template : templates/dockerfiles/init_scripts/07-cleanup.sh
# shellcheck disable=SC2317 # - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
# - - - - - - - - - - - - - - - - - - - - - - - - -
# Set bash options # Set bash options
set -o pipefail set -o pipefail
[ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS [ "$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 # Set env variables
exitCode=0 exitCode=0
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Predefined actions # Predefined actions
if [ -d "/tmp" ]; then rm -Rf "/tmp"/*; fi if [ -d "/tmp" ]; then rm -Rf "/tmp"/*; fi
if [ -d "$HOME/.cache" ]; then rm -Rf "$HOME/.cache"; fi if [ -d "$HOME/.cache" ]; then rm -Rf "$HOME/.cache"; fi
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Main script # Main script
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Set the exit code # Set the exit code
#exitCode=$? #exitCode=$?
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
exit $exitCode exit $exitCode
# - - - - - - - - - - - - - - - - - - - - - - - - -
# ex: ts=2 sw=2 et filetype=sh
# - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@@ -1,13 +1,13 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# shellcheck shell=bash # shellcheck shell=bash
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
##@Version : 202602061352-git ##@Version : 202605052024-git
# @@Author : Jason Hempstead # @@Author : Jason Hempstead
# @@Contact : jason@casjaysdev.pro # @@Contact : jason@casjaysdev.pro
# @@License : WTFPL # @@License : WTFPL
# @@ReadME : entrypoint.sh --help # @@ReadME : entrypoint.sh --help
# @@Copyright : Copyright: (c) 2026 Jason Hempstead, Casjays Developments # @@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 # @@File : entrypoint.sh
# @@Description : Entrypoint file for ampache # @@Description : Entrypoint file for ampache
# @@Changelog : New script # @@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 # 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:-}" [ -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" 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}" SERVICE_GID="${SERVICE_GID:-0}"
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# User and group in which the service switches to - IE: nginx,apache,mysql,postgres # 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_USER="${SERVICE_USER:-example}" # execute command as another user
#SERVICE_GROUP="${SERVICE_GROUP:-ampache}" # Set the service group #SERVICE_GROUP="${SERVICE_GROUP:-example}" # Set the service group
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Secondary ports # Secondary ports
# specifiy other ports # specifiy other ports
@@ -357,7 +363,7 @@ if [ "$ENTRYPOINT_FIRST_RUN" != "no" ]; then
fi fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
if [ -f "/etc/hostname" ]; then 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 hostname -F "/etc/hostname" 2>/dev/null || true
else else
HOSTNAME="$(<"/etc/hostname")" 2>/dev/null || true HOSTNAME="$(<"/etc/hostname")" 2>/dev/null || true
@@ -372,7 +378,7 @@ if [ "$ENTRYPOINT_FIRST_RUN" != "no" ]; then
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# import resolv.conf file into container # import resolv.conf file into container
if [ "$CUSTOM_DNS" != "yes" ] && [ -f "/usr/local/etc/resolv.conf" ] && [ "$UPDATE_FILE_RESOLV" = "yes" ]; then 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 fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
if [ -n "$HOME" ] && [ -d "/usr/local/etc/skel" ]; then if [ -n "$HOME" ] && [ -d "/usr/local/etc/skel" ]; then
@@ -383,12 +389,13 @@ if [ "$ENTRYPOINT_FIRST_RUN" != "no" ]; then
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
fi 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 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 fi
if [ -d "/config" ]; then 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 fi
if [ -f "/usr/local/bin/.gitkeep" ]; then if [ -f "/usr/local/bin/.gitkeep" ]; then
rm -Rf "/usr/local/bin/.gitkeep" 2>/dev/null || true 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 no pid assume container restart - clean stale files on restart
if [ -f "$ENTRYPOINT_PID_FILE" ]; then if [ -f "$ENTRYPOINT_PID_FILE" ]; then
# Check if the PID in the file is still running # 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 if [ -n "$entrypoint_pid" ] && kill -0 "$entrypoint_pid" 2>/dev/null; then
# Process is still running, don't restart services # Process is still running, don't restart services
START_SERVICES="no" START_SERVICES="no"
@@ -451,12 +458,12 @@ if [ -f "$ENTRYPOINT_PID_FILE" ]; then
# PID file exists but process is dead - this is a restart # PID file exists but process is dead - this is a restart
START_SERVICES="yes" START_SERVICES="yes"
# Clean any stale PID files on restart # 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 fi
else else
START_SERVICES=yes START_SERVICES=yes
# Clean any stale PID files on first run # 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 fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
[ "$ENTRYPOINT_MESSAGE" = "yes" ] && __printf_space "40" "The containers ip address is:" "$CONTAINER_IP4_ADDRESS" [ "$ENTRYPOINT_MESSAGE" = "yes" ] && __printf_space "40" "The containers ip address is:" "$CONTAINER_IP4_ADDRESS"
@@ -581,13 +588,13 @@ healthcheck)
services="$(echo "${SERVICES_LIST//,/ }")" services="$(echo "${SERVICES_LIST//,/ }")"
healthMessage="Everything seems to be running" healthMessage="Everything seems to be running"
[ "$healthEnabled" = "yes" ] || exit 0 [ "$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 for service in /run/healthcheck/*; do
name="${service##*/}" name="${service##*/}"
services+="$name " services+="$name "
done done
fi fi
services="$(echo "$services" | tr ' ' '\n' | sort -u | grep -v '^$')" services="$(printf '%s\n' $services | sort -u | grep -v '^$')"
for proc in $services; do for proc in $services; do
if [ -n "$proc" ]; then if [ -n "$proc" ]; then
if ! __pgrep "$proc"; then if ! __pgrep "$proc"; then
@@ -597,7 +604,7 @@ healthcheck)
fi fi
done done
for port in $ports; do 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 if ! netstat -taupln | grep -q ":$port "; then
echo "$port isn't open" >&2 echo "$port isn't open" >&2
healthStatus=$((healthStatus + 1)) healthStatus=$((healthStatus + 1))
@@ -621,14 +628,14 @@ healthcheck)
# show open ports # show open ports
ports) ports)
shift 1 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' ' ' [ -n "$ports" ] && printf '%s\n%s\n' "The following are servers:" "$ports" | tr '\n' ' '
exit $? exit $?
;; ;;
# show running processes # show running processes
procs) procs)
shift 1 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' ' ' [ -n "$ps" ] && printf '%s\n%s\n' "Found the following processes" "$ps" | tr '\n' ' '
exit $? exit $?
;; ;;

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# shellcheck shell=bash # shellcheck shell=bash
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
##@Version : 202511301145-git ##@Version : 202605051922-git
# @@Author : Jason Hempstead # @@Author : Jason Hempstead
# @@Contact : git-admin@casjaysdev.pro # @@Contact : git-admin@casjaysdev.pro
# @@License : LICENSE.md # @@License : LICENSE.md
@@ -31,7 +31,20 @@ else
set -o pipefail set -o pipefail
fi 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() { __printf_space() {
local pad=$(printf '%0.1s' " "{1..60}) local pad=$(printf '%0.1s' " "{1..60})
@@ -47,185 +60,137 @@ __printf_space() {
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
__mkdir() { __mkdir() {
if [ -n "$1" ]; then 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 fi
return 0
} }
__rm() { __rm() {
if [ -n "$1" ] && [ -e "$1" ]; then if [ -n "$1" ] && [ -e "$1" ]; then
rm -Rf "${1:?}" 2>/dev/null || true if ! rm -Rf "${1:?}" 2>/dev/null; then
fi [ "$DEBUGGER" = "on" ] && echo "Warning: Failed to remove: $1" >&2
}
__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
return 1 return 1
fi fi
else
return 1
fi 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() { __get_ip6() {
local ip6 ip a 2>/dev/null | awk '/^[[:space:]]*inet6 / {
ip6="$(ip a 2>/dev/null | grep -w 'inet6' | awk '{print $2}' | grep -vE '^::1|^fe' | sed 's|/.*||g' | head -n1 | grep '.')" split($2, a, "/"); ip = a[1]
if [ -n "$ip6" ]; then if (ip !~ /^::1$/ && ip !~ /^fe/) { print ip; exit }
echo "$ip6" }'
else
echo ''
fi
} }
__get_ip4() { __get_ip4() {
local 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 '.')" ip4=$(ip a 2>/dev/null | awk '/^[[:space:]]*inet / {
if [ -n "$ip4" ]; then split($2, a, "/"); ip = a[1]
echo "$ip4" if (ip !~ /^127\.0\.0/) { print ip; exit }
else }')
echo '127.0.0.1' echo "${ip4:-127.0.0.1}"
fi
} }
__find_and_remove() { __find_and_remove() {
find "${2:-/etc}" -iname "$1" -exec rm -Rfv {} \; 2>/dev/null || true find "${2:-/etc}" -iname "$1" -exec rm -Rfv {} \; 2>/dev/null || true
} }
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
__pgrep() { __pgrep() {
local count=3 local srvc="$1" count=3
local srvc="${1:-SERVICE_NAME}" [ -z "$srvc" ] && return 10
while [ $count -ge 0 ]; do while [ $count -ge 0 ]; do
# Use exact process name matching, not full command line search pgrep -x "$srvc" &>/dev/null && return 0
pgrep -x "$srvc" >/dev/null 2>&1 && return 0 pgrep -f "$srvc" &>/dev/null && return 0
sleep 1 ps -ef 2>/dev/null | grep -v 'grep' | grep -qw "$srvc" && return 0
[ $count -gt 0 ] && sleep 1
count=$((count - 1)) count=$((count - 1))
done done
return 10 return 10
} }
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
__find_file_relative() { __find_file_relative() {
if [ ! -e "$1" ]; then [ -e "$1" ] || return 0
return 0 find "$1"/* -not -path '*env/*' -not -path '.git*' -type f 2>/dev/null \
fi | sort -u \
find "$1"/* -not -path '*env/*' -not -path '.git*' -type f 2>/dev/null | sed 's|'$1'/||g' | sort -u | grep -v '^$' | grep '.' || true | sed "s|^$1/||" || true
} }
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
__find_directory_relative() { __find_directory_relative() {
if [ ! -d "$1" ]; then [ -d "$1" ] || return 0
return 0 find "$1"/* -not -path '*env/*' -not -path '.git*' -type d 2>/dev/null \
fi | sort -u \
find "$1"/* -not -path '*env/*' -not -path '.git*' -type d 2>/dev/null | sed 's|'$1'/||g' | sort -u | grep -v '^$' | grep '.' || true | sed "s|^$1/||" || true
} }
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
__pid_exists() { __pid_exists() { [ -n "$1" ] && [ -d "/proc/$1" ]; }
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
}
__is_running() { __is_running() {
local result="" local pat="$1"
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 '')" [ -n "$2" ] && pat="$pat.*$2"
if [ -n "$result" ]; then if command -v pgrep &>/dev/null; then
return 0 pgrep -f "$pat" &>/dev/null
else else
return 1 ps -eo args 2>/dev/null | grep -v grep | grep -Eq "$pat"
fi fi
} }
__get_pid() { __get_pid() {
local result="" if [ -z "$1" ]; then
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 '')" [ "$DEBUGGER" = "on" ] && echo "Warning: __get_pid called without process name" >&2
if [ -n "$result" ]; then
echo "$result"
return 0
else
return 1 return 1
fi 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() { __clean_variables() {
local var="$*" local var="$*"
var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters var="${var#"${var%%[![:space:]]*}"}"
var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters var="${var%"${var##*[![:space:]]}"}"
var="$(printf '%s\n' "$var" | sed 's/\( \)*/\1/g;s|^ ||g')" while [[ 202605051922-gitar == *" "* ]]; do var="${var// / }"; done
printf '%s' "$var" | grep -v '^$' [ -n "202605051922-gitar" ] && printf '%s' "$var"
} }
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
__no_exit() { __no_exit() {
@@ -235,7 +200,17 @@ __no_exit() {
local failed_services="" local failed_services=""
local failure_count=0 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 " exec bash -c "
trap 'echo \"Container shutdown requested\"; rm -f /run/.no_exit.pid /run/*.pid; exit 0' TERM INT trap 'echo \"Container shutdown requested\"; rm -f /run/.no_exit.pid /run/*.pid; exit 0' TERM INT
@@ -270,10 +245,10 @@ __no_exit() {
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
__trim() { __trim() {
local var="${*//;/ }" local var="${*//;/ }"
var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters var="${var#"${var%%[![:space:]]*}"}"
var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters var="${var%"${var##*[![:space:]]}"}"
var="$(echo "$var" | __remove_extra_spaces | sed "s| |; |g;s|;$| |g" | __remove_extra_spaces)" while [[ 202605051922-gitar == *" "* ]]; do var="${var// / }"; done
printf '%s' "$var" | sed 's|;||g' | grep -v '^$' [ -n "202605051922-gitar" ] && printf '%s' "$var"
} }
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
__banner() { __banner() {
@@ -295,21 +270,25 @@ __service_banner() {
printf '# - - - %s %-*s %s - - - #\n' "$icon" "$text_width" "$full_message" "$icon" 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_bin() { find -L '/usr'/*bin -maxdepth 4 -name 'php-fpm*' 2>/dev/null | head -n1; }
__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_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_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 | grep '.' || echo ''; } __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 | grep '.' || echo ''; } __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 | grep '.' || echo ''; } __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 | grep '.' || echo ''; } __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_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 | grep '.' || echo ''; } __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_couchdb_conf() { return; }
__find_mongodb_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() { __init_working_dir() {
local service_name="$SERVICE_NAME" # get service name local service_name="$SERVICE_NAME" # get service name
@@ -472,7 +451,8 @@ __display_user_info() {
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
__init_config_etc() { __init_config_etc() {
local copy="no" 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 etc_dir="${ETC_DIR:-/etc/$name}"
local conf_dir="${CONF_DIR:-/config/$name}" local conf_dir="${CONF_DIR:-/config/$name}"
__is_dir_empty "$conf_dir" && copy=yes __is_dir_empty "$conf_dir" && copy=yes
@@ -614,7 +594,7 @@ __cron() {
fi fi
[ $# -eq 0 ] && echo "Usage: cron [interval] [command]" && exit 1 [ $# -eq 0 ] && echo "Usage: cron [interval] [command]" && exit 1
local command="$*" local command="$*"
local bin="$(basename "${CRON_NAME:-$1}")" local bin="${CRON_NAME:-$1}"; bin="${bin##*/}"
[ -d "/run/cron" ] || mkdir -p "/run/cron" [ -d "/run/cron" ] || mkdir -p "/run/cron"
echo "$pid" >"/run/cron/$bin.pid" echo "$pid" >"/run/cron/$bin.pid"
echo "$command" >"/run/cron/$bin.run" echo "$command" >"/run/cron/$bin.run"
@@ -640,8 +620,8 @@ __find_replace() {
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# /config > /etc # /config > /etc
__copy_templates() { __copy_templates() {
local from="$1" to="$2" local from="$1" to="$2" is_link=""
is_link="$(ls -la "$dest" 2>/dev/null | awk '{print $NF}')" [ -L "$to" ] && is_link="$(readlink "$to")"
[ "$from" != "$is_link" ] || return 0 [ "$from" != "$is_link" ] || return 0
if [ -e "$from" ] && __is_dir_empty "$to"; then if [ -e "$from" ] && __is_dir_empty "$to"; then
__file_copy "$from" "$to" __file_copy "$from" "$to"
@@ -651,16 +631,18 @@ __copy_templates() {
# /config/file > /etc/file # /config/file > /etc/file
__symlink() { __symlink() {
local from="$1" to="$2" local from="$1" to="$2"
if [ -e "$to" ]; then [ -e "$to" ] || return 0
[ -e "$from" ] && __rm "$from" [ "$from" = "$to" ] && return 0
ln -sf "$to" "$from" && echo "Created symlink to $from > $to" __rm "$from"
fi [ -d "${from%/*}" ] || mkdir -p "${from%/*}" 2>/dev/null
ln -sf "$to" "$from" && echo "Created symlink to $from > $to"
} }
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
__file_copy() { __file_copy() {
local from="$1" local from="$1"
local dest="$2" 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 [ "$from" != "$is_link" ]; then
if [ -n "$from" ] && [ -e "$from" ] && [ -n "$dest" ]; then if [ -n "$from" ] && [ -e "$from" ] && [ -n "$dest" ]; then
if [ -d "$from" ]; then if [ -d "$from" ]; then
@@ -757,20 +739,40 @@ __fix_permissions() {
fi fi
} }
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
__get_gid() { grep "^$1:" /etc/group 2>/dev/null | awk -F ':' '{print $3}' || 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() { grep "^$1:" /etc/passwd 2>/dev/null | awk -F ':' '{print $3}' || return 1; } __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() { cat "/etc/passwd" 2>/dev/null | awk -F ':' '{print $3}' | sort -u | grep -q "^$1$" 2>/dev/null || return 1; } __check_for_uid() { awk -F: -v n="$1" '$3==n {found=1; exit} END {exit !found}' /etc/passwd 2>/dev/null; }
__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_guid() { awk -F: -v n="$1" '$3==n {found=1; exit} END {exit !found}' /etc/group 2>/dev/null; }
__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_user() { awk -F: -v n="$1" '$1==n {found=1; exit} END {exit !found}' /etc/passwd 2>/dev/null; }
__check_for_group() { cat "/etc/group" 2>/dev/null | awk -F ':' '{print $1}' | sort -u | grep -q "^$1$" 2>/dev/null || return 1; } __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 # check if process is already running
__proc_check() { __proc_check() {
cmd_bin="$(type -P "${1:-$EXEC_CMD_BIN}")" # Skip process check for one-shot/configuration services
cmd_name="$(basename "${cmd_bin:-$EXEC_CMD_NAME}")" if [ "$SERVICE_USES_PID" = "no" ]; then
if __pgrep "$cmd_bin" || __pgrep "$cmd_name"; 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" SERVICE_IS_RUNNING="yes"
touch "$SERVICE_PID_FILE" touch "$SERVICE_PID_FILE" 2>/dev/null || true
return 0 return 0
else else
return 1 return 1
@@ -824,11 +826,11 @@ __create_service_user() {
return 0 return 0
fi fi
# Validate user/group name format (alphanumeric, underscore, hyphen; must start with letter or underscore) # 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 echo "Error: Invalid username format '$create_user' - must start with letter/underscore, contain only lowercase alphanumeric, underscore, or hyphen" >&2
return 1 return 1
fi 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 echo "Error: Invalid group name format '$create_group' - must start with letter/underscore, contain only lowercase alphanumeric, underscore, or hyphen" >&2
return 1 return 1
fi fi
@@ -858,11 +860,11 @@ __create_service_user() {
create_gid="$random_id" create_gid="$random_id"
fi fi
# Validate UID/GID are numeric and within valid range # 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 echo "Error: Invalid UID '$create_uid' - must be a number between 1 and 65534" >&2
return 1 return 1
fi 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 echo "Error: Invalid GID '$create_gid' - must be a number between 1 and 65534" >&2
return 1 return 1
fi fi
@@ -947,9 +949,7 @@ __create_env_file() {
dir="$(dirname "$create_env")" dir="$(dirname "$create_env")"
[ -d "$dir" ] || mkdir -p "$dir" [ -d "$dir" ] || mkdir -p "$dir"
if [ -n "$create_env" ] && [ ! -f "$create_env" ]; then if [ -n "$create_env" ] && [ ! -f "$create_env" ]; then
cat <<EOF | tee -p "$create_env" >/dev/null cp -f "$sample_file" "$create_env"
$(<"$sample_file")
EOF
fi fi
[ -f "$create_env" ] || envStatus=$((1 + envStatus)) [ -f "$create_env" ] || envStatus=$((1 + envStatus))
done done
@@ -958,17 +958,17 @@ EOF
} }
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
__exec_command() { __exec_command() {
local bin=""
local arg=("$@") local arg=("$@")
local exitCode="0" local exitCode=0
local cmdExec="${arg:-}" local cmdExec="${arg:-}"
local pre_exec="--login -c" 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)" local shell bin prog
bin="$(echo "${arg[*]}" | tr ' ' '\n' | grep -v '^$' | head -n1 | sed 's| ||g' || echo 'bash')" 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")" 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}" echo "${exec_message:-Executing command: $cmdExec}"
eval $shell $pre_exec "$cmdExec" || exitCode=1 eval "$shell" $pre_exec "$cmdExec"
exitCode=$? exitCode=$?
elif [ -f "$prog" ]; then elif [ -f "$prog" ]; then
echo "$prog is not executable" echo "$prog is not executable"
@@ -997,7 +997,9 @@ __start_init_scripts() {
local critical_failures="0" local critical_failures="0"
local pidFile="/run/.start_init_scripts.pid" local pidFile="/run/.start_init_scripts.pid"
local init_dir="${1:-/usr/local/etc/docker/init.d}" 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}" local exit_on_failure="${EXIT_ON_SERVICE_FAILURE:-true}"
# Clean stale PID files from previous runs # 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 & while :; do echo "Running: $(date)" >"/data/logs/init/keep_alive" && sleep 3600; done &
else else
if [ -d "$init_dir" ]; then 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 chmod -Rf 755 "$init_dir"/*.sh
echo "🚀 Starting container services initialization" echo "🚀 Starting container services initialization"
@@ -1025,9 +1030,9 @@ __start_init_scripts() {
for init in "$init_dir"/*.sh; do for init in "$init_dir"/*.sh; do
if [ -x "$init" ]; then if [ -x "$init" ]; then
touch "$pidFile" touch "$pidFile"
name="$(basename "$init")" name="${init##*/}"
service="$(printf '%s' "$name" | sed 's/^[^-]*-//;s|.sh$||g')" service="${name#*-}"; service="${service%.sh}"
__service_banner "🔧" "Executing service script:" "$(basename "$init")" __service_banner "🔧" "Executing service script:" "${init##*/}"
# Execute the init script and capture the exit code # Execute the init script and capture the exit code
if source "$init"; then if source "$init"; then
# Check if service was disabled first # Check if service was disabled first
@@ -1044,52 +1049,48 @@ __start_init_scripts() {
sleep 1 sleep 1
# Check for service success indicators # Check for service success indicators
local expected_pid_file="/run/init.d/$service.pid" 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 if [ "$SERVICE_USES_PID" = "no" ]; then
# Service doesn't use PID files - check if expected PID file exists or assume success # Configuration service - no daemon process expected
if [ -f "$expected_pid_file" ]; then initStatus="0"
retPID="$(cat "$expected_pid_file" 2>/dev/null || echo "0")" __service_banner "✅" "Service $service completed successfully -" "configuration service"
initStatus="0"
__service_banner "✅" "Service $service started successfully -" "PID file"
else
initStatus="0"
__service_banner "✅" "Service $service started successfully -" "no PID tracking"
fi
else else
# Service uses PID tracking - verify actual running processes # Service uses PID tracking - verify actual running processes
set +e # Temporarily disable exit on error
retPID="" retPID=""
# First, try to find actual running process with various name patterns local found_process=""
for name_variant in "$service" "${service}84" "${service}d" "$(echo "$service" | sed 's/-//g')" "$(echo "$service" | tr -d '-')"; do # Try multiple name variants to find the process
for name_variant in "$service" "${service}84" "${service}d" "${service//-/}"; do
if [ -z "$retPID" ]; then if [ -z "$retPID" ]; then
retPID=$(__get_pid "$name_variant" 2>/dev/null || echo "") 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 fi
done done
set -e # Re-enable exit on error
if [ -n "$retPID" ] && [ "$retPID" != "0" ]; then if [ -n "$retPID" ] && [ "$retPID" != "0" ]; then
# Found actual running process # Found actual running process
initStatus="0" initStatus="0"
__service_banner "✅" "Service $service started successfully -" "PID: ${retPID} ($found_process)" __service_banner "✅" "Service $service started successfully -" "PID: ${retPID} ($found_process)"
elif [ -f "$expected_pid_file" ]; then elif [ -f "$expected_pid_file" ]; then
# No running process but PID file exists - verify PID is valid # 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 if [ -n "$file_pid" ] && kill -0 "$file_pid" 2>/dev/null; then
initStatus="0" initStatus="0"
__service_banner "✅" "Service $service started successfully -" "PID: $file_pid (from file)" __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 else
# PID file exists but process isn't running - treat as warning, not failure
initStatus="0" 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 fi
else 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" initStatus="0"
__service_banner "✅" "Service $service completed successfully -" "configuration service" __service_banner "✅" "Service $service completed successfully -" "configuration service"
fi fi
fi fi
set -e
fi fi
else else
initStatus="1" initStatus="1"
@@ -1102,15 +1103,19 @@ __start_init_scripts() {
done done
# Summary # Summary
echo ""
if [ $critical_failures -gt 0 ]; then if [ $critical_failures -gt 0 ]; then
echo "⚠️ Warning: $critical_failures service(s) failed to start" echo "⚠️ Warning: $critical_failures critical service(s) reported failures"
if [ "$exit_on_failure" = "true" ] && [ $critical_failures -ge 1 ]; then if [ "$exit_on_failure" = "true" ] && [ $critical_failures -ge 2 ]; then
echo "❌ Exiting due to critical service failures" echo "❌ Exiting due to multiple critical service failures (threshold: 2)"
return 1 return 1
else
echo " Continuing with $critical_failures failure(s) - container may still be functional"
fi fi
else else
echo "✅ All services started successfully" echo "✅ All service initializations completed successfully"
fi fi
echo ""
fi fi
fi fi
@@ -1129,14 +1134,14 @@ __setup_mta() {
local local_hostname="${FULL_DOMAIN_NAME:-}" local local_hostname="${FULL_DOMAIN_NAME:-}"
local account_user="${SERVER_ADMIN//@*/}" local account_user="${SERVER_ADMIN//@*/}"
local account_domain="${EMAIL_DOMAIN//*@/}" 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 ################# sSMTP relay setup
if [ -n "$(type -P 'ssmtp')" ]; then if command -v ssmtp &>/dev/null; then
[ -d "/config/ssmtp" ] || mkdir -p "/config/ssmtp" [ -d "/config/ssmtp" ] || mkdir -p "/config/ssmtp"
[ -f "/etc/ssmtp/ssmtp.conf" ] && __rm "/etc/ssmtp/ssmtp.conf" [ -f "/etc/ssmtp/ssmtp.conf" ] && __rm "/etc/ssmtp/ssmtp.conf"
symlink_files="$(__find_file_relative "/config/ssmtp")" symlink_files="$(__find_file_relative "/config/ssmtp")"
if [ ! -f "/config/ssmtp/ssmtp.conf" ]; then if [ ! -f "/config/ssmtp/ssmtp.conf" ]; then
cat <<EOF | tee -p "/config/ssmtp/ssmtp.conf" >/dev/null cat >"/config/ssmtp/ssmtp.conf" <<EOF
# ssmtp configuration. # ssmtp configuration.
root=${account_user:-root}@${account_domain:-$HOSTNAME} root=${account_user:-root}@${account_domain:-$HOSTNAME}
mailhub=${relay_server:-172.17.0.1}:$relay_port mailhub=${relay_server:-172.17.0.1}:$relay_port
@@ -1170,13 +1175,13 @@ EOF
fi fi
################# postfix relay setup ################# postfix relay setup
elif [ -n "$(type -P 'postfix')" ]; then elif command -v postfix &>/dev/null; then
[ -d "/etc/postfix" ] || mkdir -p "/etc/postfix" [ -d "/etc/postfix" ] || mkdir -p "/etc/postfix"
[ -d "/config/postfix" ] || mkdir -p "/config/postfix" [ -d "/config/postfix" ] || mkdir -p "/config/postfix"
[ -f "/etc/postfix/main.cf" ] && __rm "/etc/postfix/main.cf" [ -f "/etc/postfix/main.cf" ] && __rm "/etc/postfix/main.cf"
symlink_files="$(__find_file_relative "/config/postfix")" symlink_files="$(__find_file_relative "/config/postfix")"
if [ ! -f "/config/postfix/main.cf" ]; then if [ ! -f "/config/postfix/main.cf" ]; then
cat <<EOF | tee -p "/config/postfix/main.cf" >/dev/null cat >"/config/postfix/main.cf" <<EOF
# postfix configuration. # postfix configuration.
smtpd_banner = \$myhostname ESMTP email server smtpd_banner = \$myhostname ESMTP email server
compatibility_level = 2 compatibility_level = 2
@@ -1294,7 +1299,7 @@ __initialize_database() {
__find_replace "REPLACE_DATABASE_ROOT_PASS" "$db_admin_pass" "$dir" __find_replace "REPLACE_DATABASE_ROOT_PASS" "$db_admin_pass" "$dir"
__find_replace "REPLACE_DATABASE_NAME" "$DATABASE_NAME" "$dir" __find_replace "REPLACE_DATABASE_NAME" "$DATABASE_NAME" "$dir"
__find_replace "REPLACE_DATABASE_DIR" "$DATABASE_DIR" "$dir" __find_replace "REPLACE_DATABASE_DIR" "$DATABASE_DIR" "$dir"
if echo "$dir" | grep -q '^/etc'; then if [[ "$dir" == "/etc"* ]]; then
__find_replace "REPLACE_USER_NAME" "$db_normal_user" "/etc" __find_replace "REPLACE_USER_NAME" "$db_normal_user" "/etc"
__find_replace "REPLACE_USER_PASS" "$db_normal_pass" "/etc" __find_replace "REPLACE_USER_PASS" "$db_normal_pass" "/etc"
__find_replace "REPLACE_DATABASE_USER" "$db_normal_user" "/etc" __find_replace "REPLACE_DATABASE_USER" "$db_normal_user" "/etc"
@@ -1327,8 +1332,8 @@ __initialize_system_etc() {
local file=() local file=()
local directories="" local directories=""
if [ -n "$conf_dir" ] && [ -e "$conf_dir" ]; then if [ -n "$conf_dir" ] && [ -e "$conf_dir" ]; then
files="$(find "$conf_dir"/* -not -path '*/env/*' -type f 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 | sed 's|'/config/'||g' | sort -u | grep -v '^$' | grep '.' || false)" 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\//}" echo "Copying config files to system: $conf_dir > /etc/${conf_dir//\/config\//}"
if [ -n "$directories" ]; then if [ -n "$directories" ]; then
for d in $directories; do for d in $directories; do
@@ -1356,7 +1361,7 @@ __initialize_custom_bin_dir() {
echo "Setting up bin $SET_USR_BIN > $LOCAL_BIN_DIR" echo "Setting up bin $SET_USR_BIN > $LOCAL_BIN_DIR"
for create_bin_template in $SET_USR_BIN; do for create_bin_template in $SET_USR_BIN; do
if [ -n "$create_bin_template" ]; then 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 if [ -e "$create_bin_template" ]; then
ln -sf "$create_bin_template" "$LOCAL_BIN_DIR/$create_bin_name" ln -sf "$create_bin_template" "$LOCAL_BIN_DIR/$create_bin_name"
fi fi
@@ -1367,51 +1372,85 @@ __initialize_custom_bin_dir() {
} }
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
__initialize_default_templates() { __initialize_default_templates() {
local errors=0
if [ -n "$DEFAULT_TEMPLATE_DIR" ]; then if [ -n "$DEFAULT_TEMPLATE_DIR" ]; then
if [ "$CONFIG_DIR_INITIALIZED" = "false" ] && [ -d "/config" ]; 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 for create_config_template in "$DEFAULT_TEMPLATE_DIR"/*; do
if [ -n "$create_config_template" ]; then if [ -e "$create_config_template" ]; then
create_template_name="$(basename "$create_config_template")" create_template_name="${create_config_template##*/}"
if [ -d "$create_config_template" ]; then if [ -d "$create_config_template" ]; then
mkdir -p "/config/$create_template_name/" mkdir -p "/config/$create_template_name/" || errors=$((errors + 1))
__is_dir_empty "/config/$create_template_name" && cp -Rf "$create_config_template/." "/config/$create_template_name/" 2>/dev/null if __is_dir_empty "/config/$create_template_name"; then
elif [ -e "$create_config_template" ]; then if ! cp -Rf "$create_config_template/." "/config/$create_template_name/" 2>/dev/null; then
[ -e "/config/$create_template_name" ] || cp -Rf "$create_config_template" "/config/$create_template_name" 2>/dev/null __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
fi fi
done done
unset create_config_template create_template_name unset create_config_template create_template_name
__log_debug "Template initialization completed with $errors errors"
fi fi
fi fi
return 0
} }
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
__initialize_config_dir() { __initialize_config_dir() {
local errors=0
if [ -n "$DEFAULT_CONF_DIR" ]; then if [ -n "$DEFAULT_CONF_DIR" ]; then
if [ "$CONFIG_DIR_INITIALIZED" = "false" ] && [ -d "/config" ]; 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 for create_config_template in "$DEFAULT_CONF_DIR"/*; do
create_config_name="$(basename "$create_config_template")" if [ -e "$create_config_template" ]; then
if [ -n "$create_config_template" ]; then create_config_name="${create_config_template##*/}"
if [ -d "$create_config_template" ]; then if [ -d "$create_config_template" ]; then
mkdir -p "/config/$create_config_name" mkdir -p "/config/$create_config_name" || errors=$((errors + 1))
__is_dir_empty "/config/$create_config_name" && cp -Rf "$create_config_template/." "/config/$create_config_name/" 2>/dev/null if __is_dir_empty "/config/$create_config_name"; then
elif [ -e "$create_config_template" ]; then if ! cp -Rf "$create_config_template/." "/config/$create_config_name/" 2>/dev/null; then
[ -e "/config/$create_config_name" ] || cp -Rf "$create_config_template" "/config/$create_config_name" 2>/dev/null __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
fi fi
done done
unset create_config_template create_config_name unset create_config_template create_config_name
__log_debug "Config initialization completed with $errors errors"
fi fi
fi fi
return 0
} }
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
__initialize_data_dir() { __initialize_data_dir() {
if [ -d "/data" ]; then if [ -d "/data" ]; then
if [ "$DATA_DIR_INITIALIZED" = "false" ] && [ -n "$DEFAULT_DATA_DIR" ]; 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 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 [ -n "$create_data_template" ]; then
if [ -d "$create_data_template" ]; then if [ -d "$create_data_template" ]; then
mkdir -p "/data/$create_data_name" mkdir -p "/data/$create_data_name"
@@ -1447,11 +1486,11 @@ __is_htdocs_mounted() {
WWW_ROOT_DIR="${WWW_ROOT_DIR:-/data/htdocs}" WWW_ROOT_DIR="${WWW_ROOT_DIR:-/data/htdocs}"
[ -n "$ENV_WWW_ROOT_DIR" ] && WWW_ROOT_DIR="$ENV_WWW_ROOT_DIR" [ -n "$ENV_WWW_ROOT_DIR" ] && WWW_ROOT_DIR="$ENV_WWW_ROOT_DIR"
if [ -n "$IMPORT_FROM_GIT" ]; then 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 unset IMPORT_FROM_GIT
fi fi
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 if __is_dir_empty "$WWW_ROOT_DIR"; then
echo "Importing project from $IMPORT_FROM_GIT to $WWW_ROOT_DIR" echo "Importing project from $IMPORT_FROM_GIT to $WWW_ROOT_DIR"
git clone -q "$IMPORT_FROM_GIT" "$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 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" php -S 0.0.0.0:$PHP_DEV_SERVER_PORT -t "/usr/local/share/httpd"
fi 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 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" php -S 0.0.0.0:$PHP_DEV_SERVER_PORT -t "$1"
fi fi
@@ -1528,16 +1567,16 @@ __switch_to_user() {
if [ "$switch_user" = "root" ]; then if [ "$switch_user" = "root" ]; then
su_exec="" su_exec=""
su_cmd() { eval "$@" || return 1; } su_cmd() { eval "$@" || return 1; }
elif [ "$(builtin type -P gosu)" ]; then elif command -v gosu &>/dev/null; then
su_exec="gosu $switch_user" su_exec="gosu $switch_user"
su_cmd() { $su_exec "$@" || return 1; } 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_exec="runuser -u $switch_user"
su_cmd() { $su_exec "$@" || return 1; } 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_exec="sudo -u $switch_user"
su_cmd() { $su_exec "$@" || return 1; } 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_exec="su -s /bin/sh - $switch_user"
su_cmd() { $su_exec -c "$@" || return 1; } su_cmd() { $su_exec -c "$@" || return 1; }
else else

View File

@@ -1,39 +1,118 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# shellcheck shell=bash # shellcheck shell=bash
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# casjaysdevdocker/ampache - mariadb init.d (runs before 99-ampache.sh) ##@Version : 202605131434-git
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # @@Author : Jason Hempstead
# shellcheck disable=SC1003,SC2016,SC2031,SC2120,SC2155,SC2199,SC2317 # @@Contact : jason@casjaysdev.pro
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # @@License : WTFPL
trap 'retVal=$?;[ "$SERVICE_IS_RUNNING" != "yes" ] && [ -f "$SERVICE_PID_FILE" ] && rm -Rf "$SERVICE_PID_FILE";exit $retVal' SIGINT SIGTERM EXIT # @@ReadME : 09-mariadb.sh --help
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # @@Copyright : Copyright: (c) 2026 Jason Hempstead, Casjays Developments
[ -f "/config/.debug" ] && [ -z "$DEBUGGER_OPTIONS" ] && export DEBUGGER_OPTIONS="$(<"/config/.debug")" || DEBUGGER_OPTIONS="${DEBUGGER_OPTIONS:-}" # @@Created : Wednesday, May 13, 2026 14:34 EDT
{ [ "$DEBUGGER" = "on" ] || [ -f "/config/.debug" ]; } && echo "Enabling debugging" && set -xo pipefail -x$DEBUGGER_OPTIONS && export DEBUGGER="on" || set -o pipefail # @@File : 09-mariadb.sh
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # @@Description : mariadb init.d script for casjaysdevdocker/ampache
export PATH="/usr/local/etc/docker/bin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin" # @@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" SCRIPT_FILE="$0"
SERVICE_NAME="mariadb" SERVICE_NAME="mariadb"
SCRIPT_NAME="${SCRIPT_FILE##*/}"
# - - - - - - - - - - - - - - - - - - - - - - - - -
# Function to exit appropriately based on context
__script_exit() { __script_exit() {
local exit_code="${1:-0}" local exit_code="${1:-0}"
if [ "${BASH_SOURCE[0]}" != "${0}" ]; then return "$exit_code"; else exit "$exit_code"; fi 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 # setup debugging - https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html
echo "__start_init_scripts function hasn't been Initialized" >&2 [ -f "/config/.debug" ] && [ -z "$DEBUGGER_OPTIONS" ] && export DEBUGGER_OPTIONS="$(<"/config/.debug")" || DEBUGGER_OPTIONS="${DEBUGGER_OPTIONS:-}"
SERVICE_IS_RUNNING="no" if [ "$DEBUGGER" = "on" ] || [ -f "/config/.debug" ]; then
__script_exit 1 echo "Enabling debugging"
set -xo pipefail -x$DEBUGGER_OPTIONS
export DEBUGGER="on"
else
set -o pipefail
fi 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 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 fi
# - - - - - - - - - - - - - - - - - - - - - - - - -
# import variables
for set_env in "/root/env.sh" "/usr/local/etc/docker/env"/*.sh "/config/env"/*.sh; do 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 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" START_SCRIPT="/usr/local/etc/docker/exec/$SERVICE_NAME"
# - - - - - - - - - - - - - - - - - - - - - - - - -
# Reset environment before executing service
RESET_ENV="no" RESET_ENV="no"
# - - - - - - - - - - - - - - - - - - - - - - - - -
# Set webroot
WWW_ROOT_DIR="/usr/local/share/ampache/public" WWW_ROOT_DIR="/usr/local/share/ampache/public"
# - - - - - - - - - - - - - - - - - - - - - - - - -
# Default predefined variables
DATA_DIR="/data/db/mariadb" DATA_DIR="/data/db/mariadb"
CONF_DIR="/config/my.cnf.d" CONF_DIR="/config/my.cnf.d"
ETC_DIR="/etc/my.cnf.d" ETC_DIR="/etc/my.cnf.d"
@@ -42,151 +121,214 @@ TMP_DIR="/tmp/mysql"
RUN_DIR="/run/mysqld" RUN_DIR="/run/mysqld"
LOG_DIR="/data/logs/mariadb" LOG_DIR="/data/logs/mariadb"
WORK_DIR="" WORK_DIR=""
# - - - - - - - - - - - - - - - - - - - - - - - - -
# port which service is listening on
SERVICE_PORT="3306" SERVICE_PORT="3306"
# - - - - - - - - - - - - - - - - - - - - - - - - -
RUNAS_USER="root" RUNAS_USER="root"
SERVICE_USER="mysql" SERVICE_USER="mysql"
SERVICE_GROUP="mysql" SERVICE_GROUP="mysql"
# - - - - - - - - - - - - - - - - - - - - - - - - -
RANDOM_PASS_USER="" RANDOM_PASS_USER=""
RANDOM_PASS_ROOT="" RANDOM_PASS_ROOT=""
SERVICE_UID="0" SERVICE_UID="0"
SERVICE_GID="0" SERVICE_GID="0"
# - - - - - - - - - - - - - - - - - - - - - - - - -
# execute command variables - keep single quotes; variables will be expanded later
EXEC_CMD_BIN='mariadbd' EXEC_CMD_BIN='mariadbd'
EXEC_CMD_ARGS='--user=$SERVICE_USER --datadir=$DATABASE_DIR --socket=/run/mysqld/mysqld.sock' EXEC_CMD_ARGS='--user=$SERVICE_USER --datadir=$DATABASE_DIR --socket=/run/mysqld/mysqld.sock'
EXEC_PRE_SCRIPT='' 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_WEB_SERVER="no"
IS_DATABASE_SERVICE="yes" IS_DATABASE_SERVICE="yes"
USES_DATABASE_SERVICE="no" USES_DATABASE_SERVICE="no"
DATABASE_SERVICE_TYPE="mariadb" DATABASE_SERVICE_TYPE="mariadb"
# - - - - - - - - - - - - - - - - - - - - - - - - -
PRE_EXEC_MESSAGE="" PRE_EXEC_MESSAGE=""
POST_EXECUTE_WAIT_TIME="1" POST_EXECUTE_WAIT_TIME="1"
# - - - - - - - - - - - - - - - - - - - - - - - - -
PATH="$PATH:." PATH="$PATH:."
# - - - - - - - - - - - - - - - - - - - - - - - - -
IP4_ADDRESS="$(__get_ip4)" IP4_ADDRESS="$(__get_ip4)"
IP6_ADDRESS="$(__get_ip6)" IP6_ADDRESS="$(__get_ip6)"
# - - - - - - - - - - - - - - - - - - - - - - - - -
ROOT_FILE_PREFIX="/config/secure/auth/root" ROOT_FILE_PREFIX="/config/secure/auth/root"
USER_FILE_PREFIX="/config/secure/auth/user" USER_FILE_PREFIX="/config/secure/auth/user"
# - - - - - - - - - - - - - - - - - - - - - - - - -
root_user_name="${MARIADB_ROOT_USER_NAME:-root}" root_user_name="${MARIADB_ROOT_USER_NAME:-root}"
root_user_pass="${MARIADB_ROOT_PASS_WORD:-random}" root_user_pass="${MARIADB_ROOT_PASS_WORD:-random}"
user_name="${MARIADB_USER_NAME:-ampache}" user_name="${MARIADB_USER_NAME:-ampache}"
user_pass="${MARIADB_USER_PASS_WORD:-random}" user_pass="${MARIADB_USER_PASS_WORD:-random}"
DATABASE_CREATE="${DATABASE_CREATE:-ampache}" 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_FILES=""
ADD_APPLICATION_DIRS="" ADD_APPLICATION_DIRS=""
APPLICATION_FILES="$LOG_DIR/$SERVICE_NAME.log" APPLICATION_FILES="$LOG_DIR/$SERVICE_NAME.log"
APPLICATION_DIRS="$ETC_DIR $CONF_DIR $LOG_DIR $TMP_DIR $RUN_DIR $VAR_DIR" APPLICATION_DIRS="$ETC_DIR $CONF_DIR $LOG_DIR $TMP_DIR $RUN_DIR $VAR_DIR"
ADDITIONAL_CONFIG_DIRS="" ADDITIONAL_CONFIG_DIRS=""
CMD_ENV="" CMD_ENV=""
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Custom functions
# - - - - - - - - - - - - - - - - - - - - - - - - -
__run_precopy() { __run_precopy() {
local hostname=${HOSTNAME} local hostname=${HOSTNAME}
if builtin type -t __run_precopy_local | grep -q 'function'; then __run_precopy_local; fi 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() { __execute_prerun() {
local hostname=${HOSTNAME} local hostname=${HOSTNAME}
mkdir -p /run/mysqld /data/db/mariadb /data/logs/mariadb 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 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 if builtin type -t __execute_prerun_local | grep -q 'function'; then
__execute_prerun_local
fi
} }
# - - - - - - - - - - - - - - - - - - - - - - - - -
__run_pre_execute_checks() { __run_pre_execute_checks() {
local exitStatus=0 local exitStatus=0
local pre_execute_checks_MessageST="Running preexecute check for $SERVICE_NAME" local pre_execute_checks_MessageST="Running preexecute check for $SERVICE_NAME"
local pre_execute_checks_MessageEnd="Finished preexecute check for $SERVICE_NAME" local pre_execute_checks_MessageEnd="Finished preexecute check for $SERVICE_NAME"
__banner "$pre_execute_checks_MessageST" __banner "$pre_execute_checks_MessageST"
{ {
if [ ! -d "$DATABASE_DIR" ] || [ ! -f "$DATABASE_DIR/ibdata1" ] && [ ! -d "$DATABASE_DIR/mysql" ]; then if [ ! -d "$DATABASE_DIR" ] || [ ! -f "$DATABASE_DIR/ibdata1" ] && [ ! -d "$DATABASE_DIR/mysql" ]; then
rm -Rf "${DATABASE_DIR:?}"/* rm -Rf "${DATABASE_DIR:?}"/*
mkdir -p "$DATABASE_DIR" mkdir -p "$DATABASE_DIR"
chown -Rf $SERVICE_USER:$SERVICE_GROUP "$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 || \ 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 mysql_install_db --datadir=$DATABASE_DIR --user=$SERVICE_USER 2>/dev/null
fi fi
} }
exitStatus=$? exitStatus=$?
__banner "$pre_execute_checks_MessageEnd: Status $exitStatus" __banner "$pre_execute_checks_MessageEnd: Status $exitStatus"
if [ $exitStatus -ne 0 ]; then if [ $exitStatus -ne 0 ]; then
echo "The pre-execution check has failed" >&2 echo "The pre-execution check has failed" >&2
[ -f "$SERVICE_PID_FILE" ] && rm -Rf "$SERVICE_PID_FILE" if [ -f "$SERVICE_PID_FILE" ]; then
__script_exit 1 rm -Rf "$SERVICE_PID_FILE"
fi fi
if builtin type -t __run_pre_execute_checks_local | grep -q 'function'; then __run_pre_execute_checks_local; fi __script_exit 1
return $exitStatus 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() { __update_conf_files() {
local exitCode=0 local exitCode=0
local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" 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 if builtin type -t __update_conf_files_local | grep -q 'function'; then
return $exitCode __update_conf_files_local
fi
return $exitCode
} }
# - - - - - - - - - - - - - - - - - - - - - - - - -
__pre_execute() { __pre_execute() {
local exitCode=0 local exitCode=0
sleep 5 local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}"
if builtin type -t __pre_execute_local | grep -q 'function'; then __pre_execute_local; fi sleep 5
return $exitCode unset sysname
if builtin type -t __pre_execute_local | grep -q 'function'; then
__pre_execute_local
fi
return $exitCode
} }
# - - - - - - - - - - - - - - - - - - - - - - - - -
__post_execute() { __post_execute() {
local pid="" local pid=""
local retVal=0 local retVal=0
local ctime=${POST_EXECUTE_WAIT_TIME:-1} local ctime=${POST_EXECUTE_WAIT_TIME:-1}
local waitTime=$((ctime * 60)) local waitTime=$((ctime * 60))
local postMessageST="Running post commands for $SERVICE_NAME" local postMessageST="Running post commands for $SERVICE_NAME"
local postMessageEnd="Finished post commands for $SERVICE_NAME" local postMessageEnd="Finished post commands for $SERVICE_NAME"
local DATABASE_ROOT_PASSWORD="${root_user_pass:-$(__random_password)}" local DATABASE_ROOT_PASSWORD="${root_user_pass:-$(__random_password)}"
local db_root_user="${MYSQL_ROOT_USER_NAME:-root}" local db_root_user="${MYSQL_ROOT_USER_NAME:-root}"
echo "$DATABASE_ROOT_PASSWORD" >"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_pass" 2>/dev/null || true echo "$DATABASE_ROOT_PASSWORD" >"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_pass" 2>/dev/null || true
sleep $waitTime sleep $waitTime
( (
__banner "$postMessageST" __banner "$postMessageST"
# Wait for socket # Wait for socket
local i=0 local i=0
while [ ! -S /run/mysqld/mysqld.sock ] && [ $i -lt 30 ]; do sleep 1; i=$((i+1)); done 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 [ -f "$CONF_DIR/init.sh" ]; then bash -c "$CONF_DIR/init.sh"; fi
if [ -n "$DATABASE_CREATE" ]; then if [ -n "$DATABASE_CREATE" ]; then
mariadb -v -u $db_root_user <<MYSQL_SCRIPT mariadb -v -u $db_root_user <<MYSQL_SCRIPT
CREATE DATABASE IF NOT EXISTS \`$DATABASE_CREATE\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE DATABASE IF NOT EXISTS \`$DATABASE_CREATE\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
MYSQL_SCRIPT MYSQL_SCRIPT
fi fi
if [ "$user_name" != "root" ] && [ -n "$user_name" ]; then if [ "$user_name" != "root" ] && [ -n "$user_name" ]; then
mariadb -v -u $db_root_user <<MYSQL_SCRIPT mariadb -v -u $db_root_user <<MYSQL_SCRIPT
CREATE USER IF NOT EXISTS '$user_name'@'%' IDENTIFIED BY '$user_pass'; CREATE USER IF NOT EXISTS '$user_name'@'%' IDENTIFIED BY '$user_pass';
CREATE USER IF NOT EXISTS '$user_name'@'localhost' IDENTIFIED BY '$user_pass'; CREATE USER IF NOT EXISTS '$user_name'@'localhost' IDENTIFIED BY '$user_pass';
MYSQL_SCRIPT MYSQL_SCRIPT
fi fi
if [ "$user_name" != "root" ] && [ -n "$DATABASE_CREATE" ]; then if [ "$user_name" != "root" ] && [ -n "$DATABASE_CREATE" ]; then
mariadb -v -u $db_root_user <<MYSQL_SCRIPT mariadb -v -u $db_root_user <<MYSQL_SCRIPT
GRANT ALL PRIVILEGES ON \`$DATABASE_CREATE\`.* TO '$user_name'@'%'; GRANT ALL PRIVILEGES ON \`$DATABASE_CREATE\`.* TO '$user_name'@'%';
GRANT ALL PRIVILEGES ON \`$DATABASE_CREATE\`.* TO '$user_name'@'localhost'; GRANT ALL PRIVILEGES ON \`$DATABASE_CREATE\`.* TO '$user_name'@'localhost';
FLUSH PRIVILEGES; FLUSH PRIVILEGES;
MYSQL_SCRIPT MYSQL_SCRIPT
fi fi
mariadb -v -u $db_root_user <<MYSQL_SCRIPT mariadb -v -u $db_root_user <<MYSQL_SCRIPT
CREATE USER IF NOT EXISTS 'root'@'%' IDENTIFIED BY '$DATABASE_ROOT_PASSWORD'; CREATE USER IF NOT EXISTS 'root'@'%' IDENTIFIED BY '$DATABASE_ROOT_PASSWORD';
ALTER USER 'root'@'%' IDENTIFIED BY '$DATABASE_ROOT_PASSWORD'; ALTER USER 'root'@'%' IDENTIFIED BY '$DATABASE_ROOT_PASSWORD';
ALTER USER 'root'@'localhost' IDENTIFIED BY '$DATABASE_ROOT_PASSWORD'; ALTER USER 'root'@'localhost' IDENTIFIED BY '$DATABASE_ROOT_PASSWORD';
FLUSH PRIVILEGES; FLUSH PRIVILEGES;
MYSQL_SCRIPT MYSQL_SCRIPT
__banner "$postMessageEnd: Status $retVal" __banner "$postMessageEnd: Status $retVal"
) 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt" & ) 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt" &
pid=$! pid=$!
if builtin type -t __post_execute_local | grep -q 'function'; then __post_execute_local; fi if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
return $retVal 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() { __pre_message() {
local exitCode=0 local exitCode=0
[ -n "$PRE_EXEC_MESSAGE" ] && eval echo "$PRE_EXEC_MESSAGE" if [ -n "$PRE_EXEC_MESSAGE" ]; then
if builtin type -t __pre_message_local | grep -q 'function'; then __pre_message_local; fi eval echo "$PRE_EXEC_MESSAGE"
return $exitCode fi
if builtin type -t __pre_message_local | grep -q 'function'; then
__pre_message_local
fi
return $exitCode
} }
# - - - - - - - - - - - - - - - - - - - - - - - - -
__update_ssl_conf() { __update_ssl_conf() {
local exitCode=0 local exitCode=0
if builtin type -t __update_ssl_conf_local | grep -q 'function'; then __update_ssl_conf_local; fi local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}"
return $exitCode if builtin type -t __update_ssl_conf_local | grep -q 'function'; then
__update_ssl_conf_local
fi
return $exitCode
} }
# - - - - - - - - - - - - - - - - - - - - - - - - -
__create_service_env() { __create_service_env() {
local exitCode=0 local exitCode=0
if [ ! -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" ]; then if [ ! -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" ]; then
cat <<EOF | tee -p "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" &>/dev/null cat <<EOF | tee -p "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" &>/dev/null
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Generated by 09-mariadb.sh - edit to override defaults # Generated by 09-mariadb.sh - edit to override defaults
#root_user_name="root" #root_user_name="root"
#root_user_pass="random" #root_user_pass="random"
@@ -194,125 +336,281 @@ __create_service_env() {
#user_pass="random" #user_pass="random"
#DATABASE_CREATE="ampache" #DATABASE_CREATE="ampache"
EOF EOF
fi fi
if [ ! -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh" ]; then if [ ! -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh" ]; then
__run_precopy_local() { true; } # - - - - - - - - - - - - - - - - - - - - - - - - -
__execute_prerun_local() { true; } __run_precopy_local() { true; }
__run_pre_execute_checks_local() { true; } # - - - - - - - - - - - - - - - - - - - - - - - - -
__update_conf_files_local() { true; } __execute_prerun_local() { true; }
__pre_execute_local() { true; } # - - - - - - - - - - - - - - - - - - - - - - - - -
__post_execute_local() { true; } __run_pre_execute_checks_local() { true; }
__pre_message_local() { true; } # - - - - - - - - - - - - - - - - - - - - - - - - -
__update_ssl_conf_local() { true; } __update_conf_files_local() { true; }
fi # - - - - - - - - - - - - - - - - - - - - - - - - -
__file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" || exitCode=$((exitCode + 1)) __pre_execute_local() { true; }
__file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh" || exitCode=$((exitCode + 1)) # - - - - - - - - - - - - - - - - - - - - - - - - -
return $exitCode __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() { __run_start_script() {
local runExitCode=0 local runExitCode=0
local workdir="$(eval echo "${WORK_DIR:-}")" local workdir="$(eval echo "${WORK_DIR:-}")"
local cmd="$(eval echo "${EXEC_CMD_BIN:-}")" local cmd="$(eval echo "${EXEC_CMD_BIN:-}")"
local args="$(eval echo "${EXEC_CMD_ARGS:-}")" local args="$(eval echo "${EXEC_CMD_ARGS:-}")"
local name="$(eval echo "${EXEC_CMD_NAME:-}")" local name="$(eval echo "${EXEC_CMD_NAME:-}")"
local pre="$(eval echo "${EXEC_PRE_SCRIPT:-}")" local pre="$(eval echo "${EXEC_PRE_SCRIPT:-}")"
local extra_env="$(eval echo "${CMD_ENV//,/ }")" local extra_env="$(eval echo "${CMD_ENV//,/ }")"
local lc_type="$(eval echo "${LANG:-${LC_ALL:-$LC_CTYPE}}")" local lc_type="$(eval echo "${LANG:-${LC_ALL:-$LC_CTYPE}}")"
local home="$(eval echo "${workdir//\/root/\/tmp\/docker}")" local home="$(eval echo "${workdir//\/root/\/tmp\/docker}")"
local path="$(eval echo "$PATH")" local path="$(eval echo "$PATH")"
local message="$(eval echo "")" local message="$(eval echo "")"
local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}"
[ -f "$CONF_DIR/$SERVICE_NAME.exec_cmd.sh" ] && . "$CONF_DIR/$SERVICE_NAME.exec_cmd.sh" if [ -f "$CONF_DIR/$SERVICE_NAME.exec_cmd.sh" ]; then
if [ -z "$cmd" ]; then . "$CONF_DIR/$SERVICE_NAME.exec_cmd.sh"
__post_execute 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt" fi
retVal=$? if [ -z "$cmd" ]; then
echo "Initializing $SCRIPT_NAME has completed" __post_execute 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt"
__script_exit $retVal retVal=$?
else __log_info "Initialization of $SCRIPT_NAME has completed"
if [ ! -x "$cmd" ]; then echo "$name is not a valid executable"; return 2; fi __script_exit $retVal
if __proc_check "$name" || __proc_check "$cmd"; then echo "$name is already running" >&2; return 0; fi else
[ -n "$SERVICE_USER" ] && echo "Setting up $cmd to run as $SERVICE_USER" || SERVICE_USER="root" if [ ! -x "$cmd" ]; then
[ -n "$SERVICE_PORT" ] && echo "$name will be running on port $SERVICE_PORT" || SERVICE_PORT="" __log_error "$name is not a valid executable"
export cmd_exec="$cmd $args" return 2
message="Starting service: $name $args" fi
[ -n "$su_exec" ] && echo "using $su_exec" | tee -a -p "/data/logs/init.txt" if __proc_check "$name" || __proc_check "$cmd"; then
echo "$message" | tee -a -p "/data/logs/init.txt" __log_debug "Service $name is already running"
su_cmd touch "$SERVICE_PID_FILE" return 0
execute_command="$(__trim "$su_exec $cmd_exec")" else
if [ ! -f "$START_SCRIPT" ]; then if [ -n "$cmd" ]; then
cat <<EOF >"$START_SCRIPT" 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 <<EOF >"$START_SCRIPT"
#!/usr/bin/env bash #!/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 set -Eeo pipefail
# Setting up $cmd to run as ${SERVICE_USER:-root}
retVal=10 retVal=10
cmd="$cmd" cmd="$cmd"
args="$args"
SERVICE_NAME="$SERVICE_NAME" SERVICE_NAME="$SERVICE_NAME"
SERVICE_PID_FILE="$SERVICE_PID_FILE" 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=\$! execPid=\$!
sleep 2 sleep 2
checkPID="\$(ps ax | awk '{print \$1}' | grep -v grep | grep "\$execPid$" || false)" if [ -n "\$execPid" ] && kill -0 "\$execPid" 2>/dev/null; then
[ -n "\$execPid" ] && [ -n "\$checkPID" ] && echo "\$execPid" >"\$SERVICE_PID_FILE" && retVal=0 || retVal=10 echo "\$execPid" >"\$SERVICE_PID_FILE"
[ "\$retVal" = 0 ] && echo "\$cmd has been started" || echo "Failed to start $execute_command" >&2 retVal=0
exit \$retVal else
EOF retVal=10
fi echo "Failed to start $execute_command" >&2
[ -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"
fi 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_DIR="${DATABASE_DIR_MARIADB:-/data/db/mariadb}"
DATABASE_BASE_DIR="$DATABASE_DIR" 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})" # Allow variables via imports - Overwrite existing
[ "$root_user_pass" = "random" ] && root_user_pass="$(__random_password ${RANDOM_PASS_ROOT:-16})" if [ -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" ]; then
[ -n "$user_name" ] && echo "$user_name" >"${USER_FILE_PREFIX}/${SERVICE_NAME}_name" . "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh"
[ -n "$user_pass" ] && echo "$user_pass" >"${USER_FILE_PREFIX}/${SERVICE_NAME}_pass" fi
[ -n "$root_user_name" ] && echo "$root_user_name" >"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_name" # - - - - - - - - - - - - - - - - - - - - - - - - -
[ -n "$root_user_pass" ] && echo "$root_user_pass" >"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_pass" if [ "$user_pass" = "random" ]; then
[ -d "$LOG_DIR" ] || mkdir -p "$LOG_DIR" user_pass="$(__random_password ${RANDOM_PASS_USER:-16})"
[ -d "$RUN_DIR" ] || mkdir -p "$RUN_DIR" fi
__file_exists_with_content "${USER_FILE_PREFIX}/${SERVICE_NAME}_name" && user_name="$(<"${USER_FILE_PREFIX}/${SERVICE_NAME}_name")" if [ "$root_user_pass" = "random" ]; then
__file_exists_with_content "${USER_FILE_PREFIX}/${SERVICE_NAME}_pass" && user_pass="$(<"${USER_FILE_PREFIX}/${SERVICE_NAME}_pass")" root_user_pass="$(__random_password ${RANDOM_PASS_ROOT:-16})"
__file_exists_with_content "${ROOT_FILE_PREFIX}/${SERVICE_NAME}_name" && root_user_name="$(<"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_name")" fi
__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")" if [ -n "$user_name" ]; then
__file_exists_with_content "${ROOT_FILE_PREFIX}/db_pass_root" && DATABASE_PASS_ROOT="$(<"${ROOT_FILE_PREFIX}/db_pass_root")" 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}}" sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}"
# - - - - - - - - - - - - - - - - - - - - - - - - -
__create_service_env __create_service_env
__init_config_etc __init_config_etc
__execute_prerun __execute_prerun
@@ -328,7 +626,7 @@ __update_ssl_certs
__run_secure_function __run_secure_function
__run_precopy __run_precopy
for config_2_etc in $CONF_DIR $ADDITIONAL_CONFIG_DIRS; do 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 done
__initialize_replace_variables "$ETC_DIR" "$CONF_DIR" "$ADDITIONAL_CONFIG_DIRS" "$WWW_ROOT_DIR" __initialize_replace_variables "$ETC_DIR" "$CONF_DIR" "$ADDITIONAL_CONFIG_DIRS" "$WWW_ROOT_DIR"
__initialize_database __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" __run_start_script 2>>/dev/stderr | tee -p -a "/data/logs/entrypoint.log"
errorCode=$? errorCode=$?
if [ -n "$EXEC_CMD_BIN" ]; then 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 if [ "$errorCode" -eq 0 ]; then
SERVICE_EXIT_CODE=0 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 fi
# - - - - - - - - - - - - - - - - - - - - - - - - -
__post_execute 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt" & __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" __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 __script_exit $SERVICE_EXIT_CODE
# - - - - - - - - - - - - - - - - - - - - - - - - -
# ex: ts=2 sw=2 et filetype=sh
# - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@@ -1,38 +1,118 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# shellcheck shell=bash # shellcheck shell=bash
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# casjaysdevdocker/ampache - apache + php-fpm init.d (runs after 09-mariadb.sh) ##@Version : 202605131434-git
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # @@Author : Jason Hempstead
# shellcheck disable=SC1003,SC2016,SC2031,SC2120,SC2155,SC2199,SC2317 # @@Contact : jason@casjaysdev.pro
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # @@License : WTFPL
trap 'retVal=$?;[ "$SERVICE_IS_RUNNING" != "yes" ] && [ -f "$SERVICE_PID_FILE" ] && rm -Rf "$SERVICE_PID_FILE";exit $retVal' SIGINT SIGTERM EXIT # @@ReadME : 99-ampache.sh --help
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # @@Copyright : Copyright: (c) 2026 Jason Hempstead, Casjays Developments
[ -f "/config/.debug" ] && [ -z "$DEBUGGER_OPTIONS" ] && export DEBUGGER_OPTIONS="$(<"/config/.debug")" || DEBUGGER_OPTIONS="${DEBUGGER_OPTIONS:-}" # @@Created : Wednesday, May 13, 2026 14:34 EDT
{ [ "$DEBUGGER" = "on" ] || [ -f "/config/.debug" ]; } && echo "Enabling debugging" && set -xo pipefail -x$DEBUGGER_OPTIONS && export DEBUGGER="on" || set -o pipefail # @@File : 99-ampache.sh
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # @@Description : apache + php-fpm init.d script for casjaysdevdocker/ampache
export PATH="/usr/local/etc/docker/bin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin" # @@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" SCRIPT_FILE="$0"
SERVICE_NAME="ampache" SERVICE_NAME="ampache"
SCRIPT_NAME="${SCRIPT_FILE##*/}"
# - - - - - - - - - - - - - - - - - - - - - - - - -
# Function to exit appropriately based on context
__script_exit() { __script_exit() {
local exit_code="${1:-0}" local exit_code="${1:-0}"
if [ "${BASH_SOURCE[0]}" != "${0}" ]; then return "$exit_code"; else exit "$exit_code"; fi 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 # setup debugging - https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html
echo "__start_init_scripts function hasn't been Initialized" >&2 [ -f "/config/.debug" ] && [ -z "$DEBUGGER_OPTIONS" ] && export DEBUGGER_OPTIONS="$(<"/config/.debug")" || DEBUGGER_OPTIONS="${DEBUGGER_OPTIONS:-}"
SERVICE_IS_RUNNING="no" if [ "$DEBUGGER" = "on" ] || [ -f "/config/.debug" ]; then
__script_exit 1 echo "Enabling debugging"
set -xo pipefail -x$DEBUGGER_OPTIONS
export DEBUGGER="on"
else
set -o pipefail
fi 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 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 fi
# - - - - - - - - - - - - - - - - - - - - - - - - -
# import variables
for set_env in "/root/env.sh" "/usr/local/etc/docker/env"/*.sh "/config/env"/*.sh; do 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 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" START_SCRIPT="/usr/local/etc/docker/exec/$SERVICE_NAME"
# - - - - - - - - - - - - - - - - - - - - - - - - -
# Reset environment before executing service
RESET_ENV="no" RESET_ENV="no"
# - - - - - - - - - - - - - - - - - - - - - - - - -
# Set webroot
WWW_ROOT_DIR="/usr/local/share/ampache/public" WWW_ROOT_DIR="/usr/local/share/ampache/public"
# - - - - - - - - - - - - - - - - - - - - - - - - -
# Default predefined variables
DATA_DIR="/data/ampache" DATA_DIR="/data/ampache"
CONF_DIR="/config/apache2" CONF_DIR="/config/apache2"
ETC_DIR="/etc/apache2" ETC_DIR="/etc/apache2"
@@ -41,213 +121,524 @@ TMP_DIR="/tmp/ampache"
RUN_DIR="/run/apache2" RUN_DIR="/run/apache2"
LOG_DIR="/data/logs/apache2" LOG_DIR="/data/logs/apache2"
WORK_DIR="" WORK_DIR=""
# - - - - - - - - - - - - - - - - - - - - - - - - -
# port which service is listening on
SERVICE_PORT="80" SERVICE_PORT="80"
# - - - - - - - - - - - - - - - - - - - - - - - - -
RUNAS_USER="root" RUNAS_USER="root"
SERVICE_USER="apache" SERVICE_USER="apache"
SERVICE_GROUP="apache" SERVICE_GROUP="apache"
# - - - - - - - - - - - - - - - - - - - - - - - - -
RANDOM_PASS_USER="" RANDOM_PASS_USER=""
RANDOM_PASS_ROOT="" RANDOM_PASS_ROOT=""
SERVICE_UID="0" SERVICE_UID="0"
SERVICE_GID="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_BIN='/usr/local/etc/docker/bin/start-ampache'
EXEC_CMD_ARGS='' EXEC_CMD_ARGS=''
EXEC_PRE_SCRIPT='' 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_WEB_SERVER="yes"
IS_DATABASE_SERVICE="no" IS_DATABASE_SERVICE="no"
USES_DATABASE_SERVICE="yes" USES_DATABASE_SERVICE="yes"
DATABASE_SERVICE_TYPE="mariadb" DATABASE_SERVICE_TYPE="mariadb"
# - - - - - - - - - - - - - - - - - - - - - - - - -
PRE_EXEC_MESSAGE="Open http://localhost:${SERVICE_PORT:-80}/ to run the Ampache web installer." PRE_EXEC_MESSAGE="Open http://localhost:${SERVICE_PORT:-80}/ to run the Ampache web installer."
POST_EXECUTE_WAIT_TIME="1" POST_EXECUTE_WAIT_TIME="1"
# - - - - - - - - - - - - - - - - - - - - - - - - -
PATH="$PATH:." PATH="$PATH:."
# - - - - - - - - - - - - - - - - - - - - - - - - -
IP4_ADDRESS="$(__get_ip4)" IP4_ADDRESS="$(__get_ip4)"
IP6_ADDRESS="$(__get_ip6)" IP6_ADDRESS="$(__get_ip6)"
# - - - - - - - - - - - - - - - - - - - - - - - - -
ROOT_FILE_PREFIX="/config/secure/auth/root" ROOT_FILE_PREFIX="/config/secure/auth/root"
USER_FILE_PREFIX="/config/secure/auth/user" USER_FILE_PREFIX="/config/secure/auth/user"
# - - - - - - - - - - - - - - - - - - - - - - - - -
root_user_name="${AMPACHE_ROOT_USER_NAME:-}" root_user_name="${AMPACHE_ROOT_USER_NAME:-}"
root_user_pass="${AMPACHE_ROOT_PASS_WORD:-}" root_user_pass="${AMPACHE_ROOT_PASS_WORD:-}"
user_name="${AMPACHE_USER_NAME:-}" user_name="${AMPACHE_USER_NAME:-}"
user_pass="${AMPACHE_USER_PASS_WORD:-}" 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_FILES=""
ADD_APPLICATION_DIRS="/usr/local/share/ampache /usr/local/share/ampache/config /tmp/php-sessions" ADD_APPLICATION_DIRS="/usr/local/share/ampache /usr/local/share/ampache/config /tmp/php-sessions"
APPLICATION_FILES="$LOG_DIR/$SERVICE_NAME.log" 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" 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" ADDITIONAL_CONFIG_DIRS="/config/php84 /config/ampache"
CMD_ENV="" CMD_ENV=""
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Custom functions
# - - - - - - - - - - - - - - - - - - - - - - - - -
__run_precopy() { __run_precopy() {
local hostname=${HOSTNAME} local hostname=${HOSTNAME}
if builtin type -t __run_precopy_local | grep -q 'function'; then __run_precopy_local; fi 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() { __execute_prerun() {
local hostname=${HOSTNAME} local hostname=${HOSTNAME}
# Ensure runtime dirs # Ensure runtime dirs
mkdir -p /run/apache2 /run/php-fpm /tmp/php-sessions \ mkdir -p /run/apache2 /run/php-fpm /tmp/php-sessions \
/data/logs/apache2 /data/logs/php-fpm /data/ampache /data/logs/apache2 /data/logs/php-fpm /data/ampache
chown -Rf apache:apache /run/apache2 /run/php-fpm /tmp/php-sessions \ chown -Rf apache:apache /run/apache2 /run/php-fpm /tmp/php-sessions \
/data/logs/apache2 /data/logs/php-fpm 2>/dev/null || true /data/logs/apache2 /data/logs/php-fpm 2>/dev/null || true
# Ampache writable dirs # Ampache writable dirs
if [ -d /usr/local/share/ampache ]; then if [ -d /usr/local/share/ampache ]; then
mkdir -p /usr/local/share/ampache/config mkdir -p /usr/local/share/ampache/config
chown -Rf apache:apache /usr/local/share/ampache/config 2>/dev/null || true 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. # 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 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 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 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 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 ln -sf /config/ampache/ampache.cfg.php /usr/local/share/ampache/config/ampache.cfg.php
fi fi
fi fi
if builtin type -t __execute_prerun_local | grep -q 'function'; then __execute_prerun_local; fi if builtin type -t __execute_prerun_local | grep -q 'function'; then
__execute_prerun_local
fi
} }
# - - - - - - - - - - - - - - - - - - - - - - - - -
__run_pre_execute_checks() { __run_pre_execute_checks() {
local exitStatus=0 local exitStatus=0
__banner "Running preexecute check for $SERVICE_NAME" local pre_execute_checks_MessageST="Running preexecute check for $SERVICE_NAME"
# Wait briefly for mariadb socket local pre_execute_checks_MessageEnd="Finished preexecute check for $SERVICE_NAME"
local i=0 __banner "$pre_execute_checks_MessageST"
while [ ! -S /run/mysqld/mysqld.sock ] && [ $i -lt 30 ]; do sleep 1; i=$((i+1)); done {
if [ ! -S /run/mysqld/mysqld.sock ]; then # Wait briefly for mariadb socket
echo "Warning: mariadb socket not found after 30s; ampache install.php will need it before continuing" >&2 local i=0
fi while [ ! -S /run/mysqld/mysqld.sock ] && [ $i -lt 30 ]; do sleep 1; i=$((i+1)); done
# Validate apache config syntax if [ ! -S /run/mysqld/mysqld.sock ]; then
httpd -t -f /etc/apache2/httpd.conf 2>&1 | head -20 || exitStatus=$? echo "Warning: mariadb socket not found after 30s; ampache install.php will need it before continuing" >&2
__banner "Finished preexecute check for $SERVICE_NAME: Status $exitStatus" fi
if [ $exitStatus -ne 0 ]; then # Validate apache config syntax
echo "The pre-execution check has failed" >&2 httpd -t -f /etc/apache2/httpd.conf 2>&1 | head -20 || exitStatus=$?
[ -f "$SERVICE_PID_FILE" ] && rm -Rf "$SERVICE_PID_FILE" }
__script_exit 1 exitStatus=$?
fi __banner "$pre_execute_checks_MessageEnd: Status $exitStatus"
if builtin type -t __run_pre_execute_checks_local | grep -q 'function'; then __run_pre_execute_checks_local; fi if [ $exitStatus -ne 0 ]; then
return $exitStatus 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() { __update_conf_files() {
local exitCode=0 local exitCode=0
local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}"
__replace "REPLACE_TZ" "${TZ:-UTC}" "/etc/php84/php.ini" __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 if builtin type -t __update_conf_files_local | grep -q 'function'; then
return $exitCode __update_conf_files_local
fi
return $exitCode
} }
# - - - - - - - - - - - - - - - - - - - - - - - - -
__pre_execute() { __pre_execute() {
local exitCode=0 local exitCode=0
sleep 5 local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}"
if builtin type -t __pre_execute_local | grep -q 'function'; then __pre_execute_local; fi unset sysname
return $exitCode sleep 5
if builtin type -t __pre_execute_local | grep -q 'function'; then
__pre_execute_local
fi
return $exitCode
} }
# - - - - - - - - - - - - - - - - - - - - - - - - -
__post_execute() { __post_execute() {
local pid="" local pid=""
local retVal=0 local retVal=0
local ctime=${POST_EXECUTE_WAIT_TIME:-1} local ctime=${POST_EXECUTE_WAIT_TIME:-1}
local waitTime=$((ctime * 60)) local waitTime=$((ctime * 60))
sleep $waitTime local postMessageST="Running post commands for $SERVICE_NAME"
( local postMessageEnd="Finished post commands for $SERVICE_NAME"
__banner "Running post commands for $SERVICE_NAME" sleep $waitTime
# 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 __banner "$postMessageST"
cp -f /usr/local/share/ampache/config/ampache.cfg.php /config/ampache/ampache.cfg.php # Mirror live ampache.cfg.php out to /config once install.php has written it
ln -sf /config/ampache/ampache.cfg.php /usr/local/share/ampache/config/ampache.cfg.php if [ -f /usr/local/share/ampache/config/ampache.cfg.php ] && [ ! -L /usr/local/share/ampache/config/ampache.cfg.php ]; then
fi cp -f /usr/local/share/ampache/config/ampache.cfg.php /config/ampache/ampache.cfg.php
__banner "Finished post commands for $SERVICE_NAME: Status $retVal" ln -sf /config/ampache/ampache.cfg.php /usr/local/share/ampache/config/ampache.cfg.php
) 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt" & fi
pid=$! __banner "$postMessageEnd: Status $retVal"
if builtin type -t __post_execute_local | grep -q 'function'; then __post_execute_local; fi ) 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt" &
return $retVal 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() { __pre_message() {
local exitCode=0 local exitCode=0
[ -n "$PRE_EXEC_MESSAGE" ] && eval echo "$PRE_EXEC_MESSAGE" if [ -n "$PRE_EXEC_MESSAGE" ]; then
if builtin type -t __pre_message_local | grep -q 'function'; then __pre_message_local; fi eval echo "$PRE_EXEC_MESSAGE"
return $exitCode fi
if builtin type -t __pre_message_local | grep -q 'function'; then
__pre_message_local
fi
return $exitCode
} }
# - - - - - - - - - - - - - - - - - - - - - - - - -
__update_ssl_conf() { __update_ssl_conf() {
local exitCode=0 local exitCode=0
if builtin type -t __update_ssl_conf_local | grep -q 'function'; then __update_ssl_conf_local; fi local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}"
return $exitCode if builtin type -t __update_ssl_conf_local | grep -q 'function'; then
__update_ssl_conf_local
fi
return $exitCode
} }
# - - - - - - - - - - - - - - - - - - - - - - - - -
__create_service_env() { __create_service_env() {
local exitCode=0 local exitCode=0
if [ ! -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" ]; then if [ ! -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" ]; then
cat <<EOF | tee -p "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" &>/dev/null cat <<EOF | tee -p "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" &>/dev/null
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Generated by 99-ampache.sh - edit to override defaults # Generated by 99-ampache.sh - edit to override defaults
#user_name="" #user_name=""
#user_pass="" #user_pass=""
EOF EOF
fi fi
if [ ! -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh" ]; then if [ ! -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh" ]; then
__run_precopy_local() { true; } # - - - - - - - - - - - - - - - - - - - - - - - - -
__execute_prerun_local() { true; } __run_precopy_local() { true; }
__run_pre_execute_checks_local() { true; } # - - - - - - - - - - - - - - - - - - - - - - - - -
__update_conf_files_local() { true; } __execute_prerun_local() { true; }
__pre_execute_local() { true; } # - - - - - - - - - - - - - - - - - - - - - - - - -
__post_execute_local() { true; } __run_pre_execute_checks_local() { true; }
__pre_message_local() { true; } # - - - - - - - - - - - - - - - - - - - - - - - - -
__update_ssl_conf_local() { true; } __update_conf_files_local() { true; }
fi # - - - - - - - - - - - - - - - - - - - - - - - - -
__file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" || exitCode=$((exitCode + 1)) __pre_execute_local() { true; }
__file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh" || exitCode=$((exitCode + 1)) # - - - - - - - - - - - - - - - - - - - - - - - - -
return $exitCode __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() { __run_start_script() {
local runExitCode=0 local runExitCode=0
local cmd="$(eval echo "${EXEC_CMD_BIN:-}")" local workdir="$(eval echo "${WORK_DIR:-}")"
local args="$(eval echo "${EXEC_CMD_ARGS:-}")" local cmd="$(eval echo "${EXEC_CMD_BIN:-}")"
local name="$(eval echo "${EXEC_CMD_NAME:-}")" local args="$(eval echo "${EXEC_CMD_ARGS:-}")"
local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" local name="$(eval echo "${EXEC_CMD_NAME:-}")"
[ -f "$CONF_DIR/$SERVICE_NAME.exec_cmd.sh" ] && . "$CONF_DIR/$SERVICE_NAME.exec_cmd.sh" local pre="$(eval echo "${EXEC_PRE_SCRIPT:-}")"
if [ ! -x "$cmd" ]; then echo "$cmd is not executable" >&2; return 2; fi local extra_env="$(eval echo "${CMD_ENV//,/ }")"
if __proc_check "httpd"; then echo "httpd already running" >&2; return 0; fi local lc_type="$(eval echo "${LANG:-${LC_ALL:-$LC_CTYPE}}")"
echo "Starting $cmd $args" | tee -a -p "/data/logs/init.txt" local home="$(eval echo "${workdir//\/root/\/tmp\/docker}")"
su_cmd touch "$SERVICE_PID_FILE" local path="$(eval echo "$PATH")"
if [ ! -f "$START_SCRIPT" ]; then local message="$(eval echo "")"
cat <<EOF >"$START_SCRIPT" 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 <<EOF >"$START_SCRIPT"
#!/usr/bin/env bash #!/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 set -Eeo pipefail
# Setting up $cmd to run as ${SERVICE_USER:-root} with env
retVal=10 retVal=10
cmd="$cmd" cmd="$cmd"
args="$args"
SERVICE_NAME="$SERVICE_NAME" SERVICE_NAME="$SERVICE_NAME"
SERVICE_PID_FILE="$SERVICE_PID_FILE" 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=\$! execPid=\$!
sleep 3 sleep 1
checkPID="\$(ps ax | awk '{print \$1}' | grep -v grep | grep "\$execPid$" || false)" if [ -n "\$execPid" ] && kill -0 "\$execPid" 2>/dev/null; then
[ -n "\$execPid" ] && [ -n "\$checkPID" ] && echo "\$execPid" >"\$SERVICE_PID_FILE" && retVal=0 || retVal=10 echo "\$execPid" >"\$SERVICE_PID_FILE"
[ "\$retVal" = 0 ] && echo "\$cmd has been started" || echo "Failed to start $cmd $args" >&2 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 exit \$retVal
EOF EOF
fi fi
[ -x "$START_SCRIPT" ] || chmod 755 -Rf "$START_SCRIPT" else
[ "$CONTAINER_INIT" = "yes" ] || eval sh -c "$START_SCRIPT" if [ ! -f "$START_SCRIPT" ]; then
runExitCode=$? execute_command="$(__trim "$su_exec $cmd_exec")"
return $runExitCode cat <<EOF >"$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() { __run_secure_function() {
local filesperms local filesperms
for filesperms in "${USER_FILE_PREFIX}"/* "${ROOT_FILE_PREFIX}"/*; do if [ -n "$user_name" ] || [ -n "$user_pass" ]; then
[ -e "$filesperms" ] && { chmod -Rf 600 "$filesperms"; chown -Rf $SERVICE_USER:$SERVICE_USER "$filesperms" 2>/dev/null; } for filesperms in "${USER_FILE_PREFIX}"/*; do
done 2>/dev/null if [ -e "$filesperms" ]; then
unset filesperms 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" # Allow ENV_ variable - Import env file
__file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh" && . "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh" 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 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_FILE="/run/init.d/$EXEC_CMD_NAME.pid"
SERVICE_PID_NUMBER="$(__pgrep)" SERVICE_PID_NUMBER="$(__pgrep "$EXEC_CMD_NAME" 2>/dev/null || echo '')"
__check_service "$1" && SERVICE_IS_RUNNING=yes _resolved="$(type -P "$EXEC_CMD_BIN" 2>/dev/null)"
[ -d "$LOG_DIR" ] || mkdir -p "$LOG_DIR" [ -n "$_resolved" ] && EXEC_CMD_BIN="$_resolved"
[ -d "$RUN_DIR" ] || mkdir -p "$RUN_DIR" _resolved="$(type -P "$EXEC_PRE_SCRIPT" 2>/dev/null)"
[ -n "$USER_FILE_PREFIX" ] && { [ -d "$USER_FILE_PREFIX" ] || mkdir -p "$USER_FILE_PREFIX"; } [ -n "$_resolved" ] && EXEC_PRE_SCRIPT="$_resolved"
[ -n "$ROOT_FILE_PREFIX" ] && { [ -d "$ROOT_FILE_PREFIX" ] || mkdir -p "$ROOT_FILE_PREFIX"; } unset _resolved
[ -n "$RUNAS_USER" ] || RUNAS_USER="root" # - - - - - - - - - - - - - - - - - - - - - - - - -
[ -n "$SERVICE_USER" ] || SERVICE_USER="$RUNAS_USER" if __check_service "$1"; then
[ -n "$SERVICE_GROUP" ] || SERVICE_GROUP="${SERVICE_USER:-$RUNAS_USER}" SERVICE_IS_RUNNING=yes
[ "$IS_WEB_SERVER" = "yes" ] && RESET_ENV="yes" && __is_htdocs_mounted else
[ "$IS_WEB_SERVER" = "yes" ] && [ -z "$SERVICE_PORT" ] && SERVICE_PORT="80" SERVICE_IS_RUNNING="no"
[ -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" ] && . "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" 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}}" sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}"
# - - - - - - - - - - - - - - - - - - - - - - - - -
__create_service_env __create_service_env
__init_config_etc __init_config_etc
__execute_prerun __execute_prerun
@@ -257,14 +648,16 @@ __setup_directories
__switch_to_user __switch_to_user
__init_working_dir __init_working_dir
__pre_message __pre_message
__initialize_db_users
__update_ssl_conf __update_ssl_conf
__update_ssl_certs __update_ssl_certs
__run_secure_function __run_secure_function
__run_precopy __run_precopy
for config_2_etc in $CONF_DIR $ADDITIONAL_CONFIG_DIRS; do 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 done
__initialize_replace_variables "$ETC_DIR" "$CONF_DIR" "$ADDITIONAL_CONFIG_DIRS" "$WWW_ROOT_DIR" __initialize_replace_variables "$ETC_DIR" "$CONF_DIR" "$ADDITIONAL_CONFIG_DIRS" "$WWW_ROOT_DIR"
__initialize_database
__update_conf_files __update_conf_files
__pre_execute __pre_execute
__fix_permissions "$SERVICE_USER" "$SERVICE_GROUP" __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" __run_start_script 2>>/dev/stderr | tee -p -a "/data/logs/entrypoint.log"
errorCode=$? errorCode=$?
if [ -n "$EXEC_CMD_BIN" ]; then 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 if [ "$errorCode" -eq 0 ]; then
SERVICE_EXIT_CODE=0 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 fi
# - - - - - - - - - - - - - - - - - - - - - - - - -
__post_execute 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt" & __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" __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 __script_exit $SERVICE_EXIT_CODE
# - - - - - - - - - - - - - - - - - - - - - - - - -
# ex: ts=2 sw=2 et filetype=sh
# - - - - - - - - - - - - - - - - - - - - - - - - -