如何在Ubuntu 16.10上启动时执行命令(替代rc.local)?

我正在为我的运行Ubuntu 16.10的Linode服务器设置配额,但是我遇到了以下错误:
无法对挂载设备/dev/root进行stat()操作:没有该文件或目录
为了解决这个问题,我查阅了此帖子,其中提到需要添加以下内容来修复。
ln -s /dev/xvda /dev/root
/etc/init.d/quota restart

/etc/rc.local。但是Ubuntu 16.10不再使用rc.local,而是使用systemd。有没有rc.local的替代方案?我该如何在启动时运行上述命令?
另外,我使用systemctl enable rc-local.service启用了服务,但对我来说没有起作用。任何线索将不胜感激。

你以root身份运行它了吗,并且你重启了系统吗? - George Udosen
@George 是的,我都做了。 - Saurabh Sharma
试试这个:链接 - George Udosen
@George 这个方法也不起作用。 - Saurabh Sharma
刚刚看到这个技巧,看看是否可行... - George Udosen
刚刚测试了我的答案并进行了更新,请试一试并告诉我进展如何... - George Udosen
配额包不应该寻找/dev/root。修复潜在的错误,然后就不需要创建这个符号链接了。它应该被配置为在/etc/fstab中列出的所有文件系统(最好是通过UUID)打开配额选项。 - psusi
@psusi 我应该使用什么替代/dev/root?我正在按照这个教程进行设置:https://www.howtoforge.com/tutorial/ubuntu-perfect-server-with-apache-php-myqsl-pureftpd-bind-postfix-doveot-and-ispconfig/2/#g0.0.16 - Saurabh Sharma
@psusi 这个问题似乎特别与linode有关。您可以在https://licensecart.com/plugin/support_manager/knowledgebase/view/270/quotas-are-off-on-linode-xen-vps/5/上找到更多信息。 - Saurabh Sharma
你的/etc/fstab文件中是否提到了/dev/root?不应该这样。 - psusi
3个回答

简介

我认为你不应该按照乔治提供的链接创建一个新的服务。 rc-local.service已经存在于systemd中,服务文件建议如果rc.local存在且可执行,它会自动被拉入multi-user.target。 所以没有必要重新创建或强制执行另一种方式已经完成的事情,即systemd-rc-local-generator

一种解决方案

一个快速的解决方案(我不知道是否是规范的方法):

在终端中执行以下操作:

printf '%s\n' '#!/bin/bash' 'exit 0' | sudo tee -a /etc/rc.local
sudo chmod +x /etc/rc.local
sudo reboot

之后系统启动时会调用rc.local。你可以插入自己喜欢的内容。

背景

如果你在终端中执行以下命令:

sudo systemctl edit --full rc-local

您可以看到,头部注释包含以下内容的行:
# This unit gets pulled automatically into multi-user.target by
# systemd-rc-local-generator if /etc/rc.local is executable.

这意味着,在这个系统中,如果有一个名为/etc/rc.local的可执行文件,它将自动被拉入multi-user.target。所以你只需要创建相应的文件(sudo touch...)并使其可执行(sudo chmod +x ...)。

4不过,不要使用 #!/bin/bash,而是使用 #!/bin/sh,除非你的脚本确实需要 bash。出于性能考虑,所有其他系统脚本都使用 dash 而不是 bash。 - spikyjt
不需要重新创建或强制执行由systemd-rc-local-generator以另一种方式完成的事情。rc-local不能在其他单元之后进行排序,对吗? - x-yuri
exit 0 必须被列为 /etc/rc.local 中的最后一条命令吗? - W.M.

我看到有人建议使用systemd来解决这个问题here
  1. 创建一个服务:

    sudo vi /etc/systemd/system/rc-local.service
    
  2. 在此处添加您的代码:

    [Unit]
    Description=/etc/rc.local 兼容性
    ConditionPathExists=/etc/rc.local
    
    [Service]
    Type=forking
    ExecStart=/etc/rc.local start
    TimeoutSec=0
    StandardOutput=tty
    RemainAfterExit=yes
    SysVStartPriority=99
    
    [Install]
    WantedBy=multi-user.target
    
  3. 创建并确保 /etc/rc.local 可执行,并在其中添加以下代码:

    sudo chmod +x /etc/rc.local

    #!/bin/sh -e
    #
    # rc.local
    #
    # 此脚本在每个多用户运行级别结束时执行。
    # 确保脚本在成功时“exit 0”,在错误时为其他任何值。
    #
    # 若要启用或禁用此脚本,只需更改执行权限位。
    #
    # 默认情况下,此脚本不执行任何操作。
    
    exit 0
    
  4. 启用该服务:

    sudo systemctl enable rc-local
    
  5. 启动服务并检查状态:

    sudo systemctl start rc-local.service
    sudo systemctl status rc-local.service
    
  6. 如果一切顺利,您可以将您的 代码 添加到 /etc/rc.local 文件中,然后重新启动它。

注意:在Lubuntu 16.10上进行了测试。

来源:

https://www.linuxbabe.com/linux-server/how-to-enable-etcrc-local-with-systemd


我完成了所有的步骤。我在rc.local文件中添加了touch "hello"exit 0之前。服务似乎是激活的,但它没有在/etc/目录下创建任何文件。运行在Ubuntu 16.04 Arabian 5.31上。 - DanielZanchi
1正如@Jan的回答所指出的那样,没有必要创建一个全新的服务,因为systemd已经支持rc.local。 - TommyPeanuts
谢谢你,这真的有效。 - GPrathap

为了补充Jan的回答,与通常的rc.local文件不同,rc-local service在所有服务启动完成后执行,而是在网络上线后执行。
在某些情况下,您可能希望稍后从rc.local运行命令。 例如,我希望它在lxd启动后执行。
在这种情况下,您可以通过创建一个附加的配置文件来编辑rc-local service的启动依赖关系: /etc/systemd/system/rc-local.service.d/override.conf 其中包含以下内容:
[Unit]
After=network.target lxd.service

在这里你可以添加所需的单元名称(就像我添加了lxd.service
之后不要忘记执行systemctl daemon-reload

欢迎来到Ask Ubuntu!如果您想改进另一个答案,请建议对其进行编辑。如果您想提出部分替代方案,请重复或引用相同的部分(以防原始答案发生更改),并突出显示差异。无论如何,请不要创建新的不完整答案!谢谢。 - David Foerster