Today, I switched my workstation from sudo
to doas
. I’m running Void Linux,
and the process was fairly easy.
First, I needed to figure out how to remove sudo
(yes, I realize I could have
installed doas
first, then removed sudo
, but I decided to do it the hard way.)
As it turns out, the advanced usage section of the XBPS manual details how to use the ignorepkg
entry in xbps.d with nothing
other than this exact use case! I created the file /etc/xbps.d/20-ignorepkg-sudo.conf
with contents
and then ran sudo xbps-remove sudo
(an ironic command).
After that, because I was stupid and removed sudo
before I had set up doas
,
I had to use plain-old su
to change to the root user and run xi opendoas
. I also
configured doas
in /etc/doas.conf
with the following:
# see doas.conf(5) for configuration details
permit nopass keepenv :admin
I ran groupadd admin
, usermod -aG admin joel
, and then logged out so that my
user account would see the new group perms.
And just like that, I can now run doas xbps-install ...
and all of my other commands,
just substituting doas
for sudo
.
The one thing I immediately missed was sudoedit
. Before I accidentally tried
to use sudo
for the first time, I had already accidentally tried to run sudoedit
at least 5 times. I had to fix this. I saw a discussion on Reddit where one user
suggested writing a script to replace the sudoedit
functionality.
I quickly starting hacking together something like that. I started with:
#!/bin/sh
mkdir -p /tmp/doasedit
doas cp $1 /tmp/doasedit/tmp_file
$EDITOR /tmp/doasedit/tmp_file
And quickly ran into my first road-block. The script is going to have to change
the permissions of that file before the user can edit it. But if the script changes
the permissions, how can I restore it to the original location with the right
permissions? cp /tmp/doasedit/tmp_file $1
won’t work. I thought about just using
cat to overwrite the file contents in-place (cat /tmp/doasedit/tmp_file > $1
).
That could create some issues if a program has the file open. Instead, a better option
is to create two copies of the file–one for editing, and one for preserving file
attributes:
#!/bin/sh
mkdir -p /tmp/doasedit
doas cp $1 /tmp/doasedit/edit
doas chown -R $USER:$USER /tmp/doasedit/edit
doas cp $1 /tmp/doasedit/file
$EDITOR /tmp/doasedit/edit
cat /tmp/doasedit/edit | doas tee /tmp/doasedit/file 1>/dev/null
doas mv -f /tmp/doasedit/file $1
rm -rf /tmp/doasedit
Of course, the issue with this is that it only works with absolute paths.
I want to make it work for relative paths as well. I’m going to take advantage
of realpath
, which is part of the coreutils
package from Void. As a bonus, this
will also take care of the edge case where the given file is a symlink (IIRC,
sudoedit
didn’t follow symlinks, so I may be diverging here):
#!/bin/sh
mkdir -p /tmp/doasedit
srcfile="$(realpath $1)"
doas cp $srcfile /tmp/doasedit/edit
doas chown -R $USER:$USER /tmp/doasedit/edit
doas cp $srcfile /tmp/doasedit/file
$EDITOR /tmp/doasedit/edit
cat /tmp/doasedit/edit | doas tee /tmp/doasedit/file 1>/dev/null
doas mv -f /tmp/doasedit/file $srcfile
rm -rf /tmp/doasedit
At this point, it works…okay-ish. It can only be used in one instance currently
since I hard-coded /tmp/doasedit/file
and /tmp/doasedit/edit
, but that’s easily fixed:
#!/bin/sh
destfile_pfx="$(cat /dev/urandom | tr -cd 'a-f0-9' | head -c 32)"
while [ -d "/tmp/doasedit/$destfile_pfx" ]; do
destfile_pfx="$(cat /dev/urandom | tr -cd 'a-f0-9' | head -c 32)"
done
mkdir -p /tmp/doasedit/$destfile_pfx
srcfile="$(realpath $1)"
doas cp $srcfile /tmp/doasedit/$destfile_pfx/edit
doas chown -R $USER:$USER /tmp/doasedit/$destfile_pfx/edit
doas cp $srcfile /tmp/doasedit/$destfile_pfx/file
$EDITOR /tmp/doasedit/$destfile_pfx/edit
cat /tmp/doasedit/$destfile_pfx/edit | doas tee /tmp/doasedit/$destfile_pfx/file 1>/dev/null
doas mv -f /tmp/doasedit/$destfile_pfx/file $srcfile
rm -rf /tmp/doasedit/$destfile_pfx
At this point, the only thing missing is the check to see if the file was actually
edited:
...
cat /tmp/doasedit/$destfile_pfx/edit | doas tee /tmp/doasedit/$destfile_pfx/file 1>/dev/null
if cmp -s "/tmp/doasedit/$destfile_pfx/file" "$srcfile"; then
echo "Skipping write; no changes."
else
doas mv -f /tmp/doasedit/$destfile_pfx/file $srcfile
fi
...
I put this in a repo on GitHub if
anyone is interested. I know that a major
weakness of this script is the number of times it calls doas
, which could
break flows where password is required every time doas
is run.