Add install/uninstall scripts and rewrite the README around them
install.sh sets up a private virtualenv, the udev rule (group picked automatically), and optionally a systemd user service (--service) and LAN access with a subnet-limited firewalld/ufw rule (--lan). It records what it changed so uninstall.sh can undo exactly that. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
# dgm20-linux
|
# dgm20-linux
|
||||||
|
|
||||||
Control the **Maono DGM20** USB microphone on Linux. Maono Link only runs on Windows and macOS; this
|
Control the **Maono DGM20** USB microphone on Linux. Maono Link only runs on Windows and macOS;
|
||||||
covers the same settings with a local web page and a command-line tool.
|
this covers the same settings with a local web page and a command-line tool.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -12,59 +12,129 @@ covers the same settings with a local web page and a command-line tool.
|
|||||||
- RGB ring brightness
|
- RGB ring brightness
|
||||||
- Factory reset
|
- Factory reset
|
||||||
|
|
||||||
Pure Python 3.9+, no dependencies. Nothing leaves your machine: the page is served from localhost
|
Pure Python, no dependencies. Nothing leaves your machine: the page is served from your own
|
||||||
and loads no external fonts or scripts.
|
computer and loads no external fonts or scripts.
|
||||||
|
|
||||||
> Unofficial. Not affiliated with or endorsed by Maono. Tested on a DGM20 with USB ID
|
> Unofficial. Not affiliated with or endorsed by Maono.
|
||||||
> `352f:0105`, firmware 2.1.2. Newer DGM20 revisions (`352f:0112`) and the DGM20G/DGM20W
|
|
||||||
> use different firmware and are not supported yet.
|
## Supported hardware
|
||||||
|
|
||||||
|
| Model | USB ID | Status |
|
||||||
|
|-------|--------|--------|
|
||||||
|
| DGM20 | `352f:0105` | Supported, tested on firmware 2.1.2 |
|
||||||
|
| DGM20 (newer revision) | `352f:0112` | Not yet |
|
||||||
|
| DGM20G, DGM20W | `352f:0113`, `352f:041a`-`041d` | Not yet |
|
||||||
|
|
||||||
|
Find your mic's ID with `lsusb | grep -i maono`. If you have one of the unsupported models and want
|
||||||
|
to help, open an issue with that output.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
```sh
|
You need Python 3.9 or newer with `venv` (Debian and Ubuntu: `sudo apt install python3-venv`).
|
||||||
pipx install git+https://git.reiners.dev/ReinersCloudConsulting/dgm20-linux.git
|
|
||||||
# or, from a checkout
|
|
||||||
pipx install .
|
|
||||||
```
|
|
||||||
|
|
||||||
Let your user reach the mic without root, then unplug and replug it:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo cp udev/70-maono-dgm20.rules /etc/udev/rules.d/
|
git clone https://git.reiners.dev/ReinersCloudConsulting/dgm20-linux.git
|
||||||
sudo udevadm control --reload && sudo udevadm trigger
|
cd dgm20-linux
|
||||||
|
./install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
The rule grants access to the logged-in desktop user (`uaccess`) and to the `wheel` group, which
|
Then unplug the mic and plug it back in once.
|
||||||
covers ssh sessions. Change the group if your distro uses a different one.
|
|
||||||
|
The installer:
|
||||||
|
|
||||||
|
1. puts the program in its own virtualenv under `~/.local/share/dgm20-linux`, with the commands
|
||||||
|
`dgm20ctl` and `dgm20-web` linked into `~/.local/bin`, and
|
||||||
|
2. asks for sudo once to add a udev rule (`/etc/udev/rules.d/70-maono-dgm20.rules`) that lets you
|
||||||
|
use the mic's control channel without root.
|
||||||
|
|
||||||
|
Run it as your normal user, not with sudo.
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
| Option | What it does |
|
||||||
|
|--------|--------------|
|
||||||
|
| `--service` | Runs the control page in the background now and every time you log in (systemd user service). |
|
||||||
|
| `--lan` | Lets other devices on your network open the page too. Opens the port in firewalld or ufw for your local subnet only. Implies `--service`. |
|
||||||
|
| `--port N` | Uses a different port (default 8720). |
|
||||||
|
| `--group NAME` | Group allowed to use the mic from ssh sessions. Default: the first of `plugdev`, `wheel`, `sudo` that you belong to. Desktop logins always have access. |
|
||||||
|
| `--no-udev` | Skips the udev rule. |
|
||||||
|
| `--dry-run` | Prints every change instead of making it. |
|
||||||
|
|
||||||
|
`--lan` has no login. Anyone on your network can change your mic settings, so only use it on a
|
||||||
|
network you trust. If you run a firewall other than firewalld or ufw, the installer tells you what
|
||||||
|
to allow.
|
||||||
|
|
||||||
|
### Uninstall
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./uninstall.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This removes everything the installer added: the service, firewall rule, udev rule and program
|
||||||
|
files. The installer keeps a record of what it changed, so only those changes are undone. Your mic
|
||||||
|
keeps its current settings.
|
||||||
|
|
||||||
## Use
|
## Use
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
dgm20-web --open # control page at http://localhost:8720
|
dgm20-web --open # open the control page (http://localhost:8720)
|
||||||
dgm20ctl # show settings
|
dgm20ctl # show current settings
|
||||||
dgm20ctl set nc on nc-level 80 enhance off
|
dgm20ctl set nc on nc-level 80
|
||||||
|
dgm20ctl set monitor off enhance on brightness 40
|
||||||
dgm20ctl watch # print changes made on the mic itself
|
dgm20ctl watch # print changes made on the mic itself
|
||||||
|
dgm20ctl info # model and firmware
|
||||||
dgm20ctl factory-reset --yes
|
dgm20ctl factory-reset --yes
|
||||||
```
|
```
|
||||||
|
|
||||||
To keep the page running in the background:
|
| Setting | Values |
|
||||||
|
|---------|--------|
|
||||||
|
| `mute` | on, off |
|
||||||
|
| `nc` | on, off: noise cancellation |
|
||||||
|
| `nc-level` | 0-100: noise cancellation strength |
|
||||||
|
| `enhance` | on, off: vocal enhancement |
|
||||||
|
| `monitor` | on, off: hear yourself in headphones plugged into the mic |
|
||||||
|
| `brightness` | 0-100: RGB ring |
|
||||||
|
|
||||||
```sh
|
Settings are stored on the mic, so they stay the same after a replug and on other computers.
|
||||||
cp contrib/dgm20-web.service ~/.config/systemd/user/
|
|
||||||
systemctl --user enable --now dgm20-web
|
|
||||||
```
|
|
||||||
|
|
||||||
`dgm20-web` only listens on localhost. `--host 0.0.0.0` makes it reachable from your network, and
|
|
||||||
anyone on that network can then change your mic settings, because there is no login.
|
|
||||||
|
|
||||||
Input gain and headphone volume are standard USB audio controls. Set them in your desktop's sound
|
Input gain and headphone volume are standard USB audio controls. Set them in your desktop's sound
|
||||||
settings, `pavucontrol` or `alsamixer`. The mic does not expose them on its control channel.
|
settings, `pavucontrol` or `alsamixer`.
|
||||||
|
|
||||||
|
### Using the page from another computer without opening a port
|
||||||
|
|
||||||
|
If the mic is plugged into a machine you reach over ssh, forward the port instead of using `--lan`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ssh -L 8720:localhost:8720 that-machine
|
||||||
|
```
|
||||||
|
|
||||||
|
Then open http://localhost:8720 on your own computer.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
**"no permission to open /dev/hidrawN"**: the udev rule isn't applied yet. Unplug and replug the
|
||||||
|
mic. Over ssh, make sure you're in the group the installer printed (`id -nG`). If you were just
|
||||||
|
added to that group, log in again.
|
||||||
|
|
||||||
|
**"DGM20 (352f:0105) not found"**: check `lsusb | grep -i maono`. A different USB ID means a
|
||||||
|
model that isn't supported yet (see above).
|
||||||
|
|
||||||
|
**The page says "Mic not found"**: plug the mic in. The page reconnects by itself.
|
||||||
|
|
||||||
|
**`dgm20-web: cannot listen on 127.0.0.1:8720`**: it's already running, for example as the
|
||||||
|
service. Open http://localhost:8720, or pick another port with `--port`.
|
||||||
|
|
||||||
|
**Commands not found after installing**: `~/.local/bin` isn't on your `PATH`. Add
|
||||||
|
`export PATH="$HOME/.local/bin:$PATH"` to your shell profile.
|
||||||
|
|
||||||
|
**Service stops when you log out**: run `sudo loginctl enable-linger $USER`.
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
The settings were found by reading Maono Link's DGM20 plugin. See [PROTOCOL.md](PROTOCOL.md) for
|
The mic has a vendor HID channel next to its audio interfaces. The settings were found by reading
|
||||||
the packet format and register map. `dgm20ctl raw` gives direct register access if you want to
|
Maono Link's DGM20 plugin and then checked against a real mic. [PROTOCOL.md](PROTOCOL.md) documents
|
||||||
explore.
|
the packet format and register map. `dgm20ctl raw get|set|dump` gives direct register access for
|
||||||
|
exploring.
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Maono DGM20 web control panel (http://localhost:8720)
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
ExecStart=%h/.local/bin/dgm20-web
|
|
||||||
Restart=on-failure
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=default.target
|
|
||||||
Executable
+181
@@ -0,0 +1,181 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Install dgm20-linux for the current user.
|
||||||
|
#
|
||||||
|
# ./install.sh commands + udev rule (localhost use)
|
||||||
|
# ./install.sh --service ...and run the web page in the background
|
||||||
|
# ./install.sh --lan ...and make it reachable from your local network
|
||||||
|
#
|
||||||
|
# Run it as yourself, not root; it asks for sudo only for the udev rule and,
|
||||||
|
# with --lan, the firewall. Undo everything with ./uninstall.sh.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
APP=dgm20-linux
|
||||||
|
SRC=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||||
|
DATA=${XDG_DATA_HOME:-$HOME/.local/share}/$APP
|
||||||
|
BIN=$HOME/.local/bin
|
||||||
|
UNIT_DIR=${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user
|
||||||
|
RULE=/etc/udev/rules.d/70-maono-dgm20.rules
|
||||||
|
STATE=$DATA/install.state
|
||||||
|
|
||||||
|
PORT=8720
|
||||||
|
SERVICE=0
|
||||||
|
LAN=0
|
||||||
|
UDEV=1
|
||||||
|
GROUP=
|
||||||
|
DRY=0
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF
|
||||||
|
Usage: ./install.sh [options]
|
||||||
|
|
||||||
|
--service start the web page now and at login (systemd user service)
|
||||||
|
--lan listen on all interfaces and open the port to your local
|
||||||
|
subnet in firewalld or ufw (implies --service). There is no
|
||||||
|
login on the page: anyone on that subnet can change settings.
|
||||||
|
--port N web page port (default $PORT)
|
||||||
|
--group NAME group allowed to use the mic over ssh (default: first of
|
||||||
|
plugdev, wheel, sudo that you belong to)
|
||||||
|
--no-udev skip the udev rule
|
||||||
|
--dry-run show system changes instead of making them
|
||||||
|
-h, --help show this help
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case $1 in
|
||||||
|
--service) SERVICE=1 ;;
|
||||||
|
--lan) LAN=1; SERVICE=1 ;;
|
||||||
|
--port) PORT=${2:?--port needs a number}; shift ;;
|
||||||
|
--group) GROUP=${2:?--group needs a name}; shift ;;
|
||||||
|
--no-udev) UDEV=0 ;;
|
||||||
|
--dry-run) DRY=1 ;;
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
*) echo "unknown option: $1" >&2; usage >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
say() { printf '\033[1m==>\033[0m %s\n' "$*"; }
|
||||||
|
warn() { printf '\033[33mwarning:\033[0m %s\n' "$*" >&2; }
|
||||||
|
die() { printf '\033[31merror:\033[0m %s\n' "$*" >&2; exit 1; }
|
||||||
|
# run a command, or print it under --dry-run
|
||||||
|
run() { if [ $DRY = 1 ]; then printf ' [dry-run] %s\n' "$*"; else "$@"; fi; }
|
||||||
|
record() { [ $DRY = 1 ] || echo "$1" >> "$STATE"; }
|
||||||
|
|
||||||
|
[ "$(id -u)" != 0 ] || die "run this as your normal user, not root (it uses sudo where needed)"
|
||||||
|
[ "$(uname -s)" = Linux ] || die "this tool is for Linux"
|
||||||
|
[[ $PORT =~ ^[0-9]+$ ]] && [ "$PORT" -ge 1 ] && [ "$PORT" -le 65535 ] || die "bad port: $PORT"
|
||||||
|
|
||||||
|
command -v python3 >/dev/null || die "python3 not found; install it with your package manager"
|
||||||
|
python3 -c 'import sys; sys.exit(sys.version_info < (3, 9))' || die "python 3.9 or newer is required"
|
||||||
|
python3 -c 'import venv, ensurepip' 2>/dev/null \
|
||||||
|
|| die "python venv support is missing (Debian/Ubuntu: sudo apt install python3-venv)"
|
||||||
|
|
||||||
|
# 1. the program, in its own virtualenv
|
||||||
|
say "Installing $APP into $DATA"
|
||||||
|
run mkdir -p "$DATA" "$BIN"
|
||||||
|
[ $DRY = 1 ] || : > "$STATE"
|
||||||
|
run python3 -m venv --clear "$DATA/venv"
|
||||||
|
run "$DATA/venv/bin/python" -m pip install --quiet --disable-pip-version-check "$SRC"
|
||||||
|
for cmd in dgm20ctl dgm20-web; do
|
||||||
|
run ln -sf "$DATA/venv/bin/$cmd" "$BIN/$cmd"
|
||||||
|
done
|
||||||
|
case ":$PATH:" in
|
||||||
|
*":$BIN:"*) ;;
|
||||||
|
*) warn "$BIN is not on your PATH; add it in your shell profile" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# 2. udev rule so the mic's control channel is usable without root
|
||||||
|
if [ $UDEV = 1 ]; then
|
||||||
|
if [ -z "$GROUP" ]; then
|
||||||
|
for g in plugdev wheel sudo; do
|
||||||
|
if id -nG | tr ' ' '\n' | grep -qx "$g"; then GROUP=$g; break; fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
if [ -n "$GROUP" ]; then
|
||||||
|
getent group "$GROUP" >/dev/null || die "group $GROUP does not exist"
|
||||||
|
line="SUBSYSTEM==\"hidraw\", ATTRS{idVendor}==\"352f\", ATTRS{idProduct}==\"0105\", MODE=\"0660\", GROUP=\"$GROUP\", TAG+=\"uaccess\""
|
||||||
|
say "Installing udev rule (desktop logins + group '$GROUP'), sudo needed"
|
||||||
|
else
|
||||||
|
line='SUBSYSTEM=="hidraw", ATTRS{idVendor}=="352f", ATTRS{idProduct}=="0105", TAG+="uaccess"'
|
||||||
|
say "Installing udev rule (desktop logins only; use --group for ssh access), sudo needed"
|
||||||
|
fi
|
||||||
|
rule="# Maono DGM20 USB microphone: control channel for dgm20-linux
|
||||||
|
$line"
|
||||||
|
if [ $DRY = 1 ]; then
|
||||||
|
printf ' [dry-run] write %s:\n%s\n' "$RULE" "$(sed 's/^/ /' <<<"$rule")"
|
||||||
|
else
|
||||||
|
printf '%s\n' "$rule" | sudo tee "$RULE" >/dev/null
|
||||||
|
fi
|
||||||
|
run sudo udevadm control --reload
|
||||||
|
run sudo udevadm trigger --subsystem-match=hidraw
|
||||||
|
record "udev $RULE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3. background service
|
||||||
|
HOST=127.0.0.1
|
||||||
|
[ $LAN = 1 ] && HOST=0.0.0.0
|
||||||
|
if [ $SERVICE = 1 ]; then
|
||||||
|
command -v systemctl >/dev/null || die "--service needs systemd"
|
||||||
|
say "Installing systemd user service on $HOST:$PORT"
|
||||||
|
unit="[Unit]
|
||||||
|
Description=Maono DGM20 control page
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=$DATA/venv/bin/dgm20-web --host $HOST --port $PORT
|
||||||
|
Restart=on-failure
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target"
|
||||||
|
run mkdir -p "$UNIT_DIR"
|
||||||
|
if [ $DRY = 1 ]; then
|
||||||
|
printf ' [dry-run] write %s/dgm20-web.service\n' "$UNIT_DIR"
|
||||||
|
else
|
||||||
|
printf '%s\n' "$unit" > "$UNIT_DIR/dgm20-web.service"
|
||||||
|
fi
|
||||||
|
run systemctl --user daemon-reload
|
||||||
|
run systemctl --user enable dgm20-web.service
|
||||||
|
run systemctl --user restart dgm20-web.service
|
||||||
|
record "service dgm20-web.service"
|
||||||
|
if [ "$(loginctl show-user "$USER" -p Linger --value 2>/dev/null)" != yes ]; then
|
||||||
|
echo " The page runs while you're logged in. To keep it running after you log out:"
|
||||||
|
echo " sudo loginctl enable-linger $USER"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4. firewall, only with --lan, only for the local subnet
|
||||||
|
if [ $LAN = 1 ]; then
|
||||||
|
dev=$(ip route get 1.1.1.1 2>/dev/null | sed -n 's/.* dev \([^ ]*\).*/\1/p')
|
||||||
|
SUBNET=$(ip -o -f inet route show dev "$dev" scope link 2>/dev/null | awk '{print $1; exit}')
|
||||||
|
[ -n "$SUBNET" ] || die "could not work out your local subnet; open tcp/$PORT yourself"
|
||||||
|
if command -v firewall-cmd >/dev/null && sudo firewall-cmd --state >/dev/null 2>&1; then
|
||||||
|
rich="rule family=ipv4 source address=$SUBNET port port=$PORT protocol=tcp accept"
|
||||||
|
say "Opening tcp/$PORT to $SUBNET in firewalld"
|
||||||
|
run sudo firewall-cmd --permanent --add-rich-rule="$rich"
|
||||||
|
run sudo firewall-cmd --reload
|
||||||
|
record "firewalld $rich"
|
||||||
|
elif command -v ufw >/dev/null && sudo ufw status 2>/dev/null | grep -q 'Status: active'; then
|
||||||
|
say "Opening tcp/$PORT to $SUBNET in ufw"
|
||||||
|
run sudo ufw allow from "$SUBNET" to any port "$PORT" proto tcp comment dgm20-web
|
||||||
|
record "ufw $SUBNET $PORT"
|
||||||
|
else
|
||||||
|
warn "no active firewalld or ufw found. If another firewall is running, allow tcp/$PORT from $SUBNET yourself."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
say "Done."
|
||||||
|
if [ $UDEV = 1 ]; then
|
||||||
|
echo " Unplug and replug the mic once so the new permissions apply."
|
||||||
|
fi
|
||||||
|
if [ $SERVICE = 1 ]; then
|
||||||
|
if [ $LAN = 1 ]; then
|
||||||
|
ip=$(ip -o -f inet addr show dev "$dev" | awk '{sub("/.*", "", $4); print $4; exit}')
|
||||||
|
echo " Control page: http://localhost:$PORT/ (from other devices: http://$ip:$PORT/)"
|
||||||
|
else
|
||||||
|
echo " Control page: http://localhost:$PORT/"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " Start the control page with: dgm20-web --open"
|
||||||
|
fi
|
||||||
|
echo " Command line: dgm20ctl --help"
|
||||||
Executable
+64
@@ -0,0 +1,64 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Remove everything install.sh set up: the service, firewall rule, udev rule,
|
||||||
|
# the commands and the virtualenv. Mic settings are left as they are.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
APP=dgm20-linux
|
||||||
|
DATA=${XDG_DATA_HOME:-$HOME/.local/share}/$APP
|
||||||
|
BIN=$HOME/.local/bin
|
||||||
|
UNIT=${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user/dgm20-web.service
|
||||||
|
STATE=$DATA/install.state
|
||||||
|
DRY=0
|
||||||
|
|
||||||
|
case ${1:-} in
|
||||||
|
--dry-run) DRY=1 ;;
|
||||||
|
-h|--help) echo "Usage: ./uninstall.sh [--dry-run]"; exit 0 ;;
|
||||||
|
"") ;;
|
||||||
|
*) echo "unknown option: $1" >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
say() { printf '\033[1m==>\033[0m %s\n' "$*"; }
|
||||||
|
run() { if [ $DRY = 1 ]; then printf ' [dry-run] %s\n' "$*"; else "$@"; fi; }
|
||||||
|
|
||||||
|
[ "$(id -u)" != 0 ] || { echo "run this as your normal user, not root" >&2; exit 1; }
|
||||||
|
|
||||||
|
if [ -f "$STATE" ]; then
|
||||||
|
while IFS= read -r entry; do
|
||||||
|
kind=${entry%% *}
|
||||||
|
arg=${entry#* }
|
||||||
|
case $kind in
|
||||||
|
service)
|
||||||
|
say "Stopping the background service"
|
||||||
|
run systemctl --user disable --now "$arg" || true
|
||||||
|
run rm -f "$UNIT"
|
||||||
|
run systemctl --user daemon-reload
|
||||||
|
;;
|
||||||
|
firewalld)
|
||||||
|
say "Removing the firewalld rule"
|
||||||
|
run sudo firewall-cmd --permanent --remove-rich-rule="$arg" || true
|
||||||
|
run sudo firewall-cmd --reload
|
||||||
|
;;
|
||||||
|
ufw)
|
||||||
|
read -r subnet port <<<"$arg"
|
||||||
|
say "Removing the ufw rule"
|
||||||
|
run sudo ufw delete allow from "$subnet" to any port "$port" proto tcp || true
|
||||||
|
;;
|
||||||
|
udev)
|
||||||
|
say "Removing the udev rule, sudo needed"
|
||||||
|
run sudo rm -f "$arg"
|
||||||
|
run sudo udevadm control --reload
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done < <(tac "$STATE")
|
||||||
|
else
|
||||||
|
echo "No install record found in $STATE; removing the program files only."
|
||||||
|
fi
|
||||||
|
|
||||||
|
say "Removing the program"
|
||||||
|
for cmd in dgm20ctl dgm20-web; do
|
||||||
|
if [ -L "$BIN/$cmd" ] && [[ $(readlink "$BIN/$cmd") == "$DATA"/* ]]; then
|
||||||
|
run rm -f "$BIN/$cmd"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
run rm -rf "$DATA"
|
||||||
|
say "Done."
|
||||||
Reference in New Issue
Block a user