Cannot use vi to edit configurations in LXD 4.19

With the upgrade the to LXD 4.19 the default editor used by LXD has changed to nano. When I change the EDITOR setting to use vi

export EDITOR=vi

I get an empty empty file (rather than a file with the current configuration) when editing any configuration, e.g.

lxc config edit
lxc config edit instancename

vi reports "/proc/self/fd/9/lxd_editor_271157093.yaml" [New DIRECTORY] (were the last number appears to be random) when the file opens and if I try to save the file I get "/proc/self/fd/9/lxd_editor_271157093.yaml" E212: Can't open file for writing.

I could not find anything in the release notes about changes to the editor behaviour. Is there a way to use vi to edit configurations in LXD 4.19?

Just to clarify, when the editor opens, you don’t see anything in the editor (no config content)?

While the editor is open, can you do ps fauxww, locate the PID of the vi process and then do ls -lh /proc/PID/fd/? That should show us what’s open and maybe help understand why fd number 9 isn’t the config dir.

Correct, nothing is in the editor when using vi.

root     2482824  0.0  0.0  23928  8216 pts/0    S+   15:14   0:00  |                       \_ vi /proc/self/fd/9/lxd_editor_832650605.yaml
# ls -lh /proc/2482824/fd/
total 0
lrwx------ 1 root root 64 Oct 12 15:16 0 -> /dev/pts/0
lrwx------ 1 root root 64 Oct 12 15:16 1 -> /dev/pts/0
lrwx------ 1 root root 64 Oct 12 15:16 2 -> /dev/pts/0
lrwx------ 1 root root 64 Oct 12 15:16 3 -> /var/lib/snapd/hostfs/var/tmp/lxd_editor_832650605.yaml.swp
lr-x------ 1 root root 64 Oct 12 15:16 9 -> /tmp

The lxc config edit command was used to opened vi and the status bar has the message "/proc/self/fd/9/lxd_editor_832650605.yaml" [New DIRECTORY]

That’s very odd, it shows what I’d expect…

Can you try ls -lh /proc/PID/fd/9/ to see if there’s something weird going on with that file descriptor maybe?

# ls -lh /proc/2514893/fd/9
lr-x------ 1 root root 64 Oct 12 15:41 /proc/2514893/fd/9 -> /tmp

PID changed because of a new session.

I did notice that when using nano the editor command is

nano /tmp/lxd_editor_078441063.yaml

but with vi it is

vi /proc/self/fd/9/lxd_editor_774446867.yaml

I would naively have assumed they would both open /tmp/lxd_editor_*.yaml

The trailing / in ls -lh /proc/PID/fd/9/ mattered, I’m trying to see what’s through the link :slight_smile:

You’re getting a different path for nano than for vi because nano is built into the snap whereas vi is called from outside of it and so needs a few tricks on our part to make the file accessible.

With the trailing /

ls -lh /proc/2514893/fd/9/
total 4.0K
-rw------- 1 root root 71 Oct 12 15:41 lxd_editor_774446867.yaml

cat /proc/2514893/fd/9/lxd_editor_774446867.yaml also displays the correct expected content.

Well, that’s pretty weird… If the path that’s passed is correct and the file is accessible, then why isn’t vi editing it properly…

When I run :!ls /proc/self in vi (started via lxc config edit) I get the error

ls: cannot access '/proc/self': No such file or directory

shell returned 2

:!ls /proc returns empty (no error). It’s like vi has an empty /proc. This is only true for vi when started from lxd edit command. If I just start vi from the command line I can see the contents of /proc and /proc/self without issue. The fact that vi does not see any contents in /proc explains the New Directory status message and inability to save, but it is obviously not the expected behaviour.

It looks like /proc is not mounted in the context that vi is running.

:!ps fauxww

Error, do this: mount -t proc proc /proc

shell returned 47

:!mount -t proc proc /proc

mount: /proc: permission denied.

shell returned 32

Ah, well, that’d explain it, though that’s pretty unexpected behavior…

So I take it ls -lh /var/snap/lxd/common/mntns/var/lib/snapd/hostfs/proc/ shows you an empty dir?

Can you show nsenter --mount=/run/snapd/ns/lxd.mnt cat /proc/self/mountinfo too?

Btw, there’s a bit of a workaround you can do to get vi going for now, run EDITOR=invalid lxc config edit as the fallback for an invalid/missing editor is our built-in vim.tiny

Running the commands from within the vi process started with EDITOR=vi lxc config edit produces errors

:!ls -lh /var/snap/lxd/common/mntns/var/lib/snapd/hostfs/proc/

ls: cannot access '/var/snap/lxd/common/mntns/var/lib/snapd/hostfs/proc/': No such file or directory

shell returned 2

And :!ls -lh /var/snap/lxd/common/

-rw-r--r--  1 root root 284 Oct  4 22:04 config
drwxr-xr-x  2 root root   2 Sep 23 11:28 global-conf
drwxr-xr-x  2 root root   3 Sep 23 11:28 lxc
-rw-------  1 root root   8 Sep 23 11:28 lxcfs.pid
drwx--x--x 17 root root  22 Oct  4 22:04 lxd
-rw-r--r--  1 root root   7 Oct  4 22:04 lxd.pid
lrwxrwxrwx  1 root root  17 Oct  4 22:04 mntns -> /proc/518954/root
drwx------  2 root root  80 Sep 23 11:28 ns
drwx--x--x  2 root root   2 Sep 23 11:28 shmounts
-rw-r--r--  1 root root   0 Oct  4 22:04 state
drwxr-xr-x  3 root root   3 Sep 23 11:28 var

shows the reason is that the symbolic link into /proc for mntns fails since /proc is empty.

For :!nsenter --mount=/run/snapd/ns/lxd.mnt cat /proc/self/mountinfo

nsenter: reassociate to namespace 'ns/mnt' failed: Invalid argument

shell returned 1

From a separate shell while vi is open:

ls -lh /var/snap/lxd/common/mntns/var/lib/snapd/hostfs/proc/ is not empty, it looks the same as ls -lh /proc/

# nsenter --mount=/run/snapd/ns/lxd.mnt cat /proc/self/mountinfo
1115 1290 0:26 / /var/lib/snapd/hostfs rw,relatime master:1 - zfs rpool/ROOT/ubuntu_gzest3 rw,xattr,posixacl
1131 1115 0:24 / /var/lib/snapd/hostfs/run rw,nosuid,nodev,noexec,relatime master:5 - tmpfs tmpfs rw,size=3254272k,mode=755
1132 1131 0:28 / /var/lib/snapd/hostfs/run/lock rw,nosuid,nodev,noexec,relatime master:6 - tmpfs tmpfs rw,size=5120k
1136 1131 0:24 /snapd/ns /var/lib/snapd/hostfs/run/snapd/ns rw,nosuid,nodev,noexec,relatime - tmpfs tmpfs rw,size=3254272k,mode=755
1166 1115 0:50 / /var/lib/snapd/hostfs/root rw,relatime master:35 - zfs rpool/USERDATA/root_gzest3 rw,xattr,posixacl
1167 1115 0:51 / /var/lib/snapd/hostfs/srv rw,relatime master:36 - zfs rpool/ROOT/ubuntu_gzest3/srv rw,xattr,posixacl
1168 1115 0:52 / /var/lib/snapd/hostfs/var/games rw,relatime master:37 - zfs rpool/ROOT/ubuntu_gzest3/var/games rw,xattr,posixacl
1169 1115 0:53 / /var/lib/snapd/hostfs/usr/local rw,relatime master:38 - zfs rpool/ROOT/ubuntu_gzest3/usr/local rw,xattr,posixacl
1170 1115 0:54 / /var/lib/snapd/hostfs/var/lib rw,relatime master:39 - zfs rpool/ROOT/ubuntu_gzest3/var/lib rw,xattr,posixacl
1171 1170 0:60 / /var/lib/snapd/hostfs/var/lib/apt rw,relatime master:91 - zfs rpool/ROOT/ubuntu_gzest3/var/lib/apt rw,xattr,posixacl
1172 1170 0:61 / /var/lib/snapd/hostfs/var/lib/AccountsService rw,relatime master:93 - zfs rpool/ROOT/ubuntu_gzest3/var/lib/AccountsService rw,xattr,posixacl
1173 1170 0:62 / /var/lib/snapd/hostfs/var/lib/dpkg rw,relatime master:95 - zfs rpool/ROOT/ubuntu_gzest3/var/lib/dpkg rw,xattr,posixacl
1174 1170 0:63 / /var/lib/snapd/hostfs/var/lib/NetworkManager rw,relatime master:97 - zfs rpool/ROOT/ubuntu_gzest3/var/lib/NetworkManager rw,xattr,posixacl
1175 1115 0:55 / /var/lib/snapd/hostfs/var/log rw,relatime master:40 - zfs rpool/ROOT/ubuntu_gzest3/var/log rw,xattr,posixacl
1176 1115 0:56 / /var/lib/snapd/hostfs/var/mail rw,relatime master:41 - zfs rpool/ROOT/ubuntu_gzest3/var/mail rw,xattr,posixacl
1177 1115 0:57 / /var/lib/snapd/hostfs/var/snap rw,relatime master:42 - zfs rpool/ROOT/ubuntu_gzest3/var/snap rw,xattr,posixacl
1178 1177 0:78 / /var/lib/snapd/hostfs/var/snap/lxd/common/ns rw,relatime - tmpfs tmpfs rw,size=1024k,mode=700
1179 1115 0:58 / /var/lib/snapd/hostfs/var/spool rw,relatime master:87 - zfs rpool/ROOT/ubuntu_gzest3/var/spool rw,xattr,posixacl
1180 1115 0:59 / /var/lib/snapd/hostfs/var/www rw,relatime master:89 - zfs rpool/ROOT/ubuntu_gzest3/var/www rw,xattr,posixacl
1181 1115 0:64 / /var/lib/snapd/hostfs/tmp rw,nosuid,nodev master:151 - tmpfs tmpfs rw
1182 1115 0:65 / /var/lib/snapd/hostfs/boot rw,nodev,relatime master:154 - zfs bpool/BOOT/ubuntu_gzest3 rw,xattr,posixacl
1183 1182 8:1 / /var/lib/snapd/hostfs/boot/efi rw,relatime master:157 - vfat /dev/sda1 rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro
1184 1182 0:66 / /var/lib/snapd/hostfs/boot/grub rw,nodev,relatime master:160 - zfs bpool/grub rw,xattr,posixacl
1186 1115 0:72 / /var/lib/snapd/hostfs/data/replicas rw,relatime master:452 - zfs dpool/replicas rw,xattr,posixacl
1187 1115 7:1 / /var/lib/snapd/hostfs/snap/core20/1081 ro,nodev,relatime master:494 - squashfs /dev/loop1 ro
1188 1115 7:2 / /var/lib/snapd/hostfs/snap/lxd/21497 ro,nodev,relatime master:501 - squashfs /dev/loop2 ro
1189 1115 7:3 / /var/lib/snapd/hostfs/snap/snapd/13170 ro,nodev,relatime master:438 - squashfs /dev/loop3 ro
1190 1115 7:4 / /var/lib/snapd/hostfs/snap/lxd/21624 ro,nodev,relatime master:433 - squashfs /dev/loop4 ro
1191 1115 7:5 / /var/lib/snapd/hostfs/snap/core20/1169 ro,nodev,relatime master:492 - squashfs /dev/loop5 ro
1192 1115 7:6 / /var/lib/snapd/hostfs/snap/snapd/13270 ro,nodev,relatime master:514 - squashfs /dev/loop6 ro
1210 928 7:5 / / ro,nodev,relatime master:492 - squashfs /dev/loop5 ro
1211 1210 0:6 / /dev rw,nosuid,noexec,relatime master:2 - devtmpfs udev rw,size=16193088k,nr_inodes=4048272,mode=755
1212 1211 0:23 / /dev/pts rw,nosuid,noexec,relatime master:3 - devpts devpts rw,gid=5,mode=620,ptmxmode=000
1213 1211 0:27 / /dev/shm rw,nosuid,nodev master:4 - tmpfs tmpfs rw
1214 1211 0:47 / /dev/hugepages rw,relatime master:28 - hugetlbfs hugetlbfs rw,pagesize=2M
1215 1211 0:20 / /dev/mqueue rw,nosuid,nodev,noexec,relatime master:29 - mqueue mqueue rw
1216 1210 0:26 /etc /etc rw,relatime master:1 - zfs rpool/ROOT/ubuntu_gzest3 rw,xattr,posixacl
1217 1210 0:26 /home /home rw,relatime master:1 - zfs rpool/ROOT/ubuntu_gzest3 rw,xattr,posixacl
1219 1210 0:50 / /root rw,relatime master:35 - zfs rpool/USERDATA/root_gzest3 rw,xattr,posixacl
1220 1210 0:5 / /proc rw,nosuid,nodev,noexec,relatime master:15 - proc proc rw
1221 1220 0:46 / /proc/sys/fs/binfmt_misc rw,relatime master:27 - autofs systemd-1 rw,fd=28,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=23013
1222 1221 0:73 / /proc/sys/fs/binfmt_misc rw,nosuid,nodev,noexec,relatime master:469 - binfmt_misc binfmt_misc rw
1223 1210 0:22 / /sys rw,nosuid,nodev,noexec,relatime master:7 - sysfs sysfs rw
1224 1223 0:7 / /sys/kernel/security rw,nosuid,nodev,noexec,relatime master:8 - securityfs securityfs rw
1225 1223 0:29 / /sys/fs/cgroup ro,nosuid,nodev,noexec master:9 - tmpfs tmpfs ro,mode=755
1226 1225 0:30 / /sys/fs/cgroup/unified rw,nosuid,nodev,noexec,relatime master:10 - cgroup2 cgroup2 rw
1227 1225 0:31 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime master:11 - cgroup cgroup rw,xattr,name=systemd
1228 1225 0:35 / /sys/fs/cgroup/rdma rw,nosuid,nodev,noexec,relatime master:16 - cgroup cgroup rw,rdma
1229 1225 0:36 / /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime master:17 - cgroup cgroup rw,net_cls,net_prio
1230 1225 0:37 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime master:18 - cgroup cgroup rw,cpuset,clone_children
1231 1225 0:38 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime master:19 - cgroup cgroup rw,memory
1232 1225 0:39 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime master:20 - cgroup cgroup rw,cpu,cpuacct
1233 1225 0:40 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime master:21 - cgroup cgroup rw,blkio
1234 1225 0:41 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime master:22 - cgroup cgroup rw,devices
1235 1225 0:42 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime master:23 - cgroup cgroup rw,hugetlb
1236 1225 0:43 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime master:24 - cgroup cgroup rw,pids
1237 1225 0:44 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime master:25 - cgroup cgroup rw,freezer
1238 1225 0:45 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime master:26 - cgroup cgroup rw,perf_event
1239 1223 0:32 / /sys/fs/pstore rw,nosuid,nodev,noexec,relatime master:12 - pstore pstore rw
1240 1223 0:33 / /sys/firmware/efi/efivars rw,nosuid,nodev,noexec,relatime master:13 - efivarfs efivarfs rw
1241 1223 0:34 / /sys/fs/bpf rw,nosuid,nodev,noexec,relatime master:14 - bpf none rw,mode=700
1242 1223 0:8 / /sys/kernel/debug rw,nosuid,nodev,noexec,relatime master:30 - debugfs debugfs rw
1260 1223 0:12 / /sys/kernel/tracing rw,nosuid,nodev,noexec,relatime master:31 - tracefs tracefs rw
1261 1223 0:48 / /sys/fs/fuse/connections rw,nosuid,nodev,noexec,relatime master:32 - fusectl fusectl rw
1262 1223 0:21 / /sys/kernel/config rw,nosuid,nodev,noexec,relatime master:33 - configfs configfs rw
1263 1210 0:64 / /tmp rw,nosuid,nodev master:151 - tmpfs tmpfs rw
1264 1210 0:57 / /var/snap rw,relatime master:42 - zfs rpool/ROOT/ubuntu_gzest3/var/snap rw,xattr,posixacl
1265 1264 0:78 / /var/snap/lxd/common/ns rw,relatime - tmpfs tmpfs rw,size=1024k,mode=700
1266 1210 0:54 /snapd /var/lib/snapd rw,relatime master:39 - zfs rpool/ROOT/ubuntu_gzest3/var/lib rw,xattr,posixacl
1267 1210 0:26 /var/tmp /var/tmp rw,relatime master:1 - zfs rpool/ROOT/ubuntu_gzest3 rw,xattr,posixacl
1268 1210 0:24 / /run rw,nosuid,nodev,noexec,relatime master:5 - tmpfs tmpfs rw,size=3254272k,mode=755
1269 1268 0:28 / /run/lock rw,nosuid,nodev,noexec,relatime master:6 - tmpfs tmpfs rw,size=5120k
1270 1268 0:24 /snapd/ns /run/snapd/ns rw,nosuid,nodev,noexec,relatime - tmpfs tmpfs rw,size=3254272k,mode=755
1272 1210 0:26 /usr/lib/modules /usr/lib/modules rw,relatime master:1 - zfs rpool/ROOT/ubuntu_gzest3 rw,xattr,posixacl
1273 1210 0:26 /usr/lib/firmware /usr/lib/firmware rw,relatime master:1 - zfs rpool/ROOT/ubuntu_gzest3 rw,xattr,posixacl
1274 1210 0:26 /usr/src /usr/src rw,relatime master:1 - zfs rpool/ROOT/ubuntu_gzest3 rw,xattr,posixacl
1275 1210 0:55 / /var/log rw,relatime master:40 - zfs rpool/ROOT/ubuntu_gzest3/var/log rw,xattr,posixacl
1276 1210 0:26 /media /media rw,relatime shared:1 - zfs rpool/ROOT/ubuntu_gzest3 rw,xattr,posixacl
1277 1268 0:24 /netns /run/netns rw,nosuid,nodev,noexec,relatime shared:5 - tmpfs tmpfs rw,size=3254272k,mode=755
1278 1210 0:26 /mnt /mnt rw,relatime master:1 - zfs rpool/ROOT/ubuntu_gzest3 rw,xattr,posixacl
1279 1216 7:5 /etc/nsswitch.conf /etc/nsswitch.conf ro,nodev,relatime master:492 - squashfs /dev/loop5 ro
1280 1216 7:5 /etc/apparmor /etc/apparmor ro,nodev,relatime master:492 - squashfs /dev/loop5 ro
1281 1216 7:5 /etc/apparmor.d /etc/apparmor.d ro,nodev,relatime master:492 - squashfs /dev/loop5 ro
1282 1210 7:6 /usr/lib/snapd /usr/lib/snapd ro,nodev,relatime master:514 - squashfs /dev/loop6 ro
1283 1210 0:26 /snap /snap rw,relatime master:1 - zfs rpool/ROOT/ubuntu_gzest3 rw,xattr,posixacl
1284 1283 7:1 / /snap/core20/1081 ro,nodev,relatime master:494 - squashfs /dev/loop1 ro
1285 1283 7:2 / /snap/lxd/21497 ro,nodev,relatime master:501 - squashfs /dev/loop2 ro
1286 1283 7:3 / /snap/snapd/13170 ro,nodev,relatime master:438 - squashfs /dev/loop3 ro
1287 1283 7:4 / /snap/lxd/21624 ro,nodev,relatime master:433 - squashfs /dev/loop4 ro
1288 1283 7:5 / /snap/core20/1169 ro,nodev,relatime master:492 - squashfs /dev/loop5 ro
1289 1283 7:6 / /snap/snapd/13270 ro,nodev,relatime master:514 - squashfs /dev/loop6 ro
1290 1266 0:54 /snapd/hostfs /var/lib/snapd/hostfs rw,relatime - zfs rpool/ROOT/ubuntu_gzest3/var/lib rw,xattr,posixacl
1116 1263 0:64 /snap.lxd/tmp /tmp rw,nosuid,nodev - tmpfs tmpfs rw
1117 1212 0:86 / /dev/pts rw,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666
1124 1211 0:86 /ptmx /dev/ptmx rw,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666
883 1268 0:82 / /run/user/1000 rw,nosuid,nodev,relatime master:861 - tmpfs tmpfs rw,size=3254268k,mode=700,uid=1000,gid=1000
882 1131 0:82 / /var/lib/snapd/hostfs/run/user/1000 rw,nosuid,nodev,relatime master:861 - tmpfs tmpfs rw,size=3254268k,mode=700,uid=1000,gid=1000

(Mounts with usernames have been removed from the list.)

I got to poke around an affected system and have an idea of what’s going on and how to artificially reproduce the condition where this happens, I just need to find the best way around the problem.

I’ve pushed a tentative fix to our candidate and edge channels.

I’ve a related issue with $EDITOR.

In my case I get this:

$ lxc config edit
VIM - Vi IMproved 8.1 (2018 May 18, compiled Sep 20 2021 11:42:42)
Argument missing after: "-c"
More info with: "vim -h"
Error: exit status 1

with EDITOR=emacsclient -c

Running the $SNAP/bin/editor wrapper script with -x I see

+ EDIT_CMD=emacsclient
+ EDIT_PATH=-c
+ '[' -z -c ']'
+ '[' -n emacsclient ']'
+ exec
++ echo -c
++ sed s#/tmp/#/proc/self/fd/9/#g
+ EDIT_PATH_HOST=-c
+ find_and_spawn emacsclient -c
+ for path in / /usr/ /usr/local/
+ '[' -e /var/lib/snapd/hostfs//bin/emacsclient ']'
+ '[' -L /var/lib/snapd/hostfs//bin/emacsclient ']'
+ for path in / /usr/ /usr/local/
+ '[' -e /var/lib/snapd/hostfs//usr/bin/emacsclient ']'
+ '[' -L /var/lib/snapd/hostfs//usr/bin/emacsclient ']'
+ for path in / /usr/ /usr/local/
+ '[' -e /var/lib/snapd/hostfs//usr/local/bin/emacsclient ']'
+ '[' -L /var/lib/snapd/hostfs//usr/local/bin/emacsclient ']'
+ '[' -z emacsclient ']'
+ '[' emacsclient '!=' nano ']'
+ '[' -e /home/ack/snap/lxd/common/.vimrc ']'
+ export 'VIMINIT=source /snap/lxd/21624/etc/vimrc'
+ VIMINIT='source /snap/lxd/21624/etc/vimrc'
+ EDIT_CMD=vim.tiny
+ exec vim.tiny -c
VIM - Vi IMproved 8.1 (2018 May 18, compiled Sep 20 2021 11:42:42)
Argument missing after: "-c"
More info with: "vim -h"

so the issue seems to be that the script assumes the second argument to be a path name.

what’s odd too is that it couldn’t actually find emacsclient in the first place

Pushed a fix to use the fallback editor if we find EDITOR containing arguments.
Ideally I’d have liked to support arguments but it’s really really tricky to do in pure shell…

This is probably because emacs itself comes from a snap, and the wrapper is looking to specific dirs. Maybe /snap/bin can be added there too?

Ah yeah, that’d explain it. I wonder what would actually happen, snaps calling snaps has been problematic in the past…