untabified all init scripts
[bootcd.git] / initscripts / pl_hwinit
1 #!/usr/bin/python
2
3 import sys
4 import pypci
5 import pypcimap
6 import os
7 import time
8
9 def now():
10     format = "%H:%M:%S(%Z)"
11     return time.strftime(format, time.localtime())
12
13 def verbose_message(single):
14     print now(), single
15
16 def modprobe(module, summary_file, args = ""):
17     ret = os.system("/sbin/modprobe {} {}".format(module, args))
18     if os.WEXITSTATUS(ret) == 0:
19         summary_file.write("{}\n".format(module))
20         return True
21     else:
22         return False
23
24 def main(argv):
25     if len(argv) == 0:
26         kernel = os.uname()[2]
27     else:
28         kernel = argv[0]
29
30     if os.path.exists(kernel):
31         path = kernel
32     else:
33         path = "/lib/modules/{}/modules.pcimap".format(kernel)
34
35     blacklisted_modules = []
36     blacklists = os.listdir("/etc/modprobe.d")
37     for blacklist in blacklists:
38         blf = "/etc/modprobe.d/{}".format(blacklist)
39         if os.path.exists(blf):
40             f = open(blf)
41             for i in f.readlines():
42                 if i.startswith("blacklist"):
43                     blacklisted_modules.append(i.split()[1])
44     # unify the list
45     blacklisted_modules = list(set(blacklisted_modules))
46
47     pcimap = pypcimap.PCIMap(path)
48     verbose_message("pl_hwinit: loading applicable modules")
49     devices = pypci.get_devices()
50     storage_devices = 0
51     network_devices = 0
52     missing = []
53     with open('/tmp/loadedmodules', 'w') as loadedmodules:
54         for slot in sorted(devices.keys()):
55             dev = devices[slot]
56             modules = pcimap.get(dev)
57             base = (dev[4] & 0xff0000) >> 16
58             if len(modules) == 0:
59                 if base == 0x01 or base == 0x02:
60                     # storage or network device, in that order
61                     missing.append((slot, dev))
62             else:
63                 if base == 0x01:
64                     storage_devices += 1
65                 elif base == 0x02:
66                     network_devices += 1
67     
68                 # FIXME: This needs improved logic in the case of multiple matching modules
69                 for module in modules:
70                     if module not in blacklisted_modules:
71                         verbose_message("pl_hwinit: found and loading module {} (%s)" % (module, slot))
72                         modprobe(module, loadedmodules)
73     
74         if network_devices == 0:
75             verbose_message("pl_hwinit: no supported network devices found!")
76             verbose_message("pl_hwinit: the following devices were found, but have no driver:")
77             lines = [ "{} x {}".format(slot, dev) for slot, dev in missing ]
78             for line in lines:
79                 verbose_message("pl_hwinit: missing " + line)
80     
81         # XXX: could check for storage devices too, but older kernels have a lot of that built-in
82     
83         # sd_mod won't get loaded automatically
84         verbose_message("pl_hwinit: loading sd_mod")
85         modprobe("sd_mod", loadedmodules)
86     
87         # load usb_storage to support node conf files on flash disks
88         verbose_message("pl_hwinit: loading usb_storage")
89         modprobe("usb_storage", loadedmodules)
90     
91         verbose_message("pl_hwinit: loading floppy device driver")
92         modprobe("floppy", loadedmodules, "floppy=0,allowed_drive_mask")
93
94     # always wait a bit between loading the usb drivers, and checking /sys/
95     # for usb devices (this isn't necessarily for waiting for mass storage files,
96     # that is done below)
97     verbose_message("pl_hwinit: waiting for usb system to initialize.")
98     time.sleep(10)
99
100     # sometimes, flash devices take a while to initialize. in fact, the kernel
101     # intentionally waits 5 seconds for a device to 'settle'. some take even longer
102     # to show up. if there are any mass storage devices on the system, try to
103     # delay until they come online, up to a max delay of 30s.
104
105     # the way this will be done is to look for files in /sys/devices that are named
106     # 'bInterfaceClass', these will be a list of the usb devices on the system, and
107     # their primary usb device interface class ids. The base directory these files 
108     # exist in will be the full path to the /sys/device entry for that device.
109     # for each mass storage devices (they have an interface class value of 08),
110     # we wait for a new symbolic link named 'driver' to exist in that directory,
111     # indicating the kernel loaded a driver for that device.
112
113     # usb interface class id for mass storage
114     INTERFACE_CLASS_MASS_STORAGE = "08"
115
116     # how long to wait in seconds before continuing on if devices
117     # aren't available
118     MAX_USB_WAIT_TIME = 30
119
120     # low long in seconds to wait between checks
121     PER_CHECK_USB_WAIT_TIME = 5
122
123
124     # find out if the device identified by the /sys dir has a module
125     # loaded for it. check for a symlink in the dir named driver.
126     def does_device_dir_have_driver(device):
127         return os.path.exists(os.path.join(device, "driver"))
128
129     def filter_and_add(list, directory, files):
130         if ("bInterfaceClass" in files and
131             int(file(os.path.join(directory, "bInterfaceClass")).read(), 16) == INTERFACE_CLASS_MASS_STORAGE):
132             list.append(directory)
133
134     wait_dev_list = []
135     os.path.walk("/sys/devices", filter_and_add, wait_dev_list)
136
137     if len(wait_dev_list) > 0:
138         verbose_message("pl_hwinit: found USB mass storage device(s). Attempting to wait")
139         verbose_message("pl_hwinit: up to %d seconds for them to come online." % MAX_USB_WAIT_TIME)
140
141         total_wait_time = 0
142         success = False
143         while total_wait_time < MAX_USB_WAIT_TIME:    
144             total_wait_time += PER_CHECK_USB_WAIT_TIME
145
146             verbose_message("pl_hwinit: waiting {} seconds.".format(PER_CHECK_USB_WAIT_TIME))
147             time.sleep(PER_CHECK_USB_WAIT_TIME)
148
149             all_devices_online = True
150             for device in wait_dev_list:
151                 if not does_device_dir_have_driver(device):
152                     all_devices_online = False
153
154             if all_devices_online:
155                 success = True
156                 verbose_message("pl_hwinit: looks like the devices are now online.")
157                 break
158             else:
159                 verbose_message("pl_hwinit: not all devices online yet, waiting...")
160
161         if success:
162             verbose_message("pl_hwinit: Succesfully waited for USB mass storage devices")
163             verbose_message("pl_hwinit: to come online.")
164         else:
165             verbose_message("pl_hwinit: One or more USB mass storage devices did not")
166             verbose_message("pl_hwinit: initialize in time. Continuing anyway.")
167
168 if __name__ == "__main__":
169     main(sys.argv[1:])