--- /dev/null
+#!/bin/sh
+#-
+# Copyright (c) 2014 Universitetet i Oslo
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. The name of the author may not be used to endorse or promote
+# products derived from this software without specific prior written
+# permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+#
+# This script runs at regular intervals on the inner half of the file
+# exchange to create import / export directories for new projects.
+#
+# Note the extensive use of "return 1" instead of "set -e": DO NOT
+# CHANGE THIS as "set -e" has side effects of which you are clearly
+# not aware if you think using it is a good idea.
+#
+
+introot=/tsd
+extroot=/fx
+verbose=
+
+tmpdir=
+tmpmap=
+
+etcdir=/opt/tsd/etc
+mapfile="${etcdir}/tsdfx.map"
+
+umask 0277
+
+#
+# Verbose message
+#
+verbose() {
+ [ "${verbose}" ] && echo "$@" >&2
+}
+
+#
+# Fatal error
+#
+error() {
+ echo "$@" >&2
+ exit 1
+}
+
+#
+# Notice
+#
+notice() {
+ echo "$@" >&2
+}
+
+#
+# Create one or more directories
+#
+makedir() {
+ for dir ; do
+ if ! [ -d "${dir}" ] ; then
+ verbose "creating ${dir}"
+ mkdir "${dir}" || return 1
+ fi
+ done
+ return 0
+}
+
+#
+# Create the import and export directories for a specific project
+#
+mkp() {
+ local p="$1"
+
+ intp="${introot}/${p}/fx"
+ extp="${extroot}/${p}"
+ extimpdir="${extp}/import"
+ extexpdir="${extp}/export"
+ intimpdir="${intp}/import"
+ intexpdir="${intp}/export"
+ impgrp="${p}-import-group"
+ expgrp="${p}-export-group"
+
+ # If the inside directories do not exist, stop here
+ if ! [ -d "${intimpdir}" -a -d "${intexpdir}" ] ; then
+ verbose "missing ${intimpdir} and / or ${intexpdir}"
+ # SOFT ERROR because project directories are generated
+ # in advance of the projects themselves
+ return 0
+ fi
+
+ # If the required groups do not exist, stop here
+ if ! getent group "${impgrp}" "${expgrp}" >/dev/null ; then
+ verbose "missing ${impgrp} and / or ${expgrp}"
+ # SOFT ERROR because project directories are generated
+ # in advance of the projects themselves
+ return 0
+ fi
+
+ # Create the project directory
+ makedir "${extp}" || return 1
+ chown root:"${p}-member-group" "${extp}" || return 1
+ #chmod u=rwx,g=rx,o= "${extp}" || return 1
+ chmod u=rwx,g=rx,o=rx "${extp}" || return 1
+
+ # Create the import directory
+ makedir "${extimpdir}" || return 1
+ chown root:"${impgrp}" "${extimpdir}" || return 1
+ chmod u=rwx,g=rwxs,o= "${extimpdir}" || return 1
+
+ # Create the export directory
+ makedir "${extexpdir}" || return 1
+ chown root:"${expgrp}" "${extexpdir}" || return 1
+ #chmod u=rwx,g=rx,o= "${extexpdir}" || return 1
+ chmod u=rwx,g=rwxs,o= "${extexpdir}" || return 1
+
+ # Output tsdfx map entries
+ echo "${p}-import: ${extimpdir} => ${intimpdir}"
+ echo "${p}-export: ${intexpdir} => ${extexpdir}"
+}
+
+cleanup() {
+ [ -n "${tmpmap}" -a -f "${tmpmap}" ] && rm "${tmpmap}"
+ [ -n "${tmpdir}" -a -d "${tmpdir}" ] && rmdir "${tmpdir}"
+}
+
+usage() {
+ notice "usage: tsdfx-mkp [-v]"
+ exit 1
+}
+
+main() {
+ while getopts "v" option ; do
+ case ${option} in
+ v)
+ verbose=1
+ ;;
+ *)
+ usage
+ ;;
+ esac
+ done
+
+ # Create temporary directory
+ tmpdir="$(mktemp -d)"
+ if ! [ -n "${tmpdir}" -a -d "${tmpdir}" ] ; then
+ error "unable to create temporary directory"
+ fi
+ tmpmap="${tmpdir}/tsdfx.map"
+ trap cleanup EXIT
+
+ # Iterate over project directories
+ cd "${introot}"
+ errcnt=0
+ for p in p* ; do
+ expr "${p}" : '^p[0-9]\{2,\}$' >/dev/null || continue
+ if ! mkp "${p}" ; then
+ : $((errcnt += 1))
+ fi
+ done >"${tmpmap}"
+ if [ $errcnt -gt 0 ] ; then
+ error "one or more errors encountered"
+ elif [ ! -f "${tmpmap}" ] ; then
+ error "failed to create map file"
+ elif [ ! -s "${tmpmap}" ] ; then
+ error "empty map file"
+ elif ! cmp -s "${tmpmap}" "${mapfile}" ; then
+ verbose "installing new map file"
+ newmap="${mapfile}.$$"
+ mv "${tmpmap}" "${newmap}"
+ chmod 0640 "${newmap}"
+ mv "${newmap}" "${mapfile}"
+ verbose "reloading tsdfx"
+ pkill -HUP -f "tsdfx: master"
+ fi
+}
+
+main "$@"