为什么会发生这种情况?

为什么会发生这种情况?

事情是这样的。我正在运行 Mint 19,相对全新的安装。我听到了很多关于矮人要塞的炒作,并安装了一次;然后,需要匆忙离开,用 Control-C 将其关闭。从那时起,每次我尝试运行它时,我都会得到输出:

/tmp/dwarf-fortresss7j3cousrun/df: 6: /tmp/dwarf-fortresss7j3cousrun/df: ./libs/Dwarf_Fortress: not found
Traceback (most recent call last):
  File "/usr/games/dwarf-fortress", line 93, in <module>
    main()
  File "/usr/games/dwarf-fortress", line 90, in main
    run_df_in_unionfs_with_cleanup(user_run_dir, data_dirs, sys.argv)
  File "/usr/games/dwarf-fortress", line 60, in run_df_in_unionfs_with_cleanup
    run_df_in_unionfs(user_run_dir, data_dirs, args)
  File "/usr/games/dwarf-fortress", line 54, in run_df_in_unionfs
    run_df(tmp_dir, args)
  File "/usr/games/dwarf-fortress", line 46, in run_df
    subprocess.run(cmd).check_returncode()
  File "/usr/lib/python3.6/subprocess.py", line 369, in check_returncode self.stderr)
subprocess.CalledProcessError: Command '['/tmp/dwarf-fortresss7j3cousrun/df', '/usr/games/dwarf-fortress']'
returned non-zero exit status 127.

随后程序立即终止。我尝试删除,甚至清除并重新安装矮人堡垒,但得到了相同的结果。它运行得非常好,一次,尽管我一直盯着这个错误,但我无法理解它。

这与业务无关或其他什么,从技术上讲我什至不是玩家;但我真的很想知道为什么该程序现在失败了,以及我以什么方式破坏了它。这实在是太神秘了,不容置之不理。谢谢你的时间。

答案1

长话短说:使用以下脚本清除$XDG_DATA_HOME/$HOME中的剩余内容并卸载以前的unionfs

#!/bin/sh
set -eu

echo "Killing currently running Dwarf Fortress instances"
killall -q -9 Dwarf_Fortress || true

echo "Removing old Dwarf Fortress unionfs mounts and mount points"
find /tmp/ -maxdepth 1 -name "dwarf-fortress*" \
  -printf "  Found %f\n" \
  \( -exec fusermount -u {} \; -o -true \) \
  -exec rmdir {} \;


UNIONFSDIR="${XDG_DATA_HOME:-"${HOME:?}/.local/share/"}dwarf-fortress/run/.unionfs-fuse"

if [ -d "$UNIONFSDIR" ]; then
  echo "Removing old .unionfs-fuse directory"
  rm -r -- "$UNIONFSDIR"
fi
echo "Done. Run dwarf-fortress and praise Armok!"

为什么会发生这种情况?

dwarf-fortressUbuntu 提供的包使用 Python 包装器/usr/games/dwarf-fortress。该包装器在 中创建一个二级data层次结构,它与其他一些目录一起$XDG_DATA_HOME/.local/share/dwarf-fortress/run/.unionfs-fuse安装。unionfs(8)

这使您能够将 mods 放在$XDG_DATA_HOME/.local/share/dwarf-fortress目录中,因此您不需要更改 的内容/usr/share/games/dwarf-fortress,这太棒了!但是,unionfs必须小心处理并正确清理。当你C-c习惯退出游戏时,Python 脚本无法执行此操作。

因此,unionfs大概仍然安装,但状态不佳。

我如何解决它?

所以首先,确保游戏完全关闭:

killall -s KILL Dwarf_Fortress

然后确保没有剩余的unionfsDF 安装:

mount | grep -a -e dwarf -e unionfs
unionfs on /tmp/dwarf-fortresswvlaptrarun type fuse.unionfs (rw,nosuid,nodev,relatime,user_id=1000,group_id=1000)
unionfs on /tmp/dwarf-fortress4ylv2t19run type fuse.unionfs (rw,nosuid,nodev,relatime,user_id=1000,group_id=1000)

如您所见,我的系统上目前有两个。由于两者都已损坏,让我们用以下方法摆脱它们fusermount -u

fusermount -u /tmp/dwarf-fortresswvlaptrarun 
fusermount -u /tmp/dwarf-fortress4ylv2t19run 

最后但也是最重要的一点是,删除.unionfs-fusein $XDG_DATA_HOME/dwarf-fortress/run/。我没有XDG_DATA_HOME设置,所以我必须使用$HOME.检查env一下,以免不小心删除了错误的目录!

rm -r $HOME/.local/share/dwarf-fortress/run/.unionfs-fuse

就是这样。请注意,df_linux版本来自湾12游戏不会遇到这个问题,因为它既不使用 Python 包装器也不使用 Unionfs。

话虽如此,问题已修复2019 年发货至bullseye.不幸的是,它是不是已修复0.44.12-1,因此buster可能仍会受到影响。

您是如何想出这个解决方案的?

首先,我查看了file $(which dwarf-fortress),它告诉我这是一个 Python 脚本:

$ file $(which dwarf-fortress)
/usr/games/dwarf-fortress: Python script, ASCII text executable

然后我用任何编辑器检查了脚本并发现

def get_user_run_dir():
    old_run_dir = xdg.BaseDirectory.save_data_path('dwarf-fortress')
    new_run_dir = os.path.join(old_run_dir, 'run')
    
    ...

def run_df_in_unionfs(user_run_dir, data_dirs, args):
    mnt_dirs = user_run_dir + "=rw:" + ':'.join(data_dirs)
    with tempfile.TemporaryDirectory(suffix='run', prefix='dwarf-fortress') as tmp_dir:
        cmd = ['unionfs', '-o', 'cow,relaxed_permissions', mnt_dirs, tmp_dir]
        subprocess.run(cmd).check_returncode()
        try:
            run_df(tmp_dir, args)
        finally:
            subprocess.run(['fusermount', '-u', tmp_dir]).check_returncode()

这表明至少可以在 中找到一些东西xdg.BaseDirectory,即$HOME/.local/share(除非另有设置)。同时,fusermount -u显示退出矮人要塞后有一个未挂载的挂载,并mount | grep unionfs在 中确认了活动挂载/tmp。我删除了整个$XDG_DATA_HOME/dwarf-fortress目录,它又工作了。通过strace -ff -e trace=execve dwarf-fortress,我能够确认unionfs安装并找到.unionfs-fuse目录。

相关内容