This file is indexed.

/usr/bin/fai-deps is in fai-client 4.0.8~deb7u1.

This file is owned by root:root, with mode 0o755.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
#!/usr/bin/perl

=head1 NAME

  fai-deps - class dependencies for FAI

=head1 SYNOPSIS

  fai-deps [-h] [--man] [-d]

=head1 ABSTRACT

  implements dependencies between fai classes.

=head1 DESCRIPTION

fai-deps uses files $FAI/class/*.deps to sort the classes in $LOGDIR/FAI_CLASSES and define additional ones. While doing so, it retains the original order as much as possible.

*.deps files may contain class names, seperated by whitespace. Comments ( after # or ; ) are ignored

e.g. you have a class WORDPRESS that depends on the classes VHOST and POSTGRES . VHOST again may depend on WEBSERVER.
So if you want to install the blogging software wordpress, you add a file

  $FAI/class/WORDPRESS.deps

that contains the words
  VHOST
  POSTGRES

and a file
  $FAI/class/VHOST.deps

that contains the word
  WEBSERVER

The order often is important, so this script is taking care of it. The order of the example above would be:
  WEBSERVER VHOST POSTGRES WORDPRESS

That way, in $FAI/scripts/ first the webserver would be configured, then the vhosts, ...

It removes double entries from FAI_CLASSES and handles circular dependencies[1].

I do not recommend using circular dependencies, but if you accidentally define them, they will not break your neck. But you'll get a warning ...

=head1 ENVIROMENT

One non-standard perl module is required:
 Graph::Directed;
On debian install libgraph-perl

The following enviroment variables are used:

 $LOGDIR  : path to fai temporary files
 $FAI     : path to fai config space

=cut

INIT
  {
    unless ( $ENV{FAI} and $ENV{LOGDIR} ) {
      print STDERR '$ENV{FAI} and $ENV{LOGDIR} are not defined', $/;
      print STDERR 'This script should be called from within fai', $/;
      exit 1;
    }
  }

use strict;
use warnings;

use Getopt::Long;
use Pod::Usage;
use Graph::Directed;
#use Text::Glob qw(match_glob);
#use Data::Dumper;
#use GraphViz;

my %opts;
GetOptions( \%opts, 'help|h', 'man', 'debug|d' ) or pod2usage(1);
pod2usage(1) if $opts{help};
pod2usage(-verbose => 2) if $opts{man};

my $debug = $opts{debug};
my $fai_classes_file = "$ENV{LOGDIR}/FAI_CLASSES";
my $class_dir = "$ENV{FAI}/class";

# main
{
  # read classes and dependencies into $digraph
  # retain order of first appearance in @uniq_classes
  my $digraph = Graph::Directed->new;
  my ( @uniq_classes ) =
    read_fai_classes( $digraph, $fai_classes_file );
  push @uniq_classes,
    read_dependencies( $digraph, $class_dir, @uniq_classes );
  exit if not $digraph->has_edges;

  # debug output
  if ( $debug ) {
    print STDERR 'graph:', $/;
    print STDERR $digraph->stringify(), $/;
    print STDERR 'is strongly connected', $/
      if $digraph->is_strongly_connected;
    #   create_graphviz_output($digraph->edges);

    print STDERR 'unique list of classes, orderd by appearence', $/;
    print STDERR join('-', @uniq_classes), $/;
    print STDERR $/;
  }

  # warn if graph has cycles
  if ( $digraph->has_a_cycle ) {
    print STDERR 'Warning: cyclic class dependencies found:', $/;
    my $copy = $digraph->copy;
    while ( my @cycle = $copy->find_a_cycle ) {
      print STDERR join('-', @cycle), $/;
      $copy->delete_cycle(@cycle);
    }
    print STDERR 'I`ll try my best to retain your class order', $/;
  }

  # sort classes: retain order where possible, respect dependencies where necessary
  my @sorted_classes = sort_classes( $digraph, @uniq_classes );

  # debug output
  if ( $debug ) {
    print STDERR "list of all classes after resolving dependencies:", $/;
    print STDERR "@sorted_classes", $/;
    print STDERR 'in debug mode, this script has no effect at all!', $/x5;
    print STDERR 'Goodbye, and thank you for the fish', $/;
    exit;
  }
  # rewrite $fai_classes_file
  open FAI_CLASSES, ">$fai_classes_file"
    or die "$!: $fai_classes_file";
  print FAI_CLASSES join($/, @sorted_classes), $/;
  close FAI_CLASSES;
}
exit;                           # end main

# sort_classes:
# topological sort classes, retaining order as much as possible
my %class_finished_for;
my @order;
sub sort_classes {
  my ( $digraph, @uniq_classes ) = @_;
  @order = @uniq_classes if not @order;
  my @sorted_classes;
  for my $class ( @uniq_classes ) {
    next if exists $class_finished_for{$class};
    my %unfinished_successor_for =
      map { $_, 1 }
        grep { not exists $class_finished_for{$_} }
          successors($digraph, $class);
    # retain order for successors
    my @unfinished_successors =
      grep { $unfinished_successor_for{$_} }
        @order;
    push @sorted_classes, sort_classes( $digraph, @unfinished_successors );
    push @sorted_classes, $class;
    $class_finished_for{$class}++;
  }
  return @sorted_classes;
}

# successors: find successors for a given class
# handle circular dependencies:
# * do not return circular connected successors
# * _do_ return all successors of circular connected successors
sub successors {
  my ( $digraph, $class ) = @_;
  my $component = $digraph->strongly_connected_component_by_vertex($class);
  # strongly connected components to all successors, except own component
  my %successor_components =
    map { $_, undef }           # turn list into hash for uniqueness
      grep { $_ ne $component }
        map { $digraph->strongly_connected_component_by_vertex($_) }
          $digraph->successors($class);
  # classes for these components
  my %successors =
    map { $_, undef }           # turn list into hash for uniqueness
      map { $digraph->strongly_connected_component_by_index($_) }
        keys %successor_components;
  return keys %successors;
}

# read_fai_classes: reads fai classes from $fai_classes_file
# usually $LOGDIR/FAI_CLASSES
sub read_fai_classes {
  my ( $digraph, $fai_classes_file) = @_;
  my @uniq_classes;
  # read plain classes from $LOGDIR/FAI_CLASSES
  open FAI_CLASSES, $fai_classes_file
    or die "$!: $fai_classes_file";
  while ( <FAI_CLASSES> ) {
    chomp;
    # skip double classes
    next if $digraph->has_vertex( $_ );
    push @uniq_classes, $_;
    $digraph->add_vertex( $_ );
  }
  close FAI_CLASSES;
  return @uniq_classes;
}

# read_dependencies: reads dependencies and its classes from $class_dir/*.deps
my %deps_file_seen_for;
sub read_dependencies {
  my ( $digraph, $class_dir, @uniq_classes) = @_;
  my @new_classes;
  # read class dependencies from $class_dir/*.deps
  my $prefix = quotemeta($class_dir);
  my @deps_files = grep {
    -f "$class_dir/$_.deps"
      and not -x "$class_dir/$_.deps"
    } @uniq_classes;
  for my $class ( @deps_files ) {
    next if $deps_file_seen_for{$class}++;
    open DEPSFILE, "$class_dir/$class.deps"
      or die "$!: $class";
    while ( <DEPSFILE> ) {
      chomp;
      # remove comments, leading and trailing whitespace
      s/(#|;).*// ;
      s/ ^\s+  //x;
      s/  \s+$ //x;
      # allow multiple classes per line
      my @deps = split m/\s+/;
      for my $dep ( @deps ) {
        push @new_classes, $dep
          if not $digraph->has_vertex( $dep );
        $digraph->add_edge($class, $dep);
      }
    }
    close DEPSFILE;
    push @new_classes, read_dependencies( $digraph, $class_dir, @new_classes );
  }
  return @new_classes;
}

#sub create_graphviz_output {
#       my @edges = @_;
#       my $g = GraphViz->new();
#       for ( @edges ) {
#               $g->add_edge( @$_ );
#       }
#       return $g->as_png('graph-test.png');
#}

=head1 SEE ALSO

 http://fai-project.org

=head1 AUTHOR

 Copyright 2008 by Ingo Wichmann <iw@linuxhotel.de>

 This software ist free software; you can redistribute it and/or modify
 it unter the same terms as Perl itself.

=cut