1#!/bin/sh
2#-*-sh-*-
3
4#
5# Copyright © 2009 CNRS
6# Copyright © 2009-2019 Inria.  All rights reserved.
7# Copyright © 2009-2012 Université Bordeaux
8# See COPYING in top-level directory.
9#
10
11HWLOC_top_builddir="@HWLOC_top_builddir@"
12prefix="@prefix@"
13exec_prefix="@exec_prefix@"
14bindir="@bindir@"
15localstatedir="@localstatedir@"
16runstatedir="@HWLOC_runstatedir@"
17# this will be changed into $bindir/lstopo during make install
18lstopo="$HWLOC_top_builddir/utils/lstopo/lstopo-no-graphics"
19
20# make sure we use default numeric formats
21LANG=C
22LC_ALL=C
23export LANG LC_ALL
24
25gatherio=0
26gatherdmi=0
27
28if [ ! -x "$lstopo" ]
29then
30    error "Could not find lstopo executable in the install or build dir."
31    exit 1
32fi
33
34error()
35{
36    echo $@ 2>&1
37}
38
39usage()
40{
41   echo "$0 [options] <savepath>"
42   echo "  Saves the Linux topology files (/sys, /proc, ...) under <savepath>.tar.bz2"
43   echo "  and the corresponding lstopo verbose output under <savepath>.output"
44   echo "Options:"
45   echo "  --io   Gather I/O files (takes much longer and generates much larger tarball)"
46   echo "  --dmi  Gather SMBIOS files. Works only when run as root. Requires dmi-sysfs kernel module"
47   echo "Example:"
48   echo "  $0 /tmp/\$(uname -n)"
49}
50
51while [ x`echo "$1" | cut -c1` = x- ] ; do
52  case $1 in
53  --io) gatherio=1;;
54  --dmi) gatherdmi=1;;
55  *) echo "Unrecognized option: $1"; usage; exit 1;;
56  esac
57  shift
58done
59
60if test $# -lt 1 -o x$1 = x; then
61  usage
62  exit 1
63fi
64name="$1"
65basename=`basename "$name"`
66dirname=`dirname "$name"`
67
68if [ x$gatherio = x0 ]; then
69  echo "I/O files won't be saved (--io not given)."
70fi
71if [ x$gatherdmi = x0 ]; then
72  echo "DMI files won't be saved (--dmi not given)."
73fi
74
75echo
76echo "*** Note that this tool may be slow on large nodes or when I/O is enabled. ***"
77echo
78
79if ! mkdir -p "$dirname" ; then
80    error "Failed to create directory $dirname."
81    exit 1
82fi
83
84if [ ! -w  "$dirname" ] ; then
85    echo "$dirname is not writable."
86    exit 1
87fi
88
89destdir=`mktemp -d`
90
91# Use cat so that we properly get proc/sys files even if their
92# file length is wrong
93savefile() {
94  local dest="$1"
95  local file="$2"
96  if test -r "$file"; then
97    dir=`dirname "$file"`
98    mkdir -p "$dest/$dir" 2>/dev/null
99    cat "$file" > "$dest/$file" 2>/dev/null
100  fi
101}
102
103savelink() {
104  local dest="$1"
105  local file="$2"
106  dir=`dirname "$file"`
107  mkdir -p "$dest/$dir" 2>/dev/null
108  cp -P "$file" "$dest/$file"
109}
110
111# Gather the following list of files
112cat << EOF | while read -r path ; do savefile "$destdir/$basename" "$path" ; done
113/proc/cpuinfo
114/proc/meminfo
115/proc/mounts
116/proc/stat
117/proc/self/cpuset
118/proc/self/cgroup
119EOF
120
121# Get all files from the given directory
122# Ignore errors since some files may be missing, and some may be
123# restricted to root (but we don't need them).
124savedir() {
125  local dest="$1"
126  local path="$2"
127  # gather all directories, including empty ones
128  find "$path" -type d 2>/dev/null | while read -r dir ; do
129    mkdir -p "$dest/$dir" 2>/dev/null
130  done
131  # gather all files now
132  find "$path" -type f 2>/dev/null | while read -r file ; do
133    savefile "$dest" "$file"
134  done
135  # gather symlinks
136  find "$path" -type l 2>/dev/null | while read -r link ; do
137    savelink "$dest" "$link"
138  done
139}
140
141# Gather the following list of directories
142cat << EOF | while read -r path ; do savedir "$destdir/$basename" "$path" ; done
143/sys/devices/system/cpu/
144/sys/devices/system/node/
145/sys/bus/cpu/devices/
146/sys/bus/node/devices/
147/sys/class/dmi/id/
148/sys/devices/virtual/dmi/id/
149/sys/kernel/mm/hugepages/
150/proc/device-tree/cpus/
151EOF
152
153# Gather the default /var/run/hwloc (in case it was created by a system-wide hwloc-dump-hwdata)
154if test -d /var/run/hwloc; then
155  savedir "$destdir/$basename" /var/run/hwloc
156fi
157# Then, gather what the current hwloc installation could have created in a different $runstatedir
158if test "$runstatedir" != "/var/run" -a -d "$runstatedir/hwloc"; then
159  savedir "$destdir/$basename" "$runstatedir/hwloc/"
160  mkdir -p "$destdir/$basename/var/run"
161  ln -sr "$destdir/$basename/$runstatedir/hwloc" "$destdir/$basename/var/run/hwloc.runstatedir"
162fi
163# And gather what custom $HWLOC_DUMPED_HWDATA_DIR
164if test "x$HWLOC_DUMPED_HWDATA_DIR" != x -a -d "$HWLOC_DUMPED_HWDATA_DIR"; then
165  savedir "$destdir/$basename" "$HWLOC_DUMPED_HWDATA_DIR"
166  mkdir -p "$destdir/$basename/var/run"
167  ln -sr "$destdir/$basename/$HWLOC_DUMPED_HWDATA_DIR" "$destdir/$basename/var/run/hwloc.HWLOC_DUMPED_HWDATA_DIR"
168fi
169# Now link to /var/run/hwloc (used by default in lstopo -i) to something sane if needed
170if ! test -d "$destdir/$basename/var/run/hwloc"; then
171  if test -e "$destdir/$basename/var/run/hwloc.HWLOC_DUMPED_HWDATA_DIR"; then
172    ln -sr "$destdir/$basename/var/run/hwloc.HWLOC_DUMPED_HWDATA_DIR" "$destdir/$basename/var/run/hwloc"
173  else if test -e "$destdir/$basename/$runstatedir/hwloc"; then
174    ln -sr "$destdir/$basename/var/run/hwloc.runstatedir" "$destdir/$basename/var/run/hwloc"
175  fi fi
176fi
177
178# Optionally gather I/O directories too
179if [ x$gatherio = x1 ]; then
180  cat << EOF | while read -r path ; do savedir "$destdir/$basename" "$path" ; done
181/sys/bus/pci/devices/
182/sys/bus/pci/slots/
183/sys/block/
184/sys/class/block/
185/sys/class/dma/
186/sys/class/drm/
187/sys/class/infiniband/
188/sys/class/net/
189/sys/class/mic/
190EOF
191  ls -d /sys/devices/pci* 2>/dev/null | sed -e 's@$@/@' | while read -r path ; do savedir "$destdir/$basename" "$path" ; done
192  ls -d /run/udev/data/b* 2>/dev/null | while read -r path ; do savefile "$destdir/$basename" "$path" ; done
193fi
194
195if [ x$gatherdmi = x1 ]; then
196  savedir "$destdir/$basename" /sys/firmware/dmi/
197fi
198
199# Get an entire mount point, after decoding its path
200# we don't support path with \n since it would break in 'find ... | while read ..." above
201savemntpnt() {
202  local encodedpath=$1
203  if echo "$1" | grep "\\012" ; then
204    echo "Ignoring mount point whose filename contains an end of line."
205    return
206  fi
207  local path=$(echo "$1" | sed -e 's@\\134@\\@g' -e 's@\\040@ @g' -e 's@\\011@	@g')
208  savedir "$destdir/$basename" "${path}/"
209}
210
211# Gather cgroup/cpuset mntpnts
212cat /proc/mounts | while read -r dummy1 mntpath mnttype mntopts dummy2 ; do
213  [ x$mnttype = xcpuset ] && savemntpnt "$mntpath"
214  [ x$mnttype = xcgroup ] && echo $mntopts | grep -w cpuset >/dev/null && savemntpnt "$mntpath"
215done
216
217# export /proc/hwloc-nofile-info during lstopo (needs HWLOC_DUMP_NOFILE_INFO with HWLOC_THISSYSTEM=1)
218export HWLOC_DUMP_NOFILE_INFO="$destdir/$basename/proc/hwloc-nofile-info"
219"$lstopo" - >/dev/null
220# disable HWLOC_DUMP_NOFILE_INFO for next lstopo invocation
221export HWLOC_DUMP_NOFILE_INFO=
222
223# Create the archive and keep the tree in /tmp for testing
224( cd "$destdir/" && tar cfj "$basename.tar.bz2" "$basename" )
225mv "$destdir/$basename.tar.bz2" "$dirname/$basename.tar.bz2"
226echo "Topology files gathered in $dirname/$basename.tar.bz2 and kept in $destdir/$basename/"
227
228# Generate the output as well
229# we need "Topology not from this system" in the output so as to make test-topology.sh happy
230export HWLOC_THISSYSTEM=0
231"$lstopo" - -v > "$dirname/$basename.output"
232echo "Expected topology output stored in $dirname/$basename.output"
233"$lstopo" -.xml --whole-io --whole-system > "$dirname/$basename.xml"
234echo "XML topology stored in in $dirname/$basename.xml"
235
236echo
237echo "WARNING: Do not post these files on a public list or website unless you"
238echo "WARNING: are sure that no information about this platform is sensitive."
239
240exit 0
241