~ubuntu-branches/ubuntu/edgy/gnome-system-tools/edgy-proposed

« back to all changes in this revision

Viewing changes to backends/filesys.pl.in

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2004-10-14 18:49:22 UTC
  • Revision ID: james.westby@ubuntu.com-20041014184922-efvh7u8kpyy67a3z
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env perl
 
2
#-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 
3
 
 
4
# Working with filesystems, both local and networked.
 
5
#
 
6
# Copyright (C) 2000-2001 Ximian, Inc.
 
7
#
 
8
# Authors: Hans Petter Jansson <hpj@ximian.com>
 
9
#
 
10
# This program is free software; you can redistribute it and/or modify
 
11
# it under the terms of the GNU Library General Public License as published
 
12
# by the Free Software Foundation; either version 2 of the License, or
 
13
# (at your option) any later version.
 
14
#
 
15
# This program is distributed in the hope that it will be useful,
 
16
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
# GNU Library General Public License for more details.
 
19
#
 
20
# You should have received a copy of the GNU Library General Public License
 
21
# along with this program; if not, write to the Free Software
 
22
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
23
 
 
24
 
 
25
$SCRIPTSDIR = "@scriptsdir@";
 
26
if ($SCRIPTSDIR =~ /^@scriptsdir[@]/)
 
27
{
 
28
    $SCRIPTSDIR = ".";
 
29
    $DOTIN = ".in";
 
30
}
 
31
 
 
32
require "$SCRIPTSDIR/file.pl$DOTIN";
 
33
require "$SCRIPTSDIR/parse.pl$DOTIN";
 
34
require "$SCRIPTSDIR/xml.pl$DOTIN";
 
35
 
 
36
 
 
37
# --- Utilities --- #
 
38
 
 
39
# Merge items in hash B missing in A into A.
 
40
sub merge_hashes
 
41
{
 
42
  my ($ha, $hb) = @_;
 
43
  my $key;
 
44
 
 
45
  foreach $key (keys %$hb)
 
46
  {
 
47
    $$ha{$key} = $$hb{$key} if !exists $$ha{$key};
 
48
  }
 
49
}
 
50
 
 
51
sub gst_filesys_ext2_device_to_label  # device
 
52
{
 
53
  my ($device) = @_;
 
54
  my $label;
 
55
  my $fd;
 
56
 
 
57
  $fd = &gst_file_run_pipe_read ("e2label $device");
 
58
  return undef if $fd eq undef;
 
59
  $label = <$fd>;
 
60
  chomp $label;
 
61
  &gst_file_close ($fd);
 
62
 
 
63
  return $label;
 
64
}
 
65
 
 
66
 
 
67
# --- filesys_info; information on a particular filesystem --- #
 
68
 
 
69
 
 
70
sub gst_filesys_info_new
 
71
{
 
72
  my $info = {};
 
73
  my $opthash = {};
 
74
 
 
75
  $$info{'options'} = $opthash;
 
76
  return ($info);
 
77
}
 
78
 
 
79
# Make a deep copy of a filesys_info struct.
 
80
#
 
81
# Returns a newly allocated filesys_info, identical to the argument.
 
82
 
 
83
sub gst_filesys_info_dup           # filesys_info
 
84
{
 
85
  my $orig = $_[0];
 
86
  my $dup;
 
87
  my $options = $$orig{'options'};
 
88
 
 
89
  $dup = { %$orig };
 
90
  $$dup{'options'} = { %$options };
 
91
 
 
92
  return $dup;
 
93
}
 
94
 
 
95
sub gst_filesys_info_match  # filesys_info, device, label, uuid, network_host, network_path
 
96
{
 
97
  my ($info, $device, $label, $uuid, $network_host, $network_path, $point) = @_;
 
98
 
 
99
  if (($label && $info->{'label'} eq $label) ||
 
100
      ($uuid  && $info->{'uuid'}  eq $uuid)  ||
 
101
      ($network_host && $network_path &&
 
102
       $info->{'network_host'} eq $network_host &&
 
103
       $info->{'network_path'} eq $network_path) ||
 
104
      ($device && $device ne "none" && $info->{'device'} eq $device) ||
 
105
      ($device eq "none" && $info->{'device'} eq "none" && $point eq $info->{'point'}))
 
106
  {
 
107
    return 1;
 
108
  }
 
109
 
 
110
  return 0;
 
111
}
 
112
 
 
113
sub gst_filesys_info_settings_to_options
 
114
{
 
115
  my ($info) = @_;
 
116
 
 
117
  if (&gst_filesys_info_get_mounted ($info))
 
118
  {
 
119
    &gst_filesys_info_remove_option ($info, "noauto");
 
120
  }
 
121
  else
 
122
  {
 
123
    &gst_filesys_info_set_option ($info, "noauto", "");
 
124
  }
 
125
}
 
126
 
 
127
sub gst_filesys_info_match_options  # filesys_info, filesys_info
 
128
{
 
129
  my ($info_a, $info_b) = @_;
 
130
 
 
131
  if (&gst_filesys_info_print_options ($info_a) eq &gst_filesys_info_print_options ($info_b))
 
132
  {
 
133
    return 1;
 
134
  }
 
135
 
 
136
  return 0;
 
137
}
 
138
 
 
139
sub gst_filesys_info_match_data  # filesys_info, filesys_info
 
140
{
 
141
  my ($info_a, $info_b) = @_;
 
142
 
 
143
  if (&gst_filesys_info_get_point    ($info_a) eq &gst_filesys_info_get_point    ($info_b) &&
 
144
      &gst_filesys_info_get_fs       ($info_a) eq &gst_filesys_info_get_fs       ($info_b) &&
 
145
      &gst_filesys_info_get_dump     ($info_a) eq &gst_filesys_info_get_dump     ($info_b) &&
 
146
      &gst_filesys_info_get_priority ($info_a) eq &gst_filesys_info_get_priority ($info_b) &&
 
147
      &gst_filesys_info_match_options ($info_a, $info_b))
 
148
  {
 
149
    return 1;
 
150
  }
 
151
 
 
152
  return 0;
 
153
}
 
154
 
 
155
# Merge options in B missing in A into A.
 
156
sub gst_filesys_info_merge_options
 
157
{
 
158
  my ($info_a, $info_b) = @_;
 
159
  my ($opt_a, $opt_b, $key);
 
160
 
 
161
  $opt_a = $$info_a{'options'};
 
162
  $opt_b = $$info_b{'options'};
 
163
 
 
164
  &merge_hashes ($opt_a, $opt_b);
 
165
}
 
166
 
 
167
# Merge stuff in B missing in A into A.
 
168
sub gst_filesys_info_merge
 
169
{
 
170
  my ($info_a, $info_b) = @_;
 
171
  my $key;
 
172
 
 
173
  &merge_hashes ($info_a, $info_b);
 
174
  &gst_filesys_info_merge_options ($info_a, $info_b);
 
175
}
 
176
 
 
177
# Generic set function for filesys_info properties. We need this to
 
178
# delete keys if they don't have meaningful values, otherwise an empty
 
179
# value could override a perfectly good value in a merge.
 
180
 
 
181
sub gst_filesys_info_set           # filesys_info, key, value
 
182
{
 
183
  my ($filesys_info, $key, $value) = @_;
 
184
  
 
185
  if ($value eq "")
 
186
  {
 
187
    delete $filesys_info->{$key};
 
188
  }
 
189
  else
 
190
  {
 
191
    $filesys_info->{$key} = $value;
 
192
  }
 
193
}
 
194
 
 
195
sub gst_filesys_info_get_device        # filesys_info
 
196
{
 
197
  return $_[0]->{'device'};
 
198
}
 
199
 
 
200
sub gst_filesys_info_set_device        # filesys_info, device
 
201
{
 
202
  &gst_filesys_info_set ($_[0], 'device', $_[1]);
 
203
}
 
204
 
 
205
sub gst_filesys_info_get_label         # filesys_info
 
206
{
 
207
  return $_[0]->{'label'};
 
208
}
 
209
 
 
210
sub gst_filesys_info_set_label         # filesys_info, label
 
211
{
 
212
  &gst_filesys_info_set ($_[0], 'label', $_[1]);
 
213
}
 
214
 
 
215
sub gst_filesys_info_get_network_host  # filesys_info
 
216
{
 
217
  return $_[0]->{'network_host'};
 
218
}
 
219
 
 
220
sub gst_filesys_info_set_network_host  # filesys_info, network_host
 
221
{
 
222
  my ($info, $host) = @_;
 
223
 
 
224
  $host =~ s/^\/+//;
 
225
  &gst_filesys_info_set ($info, 'network_host', $host);
 
226
}
 
227
 
 
228
sub gst_filesys_info_get_network_path  # filesys_info
 
229
{
 
230
  return $_[0]->{'network_path'};
 
231
}
 
232
 
 
233
sub gst_filesys_info_set_network_path  # filesys_info, network_path
 
234
{
 
235
  my ($info, $path) = @_;
 
236
 
 
237
  $path = "/" . $path if (!($path =~ /^\//));
 
238
  &gst_filesys_info_set ($info, 'network_path', $path);
 
239
}
 
240
 
 
241
sub gst_filesys_info_get_uuid          # filesys_info
 
242
{
 
243
  return $_[0]->{'uuid'};
 
244
}
 
245
 
 
246
sub gst_filesys_info_set_uuid          # filesys_info, uuid
 
247
{
 
248
  &gst_filesys_info_set ($_[0], 'uuid', $_[1]);
 
249
}
 
250
 
 
251
sub gst_filesys_info_get_point         # filesys_info
 
252
{
 
253
  return $_[0]->{'point'};
 
254
}
 
255
 
 
256
sub gst_filesys_info_set_point         # filesys_info, point
 
257
{
 
258
  &gst_filesys_info_set ($_[0], 'point', $_[1]);
 
259
}
 
260
 
 
261
sub gst_filesys_info_get_fs            # filesys_info
 
262
{
 
263
  return $_[0]->{'fs'};
 
264
}
 
265
 
 
266
sub gst_filesys_info_set_fs            # filesys_info, fs
 
267
{
 
268
  &gst_filesys_info_set ($_[0], 'fs', $_[1]);
 
269
}
 
270
 
 
271
sub gst_filesys_info_get_dump          # filesys_info
 
272
{
 
273
  return $_[0]->{'dump'} || "0";
 
274
}
 
275
 
 
276
sub gst_filesys_info_set_dump          # filesys_info, dump
 
277
{
 
278
  &gst_filesys_info_set ($_[0], 'dump', $_[1]);
 
279
}
 
280
 
 
281
sub gst_filesys_info_get_priority      # filesys_info
 
282
{
 
283
  return $_[0]->{'priority'} || "0";
 
284
}
 
285
 
 
286
sub gst_filesys_info_set_priority      # filesys_info, priority
 
287
{
 
288
  &gst_filesys_info_set ($_[0], 'priority', $_[1]);
 
289
}
 
290
 
 
291
sub gst_filesys_info_get_mounted       # filesys_info
 
292
{
 
293
  return $_[0]->{'mounted'};
 
294
}
 
295
 
 
296
sub gst_filesys_info_set_mounted       # filesys_info, boolean
 
297
{
 
298
  &gst_filesys_info_set ($_[0], 'mounted', $_[1]);
 
299
}
 
300
 
 
301
sub gst_filesys_info_get_permanent     # filesys_info
 
302
{
 
303
  return $_[0]->{'permanent'};
 
304
}
 
305
 
 
306
sub gst_filesys_info_set_permanent     # filesys_info, boolean
 
307
{
 
308
  &gst_filesys_info_set ($_[0], 'permanent', $_[1]);
 
309
}
 
310
 
 
311
sub gst_filesys_info_get_detected      # filesys_info
 
312
{
 
313
  return $_[0]->{'detected'};
 
314
}
 
315
 
 
316
sub gst_filesys_info_set_detected      # filesys_info, boolean
 
317
{
 
318
  &gst_filesys_info_set ($_[0], 'detected', $_[1]);
 
319
}
 
320
 
 
321
sub gst_filesys_info_get_option      # filesys_info, option
 
322
{
 
323
  return $_[0]->{'options'}{$_[1]};
 
324
}
 
325
 
 
326
# We can't delete keys with no values here, since most fs options don't
 
327
# have values (i.e. they key's presence constitutes a boolean). A value of
 
328
# " " (one space) indicates that this entry takes a value (is non-bool), but
 
329
# has none.
 
330
 
 
331
sub gst_filesys_info_set_option        # filesys_info, option, value
 
332
{
 
333
  $_[0]->{'options'}{$_[1]} = $_[2];
 
334
}
 
335
 
 
336
sub gst_filesys_info_remove_option     # filesys_info, option
 
337
{
 
338
  delete $_[0]->{'options'}{$_[1]};
 
339
}
 
340
 
 
341
# --- filesys_table; multiple instances of filesys_info --- #
 
342
 
 
343
 
 
344
sub gst_filesys_table_new
 
345
{
 
346
  my @array;
 
347
  return \@array;
 
348
}
 
349
 
 
350
# Make a deep copy of a filesys_table struct.
 
351
#
 
352
# Returns a newly allocated filesys_table, identical to the argument.
 
353
 
 
354
sub gst_filesys_table_dup          # filesys_table
 
355
{
 
356
  my $orig = $_[0];
 
357
  my $dup = &gst_filesys_table_new ();
 
358
  my $i;
 
359
 
 
360
  foreach $i (@$orig)
 
361
  {
 
362
    &gst_filesys_table_add ($dup, &gst_filesys_info_dup ($i));
 
363
  }
 
364
 
 
365
  return $dup;
 
366
}
 
367
 
 
368
# Add a filesys_info reference to a filesys_table. Note: This function
 
369
# does not check for uniqueness, which lets you add several references
 
370
# to the same filesys_info.
 
371
 
 
372
sub gst_filesys_table_add          # filesys_table, filesys_info
 
373
{
 
374
  my ($table, $info) = @_;
 
375
 
 
376
  push @$table, $info;
 
377
}
 
378
 
 
379
# Ensure that a filesys_info reference exists in a filesys_table. If it
 
380
# doesn't, it will be added. If it does, no action will be taken.
 
381
 
 
382
sub gst_filesys_table_ensure       # filesys_table, filesys_info
 
383
{
 
384
  my ($table, $info) = @_;
 
385
  my $i;
 
386
 
 
387
  foreach $i (@$table)
 
388
  {
 
389
    return if ($i eq $info);
 
390
  }
 
391
 
 
392
  &gst_filesys_table_add ($table, $info);
 
393
}
 
394
 
 
395
# Remove a filesys_info reference from a filesys_table.
 
396
 
 
397
sub gst_filesys_table_remove       # filesys_table, filesys_info
 
398
{
 
399
  my ($table, $info) = @_;
 
400
  my $i;
 
401
 
 
402
  if ($info == undef) { return; }
 
403
 
 
404
  for ($i = 0; $i < @$table; $i++)
 
405
  {
 
406
    if (@$table [$i] eq $info)
 
407
    {
 
408
      @$table = (@$table [0 .. $i - 1], @$table [$i + 1 .. @$table - 1]);
 
409
      return;
 
410
    }
 
411
  }
 
412
 
 
413
  &gst_debug_print_line ("Entry to remove [" . $info . "] not found in filesys_table.");
 
414
}
 
415
 
 
416
# Find and return a reference to a filesys_info in a filesys_table
 
417
# matching any of the information provided.
 
418
 
 
419
sub gst_filesys_table_find         # filesys_table, device, label, uuid, network_host, network_path
 
420
{
 
421
  my ($table, $device, $label, $uuid, $network_host, $network_path, $point) = @_;
 
422
  my $i;
 
423
 
 
424
  # Match on high-quality keys.
 
425
  
 
426
  foreach $i (@$table)
 
427
  {
 
428
    if (($label && $i->{'label'} eq $label) ||
 
429
        ($uuid  && $i->{'uuid'}  eq $uuid)  ||
 
430
        ($network_host && $network_path &&
 
431
         $i->{'network_host'} eq $network_host &&
 
432
         $i->{'network_path'} eq $network_path))
 
433
    {
 
434
      return $i;
 
435
    }
 
436
  }
 
437
 
 
438
  # Match on low-quality keys.
 
439
 
 
440
  if ($device)
 
441
  {
 
442
    foreach $i (@$table)
 
443
    {
 
444
      if (($device && $device ne "none" && $i->{'device'} eq $device) ||
 
445
          ($device eq "none" && $i->{'device'} eq "none" && $point eq $i->{'point'}))
 
446
      {
 
447
        return $i;
 
448
      }
 
449
    }
 
450
  }
 
451
 
 
452
  &gst_debug_print_line ("Entry [" . $device . "] not found in filesys_table.");
 
453
  return undef;
 
454
}
 
455
 
 
456
sub gst_filesys_table_find_info_equivalent  # filesys_table, filesys_info
 
457
{
 
458
  my ($table, $info) = @_;
 
459
 
 
460
  return &gst_filesys_table_find ($table, &gst_filesys_info_get_device ($info),
 
461
                                  &gst_filesys_info_get_label ($info),
 
462
                                  &gst_filesys_info_get_uuid ($info),
 
463
                                  &gst_filesys_info_get_network_host ($info),
 
464
                                  &gst_filesys_info_get_network_path ($info),
 
465
                                  &gst_filesys_info_get_point ($info));
 
466
}
 
467
 
 
468
# Merges filesys tables A and B, resolving conflicts by giving priority to A.
 
469
# Any entries in A not in B are preserved. This can also be described as
 
470
# "salting" one table with another.
 
471
#
 
472
# Returns a newly allocated table C, which is a superset of A and B.
 
473
 
 
474
sub gst_filesys_table_merge_superset  # filesys_table A, filesys_table B
 
475
{
 
476
  my ($intab_a, $intab_b) = @_;
 
477
  my ($hash_c, $hash_b, $key);
 
478
  my $outtab;
 
479
 
 
480
  $outtab = &gst_filesys_table_dup ($intab_a);
 
481
 
 
482
  foreach $info_b (@$intab_b)
 
483
  {
 
484
    my $info_c;
 
485
 
 
486
    if ($info_c = &gst_filesys_table_find_info_equivalent ($outtab, $info_b))
 
487
    {
 
488
      &gst_filesys_info_merge ($info_c, $info_b);
 
489
    }
 
490
    else
 
491
    {
 
492
      $info_c = &gst_filesys_info_dup ($info_b);
 
493
      &gst_filesys_table_add ($outtab, $info_c);
 
494
    }
 
495
  }
 
496
 
 
497
  return $outtab;
 
498
}
 
499
 
 
500
# Merges filesys tables A and B, resolving conflicts by giving priority to A.
 
501
# Any entries not in A are dropped.
 
502
#
 
503
# Returns a newly allocated table C, which is a subset of A and B.
 
504
 
 
505
sub gst_filesys_table_merge_subset    # filesys_table A, filesys_table B
 
506
{
 
507
  my ($intab_a, $intab_b) = @_;
 
508
  my ($hash_c, $hash_b, $key);
 
509
  my $outtab;
 
510
 
 
511
  $outtab = &gst_filesys_table_dup ($intab_a);
 
512
 
 
513
  foreach $info_b (@$intab_b)
 
514
  {
 
515
    my $info_c;
 
516
 
 
517
    if ($info_c = &gst_filesys_table_find_info_equivalent ($outtab, $info_b))
 
518
    {
 
519
      &gst_filesys_info_merge ($info_c, $info_b);
 
520
    }
 
521
  }
 
522
 
 
523
  return $outtab;
 
524
}
 
525
 
 
526
# Called to indicate that entries in a filesys table are mounted.
 
527
 
 
528
sub gst_filesys_table_set_mounted_true  # filesys_table
 
529
{
 
530
  my ($table) = @_;
 
531
  foreach $i (@$table)
 
532
  {
 
533
    &gst_filesys_info_set_mounted ($i, 1);
 
534
  }
 
535
}
 
536
 
 
537
# Called to indicate that entries in a filesys table are permanent.
 
538
 
 
539
sub gst_filesys_table_set_permanent_true  # filesys_table
 
540
{
 
541
  my ($table) = @_;
 
542
  foreach $i (@$table)
 
543
  {
 
544
    &gst_filesys_info_set_permanent ($i, 1);
 
545
  }
 
546
}
 
547
 
 
548
# Called to indicate that entries in a filesys table have been detected,
 
549
# e.g. by a network or bus scanner, and were not specified in any part of
 
550
# the user's configuration.
 
551
 
 
552
sub gst_filesys_table_set_detected_true  # filesys_table
 
553
{
 
554
  my ($table) = @_;
 
555
  foreach $i (@$table)
 
556
  {
 
557
    &gst_filesys_info_set_detected ($i, 1);
 
558
  }
 
559
}
 
560
 
 
561
# --- Parsing --- #
 
562
 
 
563
sub gst_filesys_entry_identify
 
564
{
 
565
  my ($device, $fs) = @_;
 
566
  my ($label, $uuid, $network_host, $network_path);
 
567
 
 
568
  # <device> expands to "LABEL=<label>", "UUID=<uuid>" or "<device node>".
 
569
  if    ($device =~ /^LABEL=(.*)/i) { $label = $1; $device = ""; }
 
570
  elsif ($device =~ /^UUID=(.*)/i)  { $uuid  = $1; $device = ""; }
 
571
  else
 
572
  {
 
573
    # We know only the device node. Try to get label too.
 
574
    if ($fs eq "ext2" || ($fs eq "auto" && !($device =~ /fd[0-9]$/)))
 
575
    {
 
576
      $label = &gst_filesys_ext2_device_to_label ($device);
 
577
    }
 
578
    # Network filesystem devices can be separated into remote host and remote path.
 
579
    elsif ($fs eq "nfs")
 
580
    {
 
581
      $device =~ /([^:]+):(.+)/;
 
582
      $network_host = $1;
 
583
      $network_path = $2;
 
584
      $network_path = "/" . $network_path if (!($network_path =~ /^\//));
 
585
      $device = "";
 
586
    }
 
587
    elsif ($fs eq "smbfs")
 
588
    {
 
589
      $device =~ /[\\\/]*([^\\\/]+)[\\\/]+(.+)/;
 
590
      $network_host = $1;
 
591
      $network_path = $2;
 
592
      $network_path = "/" . $network_path if (!($network_path =~ /^\//));
 
593
      $device = "";
 
594
    }
 
595
  }
 
596
 
 
597
  return ($device, $label, $uuid, $network_host, $network_path);
 
598
}
 
599
 
 
600
sub gst_filesys_entry_identify_info
 
601
{
 
602
  my ($fsi, $device, $fs) = @_;
 
603
  my ($label, $uuid, $network_host, $network_path);
 
604
 
 
605
  ($device, $label, $uuid, $network_host, $network_path) = &gst_filesys_entry_identify ($device, $fs);
 
606
 
 
607
  if ($device)       { &gst_filesys_info_set_device       ($fsi, $device);       }
 
608
  if ($label)        { &gst_filesys_info_set_label        ($fsi, $label);        }
 
609
  if ($uuid)         { &gst_filesys_info_set_uuid         ($fsi, $uuid);         }
 
610
  if ($network_host) { &gst_filesys_info_set_network_host ($fsi, $network_host); }
 
611
  if ($network_path) { &gst_filesys_info_set_network_path ($fsi, $network_path); }
 
612
}
 
613
 
 
614
# Get all instances from fstab-style file. Returns a filesys_table.
 
615
#
 
616
# This is not done in smaller, atomic funcs that get single options
 
617
# per disk device, due to the fact that a device is identified either
 
618
# by its label, uuid or device node, and a label can be made to look
 
619
# like a device node. For each device, we need to specify the kind of
 
620
# key(s) used, and making a special-format string for that (which could
 
621
# be passed to option readers) would be a bad hack.
 
622
 
 
623
sub gst_filesys_fstab_parse  # filename
 
624
{
 
625
  my ($file) = @_;
 
626
  my ($fd, $table);
 
627
 
 
628
  $fd = &gst_file_open_read_from_names ($file);
 
629
  return undef if !$fd;
 
630
 
 
631
  $table = &gst_filesys_table_new ();
 
632
 
 
633
  while (($_ = &gst_parse_chomp_line_hash_comment ($fd)) != -1)
 
634
  {
 
635
    # Each line is in the following format:
 
636
    # <device> <mount point> <filesystem> <options> <dump flag> <fsck priority>
 
637
    my @line = split /[ \t]+/, $$_;
 
638
    next if (@line < 6);
 
639
    my ($device, $point, $fs, $options, $dump, $fsck) = @line;
 
640
 
 
641
    my $fsi = &gst_filesys_info_new ();
 
642
    &gst_filesys_entry_identify_info ($fsi, $device, $fs);
 
643
 
 
644
    # <mount point>, <fs>, <dump flag> and <fsck priority> are verbatim.
 
645
    &gst_filesys_info_set_point    ($fsi, $point);
 
646
    &gst_filesys_info_set_fs       ($fsi, $fs);
 
647
    &gst_filesys_info_set_dump     ($fsi, $dump);
 
648
    &gst_filesys_info_set_priority ($fsi, $fsck);
 
649
 
 
650
    # <options> expands to "<option>[,<option>[,...]]".
 
651
    my @optlist = split /[,]/, $options;
 
652
 
 
653
    foreach $option (@optlist)
 
654
    {
 
655
      # <option> expands to "<key>[=<value>]". <key> == "defaults" is ignored.
 
656
      my ($key, $value) = split /[=]/, $option;
 
657
      next if ($key eq "" || $key eq "defaults");
 
658
 
 
659
      if ($value eq "" && $option =~ /=/) { $value = " "; }
 
660
      &gst_filesys_info_set_option ($fsi, $key, $value);
 
661
    }
 
662
 
 
663
    # Link it in.
 
664
    &gst_filesys_table_add ($table, $fsi);
 
665
  }
 
666
 
 
667
  &gst_file_close ($fd);
 
668
  return $table;
 
669
}
 
670
 
 
671
# Get all instances from 'mount -p' output. Returns a filesys_table.
 
672
sub gst_filesys_freebsd_mount_cmd_parse
 
673
{
 
674
  my ($table, $mount_cmd);
 
675
  my (@output, $l);
 
676
 
 
677
  $table = &gst_filesys_table_new ();
 
678
  $mount_cmd = &gst_file_locate_tool ("mount");
 
679
  @output = (readpipe ("$mount_cmd -p"));
 
680
 
 
681
  foreach $l (@output)
 
682
  {
 
683
    # Columns are separated by any number of spaces/tabs.
 
684
    chomp $l;
 
685
    my @line = split (/[ \t]+/, $l);
 
686
 
 
687
    # Each line is in the following format:
 
688
    # <device> <mount point> <filesystem> <options> <dump flag> <fsck priority>
 
689
    next if ($#line < 5);
 
690
    my ($device, $point, $fs, $options, $dump, $fsck) = @line;
 
691
 
 
692
    my $fsi = &gst_filesys_info_new ();
 
693
    &gst_filesys_entry_identify_info ($fsi, $device, $fs);
 
694
 
 
695
    # <device> expands to "<device node>" (unlike fstab, which has dev|label|uuid).
 
696
    # <mount point>, <fs>, <dump flag> and <fsck priority> are verbatim.
 
697
    &gst_filesys_info_set_device   ($fsi, $device);
 
698
    &gst_filesys_info_set_point    ($fsi, $point);
 
699
    &gst_filesys_info_set_fs       ($fsi, $fs);
 
700
    &gst_filesys_info_set_dump     ($fsi, $dump);
 
701
    &gst_filesys_info_set_priority ($fsi, $fsck);
 
702
 
 
703
    # <options> expands to "<option>[,<option>[,...]]".
 
704
    my @optlist = split (/,/, $options);
 
705
 
 
706
    foreach $option (@optlist)
 
707
    {
 
708
      # <option> expands to "<key>[=<value>]". <key> == "defaults" is ignored.
 
709
      my ($key, $value) = split /[=]/, $option;
 
710
      next if ($key eq "" || $key eq "defaults");
 
711
 
 
712
      $value = " " if ($value eq "" && $option =~ /=/);
 
713
      &gst_filesys_info_set_option ($fsi, $key, $value);
 
714
    }
 
715
 
 
716
    # Link it in.
 
717
    &gst_filesys_table_add ($table, $fsi);
 
718
  }
 
719
 
 
720
  return $table;
 
721
}
 
722
 
 
723
# Get all instances from mtab-style file. Returns a filesys_table.
 
724
 
 
725
sub gst_filesys_mtab_parse  # filename
 
726
{
 
727
  my ($file) = @_;
 
728
  my ($fd, $table);
 
729
 
 
730
  $fd = &gst_file_open_read_from_names ($file);
 
731
  return undef if !$fd;
 
732
 
 
733
  $table = &gst_filesys_table_new ();
 
734
 
 
735
  while (($_ = &gst_parse_chomp_line_hash_comment ($fd)) != -1)
 
736
  {
 
737
    # Columns are separated by one, and only one, space. The presence of one or
 
738
    # more blank values is indicated by a string of several spaces.
 
739
    my @line = split /[ ]/, $$_;
 
740
 
 
741
    # Each line is in the following format:
 
742
    # <device> <mount point> <filesystem> <options> <dump flag> <fsck priority>
 
743
    next if (@line < 6);
 
744
    my ($device, $point, $fs, $options, $dump, $fsck) = @line;
 
745
 
 
746
    my $fsi = &gst_filesys_info_new ();
 
747
    &gst_filesys_entry_identify_info ($fsi, $device, $fs);
 
748
 
 
749
    # <device> expands to "<device node>" (unlike fstab, which has dev|label|uuid).
 
750
    # <mount point>, <fs>, <dump flag> and <fsck priority> are verbatim.
 
751
    &gst_filesys_info_set_device   ($fsi, $device);
 
752
    &gst_filesys_info_set_point    ($fsi, $point);
 
753
    &gst_filesys_info_set_fs       ($fsi, $fs);
 
754
    &gst_filesys_info_set_dump     ($fsi, $dump);
 
755
    &gst_filesys_info_set_priority ($fsi, $fsck);
 
756
 
 
757
    # <options> expands to "<option>[,<option>[,...]]".
 
758
    my @optlist = split /[,]/, $options;
 
759
 
 
760
    foreach $option (@optlist)
 
761
    {
 
762
      # <option> expands to "<key>[=<value>]". <key> == "defaults" is ignored.
 
763
      my ($key, $value) = split /[=]/, $option;
 
764
      next if ($key eq "" || $key eq "defaults");
 
765
 
 
766
      if ($value eq "" && $option =~ /=/) { $value = " "; }
 
767
      &gst_filesys_info_set_option ($fsi, $key, $value);
 
768
    }
 
769
 
 
770
    # Link it in.
 
771
    &gst_filesys_table_add ($table, $fsi);
 
772
  }
 
773
 
 
774
  &gst_file_close ($fd);
 
775
  return $table;
 
776
}
 
777
 
 
778
 
 
779
# --- Replacing --- #
 
780
 
 
781
 
 
782
sub gst_filesys_fstab_get_next_entry_line  # $infd, $outfd
 
783
{
 
784
  my ($infd, $outfd) = @_;
 
785
 
 
786
  while (<$infd>)
 
787
  {
 
788
    # Each line is in the following format:
 
789
    # <device> <mount point> <filesystem> <options> <dump flag> <fsck priority>
 
790
    my @line = split /[ \t]+/, $_;
 
791
    if ($line[0] eq "") { shift @line; }
 
792
    if (@line < 6 || &gst_ignore_line (@line)) { print $outfd $_; next; }
 
793
 
 
794
    return $_;
 
795
  }
 
796
 
 
797
  return undef;
 
798
}
 
799
 
 
800
sub gst_filesys_fstab_get_entry_line_fields  # line
 
801
{
 
802
  my ($line) = @_;
 
803
 
 
804
  # Remove leading spaces.
 
805
  $line =~ s/^[ \t]*//;
 
806
 
 
807
  # Remove trailing spaces and comments.
 
808
  $line =~ s/[ \t]*\#.*//;
 
809
 
 
810
  return split /[ \t]+/, $line;
 
811
}
 
812
 
 
813
sub gst_filesys_fstab_get_entry_line_comments  # line
 
814
{
 
815
}
 
816
 
 
817
sub gst_filesys_info_print_options       # filesys_info
 
818
{
 
819
  my ($info) = @_;
 
820
  my $optstring = "";
 
821
  my $opthash;
 
822
 
 
823
  $opthash = $$info{'options'};
 
824
 
 
825
  for $option (keys (%$opthash))
 
826
  {
 
827
    if ($optstring) { $optstring .= ","; }
 
828
    $optstring .= $option;
 
829
    if ($info->{'options'}{$option})
 
830
    {
 
831
      $optstring .= "=" . $info->{'options'}{$option};
 
832
      $optstring =~ s/ //;
 
833
    }
 
834
  }
 
835
 
 
836
  if ($optstring eq "")
 
837
  {
 
838
    $optstring = "defaults";
 
839
  }
 
840
 
 
841
  return $optstring;
 
842
}
 
843
 
 
844
sub gst_filesys_info_print_device
 
845
{
 
846
  my ($info) = @_;
 
847
  my $device;
 
848
 
 
849
  if (&gst_filesys_info_get_label ($info))
 
850
  {
 
851
    $device = "LABEL=" . &gst_filesys_info_get_label ($info);
 
852
  }
 
853
  elsif (&gst_filesys_info_get_uuid ($info))
 
854
  {
 
855
    $device = "UUID=" . &gst_filesys_info_get_uuid ($info);
 
856
  }
 
857
  elsif (&gst_filesys_info_get_network_host ($info) &&
 
858
         &gst_filesys_info_get_network_path ($info))
 
859
  {
 
860
    if (&gst_filesys_info_get_fs ($info) eq "smbfs")
 
861
    {
 
862
      $device = "//" . &gst_filesys_info_get_network_host ($info)
 
863
                     . &gst_filesys_info_get_network_path ($info);
 
864
    }
 
865
    else
 
866
    {
 
867
      $device = &gst_filesys_info_get_network_host ($info) . ":" .
 
868
              &gst_filesys_info_get_network_path ($info);
 
869
    }
 
870
  }
 
871
  else
 
872
  {
 
873
    $device = &gst_filesys_info_get_device ($info);
 
874
  }
 
875
 
 
876
  return $device;
 
877
}
 
878
 
 
879
sub gst_filesys_info_print_entry
 
880
{
 
881
  my ($info) = @_;
 
882
  my $line;
 
883
 
 
884
  # <device>
 
885
 
 
886
  $line = sprintf ("%-23s", &gst_filesys_info_print_device ($info));
 
887
 
 
888
  # <mount point>
 
889
 
 
890
  if (&gst_filesys_info_get_point ($info))
 
891
  {
 
892
    $line .= sprintf ("%-24s", (" " . &gst_filesys_info_get_point ($info))) . " ";
 
893
  }
 
894
  else
 
895
  {
 
896
    $line .= sprintf ("%-24s", (" none")) . " ";
 
897
  }
 
898
 
 
899
  # <filesystem> <options> <dump flag> <fsck priority>
 
900
 
 
901
  $line .= sprintf ("%-7s", &gst_filesys_info_get_fs ($info)) . " " .
 
902
           sprintf ("%-15s", &gst_filesys_info_print_options ($info)) . " " .
 
903
           &gst_filesys_info_get_dump ($info) . " " .
 
904
           &gst_filesys_info_get_priority ($info);
 
905
 
 
906
  return $line;
 
907
}
 
908
 
 
909
sub gst_filesys_fstab_add_entry     # filename, filesys_info
 
910
{
 
911
  my ($file, $info) = @_;
 
912
  my ($infd, $outfd);
 
913
  my ($line);
 
914
 
 
915
  ($infd, $outfd) = &gst_file_open_filter_write_from_names ($file);
 
916
  return undef if !$outfd;
 
917
 
 
918
  while (<$infd>) { print $outfd $_; }
 
919
  &gst_file_close ($infd);
 
920
 
 
921
  print $outfd &gst_filesys_info_print_entry ($info) . "\n";
 
922
  &gst_file_close ($outfd);
 
923
}
 
924
 
 
925
sub gst_filesys_fstab_update_entry  # filename, filesys_info
 
926
{
 
927
  my ($file, $info) = @_;
 
928
  my ($infd, $outfd);
 
929
  my ($line);
 
930
  my $replaced = 0;
 
931
 
 
932
  ($infd, $outfd) = &gst_file_open_filter_write_from_names ($file);
 
933
  return undef if !$outfd;
 
934
 
 
935
  while ($line = &gst_filesys_fstab_get_next_entry_line ($infd, $outfd))
 
936
  {
 
937
    my ($device, $point, $fs, $options, $dump, $fsck) = &gst_filesys_fstab_get_entry_line_fields ($line);
 
938
    my ($device, $label, $uuid, $network_host, $network_path) = &gst_filesys_entry_identify ($device, $fs);
 
939
 
 
940
    if (!$replaced && &gst_filesys_info_match ($info, $device, $label, $uuid,
 
941
                                               $network_host, $network_path, $point))
 
942
    {
 
943
      print $outfd &gst_filesys_info_print_entry ($info) . "\n";
 
944
      $replaced = 1;
 
945
    }
 
946
    else
 
947
    {
 
948
      print $outfd $line;
 
949
    }
 
950
  }
 
951
 
 
952
  &gst_file_close ($infd);
 
953
  &gst_file_close ($outfd);
 
954
}
 
955
 
 
956
sub gst_filesys_fstab_remove_entry  # filename, filesys_info
 
957
{
 
958
  my ($file, $info) = @_;
 
959
  my ($infd, $outfd);
 
960
  my ($line);
 
961
 
 
962
  ($infd, $outfd) = &gst_file_open_filter_write_from_names ($file);
 
963
  return undef if !$outfd;
 
964
 
 
965
  while ($line = &gst_filesys_fstab_get_next_entry_line ($infd, $outfd))
 
966
  {
 
967
    my ($device, $point, $fs, $options, $dump, $fsck) = &gst_filesys_fstab_get_entry_line_fields ($line);
 
968
    my ($device, $label, $uuid, $network_host, $network_path) = &gst_filesys_entry_identify ($device, $fs);
 
969
 
 
970
    if (!&gst_filesys_info_match ($info, $device, $label, $uuid, $network_host, $network_path, $point))
 
971
    {
 
972
      print $outfd $line;
 
973
    }
 
974
  }
 
975
 
 
976
  &gst_file_close ($infd);
 
977
  &gst_file_close ($outfd);
 
978
}
 
979
 
 
980
# Replace instances in fstab-style file.
 
981
 
 
982
sub gst_filesys_fstab_replace  # filename, table
 
983
{
 
984
  my ($file, $table) = @_;
 
985
  my ($new_table, $old_table);
 
986
 
 
987
  $old_table = &gst_filesys_fstab_parse ($file);
 
988
  $new_table = &gst_filesys_table_dup ($table);
 
989
 
 
990
  for $info (@$new_table)
 
991
  {
 
992
    my $old_info = &gst_filesys_table_find_info_equivalent ($old_table, $info);
 
993
 
 
994
#    print "Looking for entry - ";
 
995
    if (&gst_filesys_info_get_permanent ($info) && !$old_info)
 
996
    {
 
997
#      print "adding.\n";
 
998
      &gst_filesys_fstab_add_entry ($file, $info);
 
999
    }
 
1000
    elsif (!&gst_filesys_info_get_permanent ($info) && $old_info)
 
1001
    {
 
1002
#      print "removing.\n";
 
1003
      &gst_filesys_fstab_remove_entry ($file, $info);
 
1004
    }
 
1005
    elsif ($old_info && !&gst_filesys_info_match_data ($old_info, $info))
 
1006
    {
 
1007
#      print "updating.\n";
 
1008
      &gst_filesys_fstab_update_entry ($file, $info);
 
1009
    }
 
1010
    else
 
1011
    {
 
1012
#      print "found.\n";
 
1013
    }
 
1014
  }
 
1015
 
 
1016
#  print "---\n";
 
1017
 
 
1018
  for $old_info (@$old_table)
 
1019
  {
 
1020
#    print "Looking for entry - ";
 
1021
    if (!&gst_filesys_table_find_info_equivalent ($new_table, $old_info))
 
1022
    {
 
1023
#      print "removing.\n";
 
1024
      &gst_filesys_fstab_remove_entry ($file, $old_info);
 
1025
    }
 
1026
    else
 
1027
    {
 
1028
#      print "found.\n";
 
1029
    }
 
1030
  }
 
1031
}
 
1032
 
 
1033
 
 
1034
# --- Mounting --- #
 
1035
 
 
1036
 
 
1037
sub gst_filesys_mount_on
 
1038
{
 
1039
  my ($info) = @_;
 
1040
  my ($dev, $point, $fs);
 
1041
 
 
1042
  $dev   = &gst_filesys_info_print_device ($info);
 
1043
  $point = &gst_filesys_info_get_point ($info);
 
1044
 
 
1045
  &gst_report_enter ();
 
1046
  &gst_report ("filesys_mount", $dev, $point);
 
1047
 
 
1048
  $fs = &gst_filesys_info_get_fs ($info);
 
1049
  $fs = "auto" if ($fs eq "");
 
1050
 
 
1051
  if (&gst_file_run ("mount -t " . $fs . " -o " . &gst_filesys_info_print_options ($info) . " " .
 
1052
                     $dev . " " . $point))
 
1053
  {
 
1054
    &gst_report ("filesys_mount_failed", $dev, $point);
 
1055
  }
 
1056
 
 
1057
  &gst_report_leave ();
 
1058
}
 
1059
 
 
1060
sub gst_filesys_mount_off
 
1061
{
 
1062
  my ($info) = @_;
 
1063
  my ($dev, $point);
 
1064
 
 
1065
  $dev   = &gst_filesys_info_print_device ($info);
 
1066
  $point = &gst_filesys_info_get_point ($info);
 
1067
 
 
1068
  &gst_report_enter ();
 
1069
  &gst_report ("filesys_unmount", $dev, $point);
 
1070
 
 
1071
  if (&gst_file_run ("umount -f " . $point))
 
1072
  {
 
1073
    &gst_report ("filesys_unmount_failed", $dev, $point);
 
1074
  }
 
1075
 
 
1076
  &gst_report_leave ();
 
1077
}
 
1078
 
 
1079
sub gst_filesys_mount_sync_all
 
1080
{
 
1081
  my ($fstab_file, $mtab_file, $new_table) = @_;
 
1082
  my ($mount_table, $fs_table);
 
1083
 
 
1084
  $fs_table    = &gst_filesys_fstab_parse ($fstab_file);
 
1085
  $mount_table = &gst_filesys_mtab_parse  ($mtab_file);
 
1086
 
 
1087
  for $info (@$new_table)
 
1088
  {
 
1089
    my $mounted_info = &gst_filesys_table_find_info_equivalent ($mount_table, $info);
 
1090
 
 
1091
    if ($mounted_info && !&gst_filesys_info_get_mounted ($info))
 
1092
    {
 
1093
      &gst_filesys_mount_off ($mounted_info);
 
1094
    }
 
1095
    elsif (!$mounted_info && &gst_filesys_info_get_mounted ($info))
 
1096
    {
 
1097
      # If the mount has an fstab entry, we prefer that over the information
 
1098
      # provided by XML.
 
1099
 
 
1100
      my $fs_info = &gst_filesys_table_find_info_equivalent ($fs_table, $info);  
 
1101
 
 
1102
      if ($fs_info)
 
1103
      {
 
1104
        &gst_filesys_mount_on ($fs_info);
 
1105
      }
 
1106
      else
 
1107
      {
 
1108
        &gst_filesys_mount_on ($info);
 
1109
      }
 
1110
    }
 
1111
  }
 
1112
}
 
1113
 
 
1114
 
 
1115
1;