File: gen-snmp-subdriver.sh

package info (click to toggle)
nut 2.8.1-5
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 18,284 kB
  • sloc: ansic: 108,785; sh: 9,370; cpp: 3,370; makefile: 2,842; python: 1,029; perl: 763; xml: 47
file content (480 lines) | stat: -rwxr-xr-x 16,953 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
#!/bin/bash
#
# an auxiliary script to produce a "stub" snmp-ups subdriver from
# SNMP data from a real agent or from dump files
#
# Version: 0.15
#
# See also: docs/snmp-subdrivers.txt
#
# Copyright (C)
# 2011 - 2012 Arnaud Quette <arnaud.quette@free.fr>
# 2015 - 2022 Eaton (author: Arnaud Quette <ArnaudQuette@Eaton.com>)
# 2011 - 2022 Jim Klimov <jimklimov+nut@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# TODO:
# - Prepend sysDescription (.1.3.6.1.2.1.1.1.0) to have some more visibility
# - extend to SNMP v3 (auth.)

usage() {
	echo "Usage: $0 [options] [file]"
	echo "Options:"
	echo " -h, --help          -- show this message and quit"
	echo " -n name             -- subdriver name (use natural capitalization)"
	echo " -M DIRLIST          -- colon separated list of directories to also search for MIBs"
	echo " -k                  -- keep temporary files (for debugging)"
	echo ""
	echo "mode 1: get SNMP data from a real agent"
	echo " -H host_address     -- SNMP host IP address or name"
	echo " -c community        -- SNMP v1 community name (default: public)"
	echo " -s XXXX             -- override SNMP OID entry point (sysOID). Ex: '.1.3.6.1.4.1.534.10'"
	echo ""
	echo "mode 2: get data from files (snmpwalk dumps of 'sysOID' subtree)"
	echo " -s XXXX             -- SNMP OID entry point (sysOID). Ex: '.1.3.6.1.4.1.534.6.6.7'"
	echo " file1 file2         -- read from files instead of an host (using Net SNMP)"
	echo "                        file1: numeric SNMP walk (snmpwalk -On ... <sysOID>)"
	echo "                        file2: string SNMP walk (snmpwalk -Os ... <sysOID>)"
	echo ""
	echo "mode 3: get data from 1 file (numeric snmpwalk dump of the whole SNMP tree)"
	echo "        The sysOID is extracted from the dump, and only the pointed subtree is used"
	echo "        A MIB file MUST be provided, and is used to produce the string SNMP walk"
	echo " file1               -- read from file instead of an host (using Net SNMP)"
	echo "                        file1: numeric SNMP walk (snmpwalk -On ... <sysOID>)"
	echo ""

	echo "Notes:"
	echo " For both modes, prefer to copy the specific MIB file(s) for your device in the $0 script directory"
	echo " So that it is automatically taken into account for the string name resolution of OIDs"
	echo " Otherwise, use \"-M.\" option"
	echo ""
	echo "Example:"
	echo "mode 1: $0 -H 192.168.0.1 -n mibname -c mycommunity"
	echo "mode 2: (using sysOID .1.3.6.1.4.1.534.6.6.7)"
	echo " snmpwalk -On -v1 -c mycommunity 192.168.0.1 .1.3.6.1.4.1.534.6.6.7 2>/dev/null 1> numeric-walk-file"
	echo " snmpwalk -Os -v1 -m ALL -M+. -c mycommunity 192.168.0.1 .1.3.6.1.4.1.534.6.6.7 2>/dev/null 1> string-walk-file"
	echo " $0 -s .1.3.6.1.4.1.534.6.6.7 numeric-walk-file string-walk-file"
	echo "mode 3:"
	echo " snmpwalk -On -v1 -c mycommunity 192.168.0.1 .1 2>/dev/null 1> numeric-walk-file"
	echo " $0 numeric-walk-file"
	echo ""
	echo " You may alos need to install additional packages:"
	echo " - 'snmp' package (on Debian) for the base commands (snmpget, snmpwalk, snmptranslate)"
	echo " - 'snmp-mibs-downloader' package (on Debian) to get all standard MIBs"
}

# variables
DRIVER=""
KEEP=""
HOSTNAME=""
MIBS_DIRLIST="+."
COMMUNITY="public"
DEVICE_SYSOID=""
SYSOID=""
MODE=0

# constants
NAME=gen-snmp-subdriver
TMPDIR="${TEMPDIR:-/tmp}"
SYSOID_NUMBER=".1.3.6.1.2.1.1.2.0"
DEBUG="`mktemp "$TMPDIR/$NAME-DEBUG.XXXXXX"`"
DFL_NUMWALKFILE="`mktemp "$TMPDIR/$NAME-NUMWALK.XXXXXX"`"
DFL_STRWALKFILE="`mktemp "$TMPDIR/$NAME-STRWALK.XXXXXX"`"
TMP_NUMWALKFILE="`mktemp "$TMPDIR/$NAME-TMP-NUMWALK.XXXXXX"`"
TMP_STRWALKFILE="`mktemp "$TMPDIR/$NAME-TMP-STRWALK.XXXXXX"`"

get_snmp_data() {
	# 1) get the sysOID (points the mfr specif MIB), apart if there's an override
	if [ -z "$SYSOID" ]
	then
		SYSOID="`snmpget -On -v1 -c "$COMMUNITY" -Ov "$HOSTNAME" "$SYSOID_NUMBER" | cut -d' ' -f2`"
		echo "sysOID retrieved: ${SYSOID}"
	else
		echo "Using the provided sysOID override ($SYSOID)"
	fi
	DEVICE_SYSOID="$SYSOID"

	OID_COUNT=0
	while (test "$OID_COUNT" -eq 0)
	do
		# 2) get the content of the mfr specif MIB
		echo "Retrieving SNMP information. This may take some time"
		snmpwalk -On -v1 -c "$COMMUNITY" "$HOSTNAME" "$SYSOID" 2>/dev/null 1> "$DFL_NUMWALKFILE"
		snmpwalk -Os -v1 -m ALL -M"$MIBS_DIRLIST" -c "$COMMUNITY" "$HOSTNAME" "$SYSOID" 2>/dev/null 1> "$DFL_STRWALKFILE"

		# 3) test return value of the walk, and possibly ramp-up the path to get something.
		# The sysOID mechanism only works if we're pointed somehow in the right direction
		# i.e. doesn't work if sysOID is .1.3.6.1.4.1.705.1 and data is at .1.3.6.1.4.1.534...
		# Ex: sysOID = ".1.X.Y.Z"
		# try with ".1.X.Y.Z", if fails try with .1.X.Y", if fails try with .1.X"...
		OID_COUNT="`cat $NUMWALKFILE | wc -l`"
		if [ $OID_COUNT -eq 0 ]; then
			# ramp-up the provided sysOID by removing the last .x part
			SYSOID=${SYSOID%.*}
			echo "Warning: sysOID provided no data! Trying with a level up using $SYSOID"
		fi
	done
	return $OID_COUNT
}

generate_C() {
	# create file names, lowercase
	LDRIVER="`echo "$DRIVER" | tr A-Z a-z`"
	UDRIVER="`echo "$DRIVER" | tr a-z A-Z`"
	# keep dashes in name for files
	CFILE="$LDRIVER-mib.c"
	HFILE="$LDRIVER-mib.h"
	# but replace with underscores for the structures and defines
	LDRIVER="`echo "$LDRIVER" | tr - _`"
	UDRIVER="`echo "$UDRIVER" | tr - _`"

	# generate header file
	# NOTE: with <<-EOF leading TABs are all stripped
	echo "Creating $HFILE"
	cat > "$HFILE" <<-EOF
	/* ${HFILE} - subdriver to monitor ${DRIVER} SNMP devices with NUT
	 *
	 *  Copyright (C)
	 *  2011 - 2016	Arnaud Quette <arnaud.quette@free.fr>
	 *
	 *  This program is free software; you can redistribute it and/or modify
	 *  it under the terms of the GNU General Public License as published by
	 *  the Free Software Foundation; either version 2 of the License, or
	 *  (at your option) any later version.
	 *
	 *  This program is distributed in the hope that it will be useful,
	 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
	 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	 *  GNU General Public License for more details.
	 *
	 *  You should have received a copy of the GNU General Public License
	 *  along with this program; if not, write to the Free Software
	 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
	 */

	#ifndef ${UDRIVER}_MIB_H
	#define ${UDRIVER}_MIB_H

	#include "main.h"
	#include "snmp-ups.h"

	extern mib2nut_info_t ${LDRIVER};

	#endif /* ${UDRIVER}_MIB_H */
	EOF

	# generate source file
	# create heading boilerblate
	# NOTE: with <<-EOF leading TABs are all stripped
	echo "Creating $CFILE"
	cat > "$CFILE" <<-EOF
	/* ${CFILE} - subdriver to monitor ${DRIVER} SNMP devices with NUT
	 *
	 *  Copyright (C)
	 *  2011 - 2016	Arnaud Quette <arnaud.quette@free.fr>
	 *
	 *  Note: this subdriver was initially generated as a "stub" by the
	 *  gen-snmp-subdriver script. It must be customized!
	 *
	 *  This program is free software; you can redistribute it and/or modify
	 *  it under the terms of the GNU General Public License as published by
	 *  the Free Software Foundation; either version 2 of the License, or
	 *  (at your option) any later version.
	 *
	 *  This program is distributed in the hope that it will be useful,
	 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
	 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	 *  GNU General Public License for more details.
	 *
	 *  You should have received a copy of the GNU General Public License
	 *  along with this program; if not, write to the Free Software
	 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
	 */

	#include "${HFILE}"

	#define ${UDRIVER}_MIB_VERSION  "0.1"

	#define ${UDRIVER}_SYSOID       "${DEVICE_SYSOID}"

	/* To create a value lookup structure (as needed on the 2nd line of the example
	 * below), use the following kind of declaration, outside of the present snmp_info_t[]:
	 * static info_lkp_t onbatt_info[] = {
	 * 	{ 1, "OB" },
	 * 	{ 2, "OL" },
	 * 	{ 0, NULL }
	 * };
	 */

	/* ${UDRIVER} Snmp2NUT lookup table */
	static snmp_info_t ${LDRIVER}_mib[] = {

		/* Data format:
		 * { info_type, info_flags, info_len, OID, dfl, flags, oid2info },
		 *
		 *	info_type:	NUT INFO_ or CMD_ element name
		 *	info_flags:	flags to set in addinfo
		 *	info_len:	length of strings if ST_FLAG_STRING, multiplier otherwise
		 *	OID: SNMP OID or NULL
		 *	dfl: default value
		 *	flags: snmp-ups internal flags (FIXME: ...)
		 *	oid2info: lookup table between OID and NUT values
		 *
		 * Example:
		 * { "input.voltage", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.2.1", "", SU_INPUT_1, NULL },
		 * { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.7.3.0", "", SU_FLAG_OK | SU_STATUS_BATT, onbatt_info },
		 *
		 * To create a value lookup structure (as needed on the 2nd line), use the
		 * following kind of declaration, outside of the present snmp_info_t[]:
		 * static info_lkp_t onbatt_info[] = {
		 * 	{ 1, "OB" },
		 * 	{ 2, "OL" },
		 * 	{ 0, NULL }
		 * };
		 */

		/* standard MIB items; if the vendor MIB contains better OIDs for
		 * this (e.g. with daisy-chain support), consider adding those here
		 */
	EOF

	# Same file, indented text (TABs not stripped):
	cat >> "$CFILE" <<EOF
	{ "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL },
	{ "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL },
	{ "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL },

/* Please revise values discovered by data walk for mappings to
 * docs/nut-names.txt and group the rest under the ifdef below:
 */
#if WITH_UNMAPPED_DATA_POINTS
EOF

	# extract OID string paths, one by one
	LINENB="0"
	while IFS= read -r line; do
		LINENB="`expr $LINENB + 1`"
		FULL_STR_OID="$line"
		STR_OID="`echo "$line" | cut -d'.' -f1`"
		echo "$line" | grep STRING > /dev/null
		if [ $? -eq 0 ]; then
			ST_FLAG_TYPE="ST_FLAG_STRING"
			SU_INFOSIZE="SU_INFOSIZE"
		else
			ST_FLAG_TYPE="0"
			SU_INFOSIZE="1"
		fi
		# get the matching numeric OID
		NUM_OID="`sed -n "${LINENB}p" "${NUMWALKFILE}" | cut -d' ' -f1`"
		printf "\t/* ${FULL_STR_OID} */\n\t{ \"unmapped.${STR_OID}\", ${ST_FLAG_TYPE}, ${SU_INFOSIZE}, \"${NUM_OID}\", NULL, SU_FLAG_OK, NULL },\n"
	done < "${STRWALKFILE}" >> "${CFILE}"

	# append footer (TABs not stripped):
	cat >> "$CFILE" <<EOF
#endif	/* if WITH_UNMAPPED_DATA_POINTS */

	/* end of structure. */
	{ NULL, 0, 0, NULL, NULL, 0, NULL }
};

mib2nut_info_t  ${LDRIVER} = { "${LDRIVER}", ${UDRIVER}_MIB_VERSION, NULL, NULL, ${LDRIVER}_mib, ${UDRIVER}_DEVICE_SYSOID };
EOF

	return
}

# process command line options
while [ $# -gt 0 ]; do
	if [ $# -gt 1 -a "$1" = "-n" ]; then
		DRIVER="$2"
		shift 2
	elif [ $# -gt 1 -a "$1" = "-M" ]; then
		MIBS_DIRLIST="$MIBS_DIRLIST:$2"
		shift 2
	elif [ "$1" = "-k" ]; then
		KEEP=yes
		shift
	elif [ $# -gt 1 -a "$1" = "-H" ]; then
		HOSTNAME="$2"
		shift 2
	elif [ $# -gt 1 -a "$1" = "-c" ]; then
		COMMUNITY="$2"
		shift 2
	elif [ $# -gt 1 -a "$1" = "-s" ]; then
		SYSOID="$2"
		shift 2
	elif echo "$1" | grep -qv '^-'; then
		if [ $# -gt 1 ]; then
			NUMWALKFILE="$1"
			shift
			STRWALKFILE="$1"
			shift
		else
			NUMWALKFILE="$1"
			shift
			#usage
			#exit 1
		fi
	elif [ "$1" = "--help" -o "$1" = "-h" ]; then
		usage
		exit 0
	else
		echo "Illegal option $1. Try --help for more info." >&2
		exit 1
	fi
done

# check that the needed parameters are provided, depending on the mode
if [ -z "$NUMWALKFILE" ]; then
	# mode 1: directly get SNMP data from a real agent
	echo "Mode 1 selected"
	MODE=1
	NUMWALKFILE="$DFL_NUMWALKFILE"
	STRWALKFILE="$DFL_STRWALKFILE"

	# check if Net SNMP is available
	if [ -z "`command -v snmpget`" -o -z "`command -v snmpwalk`" ] && \
	   [ -z "`which snmpget`" -o -z "`which snmpwalk`" ]; then
		echo "Net SNMP not found! snmpget and snmpwalk commands are required." >&2
		exit 1
	fi
	# hostname is also mandatory
	while [ -z "$HOSTNAME" ]; do
		printf "\n\tPlease enter the SNMP host IP address or name.\n"
		read -p "SNMP host IP name or address: " HOSTNAME < /dev/tty
		if echo "$HOSTNAME" | grep -E -q '[^a-zA-Z0-9.-]'; then
			echo "Please use only letters, digits, dash and period character"
			HOSTNAME=""
		fi
	done
	# get data from the agent
	get_snmp_data
else
	# no string walk provided, so mode 3
	if [ -z "$STRWALKFILE" ]; then
		# mode 3: get data from 1 file,
		# Filter according to sysOID on the specific subtree
		# Generate the numeric SNMP walk using this output
		# then use snmptranslate to get the string OIDs and generated the string SNMP walk
		echo "Mode 3 selected"
		MODE=3
		RAWWALKFILE="$NUMWALKFILE"
		NUMWALKFILE="$DFL_NUMWALKFILE"
		STRWALKFILE="$DFL_STRWALKFILE"

		# check for actual file existence
		if [ ! -f "$RAWWALKFILE" ]; then
			echo "SNMP walk dump file is missing on disk. Try --help for more info." >&2
			exit 1
		fi
		# Extract the sysOID
		# Format is "1.3.6.1.2.1.1.2.0 = OID: 1.3.6.1.4.1.4555.1.1.1"
		DEVICE_SYSOID="`grep 1.3.6.1.2.1.1.2.0 "$RAWWALKFILE" | cut -d' ' -f4`"
		if [ -n "$DEVICE_SYSOID" ]; then
			echo "Found sysOID $DEVICE_SYSOID"
		else
			echo "SNMP sysOID is missing in file. Try --help for more info." >&2
			exit 1
		fi

		# Switch to the entry point, and extract the subtree
		# Extract the numeric walk
		echo -n "Extracting numeric SNMP walk..."
		grep "$DEVICE_SYSOID" "$RAWWALKFILE" | grep -E -v "1.3.6.1.2.1.1.2.0" 2>/dev/null 1> "$NUMWALKFILE"
		echo " done"

		# Create the string walk from a translation of the numeric one
		echo -n "Converting string SNMP walk..."
		while IFS=' = ' read NUM_OID OID_VALUE
		do
			STR_OID="`snmptranslate -Os  -m ALL -M+. "$NUM_OID" 2>/dev/null`"
			# Uncomment the below line to get debug logs
			#echo "Got: $STR_OID = $OID_VALUE"
			printf "."
			echo "$STR_OID = $OID_VALUE" >> "$STRWALKFILE"
		done < "$NUMWALKFILE"
		echo " done"
	else
		# mode 2: get data from files
		echo "Mode 2 selected"
		MODE=2

		# get sysOID value from command line, if needed
		while [ -z "$SYSOID" ]; do
			echo "
Please enter the value of sysOID, as displayed by snmp-ups. For example '.1.3.6.1.4.1.2254.2.4'.
You can get it using: snmpget -v1 -c XXX <host> $SYSOID_NUMBER"
			read -p "Value of sysOID: " SYSOID < /dev/tty
			if echo "$SYSOID" | grep -E -q '[^0-9.]'; then
				echo "Please use only the numeric form, with dots and digits"
				SYSOID=""
			fi
		done
		# check for actual files existence
		if [ ! -f "$NUMWALKFILE" -o  ! -f "$STRWALKFILE" ]; then
			echo "SNMP walk dump files are missing on disk. Try --help for more info." >&2
			exit 1
		fi
	fi
fi

# delete temporary files: this is called just before exiting.
cleanup () {
	rm -f "$DEBUG $DFL_NUMWALKFILE $TMP_NUMWALKFILE $DFL_STRWALKFILE $TMP_STRWALKFILE"
}
if [ -n "$KEEP" ]; then
	trap cleanup EXIT
fi

# prompt use for name of driver
while [ -z "$DRIVER" ]; do
	echo "
Please enter a name for this driver. Use only letters and numbers. Use
natural (upper- and lowercase) capitalization, e.g., 'Belkin', 'APC'."
	read -p "Name of subdriver: " DRIVER < /dev/tty
	if echo "$DRIVER" | grep -E -q '[^a-zA-Z0-9]'; then
		echo "Please use only letters and digits"
		DRIVER=""
	fi
done

# remove blank and "End of MIB" lines
grep -E -e "^[[:space:]]?$" -e "End of MIB" -v "${NUMWALKFILE}" > "${TMP_NUMWALKFILE}"
grep -E -e "^[[:space:]]?$" -e "End of MIB" -v "${STRWALKFILE}" > "${TMP_STRWALKFILE}"
NUMWALKFILE="${TMP_NUMWALKFILE}"
STRWALKFILE="${TMP_STRWALKFILE}"

# FIXME: sanity checks (! -z contents -a same `wc -l`)
NUM_OID_COUNT="`cat "$NUMWALKFILE" | wc -l`"
STR_OID_COUNT="`cat "$STRWALKFILE" | wc -l`"

echo "SNMP OIDs extracted = $NUM_OID_COUNT / $NUM_OID_COUNT"

generate_C

# Display the remaining tasks
cat <<EOF
Done.

For C-style integration, do not forget to:
* bump DRIVER_VERSION in snmp-ups.c (add "0.01")
* copy "${HFILE}" and "${CFILE}" to "../../drivers"
* add #include "${HFILE}" to drivers/snmp-ups.c
* add &${LDRIVER} to drivers/snmp-ups.c:mib2nut[] list,
* add ${LDRIVER}-mib.c to snmp_ups_SOURCES in drivers/Makefile.am
* add ${LDRIVER}-mib.h to dist_noinst_HEADERS in drivers/Makefile.am
* "./autogen.sh && ./configure && make" from the top level directory
EOF