0

I have the following systemd unit file set to automatically update all Arch Linux and AUR packages at the same time (using the yay AUR helper, of course) while also attempting to temporarily add (and then delete after it’s done, for obvious reasons) a sudoers.d entry to briefly give nobody sudo access to pacman in order to get AUR packages updated:

[Unit]
Description=Automatic Update
After=network-online.target

[Service]
Type=simple
SyslogIdentifier=autoupdate
ExecStartPre=/bin/bash -c 'echo \'nobody ALL= NOPASSWD: /usr/bin/pacman\' > /etc/sudoers.d/autoupdate'
ExecStart=/bin/bash -c \”XDG_CACHE_HOME=/var/tmp PWD=/var/tmp sudo -E -u nobody yay -Syuq --noconfirm --devel --timeupdate\”
ExecStartPost=/usr/bin/rm -f /etc/sudoers.d/autoupdate
KillMode=process
KillSignal=SIGINT

[Install]
WantedBy=multi-user.target

The problem is that bash fails to acknowledge the existence of the closing single quote on the ExecStartPre line:

nobody: -c: line 1: unexpected EOF while looking for matching `’`
nobody: -c: line 2: syntax error: unexpected end of file

This is of course despite the fact that manually typing sudo bash -c ‘echo nobody ALL\=NOPASSWD: /usr/bin/pacman > /etc/sudoers.d/autoupdate’ into my shell succeeds without incident.

What could be causing this discrepancy?

realkstrawn93
  • 722
  • 1
  • 6
  • 13
  • `’` is not `'`. And it's `"`, not `”`. And it's not `\'`, just `'` – KamilCuk Mar 28 '22 at 17:54
  • Typed this up on my phone which unlike the computer itself has a tendency to auto-change straight quotes to slanted ones, so my point still stands. As for the escaped `'` it becomes automatically expanded to `'` by systemd before it’s passed to bash. If it was just `'` then systemd would filter it out and not let bash see it — would instead just be `bash -c` without the quotes and therefore without any ability to tell when the command ends or begins. – realkstrawn93 Mar 28 '22 at 18:01
  • No, just `'`. I will find you an example, if you want. Look at `/usr/lib/systemd/system/shadow.service` on your system. And don't `\\=` just `=` (and i should be I believe `ALL=(root) NOPASSWD:` or `ALL=(ALL)` I do not know if empty `ALL=` is valid, but my sudoers is bad). And consider using a separate builder account, not nobody - nobody should be nobody, he shouldn't be able to modify your system. – KamilCuk Mar 28 '22 at 18:03
  • `shadow.service` doesn’t have any nested quotes being echoed to a file. In order for an existing service file to be analogous to what I’m trying to accomplish it would have to have an escaped string-within-a-string. And your “nobody should be nobody” argument is exactly why I delete the file afterwards; according to the [Arch wiki](https://wiki.archlinux.org/title/Makepkg#Usage) use of nobody is recommended when building packages. – realkstrawn93 Mar 28 '22 at 18:15
  • I do not understand. The service file you presented also does not have any "nested quotes". – KamilCuk Mar 28 '22 at 18:17
  • `"nobody ALL = NOPASSWD: /usr/bin/pacman"` is a string within a string. Or at least supposed to be. – realkstrawn93 Mar 28 '22 at 18:19
  • `nobody is recommended when building packages` Yes, when __building__ packages. Not for installation. Nobody is exactly recommend __because__ he can't do anything, like installing packages on your system. Once you give him permissions, it defeats the purpose. – KamilCuk Mar 28 '22 at 18:22
  • Again, that’s exactly why my unit file was configured to delete the sudoers entry in the `ExecStartPost=` command. Which, as it turns out, needed to be changed to `ExecStopPost=` in order for this to work properly, as the answer to my own question points out. – realkstrawn93 Mar 28 '22 at 18:37

2 Answers2

0

Turns out the overcomplication of the issue was rooted in the use of ExecStartPost= instead of ExecStopPost=. Once I changed the former to the latter, the original version of the unit file from long before this was posted (which was far simpler) worked perfectly.

realkstrawn93
  • 722
  • 1
  • 6
  • 13
0

regardless of why you want to use sudo even though you are root.. and without thinking about your code..
Use a script instead

 ExecStartPre=/path/to/your/script prestart
 ExecStart=/path/to/your/script start
 ExecStartPost=/path/to/your/script poststart
    

your script

#!/bin/bash
case $1 in
        prestart)  echo "nobody ALL= NOPASSWD: /usr/bin/pacman" > /etc/sudoers.d/autoupdate;;
        start)     XDG_CACHE_HOME=/var/tmp
                   PWD=/var/tmp
                   sudo -E -u nobody yay -Syuq --noconfirm --devel --timeupdate;;
        poststart) rm -f /etc/sudoers.d/autoupdate;;
esac
ufopilot
  • 3,269
  • 2
  • 10
  • 12
  • [This is why](https://wiki.archlinux.org/title/Makepkg#Usage) — the AUR helper in question builds AND installs, doesn’t just install, and you *cannot* be root if you want to run `makepkg` on all those AUR packages to keep them just as up-to-date as the system itself. Of course it goes without saying that deleting nobody’s `sudoers.d` entry is exactly what my original version does, and, again, per answer to my own question, I did manage to solve my own problem anyway. Thanks though. – realkstrawn93 Mar 28 '22 at 22:02