1#!/bin/sh
2#############################################################################
3#
4# exchange-bmc-os-info: Set OS and BMC (Baseboard Management Controller)
5#			 parameters during system startup.
6#
7# version:	0.72
8#
9# Authors:	Charles Rose <charles_rose@dell.com>
10#		Jordan Hargrave <jordan_hargrave@dell.com>
11#
12# Description:  Script to set OS information in the BMC; fetch BMC IP/URL
13#		and set in the OS for use by other scripts/user.
14#
15#		BMC IP and URL are made available in /var/run/bmc-info
16#
17#		Example to launch BMC web-interface:
18#		# . /var/run/bmc-info
19#		# xdg-open $BMC_URL
20#
21#		See here for details:
22#		https://fedoraproject.org/wiki/Features/AgentFreeManagement
23#
24# OEM Specific: OEM specific ipmi commands go in:
25#		'oem_set_os_version' and 'oem_get_bmc_url'
26#############################################################################
27#
28# chkconfig: 345 99 00
29# description: Set OS name, hostname in BMC; make BMC IP/URL available in OS
30# processname: exchange-bmc-os-info
31# config:      /etc/sysconfig/exchange-bmc-os-info
32#
33### BEGIN INIT INFO
34# Provides:          exchange-bmc-os-info
35# Required-Start:    ipmi
36# Default-Start:     3 4 5
37# Default-Stop:      0 1 2 6
38
39
40#############################################################################
41# GLOBALS
42#############################################################################
43CONFIGFILE=/etc/sysconfig/exchange-bmc-os-info
44IPMI_TOOL=/usr/bin/ipmitool
45BMC_INFO=/var/run/bmc-info
46
47# BMC Manufacturer ID used in 'oem_set_os_version' and 'oem_get_bmc_url'
48DELL="674"
49#OTHER_OEM="123"
50
51# Defaults for ${CONFIGFILE}
52SET_OS_INFO="yes"
53RESET_OS_INFO="no"
54SET_BMC_INFO="yes"
55
56# getsysinfo and setsysinfo commands
57IPMI_SET_SYSINFO="${IPMI_TOOL} mc setsysinfo"
58IPMI_GET_SYSINFO="${IPMI_TOOL} mc getsysinfo"
59#############################################################################
60SCRIPT_NAME=$(basename $0)
61
62# source config
63[ -r ${CONFIGFILE} ] && . ${CONFIGFILE}
64
65RETVAL=0
66
67if [ -f /bin/gettext.sh ]; then
68	GETTEXT=1
69	. /bin/gettext.sh
70	OUTPUT="eval_gettext"
71else
72	GETTEXT=0
73	OUTPUT="echo"
74fi
75
76#############################################################################
77# Get Vendor ID of BMC for use in 'oem_set_os_version' and 'oem_get_bmc_url'
78#
79get_bmc_vendor_id()
80{
81	BMC_VENDOR=$(${IPMI_TOOL} mc info 2>/dev/null | \
82		sed -n "s#^Manufacturer ID.*: ##p")
83	[ -z "${BMC_VENDOR}" ] && RETVAL=4
84}
85
86check_ipmitool()
87{
88	if [ -x ${IPMI_TOOL} ]; then
89	# v1.8.12 plus patches are required for set/getsysinfo support
90	# http://sourceforge.net/mailarchive/message.php?msg_id=29647222
91		[ ! ${IPMI_GET_SYSINFO} >/dev/null 2>&1 ] && \
92			RETVAL=3
93	else
94		RETVAL=2
95	fi
96}
97
98bmc_exists()
99{
100	check_ipmitool
101	[ $RETVAL -eq 0 ] && get_bmc_vendor_id
102	return $RETVAL
103}
104#############################################################################
105
106get_os_info()
107{
108	OS_HOSTNAME=$(hostname)
109	KERNEL_VERSION=$(uname -r -m)
110
111	if  [ -e /etc/lsb-release ] ; then
112		. /etc/lsb-release
113		NAME=${DISTRIB_ID}
114		VERSION="${DISTRIB_RELEASE} ${DISTRIB_CODENAME}"
115	fi
116
117	# we prefer systemd's /etc/os-release over other sources
118	[ -e /etc/os-release ] && . /etc/os-release
119
120	OS_NAME=${NAME}
121	OS_VERSION="${VERSION} kernel ${KERNEL_VERSION}"
122}
123
124oem_set_os_version()
125{
126	# OS Version setting is not standard yet
127	# we need per vendor oem commands
128	case "${BMC_VENDOR}" in
129		$DELL) ${IPMI_SET_SYSINFO} delloem_os_version \
130				"${OS_VERSION}" > /dev/null 2>&1
131			return $?
132			;;
133# Add OEM specific commands.
134# Example:
135#		$OTHER_OEM) ${IPMI_SET_SYSINFO} otheroem_os_version \
136#				"${OS_VERSION}" > /dev/null 2>&1
137#			return $?
138#			;;
139		*) 	return 0
140			;;
141	esac
142}
143
144set_os_info()
145{
146	# Set and reset OS info in the BMC
147	if [ "$1" = "reset" ]; then
148		OS_NAME=""
149		OS_HOSTNAME=""
150		OS_VERSION=""
151	fi
152
153	${IPMI_SET_SYSINFO} os_name "${OS_NAME}" >/dev/null 2>&1 \
154		|| RETVAL=6
155	${IPMI_SET_SYSINFO} primary_os_name "${OS_NAME}" >/dev/null 2>&1 \
156		|| RETVAL=6
157	${IPMI_SET_SYSINFO} system_name "${OS_HOSTNAME}" >/dev/null 2>&1 \
158		|| RETVAL=6
159	oem_set_os_version || RETVAL=6
160}
161
162#############################################################################
163valid_url()
164{
165	url="(https?|http)://[a-z0-9-]+(\.[a-z0-9-]+)+([/?].*)?"
166	printf -- "%s" "${TMP_URL}"| grep -Eq "^${url}"
167	return $?
168}
169
170oem_get_bmc_url()
171{
172	# BMC URL is not standard yet
173	# we need per vendor oem commands
174	case "$BMC_VENDOR" in
175		$DELL)	TMP_URL=$(${IPMI_GET_SYSINFO} delloem_url 2> /dev/null)
176				;;
177# Add OEM specific commands
178# Example:
179#		$OTHER_OEM)
180#			TMP_URL=$(${IPMI_GET_SYSINFO} otheroem_url 2> /dev/null)
181#				;;
182		*)  TMP_URL=""	;;
183	esac
184
185	valid_url && BMC_URL=${TMP_URL} || BMC_URL=""
186}
187
188valid_ip()
189{
190	#Thanks to mkyong.com
191	octet="([01]?[[:digit:]][[:digit:]]?|2[0-4][[:digit:]]|25[0-5])"
192
193	printf -- "%s" "${TMP_IPv4}"| grep -Eq "^${octet}\\.${octet}\\.${octet}\\.${octet}$"
194	return $?
195}
196
197get_bmc_ip()
198{
199	#Thanks to http://ingvar.blog.redpill-linpro.com
200	for CHANNEL in `seq 1 14`
201	do
202		[ $(${IPMI_TOOL} lan print ${CHANNEL} 2>/dev/null \
203			| grep -q "^Set") ] || break
204	done
205
206	# Get BMC_IPv4 and BMC_URL from BMC
207	TMP_IPv4=$(${IPMI_TOOL} lan print ${CHANNEL} 2>/dev/null \
208			| sed -n "s#^IP Address  .*: ##p")
209
210	valid_ip && BMC_IPv4=${TMP_IPv4} || BMC_IPv4=""
211}
212
213get_bmc_info()
214{
215	get_bmc_ip
216	if [ -z "${BMC_IPv4}" ] || [ "${BMC_IPv4}" = "0.0.0.0" ]; then
217		BMC_IPv4=""
218		RETVAL=5
219	else
220		# URL makes sense only if there is an IP
221		oem_get_bmc_url
222	fi
223}
224
225set_bmc_info()
226{
227	if [ ! $(touch "${BMC_INFO}" && chmod 600 "${BMC_INFO}") ]; then
228		printf "BMC_IPv4=%s\n" "${BMC_IPv4}" > "${BMC_INFO}"
229		[ -n "${BMC_URL}" ] && \
230			printf "BMC_URL=%s\n" "${BMC_URL}" >> "${BMC_INFO}"
231	else
232		RETVAL=5
233	fi
234}
235
236unset_bmc_info()
237{
238	[ -f ${BMC_INFO} ] && rm -f ${BMC_INFO} > /dev/null 2>&1
239}
240
241#############################################################################
242start()
243{
244	if bmc_exists; then
245		[ "${SET_OS_INFO}" = "yes" ] && \
246			get_os_info && set_os_info
247
248		if [ "${SET_BMC_INFO}" = "yes" ]; then
249			get_bmc_info
250			if [ ${RETVAL} -eq 0 ]; then
251				set_bmc_info
252			fi
253		fi
254	fi
255}
256
257#############################################################################
258stop()
259{
260	if bmc_exists; then
261		# reset OS info while system reboots
262		# aids with debugging OS boot-up issues
263		if [ "${RESET_OS_INFO}" = "yes" ]; then
264			set_os_info reset
265		fi
266		unset_bmc_info
267	fi
268}
269
270#############################################################################
271restart()
272{
273	stop
274	[ $RETVAL -eq 0 ] && start
275}
276
277#############################################################################
278status()
279{
280	[ -r ${BMC_INFO} ] && \
281		grep -q "BMC_IPv4" "${BMC_INFO}" >/dev/null 1>&2 && \
282			BMC_STATUS="ok" || BMC_STATUS="inactive"
283	${OUTPUT} "${SCRIPT_NAME}: ${BMC_STATUS}" 1>&2
284	[ ${GETTEXT} -eq 1 ] && echo
285}
286
287#############################################################################
288usage()
289{
290	${OUTPUT} "Usage: ${SCRIPT_NAME} {start|stop|restart|status}" 1>&2
291	[ ${GETTEXT} -eq 1 ] && echo
292	RETVAL=1
293}
294
295#############################################################################
296# MAIN
297#############################################################################
298case "$1" in
299	start) start ;;
300	stop)  stop ;;
301	restart) restart ;;
302	status)	status ;;
303	*) usage ;;
304esac
305
306case "$RETVAL" in
307	0|1) ;;
308	2) ${OUTPUT} "${SCRIPT_NAME}: ipmitool(1) not found." 1>&2 ;;
309	3) ${OUTPUT} "${SCRIPT_NAME}: this version of ipmitool does not support getsysinfo." 1>&2 ;;
310	4) ${OUTPUT} "${SCRIPT_NAME}: failed to communicate with BMC." 1>&2 ;;
311	5) ${OUTPUT} "${SCRIPT_NAME}: failed to set OS information in BMC." 1>&2 ;;
312	6) ${OUTPUT} "${SCRIPT_NAME}: failed to get BMC information." 1>&2 ;;
313	*) ${OUTPUT} "${SCRIPT_NAME}: unexpected error." 1>&2 ;;
314esac
315
316if [ ${RETVAL} -gt 1 ]; then
317	${OUTPUT} " Return code: ${RETVAL}" 1>&2
318	[ ${GETTEXT} -eq 1 ] && echo
319fi
320
321
322exit ${RETVAL}
323
324#############################################################################
325# end of file
326#############################################################################
327