40932377a45af06e8d9073e9a4688faad5a71d9f
[openafs.git] / src / tests / fs.pm
1 # CMUCS AFStools
2 # Copyright (c) 1996, 2001 Carnegie Mellon University
3 # All rights reserved.
4 #
5 # See CMU_copyright.ph for use and distribution information
6 #
7 #: * fs.pm - Wrappers around the FS commands (fileserver/cache manager)
8 #: * This module provides wrappers around the various FS commands, which
9 #: * perform fileserver and cache manager control operations.  Right now,
10 #: * these are nothing more than wrappers around 'fs'; someday, we might
11 #: * talk to the cache manager directly, but not anytime soon.
12 #:
13
14 package OpenAFS::fs;
15 use OpenAFS::CMU_copyright;
16 use OpenAFS::util qw(:DEFAULT :afs_internal);
17 use OpenAFS::wrapper;
18 use Exporter;
19
20 $VERSION   = '';
21 $VERSION   = '1.00';
22 @ISA       = qw(Exporter);
23 @EXPORT    = qw(&AFS_fs_getacl          &AFS_fs_setacl
24                 &AFS_fs_cleanacl        &AFS_fs_getquota
25                 &AFS_fs_setquota        &AFS_fs_whereis
26                 &AFS_fs_examine         &AFS_fs_setvol
27                 &AFS_fs_getmount        &AFS_fs_mkmount
28                 &AFS_fs_rmmount         &AFS_fs_checkvolumes
29                 &AFS_fs_flush           &AFS_fs_flushmount
30                 &AFS_fs_flushvolume     &AFS_fs_messages
31                 &AFS_fs_newcell         &AFS_fs_rxstatpeer
32                 &AFS_fs_rxstatproc      &AFS_fs_setcachesize
33                 &AFS_fs_setcell         &AFS_fs_setcrypt
34                 &AFS_fs_setclientaddrs  &AFS_fs_copyacl
35                 &AFS_fs_storebehind     &AFS_fs_setserverprefs
36                 &AFS_fs_checkservers    &AFS_fs_checkservers_interval
37                 &AFS_fs_exportafs       &AFS_fs_getcacheparms
38                 &AFS_fs_getcellstatus   &AFS_fs_getclientaddrs
39                 &AFS_fs_getcrypt        &AFS_fs_getserverprefs
40                 &AFS_fs_listcells       &AFS_fs_setmonitor
41                 &AFS_fs_getmonitor      &AFS_fs_getsysname
42                 &AFS_fs_setsysname      &AFS_fs_whichcell
43                 &AFS_fs_wscell);
44
45 #: ACL-management functions:
46 #: AFS access control lists are represented as a Perl list (or usually, a
47 #: reference to such a list).  Each element in such a list corresponds to
48 #: a single access control entry, and is a reference to a 2-element list
49 #: consisting of a PTS entity (name or ID), and a set of rights.  The
50 #: rights are expressed in the usual publically-visible AFS notation, as
51 #: a string of characters drawn from the class [rlidwkaABCDEFGH].  No
52 #: rights are denoted by the empty string; such an ACE will never returned
53 #: by this library, but may be used as an argument to remove a particular
54 #: ACE from a directory's ACL.
55 #:
56 #: One might be inclined to ask why we chose this representation, instead of
57 #: using an associative array, as might seem obvious.  The answer is that
58 #: doing so would have implied a nonambiguity that isn't there.  Suppose you
59 #: have an ACL %x, and want to know if there is an entry for user $U on that
60 #: list.  You might think you could do this by looking at $x{$U}.  The
61 #: problem here is that two values for $U (one numeric and one not) refer to
62 #: the same PTS entity, even though they would reference different elements
63 #: in such an ACL.  So, we instead chose a representation that wasn't a hash,
64 #: so people wouldn't try to do hash-like things to it.  If you really want
65 #: to be able to do hash-like operations, you should turn the list-form ACL
66 #: into a hash table, and be sure to do name-to-number translation on all the
67 #: keys as you go.
68 #:
69 #: AFS_fs_getacl($path)
70 #: Get the ACL on a specified path.
71 #: On success, return a list of two references to ACLs; the first is the
72 #: positive ACL for the specified path, and the second is the negative ACL.
73 #:
74 $AFS_Help{fs_getacl} = '$path => (\@posacl, \@negacl)';
75 sub AFS_fs_getacl {
76   my($path) = @_;
77   my(@args, @posacl, @negacl, $neg);
78
79   @args = ('listacl', '-path', $path);
80   &wrapper('fs', \@args,
81            [
82             [ '^(Normal|Negative) rights\:', sub {
83               $neg = ($_[0] eq 'Negative');
84             }],
85             [ '^  (.*) (\S+)$', sub { #',{
86               if ($neg) {
87                 push(@negacl, [@_]);
88               } else {
89                 push(@posacl, [@_]);
90               }
91             }]]);
92   (\@posacl, \@negacl);
93 }
94
95 #: AFS_fs_setacl(\@paths, \@posacl, \@negacl, [$clear])
96 #: Set the ACL on a specified path.  Like the 'fs setacl' command, this
97 #: function normally only changes ACEs that are mentioned in one of the two
98 #: argument lists.  If a given ACE already exists, it is changed; if not, it
99 #: is added.  To delete a single ACE, specify the word 'none' or the empty
100 #: string in the rights field.  ACEs that already exist but are not mentioned
101 #: are left untouched, unless $clear is specified.  In that case, all
102 #: existing ACE's (both positive and negative) are deleted.
103 $AFS_Help{fs_setacl} = '\@paths, \@posacl, \@negacl, [$clear] => Success?';
104 sub AFS_fs_setacl {
105   my($paths, $posacl, $negacl, $clear) = @_;
106   my($ace, $U, $access);
107
108   if (@$posacl) {
109     @args = ('setacl', '-dir', @$paths);
110     push(@args, '-clear') if ($clear);
111     push(@args, '-acl');
112     foreach $e (@$posacl) {
113       ($U, $access) = @$e;
114       $access = 'none' if ($access eq '');
115       push(@args, $U, $access);
116     }
117     &wrapper('fs', \@args);
118   }
119   if (@$negacl) {
120     @args = ('setacl', '-dir', @$paths, '-negative');
121     push(@args, '-clear') if ($clear && !@$posacl);
122     push(@args, '-acl');
123     foreach $e (@$negacl) {
124       ($U, $access) = @$e;
125       $access = 'none' if ($access eq '');
126       push(@args, $U, $access);
127     }
128     &wrapper('fs', \@args);
129   }
130   if ($clear && !@$posacl && !@$negacl) {
131     @args = ('setacl', '-dir', @$paths,
132              '-acl', 'system:anyuser', 'none', '-clear');
133     &wrapper('fs', \@args);
134   }
135   1;
136 }
137
138 #: AFS_fs_cleanacl(\@paths)
139 #: Clean the ACL on the specified path, removing any ACEs which refer to PTS
140 #: entities that no longer exist.  All the work is done by 'fs'.
141 #:
142 $AFS_Help{'fs_cleanacl'} = '\@paths => Success?';
143 sub AFS_fs_cleanacl {
144   my($paths) = @_;
145   my(@args);
146
147   @args = ('cleanacl', '-path', @$paths);
148   &wrapper('fs', \@args);
149   1;
150 }
151
152 #: AFS_fs_getquota($path) [listquota]
153 #: Get the quota on the specified path.
154 #: On success, returns the quota.
155 #:
156 $AFS_Help{'fs_getquota'} = '$path => $quota';
157 sub AFS_fs_getquota {
158   my($path) = @_;
159   my(@args, $quota);
160
161   @args = ('listquota', '-path', $path);
162   &wrapper('fs', \@args,
163            [[ '^\S+\s+(\d+)\s+\d+\s+\d+\%', \$quota ]]);
164   $quota;
165 }
166
167 #: AFS_fs_setquota($path, $quota) [setquota]
168 #: Set the quota on the specified path to $quota.  If $quota is
169 #: given as 0, there will be no limit to the volume's size.
170 #: On success, return 1
171 #:
172 $AFS_Help{'fs_setquota'} = '$path, $quota => Success?';
173 sub AFS_fs_setquota {
174   my($path, $quota) = @_;
175   my(@args);
176
177   @args = ('setquota', '-path', $path, '-max', $quota);
178   &wrapper('fs', \@args);
179   1;
180 }
181
182 #: AFS_fs_whereis($path)  [whereis, whichcell]
183 #: Locate the fileserver housing the specified path, and the cell in which it
184 #: is located.
185 #: On success, returns a list of 2 or more elements.  The first element is the
186 #: name of the cell in which the volume is located.  The remaining elements
187 #: the names of servers housing the volume; for a replicated volume, there may
188 #: (should) be more than one such server.
189 #:
190 $AFS_Help{'fs_whereis'} = '$path => ($cell, @servers)';
191 sub AFS_fs_whereis {
192   my($path) = @_;
193   my(@args, $cell, @servers);
194
195   @args = ('whichcell', '-path', $path);
196   &wrapper('fs', \@args,
197            [[ "lives in cell \'(.*)\'", \$cell ]]);
198
199   @args = ('whereis', '-path', $path);
200   &wrapper('fs', \@args,
201            [[ 'is on host(s?)\s*(.*)', sub {
202              @servers = split(' ', $_[1]);
203            }]]);
204   ($cell, @servers);
205 }
206
207 #: AFS_fs_examine($path)
208 #: Get information about the volume containing the specified path.
209 #: On success, return an associative array containing some or all
210 #: of the following elements:
211 #: - vol_name
212 #: - vol_id
213 #: - quota_max
214 #: - quota_used
215 #: - quota_pctused
216 #: - part_size
217 #: - part_avail
218 #: - part_used
219 #: - part_pctused
220 #:
221 $AFS_Help{'fs_examine'} = '$path => %info';
222 sub AFS_fs_examine {
223   my($path) = @_;
224   my(@args, %info);
225
226   @args = ('examine', '-path', $path);
227   %info = &wrapper('fs', \@args,
228                    [[ 'vid = (\d+) named (\S+)',       'vol_id', 'vol_name' ],
229                     [ 'disk quota is (\d+|unlimited)', 'quota_max' ],
230                     [ 'blocks used are (\d+)',         'quota_used' ],
231                     [ '(\d+) blocks available out of (\d+)',
232                      'part_avail', 'part_size']]);
233   if ($info{'quota_max'} eq 'unlimited') {
234     $info{'quota_max'} = 0;
235     $info{'quota_pctused'} = 0;
236   } else {
237     $info{'quota_pctused'} = ($info{'quota_used'} / $info{'quota_max'}) * 100;
238     $info{'quota_pctused'} =~ s/\..*//;
239   }
240   $info{'part_used'} = $info{'part_size'} - $info{'part_avail'};
241   $info{'part_pctused'} = ($info{'part_used'} / $info{'part_size'}) * 100;
242   $info{'part_pctused'} =~ s/\..*//;
243   %info;
244 }
245
246 #: AFS_fs_setvol($path, [$maxquota], [$motd])
247 #: Set information about the volume containing the specified path.
248 #: On success, return 1.
249 $AFS_Help{'fs_setvol'} = '$path, [$maxquota], [$motd] => Success?';
250 sub AFS_fs_setvol {
251   my($path, $maxquota, $motd) = @_;
252   my(@args);
253
254   @args = ('setvol', '-path', $path);
255   push(@args, '-max', $maxquota) if ($maxquota || $maxquota eq '0');
256   push(@args, '-motd', $motd) if ($motd);
257   &wrapper('fs', \@args);
258   1;
259 }
260
261
262 #: AFS_fs_getmount($path)
263 #: Get the contents of the specified AFS mount point.
264 #: On success, return the contents of the specified mount point.
265 #: If the specified path is not a mount point, return the empty string.
266 $AFS_Help{'fs_getmount'} = '$path => $vol';
267 sub AFS_fs_getmount {
268   my($path) = @_;
269   my(@args, $vol);
270
271   @args = ('lsmount', '-dir', $path);
272   &wrapper('fs', \@args,
273            [[ "mount point for volume '(.+)'", \$vol ]]);
274   $vol;
275 }
276
277
278 #: AFS_fs_mkmount($path, $vol, [$cell], [$rwmount], [$fast])
279 #: Create an AFS mount point at $path, leading to the volume $vol.
280 #: If $cell is specified, create a cellular mount point to that cell.
281 #: If $rwmount is specified and nonzero, create a read-write mount point.
282 #: If $fast is specified and nonzero, don't check to see if the volume exists.
283 #: On success, return 1.
284 $AFS_Help{'fs_mkmount'} = '$path, $vol, [$cell], [$rwmount], [$fast] => Success?';
285 sub AFS_fs_mkmount {
286   my($path, $vol, $cell, $rwmount, $fast) = @_;
287   my(@args);
288
289   @args = ('mkmount', '-dir', $path, '-vol', $vol);
290   push(@args, '-cell', $cell) if ($cell);
291   push(@args, '-rw') if ($rwmount);
292   push(@args, '-fast') if ($fast);
293   &wrapper('fs', \@args);
294   1;
295 }
296
297 #: AFS_fs_rmmount($path) [rmmount]
298 #: Remove an AFS mount point at $path
299 #: On success, return 1
300 $AFS_Help{'fs_rmmount'} = '$path => Success?';
301 sub AFS_fs_rmmount {
302   my($path) = @_;
303   my(@args);
304
305   @args = ('rmmount', '-dir', $path);
306   &wrapper('fs', \@args);
307   1;
308 }
309
310 #: AFS_fs_checkvolumes()
311 #: Check/update volume ID cache
312 #: On success, return 1
313 $AFS_Help{'fs_checkvolumes'} = '=> Success?';
314 sub AFS_fs_checkvolumes {
315   my(@args);
316
317   @args = ('checkvolumes');
318   &wrapper('fs', \@args);
319   1;
320 }
321
322 #: AFS_fs_flush(\@paths)
323 #: Flush files named by @paths from the cache
324 #: On success, return 1
325 $AFS_Help{'fs_flush'} = '\@paths => Success?';
326 sub AFS_fs_flush {
327   my($paths) = @_;
328   my(@args);
329
330   @args = ('flush');
331   push(@args, '-path', @$paths) if $paths;
332   &wrapper('fs', \@args);
333   1;
334 }
335
336 #: AFS_fs_flushmount(\@paths)
337 #: Flush mount points named by @paths from the cache
338 #: On success, return 1
339 $AFS_Help{'fs_flushmount'} = '\@paths => Success?';
340 sub AFS_fs_flushmount {
341   my($paths) = @_;
342   my(@args);
343
344   @args = ('flushmount');
345   push(@args, '-path', @$paths) if $paths;
346   &wrapper('fs', \@args);
347   1;
348 }
349
350 #: AFS_fs_flushvolume(\@paths)
351 #: Flush volumes containing @paths from the cache
352 #: On success, return 1
353 $AFS_Help{'fs_flushvolume'} = '\@paths => Success?';
354 sub AFS_fs_flushvolume {
355   my($paths) = @_;
356   my(@args);
357
358   @args = ('flushvolume');
359   push(@args, '-path', @$paths) if $paths;
360   &wrapper('fs', \@args);
361   1;
362 }
363
364 #: AFS_fs_messages($mode)
365 #: Set cache manager message mode
366 #: Valid modes are 'user', 'console', 'all', 'none'
367 #: On success, return 1
368 $AFS_Help{'fs_messages'} = '$mode => Success?';
369 sub AFS_fs_messages {
370   my($mode) = @_;
371   my(@args);
372
373   @args = ('messages', '-show', $mode);
374   &wrapper('fs', \@args);
375   1;
376 }
377
378 #: AFS_fs_newcell($cell, \@dbservers, [$linkedcell])
379 #: Add a new cell to the cache manager's list, or updating an existing cell
380 #: On success, return 1
381 $AFS_Help{'fs_newcell'} = '$cell, \@dbservers, [$linkedcell] => Success?';
382 sub AFS_fs_newcell {
383   my($cell, $dbservers, $linkedcell) = @_;
384   my(@args);
385
386   @args = ('newcell', '-name', $cell, '-servers', @$dbservers);
387   push(@args, '-linkedcell', $linkedcell) if $linkedcell;
388   &wrapper('fs', \@args);
389   1;
390 }
391
392 #: AFS_fs_rxstatpeer($enable, [$clear])
393 #: Control per-peer Rx statistics:
394 #: - if $enable is 1, enable stats
395 #: - if $enable is 0, disable stats
396 #: - if $clear  is 1, clear stats
397 #: On success, return 1
398 $AFS_Help{'fs_rxstatpeer'} = '$enable, [$clear] => Success?';
399 sub AFS_fs_rxstatpeer {
400   my($enable, $clear) = @_;
401   my(@args);
402
403   @args = ('rxstatpeer');
404   push(@args, '-enable')  if $enable;
405   push(@args, '-disable') if defined($enable) && !$enable;
406   push(@args, '-clear')   if $clear;
407   &wrapper('fs', \@args);
408   1;
409 }
410
411 #: AFS_fs_rxstatproc($enable, [$clear])
412 #: Control per-process Rx statistics:
413 #: - if $enable is 1, enable stats
414 #: - if $enable is 0, disable stats
415 #: - if $clear  is 1, clear stats
416 #: On success, return 1
417 $AFS_Help{'fs_rxstatproc'} = '$enable, [$clear] => Success?';
418 sub AFS_fs_rxstatproc {
419   my($enable, $clear) = @_;
420   my(@args);
421
422   @args = ('rxstatproc');
423   push(@args, '-enable')  if $enable;
424   push(@args, '-disable') if defined($enable) && !$enable;
425   push(@args, '-clear')   if $clear;
426   &wrapper('fs', \@args);
427   1;
428 }
429
430 #: AFS_fs_setcachesize($size)
431 #: Set the cache size to $size K
432 #: On success, return 1
433 $AFS_Help{'fs_setcachesize'} = '$size => Success?';
434 sub AFS_fs_setcachesize {
435   my($size) = @_;
436   my(@args);
437
438   @args = ('setcachesize', '-blocks', $size);
439   &wrapper('fs', \@args);
440   1;
441 }
442
443 #: AFS_fs_setcell(\@cells, $suid)
444 #: Set cell control bits for @cells
445 #: - if $suid is 1, enable suid programs
446 #: - if $suid is 0, disable suid programs
447 #: On success, return 1
448 $AFS_Help{'fs_setcell'} = '\@cells, [$suid] => Success?';
449 sub AFS_fs_setcell {
450   my($cells, $suid) = @_;
451   my(@args);
452
453   @args = ('setcell', '-cell', @$cells);
454   push(@args, '-suid')   if $suid;
455   push(@args, '-nosuid') if defined($suid) && !$suid;
456   &wrapper('fs', \@args);
457   1;
458 }
459
460 #: AFS_fs_setcrypt($enable)
461 #: Control cache manager encryption
462 #: - if $enable is 1, enable encrypted connections
463 #: - if $enable is 0, disable encrypted connections
464 #: On success, return 1
465 $AFS_Help{'fs_setcrypt'} = '$enable => Success?';
466 sub AFS_fs_setcrypt {
467   my($enable) = @_;
468   my(@args);
469
470   @args = ('setcrypt', '-crypt', $enable ? 'on' : 'off');
471   &wrapper('fs', \@args);
472   1;
473 }
474
475 #: AFS_fs_setclientaddrs(\@addrs)
476 #: Set client network interface addresses
477 #: On success, return 1
478 $AFS_Help{'fs_setclientaddrs'} = '\@addrs => Success?';
479 sub AFS_fs_setclientaddrs {
480   my($addrs) = @_;
481   my(@args);
482
483   @args = ('setclientaddrs');
484   push(@args, '-address', @$addrs) if $addrs;
485   &wrapper('fs', \@args);
486   1;
487 }
488
489 #: AFS_fs_copyacl($from, \@to, [$clear])
490 #: Copy the access control list on $from to each directory named in @to.
491 #: If $clear is specified and nonzero, the target ACL's are cleared first
492 #: On success, return 1
493 $AFS_Help{'fs_copyacl'} = '$from, \@to, [$clear] => Success?';
494 sub AFS_fs_copyacl {
495   my($from, $to, $clear) = @_;
496   my(@args);
497
498   @args = ('copyacl', '-fromdir', $from, '-todir', @$to);
499   push(@args, '-clear') if $clear;
500   &wrapper('fs', \@args);
501   1;
502 }
503
504 #: AFS_fs_storebehind(\@paths, [$size], [$def])
505 #: Set amount of date to store after file close
506 #: If $size is specified, the size for each file in @paths is set to $size.
507 #: If $default is specified, the default size is set to $default.
508 #: Returns the new or current default value, and a hash mapping filenames
509 #: to their storebehind sizes.  A hash entry whose value is undef indicates
510 #: that the corresponding file will use the default size.
511 $AFS_Help{'fs_storebehind'} = '\@paths, [$size], [$def] => ($def, \%sizes)';
512 sub AFS_fs_storebehind {
513   my($paths, $size, $def) = @_;
514   my(@args, %sizes, $ndef);
515
516   @args = ('storebehind', '-verbose');
517   push(@args, '-kbytes', $size) if defined($size);
518   push(@args, '-files', @$paths) if $paths && @$paths;
519   push(@args, '-allfiles', $def) if defined($def);
520   &wrapper('fs', \@args, [
521     ['^Will store up to (\d+) kbytes of (.*) asynchronously',
522      sub { $sizes{$_[1]} = $_[0] }],
523     ['^Will store (.*) according to default',
524      sub { $sizes{$_[0]} = undef }],
525     ['^Default store asynchrony is (\d+) kbytes', \$ndef],
526   ]);
527   ($ndef, \%sizes);
528 }
529
530 #: AFS_fs_setserverprefs(\%fsprefs, \%vlprefs)
531 #: Set fileserver and/or VLDB server preference ranks
532 #: Each of %fsprefs and %vlprefs maps server names to the rank to be
533 #: assigned to the specified servers.
534 #: On success, return 1.
535 $AFS_Help{'fs_setserverprefs'} = '\%fsprefs, \%vlprefs => Success?';
536 sub AFS_fs_setserverprefs {
537   my($fsprefs, $vlprefs) = @_;
538   my(@args, $srv);
539
540   @args = ('setserverprefs');
541   if ($fsprefs && %$fsprefs) {
542     push(@args, '-servers');
543     foreach $srv (keys %$fsprefs) {
544       push(@args, $srv, $$fsprefs{$srv});
545     }
546   }
547   if ($vlprefs && %$vlprefs) {
548     push(@args, '-vlservers');
549     foreach $srv (keys %$vlprefs) {
550       push(@args, $srv, $$vlprefs{$srv});
551     }
552   }
553   &wrapper('fs', \@args);
554   1;
555 }
556
557 #: AFS_fs_checkservers([$fast], [$allcells], [$cell])
558 #: Check to see what fileservers are down
559 #: If $cell is specified, fileservers in the specified cell are checked
560 #: If $allcells is specified and nonzero, fileservers in all cells are checked
561 #: If $fast is specified and nonzero, don't probe servers
562 $AFS_Help{'fs_checkservers'} = '[$fast], [$allcells], [$cell] => @down';
563 sub AFS_fs_checkservers {
564   my($fast, $allcells, $cell) = @_;
565   my(@args, @down);
566
567   @args = ('checkservers');
568   push(@args, '-all')         if $allcells;
569   push(@args, '-fast')        if $fast;
570   push(@args, '-cell', $cell) if $cell;
571   &wrapper('fs', \@args, [
572     ['^These servers unavailable due to network or server problems: (.*)\.',
573      sub { push(@down, split(' ', $_[0])) }],
574   ]);
575   @down;
576 }
577
578 #: AFS_fs_checkservers_interval([$interval])
579 #: Get and/or set the down server check interval
580 #: If $interval is specified and nonzero, it is set as the new interval
581 #: On success, returns the old interval in seconds
582 $AFS_Help{'fs_checkservers_interval'} = '$interval => $oldinterval';
583 sub AFS_fs_checkservers_interval {
584   my($interval) = @_;
585   my(@args, $oldinterval);
586
587   @args = ('checkservers', '-interval', $interval);
588   &wrapper('fs', \@args, [
589     ['^The new down server probe interval \((\d+) secs\)',    \$oldinterval],
590     ['^The current down server probe interval is (\d+) secs', \$oldinterval],
591   ]);
592   $oldinterval;
593 }
594
595 #: AFS_fs_exportafs($type, \%options);
596 #: Get and/or modify protocol translator settings
597 #: $type is the translator type, which must be 'nfs'
598 #: %options specifies the options to be set.  Each key is the name of an
599 #: option, which is enabled if the value is 1, and disabled if the value
600 #: is 0.  The following options are supported:
601 #:   start       Enable exporting of AFS
602 #:   convert     Copy AFS owner mode bits to UNIX group/other mode bits
603 #:   uidcheck    Strict UID checking
604 #:   submounts   Permit mounts of /afs subdirectories
605 #: On success, returns an associative array %modes, which is of the same
606 #: form, indicating which options are enabled.
607 $AFS_Help{'fs_exportafs'} = '$type, \%options => %modes';
608 sub AFS_fs_exportafs {
609   my($type, $options) = @_;
610   my(@args, %modes);
611
612   @args = ('exportafs', '-type', $type);
613   foreach (qw(start convert uidcheck submounts)) {
614     push(@args, "-$_", $$options{$_} ? 'on' : 'off') if exists($$options{$_});
615   }
616
617   &wrapper('fs', \@args, [
618     ['translator is disabled',  sub { $modes{'start'}     = 0 }],
619     ['translator is enabled',   sub { $modes{'start'}     = 1 }],
620     ['strict unix',             sub { $modes{'convert'}   = 0 }],
621     ['convert owner',           sub { $modes{'convert'}   = 1 }],
622     [q/no 'passwd sync'/,       sub { $modes{'uidcheck'}  = 0 }],
623     [q/strict 'passwd sync'/,   sub { $modes{'uidcheck'}  = 1 }],
624     ['Only mounts',             sub { $modes{'submounts'} = 0 }],
625     ['Allow mounts',            sub { $modes{'submounts'} = 1 }],
626   ]);
627   %modes;
628 }
629
630
631 #: AFS_fs_getcacheparms()
632 #: Returns the size of the cache, and the amount of cache space used.
633 #: Sizes are returned in 1K blocks.
634 $AFS_Help{'fs_getcacheparms'} = 'void => ($size, $used)';
635 sub AFS_fs_getcacheparms {
636   my(@args, $size, $used);
637
638   @args = ('getcacheparms');
639   &wrapper('fs', \@args, [
640     [q/AFS using (\d+) of the cache's available (\d+) 1K byte blocks/,
641      \$used, \$size],
642   ]);
643   ($size, $used);
644 }
645
646 #: AFS_fs_getcellstatus(\@cells)
647 #: Get cell control bits for cells listed in @cells.
648 #: On success, returns a hash mapping cells to their status; keys are
649 #: cell names, and values are 1 if SUID programs are permitted for that
650 #: cell, and 0 if not.
651 $AFS_Help{'fs_getcellstatus'} = '\@cells => %status';
652 sub AFS_fs_getcellstatus {
653   my($cells) = @_;
654   my(@args, %status);
655
656   @args = ('getcellstatus', '-cell', @$cells);
657   &wrapper('fs', \@args, [
658     ['Cell (.*) status: setuid allowed',    sub { $status{$_[0]} = 1 }],
659     ['Cell (.*) status: no setuid allowed', sub { $status{$_[0]} = 0 }],
660   ]);
661   %status;
662 }
663
664 #: AFS_fs_getclientaddrs
665 #: Returns a list of the client interface addresses
666 $AFS_Help{'fs_getclientaddrs'} = 'void => @addrs';
667 sub AFS_fs_getclientaddrs {
668   my(@args, @addrs);
669
670   @args = ('getclientaddrs');
671   &wrapper('fs', \@args, [
672     ['^(\d+\.\d+\.\d+\.\d+)', \@addrs ]
673   ]);
674   @addrs;
675 }
676
677 #: AFS_fs_getcrypt
678 #: Returns the cache manager encryption flag
679 $AFS_Help{'fs_getcrypt'} = 'void => $crypt';
680 sub AFS_fs_getcrypt {
681   my(@args, $crypt);
682
683   @args = ('getcrypt');
684   &wrapper('fs', \@args, [
685     ['^Security level is currently clear', sub { $crypt = 0 }],
686     ['^Security level is currently crypt', sub { $crypt = 1 }],
687   ]);
688   $crypt;
689 }
690
691 #: AFS_fs_getserverprefs([$vlservers], [$numeric])
692 #: Get fileserver or vlserver preference ranks
693 #: If $vlservers is specified and nonzero, VLDB server ranks
694 #: are retrieved; otherwise fileserver ranks are retrieved.
695 #: If $numeric is specified and nonzero, servers are identified
696 #: by IP address instead of by hostname.
697 #: Returns a hash whose keys are server names or IP addresses, and
698 #: whose values are the ranks of those servers.
699 $AFS_Help{'fs_getserverprefs'} = '[$vlservers], [$numeric] => %prefs';
700 sub AFS_fs_getserverprefs {
701   my($vlservers, $numeric) = @_;
702   my(@args, %prefs);
703
704   @args = ('getserverprefs');
705   push(@args, '-numeric')   if $numeric;
706   push(@args, '-vlservers') if $vlservers;
707   &wrapper('fs', \@args, [
708     ['^(\S+)\s*(\d+)', \%prefs],
709   ]);
710   %prefs;
711 }
712
713 #: AFS_fs_listcells([$numeric')
714 #: Get a list of cells known to the cache manager, and the VLDB
715 #: servers for each cell.
716 #: If $numeric is specified and nonzero, VLDB servers are identified
717 #: by IP address instead of by hostname.
718 #: Returns a hash where each key is a cell name, and each value is
719 #: a list of VLDB servers for the corresponding cell.
720 $AFS_Help{'fs_listcells'} = '[$numeric] => %cells';
721 sub AFS_fs_listcells {
722   my($numeric) = @_;
723   my(@args, %cells);
724
725   @args = ('listcells');
726   push(@args, '-numeric') if $numeric;
727   &wrapper('fs', \@args, [
728     ['^Cell (\S+) on hosts (.*)\.',
729       sub { $cells{$_[0]} = [ split(' ', $_[1]) ] }],
730   ]);
731   %cells;
732 }
733
734 #: AFS_fs_setmonitor($server)
735 #: Set the cache manager monitor host to $server.
736 #: If $server is 'off' or undefined, monitoring is disabled.
737 #: On success, return 1.
738 $AFS_Help{'fs_setmonitor'} = '$server => Success?';
739 sub AFS_fs_setmonitor {
740   my($server) = @_;
741   my(@args);
742
743   @args = ('monitor', '-server', defined($server) ? $server : 'off');
744   &wrapper('fs', \@args);
745   1;
746 }
747
748 #: AFS_fs_getmonitor
749 #: Return the cache manager monitor host, or undef if monitoring is disabled.
750 $AFS_Help{'fs_getmonitor'} = 'void => $server';
751 sub AFS_fs_getmonitor {
752   my(@args, $server);
753
754   @args = ('monitor');
755   &wrapper('fs', \@args, [
756     ['Using host (.*) for monitor services\.', \$server],
757   ]);
758   $server;
759 }
760
761 #: AFS_fs_getsysname
762 #: Returns the current list of system type names
763 $AFS_Help{'fs_getsysname'} = 'void => @sys';
764 sub AFS_fs_getsysname {
765   my(@args, @sys);
766
767   @args = ('sysname');
768   &wrapper('fs', \@args, [
769     [q/Current sysname is '(.*)'/, \@sys],
770     [q/Current sysname list is '(.*)'/,
771       sub { push(@sys, split(q/' '/, $_[0])) }],
772   ]);
773   @sys;
774 }
775
776 #: AFS_fs_setsysname(\@sys)
777 #: Sets the system type list to @sys
778 #: On success, return 1.
779 $AFS_Help{'fs_setsysname'} = '$server => Success?';
780 sub AFS_fs_setsysname {
781   my($sys) = @_;
782   my(@args);
783
784   @args = ('sysname', '-newsys', @$sys);
785   &wrapper('fs', \@args);
786   1;
787 }
788
789 #: AFS_fs_whichcell(\@paths)
790 #: Get the cells containing the specified paths
791 #: Returns a hash in which each key is a pathname, and each value
792 #: is the name of the cell which contains the corresponding file.
793 $AFS_Help{'fs_whichcell'} = '\@paths => %where';
794 sub AFS_fs_whichcell {
795   my($paths) = @_;
796   my(@args, %where);
797
798   @args = ('whichcell', '-path', @$paths);
799   &wrapper('fs', \@args, [
800     [q/^File (.*) lives in cell '(.*)'/, \%where],
801   ]);
802   %where;
803 }
804
805 #: AFS_fs_wscell
806 #: Returns the name of the workstation's home cell
807 $AFS_Help{'fs_wscell'} = 'void => $cell';
808 sub AFS_fs_wscell {
809   my(@args, $cell);
810
811   @args = ('wscell');
812   &wrapper('fs', \@args, [
813     [q/^This workstation belongs to cell '(.*)'/, \$cell],
814   ]);
815   $cell;
816 }
817