1#!/bin/sh
2#
3#
4
5# Print newline-separated list of devices available for mounting.
6# If there is a filesystem label - use it, otherwise use device name.
7print_available() {
8	local _fstype _fstype_and_label _label _p
9
10	for _p in ${providers}; do
11		_fstype_and_label="$(fstyp -l "/dev/${_p}" 2> /dev/null)"
12		if [ $? -ne 0 ]; then
13			# Ignore devices for which we were unable
14			# to determine filesystem type.
15			continue
16		fi
17
18		_fstype="${_fstype_and_label%% *}"
19		if [ "${_fstype}" != "${_fstype_and_label}" ]; then
20			_label="${_fstype_and_label#* }"
21			# Replace plus signs and slashes with minuses;
22			# leading plus signs have special meaning in maps,
23			# and multi-component keys are just not supported.
24			_label="$(echo ${_label} | sed 's,[+/],-,g')"
25			echo "${_label}"
26			continue
27		fi
28
29		echo "${_p}"
30	done
31}
32
33# Print a single map entry.
34print_map_entry() {
35	local _fstype _p
36
37	_fstype="$1"
38	_p="$2"
39
40	case "${_fstype}" in
41	"exfat")
42		if [ -f "/usr/local/sbin/mount.exfat" ]; then
43			echo "-mountprog=/usr/local/sbin/mount.exfat,fstype=${_fstype},sync	:/dev/${_p}"
44		else
45			/usr/bin/logger -p info -t "special_media[$$]" \
46			    "Cannot mount ${_fstype} formatted device /dev/${_p}: Install sysutils/fusefs-exfat first"
47			exit 1
48		fi
49		;;
50	"ntfs")
51		if [ -f "/usr/local/bin/ntfs-3g" ]; then
52			echo "-mountprog=/usr/local/bin/ntfs-3g,fstype=${_fstype},sync	:/dev/${_p}"
53		else
54			/usr/bin/logger -p info -t "special_media[$$]" \
55			    "Cannot mount ${_fstype} formatted device /dev/${_p}: Install sysutils/fusefs-ntfs first"
56			exit 1
57		fi
58		;;
59	"msdosfs")
60		echo "-fstype=${_fstype},sync	:/dev/${_p}"
61		;;
62	"ext2fs")
63		echo "-fstype=${_fstype},async	:/dev/${_p}"
64		;;
65	*)
66		echo "-fstype=${_fstype}	:/dev/${_p}"
67		;;
68	esac
69}
70
71# Determine map entry contents for the given key and print out the entry.
72print_one() {
73	local _fstype _fstype_and_label _label _key _p
74
75	_key="$1"
76
77	_fstype="$(fstyp "/dev/${_key}" 2> /dev/null)"
78	if [ $? -eq 0 ]; then
79		print_map_entry "${_fstype}" "${_key}"
80		return
81	fi
82
83	for _p in ${providers}; do
84		_fstype_and_label="$(fstyp -l "/dev/${_p}" 2> /dev/null)"
85		if [ $? -ne 0 ]; then
86			# Ignore devices for which we were unable
87			# to determine filesystem type.
88			continue
89		fi
90
91		_fstype="${_fstype_and_label%% *}"
92		if [ "${_fstype}" = "${_fstype_and_label}" ]; then
93			# No label, try another device.
94			continue
95		fi
96
97		_label="${_fstype_and_label#* }"
98		# Replace plus signs and slashes with minuses;
99		# leading plus signs have special meaning in maps,
100		# and multi-component keys are just not supported.
101		_label="$(echo ${_label} | sed 's,[+/],-,g')"
102		if [ "${_label}" != "${_key}" ]; then
103			# Labels don't match, try another device.
104			continue
105		fi
106
107		print_map_entry "${_fstype}" "${_p}"
108	done
109
110	# No matching device - don't print anything, autofs will handle it.
111}
112
113# Obtain a list of (geom-provider-name, access-count) pairs, turning this:
114#
115# z0xfffff80005085d00 [shape=hexagon,label="ada0\nr2w2e3\nerr#0\nsector=512\nstripe=0"];
116#
117# Into this:
118#
119# ada0 r2w2e3
120#
121# XXX: It would be easier to use kern.geom.conftxt instead, but it lacks
122#      access counts.
123pairs=$(sysctl kern.geom.confdot | sed -n 's/^.*hexagon,label="\([^\]*\)\\n\([^\]*\).*/\1 \2/p')
124
125# Obtain a list of GEOM providers that are not already open - not mounted,
126# and without other GEOM class, such as gpart, attached.  In other words,
127# grep for "r0w0e0".  Skip providers with names containing slashes; we're
128# not interested in geom_label(4) creations.
129providers=$(echo "$pairs" | awk '$2 == "r0w0e0" && $1 !~ /\// { print $1 }')
130
131if [ $# -eq 0 ]; then
132	print_available
133	exit 0
134fi
135
136print_one "$1"
137exit 0
138
139