I need to improve my Bash script so that it runs flawlessly without having issues. This script uses ds4drv in it and it has some issues that I'm unsure on how to correct.

First issue is that it doesn't always run or work when the controller is detected, I had created a udev rule for it but it's not clear why it doesn't always run this script when it's detected.

Second issue, ds4drv can only be allowed to run as root only, instead of being run as normal user.

Third issue, I do not know the proper way of dealing with PID lock files once they've been created, so that when the PID process no longer exists it deletes the PID lock file after. It's hard to find proper documentation on how to use PID files in bash scripts so that there can only be 1 running instance.

heres' my udev rule for ds4drv: 50-ds4drv.rules

KERNEL=="uinput", GROUP="users", MODE="0666"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="05c4", GROUP="users", MODE="0
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", KERNELS=="0005:054C:05C4.*", GROUP="users" MODE="0666"
ACTION=="add", SUBSYSTEM="usb", ATTRS{idProduct}=="054c", RUN+="/home/user/scripts/ds4check.sh", GROUP="users"
, MODE="0666"

I'm pretty sure that's how the udev rule should be like, permissions seem to be correct to me since it's read-write for GROUP users. There does seem to be some instance of an issue that once my bash script has run and this rule is set to run automatically when the controller device is connected, that some games become unresponsive like there is no controller device connected when there is, it's suppose to act on /dev/js0 but instead acts on /dev/js1 instead. It may often return this error in particular if it's not executed as root;

OSError: [Errno 13] Permission denied: '/dev/input/event17'

and the bash script of course; ds4check.sh

# DS4 Check Script


# check if process is already running
for pid in $(pidof -x /home/user/scripts/ds4check.sh $pidfile); do
    if [ $pid != $$ ]; then
      echo "[$(date)] : ds4check.sh : Proccess is already running with PID $pid" >> /home/user/.cache/ds4drv.log
      exit 1
# if not running then run and apply config
      else  ( ds4drv --hidraw --config /home/user/.config/ds4drv.conf )

      exit 0

# remove PID file on exit... hopefully
trap "srm -rv -- '$pidfile'" EXIT >> /home/user/.cache/ds4drv.log
  • Can you post the udev rule?
    – Joe
    Feb 3, 2016 at 17:25
  • @Joe If you had read my post, you'd see it's already there in my main post.
    – user91679
    Feb 3, 2016 at 17:27
  • That use of /tmp is a local security flaw (arbitrary file deletion against user running script), better to use /var/run or such. PID files otherwise will only be a so-so solution with edge cases and gotchas, depending on how things fall apart.
    – thrig
    Feb 6, 2016 at 0:05

1 Answer 1


I'm concerned about 2 points

  • PID files which I'm not familiar with, but I would suggest using pgrep as workaround.
  • ds4drv seems a daemon but udev supports only short running processes.



    This can only be used for very short-running foreground tasks. Running an event process for a long period of time may block all further events for this or a dependent device.

    Starting daemons or other long-running processes is not appropriate for udev; the forked processes, detached or not, will be unconditionally killed after the event handling has finished.

Make a copy of that script:

# DS4 Check Script

pgrep ds4drv || ds4drv --hidraw --config /home/user/.config/ds4drv.conf & disown
  • 1
    Yes, ds4drv is a daemon which runs in the background, but problem with my current script it's not letting it attach to /dev/js0 but instead attaching to a new instance on /dev/js1 instead. My udev rule should be fixing it to run on /dev/js0 but it's not doing it correctly.As for your little snippet, it doesn't function as intended, probably because of that double pipe, because when I try to run it, it doesn't do a thing.
    – user91679
    Feb 5, 2016 at 16:28
  • @user94959 , AFAIK it is not possible to fix it to js0, the kernel will make an increment for each device connection (even same device replugged). The best is to /add a udev rule to create a symlink. I checked the upstream documentation, it suggest using service file that will start the daemon at boot. Could I ask what the inconvenient in using that method?
    – user.dz
    Feb 8, 2016 at 9:09
  • I think the issue is that /dev/js0 is default user level, but since the script is forcing me to run it on root level, it attaches it to /dev/js1 instead, what I need is for the script to execute as normal user instead of root. The reason it forces me to run as root is because the config file I have won't apply at all otherwise. The daemon expects root, instead of normal user. There was suppose to be a little thing you could do to make it run at normal user level, but it didn't work for me.
    – user91679
    Feb 8, 2016 at 18:38

You must log in to answer this question.