How to write startup script for systemd

  • I have 2 graphics cards on my laptop. One is IGP and another discrete.

    I've written a shell script to to turn off the discrete graphics card.

    How can I convert it to systemd script to run it at start-up?

  • don_crissti

    don_crissti Correct answer

    8 years ago

    There are mainly two approaches to do that:

    • If you have to run a script, you don't convert it but rather run the script via a systemd service.

    Therefore you need two files: the script and the .service file (unit configuration file).
    Make sure your script is executable and the first line (the shebang) is #!/bin/sh. Then create the .service file in /etc/systemd/system (a plain text file, let's call it vgaoff.service).
    For example:

    1. the script: /usr/bin/vgaoff
    2. the unit file: /etc/systemd/system/vgaoff.service

    Now, edit the unit file. Its content depends on how your script works:

    If vgaoff just powers off the gpu, e.g.:

    exec blah-blah pwrOFF etc 
    

    then the content of vgaoff.service should be:

    [Unit]
    Description=Power-off gpu
    
    [Service]
    Type=oneshot
    ExecStart=/usr/bin/vgaoff
    
    [Install]
    WantedBy=multi-user.target
    

    If vgaoff is used to power off the GPU and also to power it back on, e.g.:

    start() {
      exec blah-blah pwrOFF etc
    }
    
    stop() {
      exec blah-blah pwrON etc
    }
    
    case $1 in
      start|stop) "$1" ;;
    esac
    

    then the content of vgaoff.service should be:

    [Unit]
    Description=Power-off gpu
    
    [Service]
    Type=oneshot
    ExecStart=/usr/bin/vgaoff start
    ExecStop=/usr/bin/vgaoff stop
    RemainAfterExit=yes
    
    [Install]
    WantedBy=multi-user.target
    
    • For the most trivial cases, you can do without the script and execute a certain command directly:

    To power off:

    [Unit]
    Description=Power-off gpu
    
    [Service]
    Type=oneshot
    ExecStart=/bin/sh -c "echo OFF > /whatever/vga_pwr_gadget/switch"
    
    [Install]
    WantedBy=multi-user.target
    

    To power off and on:

    [Unit]
    Description=Power-off gpu
    
    [Service]
    Type=oneshot
    ExecStart=/bin/sh -c "echo OFF > /whatever/vga_pwr_gadget/switch"
    ExecStop=/bin/sh -c "echo ON > /whatever/vga_pwr_gadget/switch"
    RemainAfterExit=yes
    
    [Install]
    WantedBy=multi-user.target
    

    Once you're done with the files, enable the service:

    systemctl enable vgaoff.service
    

    It will start automatically on next boot. You could even enable and start the service in one go with

    systemctl enable --now vgaoff.service
    

    as of systemd v.220 (on older setups you'll have to start it manually).
    For more details see systemd.service manual page.


    Troubleshooting.
    Start here:
    How to see full log of a systemd service?
    systemd service exit codes and status information explanation

    Thanks for detailed answer. The script contains one command "echo OFF > /sys/kernel/debug/vgaswitcheroo/switch"

    it fails with following message vgaoff.service - Power-off gpu Loaded: loaded (/usr/lib/systemd/system/vgaoff.service; enabled) Active: failed (Result: exit-code) since Tue, 11 Sep 2012 23:46:46 +0530; 30s ago Process: 5258 ExecStart=/usr/lib/systemd/scripts/vgaoff (code=exited, status=203/EXEC) CGroup: name=systemd:/system/vgaoff.service

    oops,not again, I missed this small thing, it is working fine.. thanks again.

    Thanks for your detailed and useful guide, but one command is IMHO dangerous: /bin/sh -c "echo OFF > /whatever/vga_pwr_gadget/switch" overwrites /whatever/vga_pwr_gadget/switch with the text "OFF". shouldn't it be & instead of >, which would be: /bin/sh -c "echo OFF & /whatever/vga_pwr_gadget/switch"? Or without the echo part at all? (that's the way I use it successfully.)

    @don_crissti: at least I was foolish enough to overwrite my /sbin/hdparm file/program that way... ...which wasn't too bad, it was easy getting the original back. But it could be a potential trap for users which aren't too CLI experienced like me or even less - then they won't get the original back. ;-)

    @Bazon - according to this logic, thousands of answers on this site are "potential traps" for inexperienced users. People who don't know / fully understand what `echo SOMETHING > /some/file` does (or any other command as a matter of fact) should get familiar with the basics of CLI before attempting to run stuff on their systems. That aside, FYI, read how to switch dGPU off on several laptop models, see if the commands used there could be replaced with something like you suggest. Also, to restore the original file you usually reinstall the package that owns it.

    @don_crissti Maybe you could comment on my new related question: http://unix.stackexchange.com/q/224992/33386

    Perfect answer! want more of these types!

    On Ubuntu Xenial LTS I had to make sure that my init script had LSB header. Which is a block of code that starts with "### BEGIN INIT INFO" and ends with "### END INIT INFO". Otherwise, systemctl enable would fail. You can see an example of such LSB header in almost any init script under /etc/init.d/ on Ubuntu Xenial LTS.

    @don_crissti whoops! thanks for the tip. (deleted my original comment to avoid propagation of misleading information.)

    DO NOT install your script into init.d for the old systemV and then call this script from a mydaemon.service file. This will break horrible. I learned something today

    For more information on .service files and how to customize one for your needs, see https://www.freedesktop.org/software/systemd/man/systemd.service.html

    If you're on Ubuntu 16 and when you do `sudo systemctl enable ...` it reports `Failed to execute operation: Too many levels of symbolic links`, you may need to put the file in `/lib/systemd/system/` instead of `/usr/lib/systemd/system/` before running that `enabe` command. Also, make sure to delete the file in `/usr/lib/systemd/system/` if you did so. Anyways, that's what worked for me.

License under CC-BY-SA with attribution


Content dated before 6/26/2020 9:53 AM