#! /bin/sh # Copyright (c) Feb 2000, by Denys Duchier, Universitaet des Saarlandes # # ozinstall is a shell script to install files and directories. It is # hopefully written in pure sh and thus should be maximally portable. # It assumes the existence of cp, mkdir, chmod, and chgrp, and further # assumes that cp supports the -f flag (force). ozinstall makes it # unnecessary to fight incompatible install programs and covers # concisely all the cases useful for Mozart packages. An `install' # script must in any case be included in any distributed package to # permit installation on machines which do not have an install program. # We might as well always use ozinstall. # # One feature of ozinstall is that it will create the destination # directory structure. This greatly simplifies Makefiles since no # rules are necessary to create installation directories. # # SYNOPSIS # # ozinstall OPTIONS -d DIR # # if directory DIR is not present, it is installed # # ozinstall OPTIONS [-f|-x|-M] SRCFILE DSTFILE # ozinstall OPTIONS [-f|-x|-M] SRCFILE DSTDIR/ # ozinstall OPTIONS [-f|-x|-M] SRCFILE -d DSTDIR # # SRCFILE is installed as DSTFILE. If the directory of # DSTFILE does not exist yet, it is also installed. -f # installs a regular data file, -x installs an executable # file, and -M decides which of -f or -x to use based on # whether the file to install is executable or not. # # OPTIONS # # -g GROUP set group (--group) # -m MODE set mode (--mode) # # ENVIRONMENT VARIABLES # # OZSKEL_MODE_DIR default mode for directories # OZSKEL_MODE_FILE default mode for data files # OZSKEL_MODE_BIN default mode for executable files # OZSKEL_GROUP default group PGM="ozinstall" defaultIFS=' ' IFS="${IFS:-${defaultIFS}}" explode() { tmp=`echo "$1" | sed -e 's@/@%@g' -e 's@^%@/@'` echo "$tmp%O_Z_S_K_E_L" } basename() { tmp=`explode "$1"` last= oIFS="$IFS" IFS='%' for x in $tmp; do if test "$x" = O_Z_S_K_E_L; then break; else last="$x"; fi done IFS="$oIFS" echo "$last" } dirname() { tmp=`explode "$1"` sofar= last= oIFS="$IFS" IFS='%' for x in $tmp; do if test "$x" = O_Z_S_K_E_L; then break; else sofar="$sofar${sofar:+/}$last" last="$x" fi done IFS="$oIFS" echo "$sofar" } isslashed() { tmp=`basename "$1"` test -z "$tmp" } VERBOSE= trace() { test -n "$VERBOSE" && echo "$1" 1>&2 } error() { echo "$PGM: $1" 1>&2 exit 1 } : ${OZSKEL_MODE_DIR:=775} : ${OZSKEL_MODE_FILE:=444} : ${OZSKEL_MODE_BIN:=555} OZSKEL_GROUP= OZSKEL_MODE= USE_MODE= USE_GROUP= installfix() { if test -n "$USE_GROUP"; then trace "chgrp($USE_GROUP,$1)" chgrp "$USE_GROUP" "$1" || error "chgrp($USE_GROUP,$1) failed" fi if test -n "$USE_MODE"; then trace "chmod($USE_MODE,$1)" chmod "$USE_MODE" "$1" || error "chmod($USE_MODE,$1) failed" fi } installdir() { test -n "$1" || error "installdir($1), empty name" if test -r "$1"; then test -d "$1" || error "installdir($1), file exists" else tmp=`explode "$1"` oIFS="$IFS" IFS='%' sofar= for x in $tmp; do if test "$x" = O_Z_S_K_E_L; then break; else sofar="$sofar${sofar:+/}$x" test -d "$sofar" && continue trace "mkdir($sofar)" mkdir "$sofar" || error "mkdir($1) failed" installfix "$sofar" fi done IFS="$oIFS" fi } installfile() { test -d "$2" && error "installfile($1,$2), destination is directory" tmp=`dirname "$2"` test -d "$2" && error "installfile($1,$2), destination's directory non-existent" trace "cp($1,$2)" cp -f "$1" "$2" || error "cp($1,$2) failed" installfix "$2" } USER_MODE= USER_GROUP= USER_SRC= USER_DST= USER_ACTION= USER_DIR= VAR= OPT= VAL= for ARG do # grab argument for preceding option if test -n "$VAR"; then eval "$VAR=\$ARG" VAR= OPT= continue fi case "$ARG" in -*=*) VAL=`echo "$ARG" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) VAL= ;; esac case "$ARG" in -m=*|-mode=*|--mode=*) USER_MODE="$VAL" ;; -m|--mode) OPT="$ARG" VAR=USER_MODE ;; -g=*|-group=*|--group=*) USER_GROUP="$VAL" ;; -g|-group|--group) OPT="$ARG" VAR=USER_GROUP ;; -v|--verbose) VERBOSE=yes ;; -f|-x|-M) test -z "$USER_ACTION" || error "only one of -f,-x,-M is allowed" USER_ACTION="$ARG" ;; -d) test -z "$USER_DIR" || error "-d supplied twice" OPT="$ARG" VAR=USER_DIR ;; -*) error "invalid option $ARG" ;; *) if test -n "$USER_DST"; then error "too may arguments" elif test -n "$USER_SRC"; then USER_DST="$ARG" else USER_SRC="$ARG" fi ;; esac done # check if we were expecting to grab an option's argument test -z "$VAR" || error "missing argument for $OPT" # we cannot allow both `-d DIR' and `DSTFILE' if test -n "$USER_DST" && test -n "$USER_DIR"; then error "it is illegal to supply both -d dir and destination arg" fi # for convenience strip off the slash in `-d DIR/' if test -n "$USER_DIR" && isslashed "$USER_DIR"; then USER_DIR=`dirname "$USER_DIR"` fi # if no action specified: if SRC was supplied, then assume `-f' # else if `-d DIR' was supplied, use `-d', else its an error. if test -z "$USER_ACTION"; then if test -n "$USER_SRC"; then USER_ACTION="-f" elif test -n "$USER_DIR"; then USER_ACTION="-d" else error "too few arguments" fi fi if test -n "$USER_SRC"; then test -r "$USER_SRC" || error "source file non-existent" fi case "$USER_ACTION" in -f|-x|-M) test -n "$USER_SRC" || error "source file argument missing" if test -n "$USER_DIR"; then tmp=`basename "$USER_SRC"` USER_DST="$USER_DIR/$tmp" elif test -n "$USER_DST"; then if isslashed "$USER_DST"; then tmp=`basename "$USER_SRC"` USER_DST="${USER_DST}$tmp" fi else error "no destination specified" fi USE_MODE="${OZSKEL_MODE_DIR}" USE_GROUP="$USER_GROUP" tmp=`dirname "$USER_DST"` test -n "$tmp" && installdir "$tmp" if test -z "$USER_MODE"; then case "$USER_ACTION" in -f) USER_MODE="$OZSKEL_MODE_FILE" ;; -x) USER_MODE="$OZSKEL_MODE_BIN" ;; -M) if test -x "$USER_SRC"; then USER_MODE="$OZSKEL_MODE_BIN" else USER_MODE="$OZSKEL_MODE_FILE" fi ;; esac fi USE_MODE="${USER_MODE}" installfile "$USER_SRC" "$USER_DST" ;; -d) USE_MODE="${USER_MODE:-$OZSKEL_MODE_DIR}" USE_GROUP="$USER_GROUP" installdir "$USER_DIR" ;; esac exit 0