30 | | # Add the path of the installed dependent files |
---|
31 | | sys.path.insert(0, "$PYTHONDIR" ) |
---|
32 | | |
---|
33 | | import listirqinfo |
---|
34 | | import helpstrings |
---|
35 | | from ffado_diag_helpers import * |
---|
36 | | |
---|
37 | | ## message strings |
---|
38 | | FFADODIAG_VERSION = "$VERSION$REVISIONSTRING" |
---|
39 | | |
---|
40 | | welcome_msg = """ |
---|
41 | | |
---|
42 | | FFADO diagnostic utility """ + FFADODIAG_VERSION + """ |
---|
43 | | ============================ |
---|
44 | | (C) 2008 Pieter Palmers |
---|
45 | | 2009-2010 Arnold Krille |
---|
46 | | |
---|
47 | | """ |
---|
48 | | |
---|
49 | | ## main program |
---|
50 | | if __name__== '__main__': |
---|
51 | | |
---|
52 | | print (welcome_msg) |
---|
53 | | |
---|
54 | | parse_command_line () |
---|
55 | | |
---|
56 | | print ("=== CHECK ===") |
---|
57 | | print (" Base system...") |
---|
58 | | |
---|
59 | | # check kernel |
---|
60 | | kernel_version = get_kernel_version() |
---|
61 | | print (" kernel version............ " + str(kernel_version)) |
---|
62 | | kernel_is_preempt = get_kernel_preempt() |
---|
63 | | print (" Preempt (low latency)... " + str(kernel_is_preempt)) |
---|
64 | | # Hint: The main parts of the rt patches are in mainline-kernels nowadays. Performance with stock kernels is sufficient... |
---|
65 | | kernel_is_rt_patched = get_kernel_rt_patched() |
---|
66 | | print (" RT patched.............. " + str(kernel_is_rt_patched)) |
---|
67 | | |
---|
68 | | # check modules |
---|
69 | | oldstack_present = check_1394oldstack_present() |
---|
70 | | oldstack_loaded = check_1394oldstack_loaded() |
---|
71 | | oldstack_active = check_1394oldstack_active() |
---|
72 | | oldstack_statically_linked = not check_1394oldstack_loaded() and check_1394oldstack_linked() |
---|
73 | | newstack_present = check_1394newstack_present() |
---|
74 | | newstack_loaded = check_1394newstack_loaded() |
---|
75 | | newstack_active = check_1394newstack_active() |
---|
76 | | newstack_statically_linked = not check_1394newstack_loaded() and check_1394newstack_linked() |
---|
77 | | |
---|
78 | | print (" old 1394 stack present.... " + str(oldstack_present)) |
---|
79 | | print (" old 1394 stack loaded..... " + str(oldstack_loaded)) |
---|
80 | | print (" old 1394 stack active..... " + str(oldstack_active)) |
---|
81 | | print (" new 1394 stack present.... " + str(newstack_present)) |
---|
82 | | print (" new 1394 stack loaded..... " + str(newstack_loaded)) |
---|
83 | | print (" new 1394 stack active..... " + str(newstack_active)) |
---|
84 | | |
---|
85 | | # check /dev/raw1394 node presence |
---|
86 | | devnode_present = check_1394oldstack_devnode_present() |
---|
87 | | print (" /dev/raw1394 node present. " + str(devnode_present)) |
---|
88 | | if devnode_present: |
---|
89 | | # check /dev/raw1394 access permissions |
---|
90 | | devnode_permissions = check_1394oldstack_devnode_permissions() |
---|
91 | | print (" /dev/raw1394 permissions.. " + str(devnode_permissions)) |
---|
| 30 | # Prefer reproducible output with few non-ASCII characters. |
---|
| 31 | os.environ ["LC_ALL"] = "C" |
---|
| 32 | |
---|
| 33 | # Consistent formatting. |
---|
| 34 | def show_pair (key, value): |
---|
| 35 | # rstrip () for convenience, but do not assume that value is a string. |
---|
| 36 | print ("{:25} {}".format (key, value).rstrip ()) |
---|
| 37 | def indent (lines): |
---|
| 38 | print (" {}".format (lines.rstrip ().replace ("\n", "\n "))) |
---|
| 39 | |
---|
| 40 | # Convenient shortcuts. |
---|
| 41 | def stdout (*args): |
---|
| 42 | return subprocess.check_output (args).decode ("utf8") |
---|
| 43 | |
---|
| 44 | def which (command): |
---|
| 45 | popen = subprocess.Popen (("which", command), stdout=subprocess.PIPE, |
---|
| 46 | stderr=subprocess.PIPE) |
---|
| 47 | stdout, stderr = popen.communicate () |
---|
| 48 | if popen.returncode == 0: |
---|
| 49 | return stdout.decode ("utf8").rstrip () |
---|
| 50 | elif popen.returncode == 1: |
---|
| 51 | return None |
---|
93 | | devnode_permissions = None |
---|
94 | | |
---|
95 | | if newstack_active: |
---|
96 | | # check permissions |
---|
97 | | newstack_permissions = get_juju_permissions() |
---|
98 | | print (" /dev/fw* permissions:") |
---|
99 | | print (newstack_permissions) |
---|
100 | | |
---|
101 | | print (" User IDs:") |
---|
102 | | print (get_user_ids()) |
---|
103 | | |
---|
104 | | |
---|
105 | | # check libraries |
---|
106 | | print(" Prerequisites (dynamic at run-time)...") |
---|
107 | | check_libraries () |
---|
108 | | |
---|
109 | | print (" Prerequisites (static at compile-time)...") |
---|
110 | | try: |
---|
111 | | with open( "$PYTHONDIR/static_info.txt", "r" ) as f: |
---|
112 | | for line in f: |
---|
113 | | if line.startswith(" "): |
---|
114 | | print (line, end='') |
---|
115 | | except: |
---|
116 | | print ("Failed to read $PYTHONDIR/static_info.txt.") |
---|
117 | | |
---|
118 | | # libraw |
---|
119 | | |
---|
120 | | print (" uname -a...") |
---|
121 | | print (" " + run_command_string (('uname', '-a'))) |
---|
122 | | |
---|
123 | | print (" Hardware...") |
---|
124 | | # check host controller |
---|
125 | | print (" Host controllers:") |
---|
126 | | list_host_controllers() |
---|
127 | | print (" CPU info:") |
---|
128 | | try: |
---|
129 | | lscpu_path = run_command (('which', 'lscpu')).rstrip () |
---|
130 | | print (run_command_string ((lscpu_path,))) |
---|
131 | | except subprocess.CalledProcessError: |
---|
132 | | with open ('/proc/cpuinfo') as f: |
---|
133 | | for l in f: |
---|
134 | | print (l, end='') |
---|
135 | | |
---|
136 | | print (" Configuration...") |
---|
137 | | # check RT settings |
---|
138 | | |
---|
139 | | # check IRQ settings |
---|
140 | | print (" IRQ information") |
---|
141 | | info = listirqinfo.IRQInfo() |
---|
142 | | info.load() |
---|
143 | | info.display() |
---|
144 | | |
---|
145 | | print ("") |
---|
146 | | print ("=== REPORT ===") |
---|
147 | | |
---|
148 | | # do the interpretation of the tests |
---|
149 | | print ("FireWire kernel drivers:") |
---|
150 | | if (oldstack_loaded or oldstack_statically_linked) and \ |
---|
151 | | (newstack_loaded or newstack_statically_linked): |
---|
152 | | print (helpstrings.MODULES_BOTH_STACKS_LOADED) |
---|
153 | | sys.exit(-1) |
---|
154 | | elif newstack_loaded or newstack_statically_linked: |
---|
155 | | print (helpstrings.MODULES_NEW_STACK_LOADED) |
---|
156 | | sys.exit(-1) |
---|
157 | | elif oldstack_statically_linked: |
---|
158 | | print ("[PASS] Kernel drivers statically linked into the kernel.") |
---|
159 | | elif not oldstack_present: |
---|
160 | | print (helpstrings.MODULES_OLD_STACK_NOT_INSTALLED) |
---|
161 | | sys.exit(-1) |
---|
162 | | elif not oldstack_loaded: |
---|
163 | | print (helpstrings.MODULES_OLD_STACK_NOT_LOADED) |
---|
164 | | sys.exit(-1) |
---|
| 53 | print (stderr) |
---|
| 54 | sys.exit (1) |
---|
| 55 | |
---|
| 56 | # Parse command line. |
---|
| 57 | usage = """Usage: ffado-diag [--static | -V | --version | --usage] |
---|
| 58 | --static Only display executable paths and libraries. |
---|
| 59 | -V, --version Display version information. |
---|
| 60 | --usage Print a short usage message and exit.""" |
---|
| 61 | if len (sys.argv) == 1: |
---|
| 62 | static_option = False |
---|
| 63 | elif len (sys.argv) == 2: |
---|
| 64 | if sys.argv [1] == "--static": |
---|
| 65 | static_option = True |
---|
| 66 | elif sys.argv [1] in ("-V", "--version"): |
---|
| 67 | print (version_info) |
---|
| 68 | sys.exit (0) |
---|
| 69 | elif sys.argv [1] == "--usage": |
---|
| 70 | print (usage) |
---|
| 71 | sys.exit (0) |
---|
176 | | print ("[PASS] /dev/raw1394 node present and accessible.") |
---|
| 107 | show_pair (lib, stdout (pkg_config, "--modversion", lib)) |
---|
| 108 | show_pair ('', stdout (pkg_config, "--cflags", "--libs", lib)) |
---|
| 109 | |
---|
| 110 | # If the "static" command line argument has been given, stop here. |
---|
| 111 | # Else, attempt to display static_info.txt and go on. |
---|
| 112 | if static_option: |
---|
| 113 | sys.exit (0) |
---|
| 114 | |
---|
| 115 | print ('') |
---|
| 116 | show_pair ("Build time info", static_info) |
---|
| 117 | try: |
---|
| 118 | with open (static_info, "r" ) as f: |
---|
| 119 | for line in f: |
---|
| 120 | indent (line) |
---|
| 121 | except: |
---|
| 122 | indent ("Failed to read build time info.") |
---|
| 123 | |
---|
| 124 | print ('') |
---|
| 125 | kernel_version = stdout ("uname", "-r").rstrip () |
---|
| 126 | show_pair ("kernel version", kernel_version) |
---|
| 127 | |
---|
| 128 | uname_v = stdout ("uname", "-v") |
---|
| 129 | show_pair ("Preempt (low latency)", " PREEMPT " in uname_v and not " RT " in uname_v) |
---|
| 130 | show_pair ("RT patched", "PREEMPT RT" in uname_v) |
---|
| 131 | # Hint: |
---|
| 132 | # The main parts of the rt patches are in mainline-kernels nowadays. |
---|
| 133 | # Performance with stock kernels is sufficient... |
---|
| 134 | |
---|
| 135 | fw_devices = glob.glob ("/dev/fw*") |
---|
| 136 | show_pair ("/dev/fw*", fw_devices) |
---|
| 137 | if fw_devices: |
---|
| 138 | indent (stdout (*(["ls", "-lh"] + fw_devices))) |
---|
| 139 | |
---|
| 140 | show_pair ("User IDs", stdout ("id")) |
---|
| 141 | |
---|
| 142 | show_pair ("uname -a", stdout ("uname", "-a")) |
---|
| 143 | |
---|
| 144 | lspci = which ("lspci") |
---|
| 145 | if not lspci and os.path.exists ("/sbin/lspci"): |
---|
| 146 | lspci = "/sbin/lspci" |
---|
| 147 | show_pair ("lspci", lspci) |
---|
| 148 | if lspci: |
---|
| 149 | for m in re.findall ("^\([^ ]*\).*1394.*", stdout (lspci), re.MULTILINE): |
---|
| 150 | indent (stdout (lspci, "-vv", "-nn", "-s", m.group (1))) |
---|
| 151 | |
---|
| 152 | lscpu = which ("lscpu") |
---|
| 153 | show_pair ("lscpu", lscpu) |
---|
| 154 | if lscpu: |
---|
| 155 | indent (stdout (lscpu)) |
---|
| 156 | else: |
---|
| 157 | print ("/proc/cpuinfo") |
---|
| 158 | with open ("/proc/cpuinfo") as f: |
---|
| 159 | for l in f: |
---|
| 160 | indent (l) |
---|
| 161 | |
---|
| 162 | ###################################################################### |
---|
| 163 | class IRQ: |
---|
| 164 | def __init__(self, number): |
---|
| 165 | self.number = number |
---|
| 166 | self.pid = "" |
---|
| 167 | self.scheduling_class = "" |
---|
| 168 | self.scheduling_priority = "" |
---|
| 169 | self.drivers = "" |
---|
| 170 | self.cpu_counts = "" |
---|
| 171 | def description (self): |
---|
| 172 | return "IRQ{:>4} PID{:>5} count{:>18} Sched{:>4} priority{:>4} drivers {}"\ |
---|
| 173 | .format (self.number, self.pid, self.cpu_counts, self.scheduling_class, |
---|
| 174 | self.scheduling_priority, self.drivers) |
---|
| 175 | |
---|
| 176 | class SoftIRQ: |
---|
| 177 | def __init__(self, pid, scheduling_class, scheduling_priority, fullname): |
---|
| 178 | self.pid = pid |
---|
| 179 | self.fullname = fullname |
---|
| 180 | self.scheduling_class = scheduling_class |
---|
| 181 | self.scheduling_priority = scheduling_priority |
---|
| 182 | def name (self): |
---|
| 183 | return "{}-{}".format (self.fullname, self.pid) |
---|
| 184 | def description (self): |
---|
| 185 | return "SoftIRQ{:>12} PID{:>6} Sched{:>4} priority{:>4}) name softirq-{}"\ |
---|
| 186 | .format (self.name (), self.pid, self.scheduling_class, |
---|
| 187 | self.scheduling_priority, self.fullname) |
---|
| 188 | |
---|
| 189 | # get PID info |
---|
| 190 | outtext = stdout ("ps", "-eLo", "pid,cmd,class,rtprio") |
---|
| 191 | |
---|
| 192 | softIRQs = {} |
---|
| 193 | for m in re.findall (r"^([0-9]+) +\[softirq-(.*)\] +([A-Z]+) +([-0-9]+)", outtext, re.MULTILINE): |
---|
| 194 | irq = SoftIRQ (pid = m.group (1), |
---|
| 195 | fullname = m.group (2), |
---|
| 196 | scheduling_class = m.group (3), |
---|
| 197 | scheduling_priority = m.group (4)) |
---|
| 198 | softIRQs [irq.name ()] = irq |
---|
| 199 | |
---|
| 200 | IRQs = {} |
---|
| 201 | for m in re.findall (r"^([0-9]+) +\[IRQ-([0-9]+)\] +([A-Z]{2}) +([-0-9]+)", outtext, re.MULTILINE): |
---|
| 202 | irq = IRQ (number = int (m.group (2))) |
---|
| 203 | IRQs [irq.number] = irq |
---|
| 204 | irq.pid = m.group (1) |
---|
| 205 | irq.scheduling_class = m.group (3) |
---|
| 206 | irq.scheduling_priority = m.group (4) |
---|
| 207 | |
---|
| 208 | # get irq info |
---|
| 209 | regex_irq = re.compile (r"^ *([0-9]+): *((?:[0-9]+ +)+)(.*)$") |
---|
| 210 | with open ("/proc/interrupts") as f: |
---|
| 211 | for line in f: |
---|
| 212 | m = regex_irq.search (line) |
---|
| 213 | if m: |
---|
| 214 | irq_number = int (m.group(1)) |
---|
| 215 | if irq_number in IRQs: |
---|
| 216 | irq = IRQs [irq_number] |
---|
| 217 | else: |
---|
| 218 | irq = IRQ (number = irq_number) |
---|
| 219 | IRQs [irq_number] = irq |
---|
| 220 | irq.cpu_counts = ",".join (m.group (2).split ()) |
---|
| 221 | irq.drivers = ",".join (m.group (3).split ()) |
---|
| 222 | |
---|
| 223 | print ("\nHardware interrupts") |
---|
| 224 | for _, irq in sorted (IRQs.items ()): |
---|
| 225 | indent (irq.description ()) |
---|
| 226 | print ("\nSoftware interrupts") |
---|
| 227 | for _, irq in sorted (softIRQs.items ()): |
---|
| 228 | indent (irq.description ()) |
---|
| 229 | print ('') |
---|
| 230 | |
---|
| 231 | ###################################################################### |
---|
| 232 | |
---|
| 233 | def module_loaded (module_name, procfile): |
---|
| 234 | with open (procfile) as f: |
---|
| 235 | for l in f: |
---|
| 236 | if module_name in l or module_name.replace ("-", "_") in l: |
---|
| 237 | return True |
---|
| 238 | return False |
---|
| 239 | |
---|
| 240 | module_dir = "/lib/modules/" + kernel_version |
---|
| 241 | show_pair ("module directory", module_dir) |
---|
| 242 | |
---|
| 243 | class Stack: |
---|
| 244 | def __init__ (self, modules, main_module): |
---|
| 245 | self.present = True |
---|
| 246 | self.loaded = True |
---|
| 247 | for module_name in modules: |
---|
| 248 | if module_name in stdout ("find", module_dir, "-name", module_name + ".ko"): |
---|
| 249 | indent (module_name + " present") |
---|
| 250 | else: |
---|
| 251 | indent (module_name + " not present") |
---|
| 252 | self.present = False |
---|
| 253 | |
---|
| 254 | if module_loaded (module_name, "/proc/modules"): |
---|
| 255 | indent (module_name + " loaded") |
---|
| 256 | else: |
---|
| 257 | indent (module_name + " not loaded") |
---|
| 258 | self.loaded = False |
---|
| 259 | |
---|
| 260 | self.active = self.loaded and module_loaded (main_module, "/proc/interrupts") |
---|
| 261 | show_pair ("stack active", self.active) |
---|
| 262 | |
---|
| 263 | self.statically_linked = not self.loaded and os.access ("/sys/module/" + main_module, os.F_OK) |
---|
| 264 | show_pair ("statically linked", self.statically_linked) |
---|
| 265 | |
---|
| 266 | print ("Old 1394 stack") |
---|
| 267 | oldstack = Stack (("ieee1394", "ohci1394", "raw1394"), "ohci1394") |
---|
| 268 | |
---|
| 269 | print ("New 1394 stack") |
---|
| 270 | newstack = Stack (("firewire-core", "firewire-ohci"), "firewire-ohci") |
---|
| 271 | |
---|
| 272 | print ("Kernel support:") |
---|
| 273 | if (oldstack.loaded or oldstack.statically_linked) and \ |
---|
| 274 | (newstack.loaded or newstack.statically_linked): |
---|
| 275 | indent ("""Both old and new FireWire kernel modules are loaded, your system |
---|
| 276 | configuration is bogus.""") |
---|
| 277 | sys.exit (1) |
---|
| 278 | elif newstack.loaded or newstack.statically_linked: |
---|
| 279 | indent ("""The new FireWire kernel stack is loaded. |
---|
| 280 | If running a kernel earlier than 2.6.37 and problems are experienced, either |
---|
| 281 | try with the old Firewire kernel stack or upgrade to a newer kernel |
---|
| 282 | (preferrably 2.6.37 or later).""") |
---|
| 283 | sys.exit (1) |
---|
| 284 | elif oldstack.statically_linked: |
---|
| 285 | indent ("[PASS] Kernel drivers statically linked into the kernel.") |
---|
| 286 | elif not oldstack.present: |
---|
| 287 | indent ("""FireWire kernel module(s) not found. |
---|
| 288 | Please ensure that the raw1394 module is loaded.""") |
---|
| 289 | sys.exit (1) |
---|
| 290 | elif not oldstack.loaded: |
---|
| 291 | indent ("""FireWire kernel stack not present. |
---|
| 292 | Please compile the kernel with FireWire support.""") |
---|
| 293 | sys.exit (1) |
---|
| 294 | else: |
---|
| 295 | indent ("[PASS] Kernel modules present and correctly loaded.") |
---|
| 296 | |
---|
| 297 | ###################################################################### |
---|
| 298 | print ("/dev/raw1394 devices:") |
---|
| 299 | |
---|
| 300 | if not os.path.exists ("/dev/raw1394"): |
---|
| 301 | indent ("""/dev/raw1394 device node not present. |
---|
| 302 | Please fix your udev configuration or add it as a static node.""") |
---|
| 303 | sys.exit (1) |
---|
| 304 | |
---|
| 305 | try: |
---|
| 306 | with open ("/dev/raw1394", "w"): |
---|
| 307 | pass |
---|
| 308 | except: |
---|
| 309 | indent ("""Not enough permissions to access /dev/raw1394 device. |
---|
| 310 | Please fix your udev configuration, the node permissions or |
---|
| 311 | the user/group permissions.""") |
---|
| 312 | sys.exit (1) |
---|
| 313 | |
---|
| 314 | indent ("[PASS] /dev/raw1394 node present and accessible.") |
---|