diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..ffacabd --- /dev/null +++ b/.env.example @@ -0,0 +1,8 @@ +# Samba configuration +# Copy this file to .env and set your values + +# User passwords +SAMBA_BOB_PASSWORD=changeme + +# Timezone +TZ=EST5EDT diff --git a/.gitignore b/.gitignore index 62c8935..6a80527 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -.idea/ \ No newline at end of file +.idea/ +.env +.DS_Store \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index ecd8287..9448256 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,9 @@ -FROM hub.docker.struchkov.dev/alpine:latest -MAINTAINER Struchkov Mark +ARG ALPINE_VERSION=3.21 +FROM hub.docker.struchkov.dev/alpine:${ALPINE_VERSION} + +LABEL maintainer="Struchkov Mark " +LABEL org.opencontainers.image.source="https://github.com/upagge/samba" +LABEL org.opencontainers.image.description="Samba file server with Time Machine support" # Install samba RUN apk --no-cache --no-progress upgrade && \ @@ -59,8 +63,8 @@ COPY samba.sh /usr/bin/ EXPOSE 137/udp 138/udp 139 445 -HEALTHCHECK --interval=60s --timeout=15s \ - CMD smbclient -L \\localhost -U % -m SMB3 +HEALTHCHECK --interval=60s --timeout=15s --start-period=10s --retries=3 \ + CMD smbclient -L \\localhost -U % -m SMB3 || exit 1 VOLUME ["/etc", "/var/cache/samba", "/var/lib/samba", "/var/log/samba",\ "/run/samba"] diff --git a/docker-compose.yml b/docker-compose.yml index fe3d3aa..7ebadce 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,10 +1,15 @@ -version: '3.4' - services: samba: image: docker.struchkov.dev/samba environment: TZ: 'EST5EDT' + # Use environment variables for shares and users instead of command line + # SHARE: "Mount;/mnt" + # SHARE2: "Bobs Volume;/mnt2;yes;no;no;bob" + # USER: "bob;${SAMBA_BOB_PASSWORD}" + # PERMISSIONS: "true" + env_file: + - .env # Put sensitive data like passwords here networks: - default ports: @@ -21,7 +26,13 @@ services: volumes: - /mnt:/mnt:z - /mnt2:/mnt2:z - command: '-s "Mount;/mnt" -s "Bobs Volume;/mnt2;yes;no;no;bob" -u "bob;bobspasswd" -p' + deploy: + resources: + limits: + memory: 512M + reservations: + memory: 128M + command: '-s "Mount;/mnt" -s "Bobs Volume;/mnt2;yes;no;no;bob" -u "bob;${SAMBA_BOB_PASSWORD:-changeme}" -p' networks: - default: \ No newline at end of file + default: diff --git a/samba.sh b/samba.sh index d8a65ef..60317ba 100755 --- a/samba.sh +++ b/samba.sh @@ -18,6 +18,28 @@ set -o nounset # Treat unset variables as an error +### parse_args: safely parse semicolon-separated arguments +# Arguments: +# input) semicolon-separated string +# Return: array PARSED_ARGS with parsed values +parse_args() { + local input="$1" + PARSED_ARGS=() + local current="" + local i=0 + while [ $i -lt ${#input} ]; do + local char="${input:$i:1}" + if [ "$char" = ";" ]; then + PARSED_ARGS+=("$current") + current="" + else + current+="$char" + fi + i=$((i + 1)) + done + PARSED_ARGS+=("$current") +} + ### charmap: setup character mapping for file/directory names # Arguments: # chars) from:to character mappings separated by ',' @@ -245,15 +267,15 @@ while getopts ":hc:G:g:i:nprs:Su:Ww:I:" opt; do case "$opt" in h) usage ;; c) charmap "$OPTARG" ;; - G) eval generic $(sed 's/^/"/; s/$/"/; s/;/" "/g' <<< $OPTARG) ;; + G) parse_args "$OPTARG"; generic "${PARSED_ARGS[@]}" ;; g) global "$OPTARG" ;; i) import "$OPTARG" ;; n) NMBD="true" ;; p) PERMISSIONS="true" ;; r) recycle ;; - s) eval share $(sed 's/^/"/; s/$/"/; s/;/" "/g' <<< $OPTARG) ;; + s) parse_args "$OPTARG"; share "${PARSED_ARGS[@]}" ;; S) smb ;; - u) eval user $(sed 's/^/"/; s/$/"/; s/;/" "/g' <<< $OPTARG) ;; + u) parse_args "$OPTARG"; user "${PARSED_ARGS[@]}" ;; w) workgroup "$OPTARG" ;; W) widelinks ;; I) include "$OPTARG" ;; @@ -265,7 +287,7 @@ shift $(( OPTIND - 1 )) [[ "${CHARMAP:-""}" ]] && charmap "$CHARMAP" while read i; do - eval generic $(sed 's/^/"/; s/$/"/; s/;/" "/g' <<< $i) + parse_args "$i"; generic "${PARSED_ARGS[@]}" done < <(env | awk '/^GENERIC[0-9=_]/ {sub (/^[^=]*=/, "", $0); print}') while read i; do global "$i" @@ -273,11 +295,11 @@ done < <(env | awk '/^GLOBAL[0-9=_]/ {sub (/^[^=]*=/, "", $0); print}') [[ "${IMPORT:-""}" ]] && import "$IMPORT" [[ "${RECYCLE:-""}" ]] && recycle while read i; do - eval share $(sed 's/^/"/; s/$/"/; s/;/" "/g' <<< $i) + parse_args "$i"; share "${PARSED_ARGS[@]}" done < <(env | awk '/^SHARE[0-9=_]/ {sub (/^[^=]*=/, "", $0); print}') [[ "${SMB:-""}" ]] && smb while read i; do - eval user $(sed 's/^/"/; s/$/"/; s/;/" "/g' <<< $i) + parse_args "$i"; user "${PARSED_ARGS[@]}" done < <(env | awk '/^USER[0-9=_]/ {sub (/^[^=]*=/, "", $0); print}') [[ "${WORKGROUP:-""}" ]] && workgroup "$WORKGROUP" [[ "${WIDELINKS:-""}" ]] && widelinks