当前位置: 首页>>技术教程>>正文


如果我不小心在系统目录(/,/etc,…)上运行命令“chmod -R”怎么办?

, , ,

问题描述

我意外地跑了

sudo chmod 755 -R /

代替

sudo chmod 755 -R ./

几秒钟后我停了下来,但现在出现了一些问题

sudo: must be setuid root

如何恢复权限?

最佳解决方案

简而言之:您不能重新安装系统。

我的意思是,Posix权限被大量使用和依赖;文件系统中有很多地方错误的权限会破坏操作系统(SUID标志),甚至更糟糕的是,它显示工作正常时暴露security-wise(/etc/ssh/ssh_host_rsa_key)。

因此,这样的恢复很难做得很好。想念一件事 – 你搞砸了。你已经搞砸了你的sudo chmod命令(如果这是你的朋友而不是你,她也可以学习一些Linux课程) – 这是一个非常简单的命令。适当的恢复需要更多的命令和更多的警惕。即使你使用一些人的脚本。

所以相信我,只需重新安装。这是一个安全的赌注,保证让你摆脱困境。


最后,这里有一些相关提示。

首先:如果下次在单独的分区上设置/home,重新安装将不那么痛苦。实际上,他们将是一件轻而易举的事。

第二:考虑在像VirtualBox这样的virtual machine中做疯狂的Linux科学,然后做你的快照。

第三:chmod -R .有效。没有必要附加斜线。你可以避免在主要地跳过点的灾难性风险;仅仅是chmod: missing operand after ‘755’ VS一个破败的系统。

次佳解决方案

我写了几年并且已经使用了几个Ruby脚本来获得rsync权限和所有权。脚本get-filesystem-acl通过递归遍历所有文件来收集所有信息,并将其全部放入文件.acl中。脚本.acl-restore将读取.acl并应用所有chownchmod

您可以在类似的Ubuntu安装上运行get-filesystem-acl,然后将.acl文件复制到chmod-damaged框,将.acl.acl-restore放入/,然后运行.acl-restore

您将需要拥有root,以便像Marco Ceppi建议的那样修复您的sudo

我可以为我的Ubuntu生成并提供.acl文件。

get-filesystem-acl

#!/usr/bin/ruby

RM   = "/bin/rm"
SORT = "/usr/bin/sort"
TMP  = "/tmp/get_acl_#{Time.now.to_i}_#{rand * 899 + 100}"

require 'find'

IGNORE = [".git"]

def numeric2human(m)
  return sprintf("%c%c%c%c%c%c%c%c%c",
            (m & 0400 == 0 ? ?- : ?r),
            (m & 0200 == 0 ? ?- : ?w),
            (m & 0100 == 0 ? (m & 04000 == 0 ? ?- : ?S) :
                             (m & 04000 == 0 ? ?x : ?s)),
            (m & 0040 == 0 ? ?- : ?r),
            (m & 0020 == 0 ? ?- : ?w),
            (m & 0010 == 0 ? (m & 02000 == 0 ? ?- : ?S) :
                             (m & 02000 == 0 ? ?x : ?s)),
            (m & 0004 == 0 ? ?- : ?r),
            (m & 0002 == 0 ? ?- : ?w),
            (m & 0001 == 0 ? (m & 01000 == 0 ? ?- : ?T) :
                             (m & 01000 == 0 ? ?x : ?t)))
end


File.open(TMP, "w") do |acl_file|

  # TODO: Instead of the current dir, find the .git dir, which could be
  #       the same or outside of the current dir
  Find.find(".") do |path|

    next if IGNORE.collect {|ig| !!(path[2..-1] =~ /\A#{ig}/)}.include? true
    next if File.symlink?(path)

    stat = File.lstat(path)
    group_id = stat.gid
    rules    = "#{type}#{numeric2human(stat.mode)}" 

    acl_file.puts "#{path} #{rules} #{owner_id} #{group_id}"
  end
end

`#{SORT} #{TMP} > .acl`
`#{RM}   #{TMP}`

.acl-restore

#!/usr/bin/ruby

# This script will only work with .acl_ids

# Restore from...
FROM  = ".acl"

MKDIR = "/bin/mkdir"
CHMOD = "/bin/chmod"
CHOWN = "/bin/chown"
known_content_missing = false


def numeric2human(m)
  return sprintf("%c%c%c%c%c%c%c%c%c",
            (m & 0400 == 0 ? ?- : ?r),
            (m & 0200 == 0 ? ?- : ?w),
            (m & 0100 == 0 ? (m & 04000 == 0 ? ?- : ?S) :
                             (m & 04000 == 0 ? ?x : ?s)),
            (m & 0040 == 0 ? ?- : ?r),
            (m & 0020 == 0 ? ?- : ?w),
            (m & 0010 == 0 ? (m & 02000 == 0 ? ?- : ?S) :
                             (m & 02000 == 0 ? ?x : ?s)),
            (m & 0004 == 0 ? ?- : ?r),
            (m & 0002 == 0 ? ?- : ?w),
            (m & 0001 == 0 ? (m & 01000 == 0 ? ?- : ?T) :
                             (m & 01000 == 0 ? ?x : ?t)))
end

def human2chmod(mode)
  raise unless mode =~ /([r-][w-][xtsTS-])([r-][w-][xtsTS-])([r-][w-][xtsTS-])/
  triple = [$1, $2, $3]
  u,g,o = triple.collect do |i|
    i.sub('s', 'sx').sub('t', 'tx').downcase.gsub('-', '')
  end

  return "u=#{u},g=#{g},o=#{o}" 
end



File.open(FROM).each do |acl|
  raise unless acl =~ /\A(([^ ]*? )+)([^ ]+) ([^ ]+) ([^ ]+)\Z/
  path, rules, owner_id, group_id = $1, $3, $4, $5
  path = path.strip
  owner_id = owner_id.to_i
  group_id = group_id.to_i

  if !File.exists?(path) and !File.symlink?(path)
    if rules =~ /\Ad/
      STDERR.puts "Restoring a missing directory: #{path}"
      STDERR.puts "Probably it was an empty directory. Git goes not track them."
      `#{MKDIR} -p '#{path}'` # Creating the any parents
    else
      known_content_missing = true
      STDERR.puts "ERROR: ACL is listed but the file is missing: #{path}"
      next
    end
  end

  s = File.lstat(path)
  t = s.ftype[0..0].sub('f', '-') # Single character for the file type
                                  # But a "-" istead of "f"

  # Actual, but not neccesarely Desired 
  actual_rules    = "#{t}#{numeric2human(s.mode)}"
  actual_owner_id = s.uid 
  actual_group_id = s.gid 

  unless [actual_rules, actual_owner_id, actual_group_id] ==
    [rules, owner_id, group_id]

    chmod_argument = human2chmod(rules)

    # Debug
    #p chmod_argument
    #p s.mode

    ## Verbose
    puts path
    puts "Wrong: #{[actual_rules, actual_owner_id, actual_group_id].inspect}"
    puts "Fixed: #{[rules, owner_id, group_id].inspect}"
    `#{CHMOD} #{chmod_argument} '#{path}'`

    #puts
  end

end

if known_content_missing
  STDERR.puts "-" * 80 
  STDERR.puts "Some files that are listed in #{FROM.inspect} are missing in " +
              "the current directory."
  STDERR.puts
  STDERR.puts "Is #{FROM.inspect} outdated?"
  STDERR.puts "(Try retrograding the current directory to an earlier version)"
  STDERR.puts
  STDERR.puts "Or is the current directory incomplete?"
  STDERR.puts "(Try to recover the current directory)"
  STDERR.puts "-" * 80 
end

第三种解决方案

总之:你可以。您需要从Live CD安装文件系统,然后开始在适当的位置恢复权限。至少要获得sudo,你需要在LiveCD会话中运行sudo chmod u+s /usr/bin/sudo – 这将修复必须是setuid root。

但是,简单地重新安装系统可能会更容易。

第四种方案

我会尝试使用apt-get install --reinstall重新安装所有软件包,可能使用dpkg --get-selections | grep install的输出来获取它们的列表。

第五种方案

好吧,我没有测试过这个(所以请自行承担使用风险),但它仍然有用。当我有机会在虚拟机中测试时:

首先,在一个仍在工作的系统中,我执行以下操作以获取列表中的所有文件权限,跳过/home/目录:

sudo find / -not -path /home -printf "%m:%p\0" > /tmp/fileper.log

这将打印系统上每个文件或目录的权限和文件名,后跟一个\0字符(稍后需要处理奇怪的文件名,例如包含换行符的文件名)。

然后,在文件权限受到威胁的系统上:

while IFS=: read -r -d '' perm file; do  
    chmod "$perm" "$file"
done < /tmp/fileper.log 

这将读取fileper.log的每一行,将权限保存为$perm,文件名保存为$file,然后将文件(或目录)的权限设置为fileper.log中列出的任何内容


这里有几点需要注意:

  • 在输出到文件时:/tmp/fileper.log,您可能会列出自定义设置和proc等。

  • 您可能无法启动或运行命令,

我建议用你的磁盘上的Linux版本启动一个LiveCD,运行命令,修改你安装本地磁盘的路径,然后运行第二个命令!


我测试过,当从Ubuntu CD /USB启动时,我可以选择不格式化磁盘,这意味着它将替换/目录中的所有内容,但跳过/home/目录。这意味着您的用户将仍然保持应用程序/数据(音乐,视频,文档)的配置。通过更换系统文件,chmod设置为正确的编号。

第六种方案

(我知道我不应该在答案中发表评论,但没有足够的声誉来发表评论。)

blade19899的答案对我有用,除了符号链接。例如。它将755应用于/bin /bash,但随后将777应用于symlink /bin /rbash,实际上是777-ing /bin /bash。

因为我已经有了fileper.log文件,所以我只修改了destination-end命令:

while IFS=: read -r -d '' perm file; do  
    if [[ ! -L "$file" ]]; then    
        chmod "$perm" "$file"
    fi
done < /tmp/fileper.log 

第七种方案

您可以尝试使用apt-get恢复权限。

如果无法使用sudo运行这些命令,则可能需要引导至恢复模式并以root身份运行它们。

要启动到恢复模式,请参阅https://wiki.ubuntu.com/RecoveryMode

来自http://hyperlogos.org/page/Restoring-Permissions-Debian-System

注意:这最初发布在Ubuntu论坛上,但我找不到原帖。

按顺序尝试

sudo apt-get --reinstall install `dpkg --get-selections | grep install | grep -v deinstall | cut -f1`

如果失败:

sudo apt-get --reinstall install `dpkg --get-selections | grep install | grep -v deinstall | cut -f1 | egrep -v '(package1|package2)'`

最后,作为最后的手段,

sudo dpkg --get-selections | grep install | grep -v deinstall | cut -f1 | xargs apt-get --reinstall -y --force-yes install

使用apt-get

这是相关的剪辑,编辑正确并重新格式化:

sudo apt-get --reinstall install `dpkg --get-selections | grep install | grep -v deinstall | cut -f1` 

Let’s say you get messages about some packages that can’t be reinstalled, and the command fails. Here’s one way to fix it by skipping the packages in question:

sudo apt-get --reinstall install `dpkg --get-selections | grep install | grep -v deinstall | cut -f1 | egrep -v '(package1|package2)'` 

And finally, if you should somehow have so many things installed that the above command fails saying your argument list is too long, here’s the fix, which will run apt-get many more times than you might like:

sudo dpkg --get-selections | grep install | grep -v deinstall | cut -f1 | xargs apt-get --reinstall -y --force-yes install 

Note the -y and --force-yes options, which will stop apt-get from prompting you over and over again. These are always fun options, if you’re sure you know what you’re doing.

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/1809.html,未经允许,请勿转载。