#!/bin/bash
#< Wrapper for mkdir that allows -m (mode) and -o (owner:group)
# Only supports local passwd/group files - i.e. not NIS, etc

BASENAME="/usr/bin/basename"
CHMOD="/usr/bin/chmod"
CHOWN="/usr/bin/chown"
CUT="/usr/bin/cut"
ECHO="/bin/echo"
EGREP="/bin/egrep"
GREP="/bin/grep"
MKDIR="/bin/mkdir"
SED="/usr/bin/sed"

MKDIR_OPTS=""

F_GROUP="/etc/group"
F_PASSWD="/etc/passwd"
THISPROG=$( ${BASENAME} $0 )

VERBOSE=0

function print_error {
   ${ECHO} "Error: $@" >&2
}

function printv {
   (( VERBOSE )) && {
      ${ECHO} "--> $@"
   }
}

function print_usage {
   {
      ${ECHO} "Usage: ${THISPROG} [-hpv] [-o <owner:group] [-m <mode>] directories"   
      ${ECHO} "       -h   Display this usage message"
      ${ECHO} "       -o   Specify owner and group"
      ${ECHO} "       -p   Create parent directories as required"
      ${ECHO} "       -m   Specify octal permissions mode"
      ${ECHO} "       -v   Verbose mode"
   } >&2
}

function check_mode {
	# mode can be three or four octal bits
	OCTAL_BITS="${#MODE}"
	if [ "${OCTAL_BITS}" -ne "3" -a "${OCTAL_BITS}" -ne "4" ]; then
		print_error "Mode must contain three or four octal bits"
		exit 1
	fi
   ${ECHO} "${MODE}" | ${SED} 's/\(.\)/\1\
/g' | ${SED} '$d' | while read BIT; do
		${ECHO} "${BIT}" | ${EGREP} -qs '^[0-9]$'
		if [ "$?" -ne "0" ]; then
			print_error "Error in octal mode"
			exit 1
		fi
		if [ "${BIT}" -lt "0" -o "${BIT}" -gt "7" ]; then
			print_error "Mode out of bounds"
			exit 1
		fi
	done
	# if we've got this far, mode is assumed to be ok
}

function check_owner {
	${ECHO} "${OWNER}" | ${EGREP} -qs '^[a-zA-Z0-9]+:[a-zA-Z0-9]+$'
	if [ "$?" -ne "0" ]; then
		print_error "Specify owner as owner:group"
		exit 1
	fi
	C_OWNER=$( ${ECHO} "${OWNER}" | ${CUT} -d: -f1 )
	C_GROUP=$( ${ECHO} "${OWNER}" | ${CUT} -d: -f2 )
	${GREP} -qs "^${C_OWNER}:" ${F_PASSWD}
	if [ "$?" -ne "0" ]; then
		print_error "${C_OWNER} not a valid user"
		exit 1
	fi
	${GREP} -qs "^${C_GROUP}:" ${F_GROUP}
	if [ "$?" -ne "0" ]; then
		print_error "${C_GROUP} not a valid group"
		exit 1
	fi
}

function check_args {
	if [ -n "${MODE}" ]; then
		check_mode
	fi
	if [ -n "${OWNER}" ]; then
		check_owner
	fi
}

function do_mkdir {
	for DIR in ${DIRLIST}; do
		${MKDIR} ${MKDIR_OPTS} ${DIR}
		if [ "$?" -ne "0" ]; then
			# leave mkdir itself to report the error
			exit 1
		fi
		if [ -n "${MODE}" ]; then
			${CHMOD} ${MODE} ${DIR}
			if [ "$?" -ne "0" ]; then
				# leave chmod itself to report the error	
				exit 1
			fi
		fi
		if [ -n "${OWNER}" ]; then
			${CHOWN} ${OWNER} ${DIR}
			if [ "$?" -ne "0" ]; then
				# leave chown itself to report the error	
				exit 1
			fi
		fi
	done
}

#
# main()
#
while getopts ":hm:o:pv" OPTION; do
  case ${OPTION} in
     "h")  print_usage && exit 0   ;;
     "m")  MODE="${OPTARG}"        ;;
     "o")  OWNER="${OPTARG}"       ;;
     "p")  MKDIR_OPTS="-p"         ;;
     "v")  VERBOSE=1               ;;
     *  )  print_usage && exit 1   ;;
  esac
done

shift $(( ${OPTIND} - 1 ))

if [ "$#" -eq "0" ]; then
	print_error "At least one directory must be specified"
	exit 1
else
	DIRLIST="$@"
fi

check_args
do_mkdir

exit 0