4

For my application, I need to cut off the USB power at the earliest possible stage. Right now it starts early in init.d but I would like it, if possible, to start before the init.d stuff starts. I read somewhere that Linux normally calls /sbin/init after it boots the kernel. I looked at that file and I only calls this binary "/lib/systemd/systemd" Is this the case for Raspi as well? Can I put stuff right before or after that line?

I did:

journalctl -u disableusb.service
No journal files were found.

And yes, I did a sudo systemctl enable disableusb before. And it said it created a link to it.

pi@raspberrypi:~$ systemd-analyze
Startup finished in 3.312s (kernel) + 14.995s (userspace) = 18.308s

multi-user.target @14.786s
└─getty.target @14.767s
  └─serial-getty@ttyAMA0.service @14.733s
    └─systemd-user-sessions.service @13.720s +251ms
      └─network.target @13.142s
        └─dhcpcd.service @11.656s +1.249s
          └─basic.target @11.571s
            └─timers.target @11.552s
              └─systemd-tmpfiles-clean.timer @11.551s
                └─sysinit.target @11.522s
                  └─networking.service @7.911s +3.569s
                    └─local-fs.target @7.757s
                      └─boot.mount @7.503s +162ms
                        └─systemd-fsck@dev-mmcblk0p6.service @7.195s +248ms
                          └─dev-mmcblk0p6.device @7.166s
  • Which operating system are you using? Raspbian Stretch? – Aurora0001 Jan 19 '18 at 14:07
  • raspbian-jessie – Radu Jan 19 '18 at 14:13
  • 2
    Most linux distros use systemd for the init implementation now. /etc/init.d is only around for backward compatibility (and possible cross compatibility with other *nixes). The best opportunity for fine tuning is, as Aurora0001 indicates, using systemd facilities. – goldilocks Jan 19 '18 at 14:29
11

If you're using systemd (which you are if you have Jessie or Stretch), you'll want to create a systemd unit that will run your script as early as possible. In your /lib/systemd/system (note: not /lib/systemd/systemd, unlike some other distributions — see the official Pi docs) directory, create a new file called disableusb.service, containing the following:

[Unit]
Description=Disable USB power
Before=basic.target
After=local-fs.target sysinit.target
DefaultDependencies=no

[Service]
Type=oneshot
ExecStart=/path/to/script

[Install]
WantedBy=basic.target

Then, run systemctl enable disableusb, and the script should run on reboot.


Systemd works by running 'units' in order of their dependencies. A chart showing which order units are booted is available on the systemd website, reproduced here for reference:

local-fs-pre.target
         |
         v
(various mounts and   (various swap   (various cryptsetup
 fsck services...)     devices...)        devices...)       (various low-level   (various low-level
         |                  |                  |             services: udevd,     API VFS mounts:
         v                  v                  v             tmpfiles, random     mqueue, configfs,
  local-fs.target      swap.target     cryptsetup.target    seed, sysctl, ...)      debugfs, ...)
         |                  |                  |                    |                    |
         \__________________|_________________ | ___________________|____________________/
                                              \|/
                                               v
                                        sysinit.target
                                               |
          ____________________________________/|\________________________________________
         /                  |                  |                    |                    \
         |                  |                  |                    |                    |
         v                  v                  |                    v                    v
     (various           (various               |                (various          rescue.service
    timers...)          paths...)              |               sockets...)               |
         |                  |                  |                    |                    v
         v                  v                  |                    v              rescue.target
   timers.target      paths.target             |             sockets.target
         |                  |                  |                    |
         v                  \_________________ | ___________________/
                                              \|/
                                               v
                                         basic.target
                                               |
          ____________________________________/|                                 emergency.service
         /                  |                  |                                         |
         |                  |                  |                                         v
         v                  v                  v                                 emergency.target
     display-        (various system    (various system
 manager.service         services           services)
         |             required for            |
         |            graphical UIs)           v
         |                  |           multi-user.target
         |                  |                  |
         \_________________ | _________________/
                           \|/
                            v
                  graphical.target

The earliest you could realistically run your service is after sysinit.target, when the low-level services are initialized, I suspect. The systemd configuration above will execute the script path declared by ExecStart= after sysinit.target is complete, which should be relatively early in the boot sequence.

  • 1
    Thank you very much. I will experiment with this, and if it works well, I will try to move it even earlier than that, until it doesn't work or it hangs on boot :) – Radu Jan 19 '18 at 14:42
  • Btw, my script is actually just a line of code, "echo 0 | tee /sys/devices/platform/soc/20980000.usb/buspower >/dev/null" Can I just put that in ExecStart, or does it have to be a path to an actual script? – Radu Jan 19 '18 at 14:53
  • 1
    Just replace your old disableusb.service with the new one – I've edited my post with the correct version now, so just copy that and put it in disableusb.service, then re-enable it. – Aurora0001 Jan 19 '18 at 15:47
  • 1
    Worked really well, ty. Now that I know the magic behind it, I will try to experiment more, I will try to put it before the network target, since I'd like to shut down the networking at all (at least the wifi part of it). – Radu Jan 19 '18 at 15:54
  • 1
    That's a cracking looking chart that. – codinghands Jan 19 '18 at 17:52
2

The earliest possible place is in the initrd (init ramdisk). For this you should look into creating an initramfs-tools hook in /etc/initramfs-tools/hooks or similar. You probably best look for some examples how other programs do it.

The initrd-code will be executed right after the kernel is loaded and sets up the most important things like loading different kernel modules needed for booting, mounting cryptoroot, etc. Something like you need to do would be possible there and prevent any programs from accessing usb things before your script ran.

  • Thanks. I took a look in /etc/initramfs-tools/ and it's pretty much empty. No hooks, no scripts no nothing, except for a few mostly empty files. Also, I think I need the file system to be there, because there will be a file that decides if I want the usb to start or not. – Radu Jan 19 '18 at 16:28
  • Have a look at the files in /usr/share/initramfs-tools, there are the file supplied by the system. For an example how to extend it you can install dropbear-initramfs (ssh server in the initrd to remotely unlock a cryptoroot). – allo Jan 21 '18 at 9:40
  • How to set and read the flag if you want usb to be enabled is up to you. Probably you could hook into some "rootfs mounted" step in the initrd, but I guess for the details you need to experiment yourself. – allo Jan 21 '18 at 9:41
  • Thanks, that looks interesting, I guess I could use an external MCU to pull some GPIO so I know when to disable the usb and when not to. – Radu Jan 21 '18 at 12:17
0

Possibly this answer is outside "earliest in the boot process". But if you really need USB disabled at the earliest possible time, you will need to modify the USB drivers in the kernel so that they initialize the USB hardware as "off". Ideally you could control this with a writeable module parameter. Then you could set the desired value as a kernel command line option and change it later by writing to /sys/module/parameters/. Sorry I don't have a patch. ps: Awesome systemd dependency chart from Aurora.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.