8

在服务器故障上,如何列出符号链接链?(不是我的问题)谈到列出所有符号链接并关注它们。为了使这可行,让我们首先考虑一个目录。

我想编写一个简短的实用程序来执行此操作。将符号链接中的对放入散列然后处理散列看起来很容易。

但后来我可能有类似的东西:

ls -l
total 0
lrwxrwxrwx 1 pjb pjb 1 2010-02-23 08:48 a -> b
lrwxrwxrwx 1 pjb pjb 1 2010-02-23 08:48 b -> c
lrwxrwxrwx 1 pjb pjb 1 2010-02-23 09:03 c -> a
lrwxrwxrwx 1 pjb pjb 1 2010-02-23 09:17 trap -> b
lrwxrwxrwx 1 pjb pjb 1 2010-02-23 09:17 x -> y
lrwxrwxrwx 1 pjb pjb 1 2010-02-23 09:17 y -> b

很明显这a->b->c是一个循环,并且那个陷阱指向一个循环,但是要知道x指向一个循环的点,我需要遵循一点。

一种哈希表示是:

a => b
b => c
c => a
trap => b
x => y
y => b

但是,一旦我知道循环是什么,反向表示更适合将循环标记到错误的起点。

所以这里有一些问题:

  • 散列是表示符号链接的最佳结构吗?
  • 将文件系统图分开以将循环组件从树组件告诉带有循环类型片段的树枝的最佳方法是什么?
  • 有没有比从所有起点手动搜索所有循环更好的算法?
  • 从图论的角度来看——CPAN中已经有这种东西了吗?如果没有,有哪些好的辅助模块?
4

3 回答 3

7

CPAN 上有一个Graph模块,您可以使用如下所示:

#! /usr/bin/perl

use warnings;
use strict;

use Graph;

my $g = Graph->new;
my $dir = @ARGV ? shift : ".";

opendir my $dh, $dir or die "$0: opendir $dir: $!";
while (defined(my $name = readdir $dh)) {
  my $path = $dir . "/" . $name;

  if (-l $path) {
    my $dest = readlink $path;
    die "$0: readlink $path: $!" unless defined $dest;

    $g->add_edge($name => $dest);
  }
  else {
    $g->add_vertex($name);
  }
}

my @cycle = $g->find_a_cycle;
if (@cycle) {
  $" = ' -> '; #" # highlighting error
  print "$0: $dir: at least one cycle: @cycle\n";
}
else {
  print "$0: $dir: no cycles\n";
}

例如,在结构与您问题中的目录相似的目录中,输出为

$ ../has-cycle
../has-cycle: .: 至少一个循环:c -> a -> b
于 2010-02-23T18:39:41.583 回答
2

看看 CPAN 模块File::Spec::Link。resolve 方法表示它反复遍历链接以找到链接的目标。

模块的resolve方法是这样说的:

resolve($link)
  通过重复调用linked,返回由$link 最终链接的非链接。如果无法解析链接,则返回 undef

我曾使用此模块找到符号链接的目标,其目标又是符号链接,依此类推。但我不确定这是否检测到循环符号链接。

于 2010-02-23T17:46:17.013 回答
-1

您需要存储的不仅仅是链接的名称。获取 inode 编号(如果您的 FS 支持)或其他一些独特的方面。如果不存在,则考虑创建自己的,也许通过校验名称/创建/上次修改日期。无论哪种方式,您都需要某种方式来唯一标识每个链接。我见过一些实用程序,它们只是限制了链接的数量(8 到 255 之间),并声明任何超过此限制的内容为循环,但我一直认为这是“采取廉价的方式”。:)

于 2010-02-23T20:07:35.240 回答