install.sh (5195B)
1 #!/bin/sh 2 # 3 # Copyright (c) 2026 Fred Großkopf 4 # 5 # Permission to use, copy, modify, and/or distribute this software for any 6 # purpose with or without fee is hereby granted, provided that the above 7 # copyright notice and this permission notice appear in all copies. 8 # 9 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 17 set -eu 18 19 log() { printf 'info: %s\n' "$1"; } 20 warn() { printf 'warning: %s\n' "$1" >&2; } 21 error() { 22 printf 'error: %s\n' "$1" >&2 23 exit 1 24 } 25 26 usage() { 27 printf 'usage: %s <git-user> <git-src> <web-root>\n' "$(basename "$0")" 28 exit 1 29 } 30 31 setup_dirs() { 32 install -d -m 755 -o "$USER_NAME" -g "$GROUP_NAME" "$VAR_DIR" "$LOG_DIR" 33 install -d -m 755 "$BIN_DIR" "$SPOOL_DIR" 34 install -d -m 755 -o "$USER_NAME" -g "$GROUP_NAME" "$VAR_DIR/staging" 35 } 36 37 setup_group() { 38 if ! groupinfo "$GROUP_NAME" > /dev/null 2>&1; then 39 if command -v groupadd > /dev/null 2>&1; then 40 groupadd "$GROUP_NAME" 41 log "Created group $GROUP_NAME" 42 else 43 error "Neither groupinfo nor groupadd found; cannot create group $GROUP_NAME. Please create it manually." 44 fi 45 fi 46 } 47 48 setup_user() { 49 if ! id "$USER_NAME" > /dev/null 2>&1; then 50 useradd -s /sbin/nologin \ 51 -d "$VAR_DIR" \ 52 -c "Gitpages service user" \ 53 -g "$GROUP_NAME" \ 54 -G "$GIT_USER" \ 55 "$USER_NAME" 56 log "Created user $USER_NAME (primary group: $GROUP_NAME)" 57 fi 58 } 59 60 setup_spool() { 61 install -d -m 2775 -o "$GIT_USER" -g "$GROUP_NAME" "$QUEUE_DIR" 62 } 63 64 install_scripts() { 65 for script in gitpages.sh gitpages-init.sh gitpages-mirror-git.sh gitpages-update.sh; do 66 if [ -f "./$script" ]; then 67 install -m 755 -o root -g wheel "./$script" "$BIN_DIR/$script" 68 log "Installed $script to $BIN_DIR" 69 else 70 warn "$script not found, skipping." 71 fi 72 done 73 } 74 75 setup_config() { 76 config="$ETC_DIR/gitpages.conf" 77 backup="$config.bak" 78 79 if [ -f "$config" ]; then 80 n=1 81 while [ -f "$backup.$n" ]; do 82 n=$((n + 1)) 83 done 84 cp -p "$config" "$backup.$n" 85 log "Backed up $config to $backup.$n" 86 fi 87 88 tmp="$(mktemp "$ETC_DIR/gitpages.conf.XXXXXX")" 89 trap 'rm -f "$tmp"' EXIT INT TERM 90 cat > "$tmp" << EOF 91 GIT_SRC=$GIT_SRC 92 WEB_ROOT=$WEB_ROOT 93 GIT_RAW=$GIT_RAW 94 GIT_HTML=$GIT_HTML 95 ASSETS_DIR=$ASSETS_DIR 96 EOF 97 98 mv "$tmp" "$config" 99 trap - EXIT INT TERM 100 log "Wrote config to $config" 101 } 102 103 setup_logrotation() { 104 if ! grep -q "$LOG_DIR/updates.log" "$ETC_DIR"/newsyslog.conf; then 105 echo "$LOG_DIR/updates.log ${USER_NAME}:${GROUP_NAME} 640 5 100 * J" >> "$ETC_DIR"/newsyslog.conf 106 log "Log rotation appended to $ETC_DIR/newsyslog.conf." 107 else 108 log "Log rotation already configured in $ETC_DIR/newsyslog.conf." 109 fi 110 } 111 112 setup_cron() { 113 cron_line="*/5 * * * * $BIN_DIR/gitpages-update.sh" 114 115 if [ ! -f "$BIN_DIR/gitpages-update.sh" ]; then 116 error "Cannot setup cron: $BIN_DIR/gitpages-update.sh not found." 117 fi 118 119 if crontab -u "$USER_NAME" -l 2> /dev/null | grep -qF "$cron_line"; then 120 log "Cronjob already exists and is configured correctly." 121 else 122 echo "$cron_line" | crontab -u "$USER_NAME" - 123 log "Cronjob set for gitpages user." 124 fi 125 } 126 127 setup_webroot() { 128 install -d -m 755 -o "root" -g "wheel" "$WEB_ROOT" 129 install -d -m 755 -o "$USER_NAME" -g "$GROUP_NAME" "$WEB_ROOT/git" 130 install -d -m 755 -o "$USER_NAME" -g "$GROUP_NAME" "$WEB_ROOT/git-raw" 131 log "Created web root and subdirectories under $WEB_ROOT" 132 } 133 134 main() { 135 [ $# -ne 3 ] && usage 136 GIT_USER="$1" 137 GIT_SRC="$2" 138 WEB_ROOT="$3" 139 140 USER_NAME="_gitpages" 141 GROUP_NAME="gitpages" 142 143 GIT_RAW=git-raw 144 GIT_HTML=git 145 ASSETS_DIR=/var/gitpages/assets 146 147 BIN_DIR="/usr/local/sbin" 148 ETC_DIR="/etc" 149 VAR_DIR="/var/gitpages" 150 LOG_DIR="/var/log/gitpages" 151 SPOOL_DIR="/var/spool" 152 QUEUE_DIR="$SPOOL_DIR/gitpages/queue" 153 154 # Validation 155 if ! id "$GIT_USER" > /dev/null 2>&1; then 156 error "User '$GIT_USER' does not exist." 157 fi 158 159 case "$GIT_SRC" in 160 /*) : ;; 161 *) error "GIT_SRC must be an absolute path" ;; 162 esac 163 164 [ -d "$GIT_SRC" ] || error "GIT_SRC directory '$GIT_SRC' not found" 165 166 if ! su - "$GIT_USER" -c "test -r '$GIT_SRC'"; then 167 error "GIT_USER '$GIT_USER' cannot read GIT_SRC '$GIT_SRC'" 168 fi 169 170 case "$WEB_ROOT" in 171 /*) : ;; 172 *) error "WEB_ROOT must be an absolute path" ;; 173 esac 174 175 log "Installing gitpages environment for git-user: $GIT_USER" 176 log "Using WEB_ROOT: $WEB_ROOT" 177 178 # Determine and switch to where this script resides 179 # so ./gitpages-*.sh work no matter where script is invoked from 180 SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)" 181 cd "$SCRIPT_DIR" || error "cannot cd to $SCRIPT_DIR" 182 183 setup_group 184 setup_user 185 setup_dirs 186 setup_spool 187 install_scripts 188 setup_config 189 setup_webroot 190 setup_logrotation 191 setup_cron 192 193 log "Installation complete." 194 } 195 196 main "$@"