Handle hostnames with upper-case letters
[webmin.git] / mount / netbsd-lib.pl
1 # openbsd-lib.pl
2 # Mount table functions for openbsd
3
4 $uname_release = `uname -r`;
5
6 # Return information about a filesystem, in the form:
7 #  directory, device, type, options, fsck_order, mount_at_boot
8 # If a field is unused or ignored, a - appears instead of the value.
9 # Swap-filesystems (devices or files mounted for VM) have a type of 'swap',
10 # and 'swap' in the directory field
11 sub list_mounts
12 {
13 local(@rv, @p, @o, $_, $i, $j); $i = 0;
14
15 # Get /etc/fstab mounts
16 open(FSTAB, $config{'fstab_file'});
17 while(<FSTAB>) {
18         local(@o, $at_boot);
19         chop; s/#.*$//g;
20         if (!/\S/) { next; }
21         @p = split(/\s+/, $_);
22         if ($p[2] eq "proc" || $p[2] eq "procfs") { $p[2] = $p[0] = "proc"; }
23         if ($p[2] eq "swap") { $p[1] = "swap"; }
24         $rv[$i] = [ $p[1], $p[0], $p[2] ];
25         $rv[$i]->[5] = "yes";
26         @o = split(/,/ , $p[3] eq "defaults" ? "" : $p[3]);
27         if (($j = &indexof("noauto", @o)) >= 0) {
28                 # filesytem is not mounted at boot
29                 splice(@o, $j, 1);
30                 $rv[$i]->[5] = "no";
31                 }
32         $rv[$i]->[3] = (@o ? join(',' , @o) : "-");
33         $rv[$i]->[4] = (@p >= 5 ? $p[5] : 0);
34         $i++;
35         }
36 close(FSTAB);
37 return @rv;
38 }
39
40
41 # create_mount(directory, device, type, options, fsck_order, mount_at_boot)
42 # Add a new entry to the fstab file, old or new automounter file
43 sub create_mount
44 {
45 local(@mlist, @amd, $_); local($opts);
46
47 # Adding a normal mount to the fstab file
48 &open_tempfile(FSTAB, ">>$config{'fstab_file'}");
49 &print_tempfile(FSTAB, "$_[1]  $_[0]  $_[2]");
50 $opts = $_[3] eq "-" ? "" : $_[3];
51 if ($_[5] eq "no") {
52         $opts = join(',' , (split(/,/ , $opts) , "noauto"));
53         }
54 if ($opts eq "") { &print_tempfile(FSTAB, "  defaults"); }
55 else { &print_tempfile(FSTAB, "  $opts"); }
56 &print_tempfile(FSTAB, "  0  ");
57 &print_tempfile(FSTAB, $_[4] eq "-" ? "0\n" : "$_[4]\n");
58 &close_tempfile(FSTAB);
59 }
60
61
62 # change_mount(num, directory, device, type, options, fsck_order, mount_at_boot)
63 # Change an existing permanent mount
64 sub change_mount
65 {
66 local($i, @fstab, $line, $opts, $j, @amd);
67 $i = 0;
68
69 # Update fstab file
70 open(FSTAB, $config{'fstab_file'});
71 @fstab = <FSTAB>;
72 close(FSTAB);
73 &open_tempfile(FSTAB, ">$config{'fstab_file'}");
74 foreach (@fstab) {
75         chop; ($line = $_) =~ s/#.*$//g;
76         if ($line =~ /\S/ && $i++ == $_[0]) {
77                 # Found the line to replace
78                 &print_tempfile(FSTAB, "$_[2]  $_[1]  $_[3]");
79                 $opts = $_[4] eq "-" ? "" : $_[4];
80                 if ($_[6] eq "no") {
81                         $opts = join(',' , (split(/,/ , $opts) , "noauto"));
82                         }
83                 if ($opts eq "") { &print_tempfile(FSTAB, "  defaults"); }
84                 else { &print_tempfile(FSTAB, "  $opts"); }
85                 &print_tempfile(FSTAB, "  0  ");
86                 &print_tempfile(FSTAB, $_[5] eq "-" ? "0\n" : "$_[5]\n");
87                 }
88         else {
89                 &print_tempfile(FSTAB, $_,"\n");
90                 }
91         }
92 &close_tempfile(FSTAB);
93 }
94
95
96 # delete_mount(index)
97 # Delete an existing permanent mount
98 sub delete_mount
99 {
100 local($i, @fstab, $line, $opts, $j, @amd);
101 $i = 0;
102
103 # Update fstab file
104 open(FSTAB, $config{'fstab_file'});
105 @fstab = <FSTAB>;
106 close(FSTAB);
107 &open_tempfile(FSTAB, ">$config{'fstab_file'}");
108 foreach (@fstab) {
109         chop; ($line = $_) =~ s/#.*$//g;
110         if ($line !~ /\S/ || $i++ != $_[0]) {
111                 # Don't delete this line
112                 &print_tempfile(FSTAB, $_,"\n");
113                 }
114         }
115 &close_tempfile(FSTAB);
116 }
117
118
119 # list_mounted()
120 # Return a list of all the currently mounted filesystems and swap files.
121 # The list is in the form:
122 #  directory device type options
123 # Under OpenBSD, there seems to be no way to get additional mount options
124 # used by filesystems like NFS etc. Even getting the full details of mounted
125 # filesystems requires C code! So we have to call a specially-written external
126 # program to get the mount list
127 sub list_mounted
128 {
129 # get the list of mounted filesystems
130 local(@rv, $_);
131 local $cmd = $uname_release =~ /^[345]\.[0-9]/ ? "netbsd-mounts-3" :
132              $uname_release =~ /^2\.[0-9]/ ? "netbsd-mounts-2" :
133                                              "netbsd-mounts";
134 &compile_program($cmd);
135 open(CMD, "$module_config_directory/$cmd |");
136 while(<CMD>) {
137         local @p = split(/\t/, $_);
138         if ($p[2] eq "procfs" || $p[1] eq "procfs") { $p[1] = $p[2] = "proc"; }
139         push(@rv, \@p);
140         }
141 close(CMD);
142
143 # add output from swapinfo
144 &open_execute_command(SWAP, "swapinfo", 1, 1);
145 while(<SWAP>) {
146         if (/^(\/\S+)\s+\d+\s+\d+/) {
147                 push(@rv, [ "swap", $1, "swap", "-" ]);
148                 }
149         }
150 close(SWAP);
151 return @rv;
152 }
153
154
155 # mount_dir(directory, device, type, options)
156 # Mount a new directory from some device, with some options. Returns 0 if ok,
157 # or an error string if failed
158 sub mount_dir
159 {
160 local($out, $opts, $shar, %options, %smbopts);
161 if ($_[2] eq "swap") {
162         # Use swapon to add the swap space..
163         $out = &backquote_logged("swapon $_[1] 2>&1");
164         if ($?) { return "<pre>$out</pre>"; }
165         }
166 else {
167         # some disk-based filesystem
168         $opts = $_[3] eq "-" ? "" : "-o \"$_[3]\"";
169         $opts = join(',', grep { !/quota/ } split(/,/, $opts));
170         $out = &backquote_logged("mount -t $_[2] $opts $_[1] $_[0] 2>&1");
171         if ($?) { return "<pre>$out</pre>"; }
172         }
173 return 0;
174 }
175
176
177 # unmount_dir(directory, device, type)
178 # Unmount a directory that is currently mounted. Returns 0 if ok,
179 # or an error string if failed
180 sub unmount_dir
181 {
182 local($out, %smbopts, $dir);
183 if ($_[2] eq "swap") {
184         # Not possible!
185         &error("Swap space cannot be removed");
186         }
187 else {
188         $out = &backquote_logged("umount $_[0] 2>&1");
189         if ($?) { return "<pre>$out</pre>"; }
190         }
191 return 0;
192 }
193
194
195 # mount_modes(type)
196 # Given a filesystem type, returns 4 numbers that determine how the file
197 # system can be mounted, and whether it can be fsck'd
198 # The first is:
199 #  0 - cannot be permanently recorded
200 #       (smbfs under linux)
201 #  1 - can be permanently recorded, and is always mounted at boot
202 #       (swap under linux)
203 #  2 - can be permanently recorded, and may or may not be mounted at boot
204 #       (most normal filesystems)
205 # The second is:
206 #  0 - mount is always permanent => mounted when saved
207 #       (swap under linux)
208 #  1 - doesn't have to be permanent
209 #       (normal fs types)
210 # The third is:
211 #  0 - cannot be fsck'd at boot time
212 #  1 - can be be fsck'd at boot
213 # The fourth is:
214 #  0 - can be unmounted
215 #  1 - cannot be unmounted
216 sub mount_modes
217 {
218 if ($_[0] eq "swap")
219         { return (2, 1, 0, 1); }
220 elsif ($_[0] eq "ffs")
221         { return (2, 1, 1, 0); }
222 else
223         { return (2, 1, 0, 0); }
224 }
225
226
227 # disk_space(type, directory)
228 # Returns the amount of total and free space for some filesystem, or an
229 # empty array if not appropriate.
230 sub disk_space
231 {
232 if (&get_mounted($_[1], "*") < 0) { return (); }
233 if ($_[0] eq "proc" || $_[0] eq "swap") { return (); }
234 if (&backquote_command("df -k ".quotemeta($_[1]), 1) =~
235     /Mounted on\n\S+\s+(\S+)\s+\S+\s+(\S+)/) {
236         return ($1, $2);
237         }
238 return ( );
239 }
240
241
242 # list_fstypes()
243 # Returns an array of all the supported filesystem types. If a filesystem is
244 # found that is not one of the supported types, generate_location() and
245 # generate_options() will not be called for it.
246 sub list_fstypes
247 {
248 local @rv = ("ffs", "nfs", "cd9660", "msdos", "swap");
249 push(@rv, "ext2fs") if (&has_command("mount_ext2fs"));
250 return @rv;
251 }
252
253
254 # fstype_name(type)
255 # Given a short filesystem type, return a human-readable name for it
256 sub fstype_name
257 {
258 local(%fsmap);
259 %fsmap = ("ffs", "NetBSD Unix Filesystem",
260           "nfs","Network Filesystem",
261           "cd9660","ISO9660 CD-ROM",
262           "msdos","MS-DOS Filesystem",
263           "ext2fs","Linux Filesystem",
264           "swap","Virtual Memory",
265           "proc","Process Image Filesystem");
266 return $config{long_fstypes} && $fsmap{$_[0]} ? $fsmap{$_[0]} : uc($_[0]);
267 }
268
269
270 # multiple_mount(type)
271 # Returns 1 if filesystems of this type can be mounted multiple times, 0 if not
272 sub multiple_mount
273 {
274 return $_[0] eq "nfs";
275 }
276
277
278 # generate_location(type, location)
279 # Output HTML for editing the mount location of some filesystem.
280 sub generate_location
281 {
282 if ($_[0] eq "nfs") {
283         # NFS mount from some host and directory
284         $_[1] =~ /^([^:]+):(.*)$/;
285         print "<tr> <td><b>NFS Hostname</b></td>\n";
286         print "<td><input name=nfs_host size=20 value=\"$1\">\n";
287         &nfs_server_chooser_button("nfs_host");
288         print "</td>\n";
289         print "<td><b>NFS Directory</b></td>\n";
290         print "<td><input name=nfs_dir size=20 value=\"$2\">\n";
291         &nfs_export_chooser_button("nfs_host", "nfs_dir");
292         print "</td> </tr>\n";
293         }
294 else {
295         if ($_[0] eq "swap") {
296                 # Swap file or device
297                 printf "<tr> <td valign=top><b>Swap File</b></td>\n";
298                 }
299         else {
300                 # Disk-based filesystem
301                 printf "<tr> <td valign=top><b>%s Disk</b></td>\n",
302                         &fstype_name($_[0]);
303                 }
304         print "<td colspan=3>\n";
305         if ($_[1] =~ /^\/dev\/wd(\d)s(\d)([a-z]*)$/) {
306                 $disk_dev = 0; $ide_t = $1; $ide_s = $2; $ide_p = $3;
307                 }
308         elsif ($_[1] =~ /^\/dev\/sd(\d)s(\d)([a-z]*)$/) {
309                 $disk_dev = 1; $scsi_t = $1; $scsi_s = $2; $scsi_p = $3;
310                 }
311         else { $disk_dev = 2; }
312
313         printf "<input type=radio name=disk_dev value=0 %s> IDE Hard Disk:\n",
314                 $disk_dev == 0 ? "checked" : "";
315         print "Device <input name=ide_t size=3 value=\"$ide_t\">\n";
316         print "Slice <input name=ide_s size=3 value=\"$ide_s\">\n";
317         print "Partition <input name=ide_p size=3 value=\"$ide_p\"><br>\n";
318
319         printf "<input type=radio name=disk_dev value=1 %s> SCSI Disk:\n",
320                 $disk_dev == 1 ? "checked" : "";
321         print "Device <input name=scsi_t size=3 value=\"$scsi_t\">\n";
322         print "Slice <input name=scsi_s size=3 value=\"$scsi_s\">\n";
323         print "Partition <input name=scsi_p size=3 value=\"$scsi_p\"><br>\n";
324
325         printf "<input type=radio name=disk_dev value=2 %s> Other Device:\n",
326                 $disk_dev == 2 ? "checked" : "";
327         printf "<input size=20 name=dev_path value=\"%s\"><br>\n",
328                 $disk_dev == 2 ? $_[1] : "";
329         print "</td> </tr>\n";
330         }
331 }
332
333
334 # generate_options(type, newmount)
335 # Output HTML for editing mount options for a particular filesystem 
336 # under this OS
337 sub generate_options
338 {
339 if ($_[0] ne "swap") {
340         # These options are common to all filesystems
341         print "<tr> <td><b>Read-only?</b></td>\n";
342         printf "<td nowrap><input type=radio name=bsd_ro value=1 %s> Yes\n",
343                 defined($options{"rdonly"}) || defined($options{"ro"})
344                         ? "checked" : "";
345         printf "<input type=radio name=bsd_ro value=0 %s> No</td>\n",
346                 defined($options{"rdonly"}) || defined($options{"ro"})
347                         ? "" : "checked";
348
349         print "<td><b>Buffer writes to filesystem?</b></td>\n";
350         printf"<td nowrap><input type=radio name=bsd_sync value=0 %s> Yes\n",
351                 defined($options{"sync"}) ? "" : "checked";
352         printf "<input type=radio name=bsd_sync value=1 %s> No</td> </tr>\n",
353                 defined($options{"sync"}) ? "checked" : "";
354
355         print "<tr> <td><b>Allow device files?</b></td>\n";
356         printf "<td nowrap><input type=radio name=bsd_nodev value=0 %s> Yes\n",
357                 defined($options{"nodev"}) ? "" : "checked";
358         printf "<input type=radio name=bsd_nodev value=1 %s> No</td>\n",
359                 defined($options{"nodev"}) ? "checked" : "";
360
361         print "<td><b>Allow execution of binaries?</b></td>\n";
362         printf"<td nowrap><input type=radio name=bsd_noexec value=0 %s> Yes\n",
363                 defined($options{"noexec"}) ? "" : "checked";
364         printf "<input type=radio name=bsd_noexec value=1 %s> No</td> </tr>\n",
365                 defined($options{"noexec"}) ? "checked" : "";
366
367         print "<tr> <td><b>Disallow setuid programs?</b></td>\n";
368         printf "<td nowrap><input type=radio name=bsd_nosuid value=1 %s> Yes\n",
369                 defined($options{"nosuid"}) ? "checked" : "";
370         printf "<input type=radio name=bsd_nosuid value=0 %s> No</td>\n",
371                 defined($options{"nosuid"}) ? "" : "checked";
372
373         print "<td><b>Update access times?</b></td>\n";
374         printf"<td nowrap><input type=radio name=bsd_noatime value=0 %s> Yes\n",
375                 defined($options{"noatime"}) ? "" : "checked";
376         printf "<input type=radio name=bsd_noatime value=1 %s> No</td> </tr>\n",
377                 defined($options{"noatime"}) ? "checked" : "";
378
379         }
380
381 if ($_[0] eq "ffs") {
382         # FFS filesystems support quotas
383         print "<tr> <td><b>User quotas at boot</b></td> <td colspan=3>\n";
384         printf "<input type=radio name=ffs_userquota value=0 %s> Disabled\n",
385                 defined($options{'userquota'}) ? "" : "checked";
386         printf "<input type=radio name=ffs_userquota value=1 %s> Enabled\n",
387                 defined($options{'userquota'}) && $options{'userquota'} eq ""
388                         ? "checked" : "";
389         printf "<input type=radio name=ffs_userquota value=2 %s>\n",
390                 $options{'userquota'} ? "checked" : "";
391         print "Enabled, use file\n";
392         printf "<input name=ffs_userquota_file size=30 value=\"%s\">\n",
393                 $options{'userquota'};
394         print "</td> </tr>\n";
395                 
396         print "<tr> <td><b>Group quotas at boot</b></td> <td colspan=3>\n";
397         printf "<input type=radio name=ffs_groupquota value=0 %s> Disabled\n",
398                 defined($options{'groupquota'}) ? "" : "checked";
399         printf "<input type=radio name=ffs_groupquota value=1 %s> Enabled\n",
400                 defined($options{'groupquota'}) && $options{'groupquota'} eq ""
401                         ? "checked" : "";
402         printf "<input type=radio name=ffs_groupquota value=2 %s>\n",
403                 $options{'groupquota'} ? "checked" : "";
404         print "Enabled, use file\n";
405         printf "<input name=ffs_groupquota_file size=30 value=\"%s\">\n",
406                 $options{'groupquota'};
407         print "</td> </tr>\n";
408         }
409 elsif ($_[0] eq "nfs") {
410         # NFS filesystems have lots more options
411         print "<tr> <td><b>Retry mounts in background?</b></td>\n";
412         printf "<td nowrap><input type=radio name=nfs_b value=1 %s> Yes\n",
413                 defined($options{"-b"}) ? "checked" : "";
414         printf "<input type=radio name=nfs_b value=0 %s> No</td>\n",
415                 defined($options{"-b"}) ? "" : "checked";
416
417         print "<td><b>Return error on timeouts?</b></td>\n";
418         printf "<td nowrap><input type=radio name=nfs_s value=1 %s> Yes\n",
419                 defined($options{"-s"}) ? "checked" : "";
420         printf "<input type=radio name=nfs_s value=0 %s> No</td> </tr>\n",
421                 defined($options{"-s"}) ? "" : "checked";
422
423         print "<tr> <td><b>Timeout</b></td>\n";
424         printf "<td nowrap><input type=radio name=nfs_t_def value=1 %s> Default\n",
425                 defined($options{"-t"}) ? "" : "checked";
426         printf "<input type=radio name=nfs_t_def value=0 %s>\n",
427                 defined($options{"-t"}) ? "checked" : "";
428         printf "<input size=5 name=nfs_t value=\"$options{'-t'}\"></td>\n";
429
430         print "<td><b>Number of Retransmissions</b></td>\n";
431         printf "<td nowrap><input type=radio name=nfs_x_def value=1 %s> Default\n",
432                 defined($options{"-x"}) ? "" : "checked";
433         printf "<input type=radio name=nfs_x_def value=0 %s>\n",
434                 defined($options{"-x"}) ? "checked" : "";
435         print "<input size=5 name=nfs_x value=\"$options{'-x'}\"></td> </tr>\n";
436
437         print "<tr> <td><b>NFS version</b></td> <td nowrap>\n";
438         local $v = defined($options{"-2"}) ? 2 :
439                    defined($options{"-3"}) ? 3 : 0;
440         printf "<input type=radio name=nfs_ver value=0 %s> Auto\n",
441                 $v ? "" : "checked";
442         printf "<input type=radio name=nfs_ver value=2 %s> V2\n",
443                 $v == 2 ? "checked" : "";
444         printf "<input type=radio name=nfs_ver value=3 %s> V3</td>\n",
445                 $v == 3 ? "checked" : "";
446
447         print "<td><b>Mount retries</b></td>\n";
448         printf "<td nowrap><input type=radio name=nfs_r_def value=1 %s> Default\n",
449                 defined($options{"-R"}) ? "" : "checked";
450         printf "<input type=radio name=nfs_r_def value=0 %s>\n",
451                 defined($options{"-R"}) ? "checked" : "";
452         print "<input size=5 name=nfs_r value=\"$options{'-R'}\"></td> </tr>\n";
453
454         print "<tr> <td><b>Read-ahead blocks</b></td>\n";
455         printf "<td nowrap><input type=radio name=nfs_a_def value=1 %s> Default\n",
456                 defined($options{"-a"}) ? "" : "checked";
457         printf "<input type=radio name=nfs_a_def value=0 %s>\n",
458                 defined($options{"-a"}) ? "checked" : "";
459         print "<input size=5 name=nfs_a value=\"$options{'-a'}\"></td> </tr>\n";
460
461         print "<tr> <td><b>RPC Protocol</b></td>\n";
462         printf "<td nowrap><input type=radio name=nfs_t2 value=1 %s> TCP\n",
463                 defined($options{"-T"}) ? "checked" : "";
464         printf "<input type=radio name=nfs_t2 value=0 %s> UDP</td> </tr>\n",
465                 defined($options{"-T"}) ? "" : "checked";
466         }
467 elsif ($_[0] eq "msdos"){
468         # MS-DOS filesystems options deal with filling in
469         # missing unix functionality
470         print "<tr> <td><b>User files are owned by</b></td>\n";
471         printf "<td><input name=msdos_u size=8 value=\"%s\">\n",
472                 defined($options{"-u"}) ? getpwuid($options{"-u"}) : "";
473         print &user_chooser_button("msdos_u", 0),"</td>\n";
474
475         print "<td><b>Group files are owned by</b></td>\n";
476         printf "<td><input name=msdos_g size=8 value=\"%s\">\n",
477                 defined($options{"-g"}) ? getgrgid($options{"-g"}) : "";
478         print &group_chooser_button("msdos_g", 0),"</td>\n";
479
480         print "<tr> <td><b>File permissions mask</b></td>\n";
481         printf "<td><input type=radio name=msdos_m_def value=1 %s> Default\n",
482                 defined($options{"-m"}) ? "" : "checked";
483         printf "<input type=radio name=msdos_m_def value=0 %s>\n",
484                 defined($options{"-m"}) ? "checked" : "";
485         print "<input size=5 name=msdos_m value=\"$options{'-m'}\"></td>\n";
486         }
487 elsif ($_[0] eq "cd9660") {
488         # CDROM filesystem
489         print "<tr> <td><b>Ignore Unix Attributes?</b></td>\n";
490         printf "<td><input type=radio name=cd9660_r value=1 %s> Yes\n",
491                 defined($options{"-r"}) ? "checked" : "";
492         printf "<input type=radio name=cd9660_r value=0 %s> No</td>\n",
493                 defined($options{"-r"}) ? "" : "checked";
494
495         print "<td><b>Show version numbers?</b></td>\n";
496         printf "<td><input type=radio name=cd9660_g value=1 %s> Yes\n",
497                 defined($options{"-g"}) ? "checked" : "";
498         printf "<input type=radio name=cd9660_g value=0 %s> No</td> </tr>\n",
499                 defined($options{"-g"}) ? "" : "checked";
500
501         print "<tr> <td><b>Use extended attributes?</b></td>\n";
502         printf "<td><input type=radio name=cd9660_e value=1 %s> Yes\n",
503                 defined($options{"-e"}) ? "checked" : "";
504         printf "<input type=radio name=cd9660_e value=0 %s> No</td> </tr>\n",
505                 defined($options{"-e"}) ? "" : "checked";
506         }
507 elsif ($_[0] eq "swap") {
508         # Swap has no options..
509         print "<tr> <td><i>No Options Available</i></td> </tr>\n";
510         }
511 }
512
513
514 # check_location(type)
515 # Parse and check inputs from %in, calling &error() if something is wrong.
516 # Returns the location string for storing in the fstab file
517 sub check_location
518 {
519 if ($_[0] eq "nfs") {
520         local($out, $temp, $mout, $dirlist);
521
522         # Use ping and showmount to see if the host exists and is up
523         if ($in{nfs_host} !~ /^\S+$/) {
524                 &error("'$in{nfs_host}' is not a valid hostname");
525                 }
526         $out = &backquote_command("ping -c 1 '$in{nfs_host}' 2>&1");
527         if ($out =~ /unknown host/i) {
528                 &error("The host '$in{nfs_host}' does not exist");
529                 }
530         elsif ($out =~ /100\% packet loss/) {
531                 &error("The host '$in{nfs_host}' is down");
532                 }
533         $out = &backquote_command("showmount -e '$in{nfs_host}' 2>&1");
534         if ($out =~ /Unable to receive/) {
535                 &error("The host '$in{nfs_host}' does not support NFS");
536                 }
537         elsif ($?) {
538                 &error("Failed to get mount list : $out");
539                 }
540
541         # Validate directory name
542         foreach (split(/\n/, $out)) {
543                 if (/^(\/\S+)/) { $dirlist .= "$1\n"; }
544                 }
545         if ($in{nfs_dir} !~ /^\/\S+$/) {
546                 &error("'$in{nfs_dir}' is not a valid directory name. The ".
547                        "available directories on $in{nfs_host} are:".
548                        "<pre>$dirlist</pre>");
549                 }
550
551         # Try a test mount to see if filesystem is available
552         $temp = &transname();
553         &make_dir($temp, 0755);
554         $mout = &backquote_command("mount $in{nfs_host}:$in{nfs_dir} $temp 2>&1");
555         if ($mout =~ /No such file or directory/) {
556                 &error("The directory '$in{nfs_dir}' does not exist on the ".
557                        "host $in{nfs_host}. The available directories are:".
558                        "<pre>$dirlist</pre>");
559                 }
560         elsif ($mout =~ /Permission denied/) {
561                 &error("This host is not allowed to mount the directory ".
562                        "$in{nfs_dir} from $in{nfs_host}");
563                 }
564         elsif ($?) {
565                 &error("NFS Error - $mout");
566                 }
567         # It worked! unmount
568         &execute_command("umount $temp");
569         &unlink_file($temp);
570         return "$in{nfs_host}:$in{nfs_dir}";
571         }
572 else {
573         # This is some kind of disk-based filesystem.. get the device name
574         if ($in{'disk_dev'} == 0) {
575                 $in{'ide_t'} =~ /^\d+$/ ||
576                         &error("'$in{ide_t}' is not a valid device number");
577                 $in{'ide_s'} =~ /^\d+$/ ||
578                         &error("'$in{ide_s}' is not a valid slice number");
579                 $in{'ide_p'} =~ /^[a-z]*$/ ||
580                         &error("'$in{ide_p}' is not a valid partition letter");
581                 $dv = "/dev/wd$in{ide_t}s$in{ide_s}$in{ide_p}";
582                 }
583         elsif ($in{'disk_dev'} == 1) {
584                 $in{'scsi_t'} =~ /^\d+$/ ||
585                         &error("'$in{scsi_t}' is not a valid device number");
586                 $in{'scsi_s'} =~ /^\d+$/ ||
587                         &error("'$in{scsi_s}' is not a valid slice number");
588                 $in{'scsi_p'} =~ /^[a-z]*$/ ||
589                         &error("'$in{scsi_p}' is not a valid partition letter");
590                 $dv = "/dev/sd$in{scsi_t}s$in{scsi_s}$in{scsi_p}";
591                 }
592         else {
593                 $dv = $in{'dev_path'};
594                 }
595
596         # If the device entered is a symlink, follow it
597         if ($dvlink = readlink($dv)) {
598                 if ($dvlink =~ /^\//) { $dv = $dvlink; }
599                 else {  $dv =~ /^(.*\/)[^\/]+$/;
600                         $dv = $1.$dvlink;
601                         }
602                 }
603
604         # Check if the device actually exists and uses the right filesystem
605         (-r $dv) || &error("The device file '$dv' does not exist");
606         return $dv;
607         }
608 }
609
610 # check_options(type, device, directory)
611 # Read options for some filesystem from %in, and use them to update the
612 # %options array. Options handled by the user interface will be set or
613 # removed, while unknown options will be left untouched.
614 sub check_options
615 {
616 local($k, @rv);
617
618 # Parse the common options first..
619 if ($_[0] ne "swap") {
620         delete($options{"ro"}); delete($options{"rw"});
621         delete($options{"rdonly"});
622         if ($in{'bsd_ro'}) { $options{'ro'} = ''; }
623         else { $options{'rw'} = ""; }
624
625         delete($options{"sync"}); delete($options{"async"});
626         if ($in{'bsd_sync'}) { $options{'sync'} = ''; }
627
628         delete($options{'nodev'});
629         if ($in{'bsd_nodev'}) { $options{'nodev'} = ''; }
630
631         delete($options{'noexec'});
632         if ($in{'bsd_noexec'}) { $options{'noexec'} = ''; }
633
634         delete($options{'nosuid'});
635         if ($in{'bsd_nosuid'}) { $options{'nosuid'} = ''; }
636
637         delete($options{'noatime'});
638         if ($in{'bsd_noatime'}) { $options{'noatime'} = ''; }
639
640         }
641 else {
642         # Swap always has the sw option
643         $options{'sw'} = "";
644         }
645
646 if ($_[0] eq "ffs") {
647         # Parse FFS quota options
648         delete($options{'userquota'}) if ($in{'ffs_userquota'} == 0);
649         $options{'userquota'} = "" if ($in{'ffs_userquota'} == 1);
650         $options{'userquota'} = $in{'ffs_groupquota_file'}
651                 if ($in{'ffs_userquota'} == 2);
652
653         delete($options{'groupquota'}) if ($in{'ffs_groupquota'} == 0);
654         $options{'groupquota'} = "" if ($in{'ffs_groupquota'} == 1);
655         $options{'groupquota'} = $in{'ffs_groupquota_file'}
656                 if ($in{'ffs_groupquota'} == 2);
657         }
658 elsif ($_[0] eq "nfs") {
659         # NFS has a few specific options..
660         delete($options{'-b'});
661         $options{'-b'} = "" if ($in{'nfs_b'});
662
663         delete($options{'-s'});
664         $options{'-s'} = "" if ($in{'nfs_s'});
665
666         delete($options{'-t'});
667         $options{'-t'} = $in{'nfs_t'} if (!$in{'nfs_t_def'});
668
669         delete($options{'-x'});
670         $options{'-x'} = $in{'nfs_x'} if (!$in{'nfs_x_def'});
671
672         delete($options{'-2'}); delete($options{'-3'});
673         $options{'-2'} = "" if ($in{'nfs_ver'} == 2);
674         $options{'-3'} = "" if ($in{'nfs_ver'} == 3);
675
676         delete($options{'-R'});
677         $options{'-R'} = $in{'nfs_r'} if (!$in{'nfs_r_def'});
678
679         delete($options{'-a'});
680         $options{'-a'} = $in{'nfs_a'} if (!$in{'nfs_a_def'});
681
682         delete($options{'-T'});
683         $options{'-T'} = "" if ($in{'nfs_t2'});
684         }
685 elsif ($_[0] eq "msdos") {
686         # MSDOS options for file ownership/perms
687         delete($options{"-u"}); delete($options{"-g"});
688         if ($in{'msdos_u'} ne "") { $options{'-u'} = getpwnam($in{'msdos_u'}); }
689         if ($in{'msdos_g'} ne "") { $options{'-g'} = getgrnam($in{'msdos_g'}); }
690
691         delete($options{"-m"});
692         if (!$in{'msdos_m_def'}) {
693                 $in{'msdos_m'} =~ /^[0-7]{3}$/ ||
694                         &error("'$in{'msdos_m'}' is not a valid octal mask");
695                 $options{'-m'} = $in{'msdos_m'};
696                 }
697         }
698 elsif ($_[0] eq "cd9660") {
699         # Options for iso9660 cd-roms
700         delete($options{'-r'});
701         $options{'-r'} = "" if ($in{'cd9660_r'});
702
703         delete($options{'-g'});
704         $options{'-g'} = "" if ($in{'cd9660_g'});
705
706         delete($options{'-e'});
707         $options{'-e'} = "" if ($in{'cd9660_e'});
708         }
709
710 # Return options string
711 foreach $k (keys %options) {
712         if ($options{$k} eq "") { push(@rv, $k); }
713         else { push(@rv, "$k=$options{$k}"); }
714         }
715 return @rv ? join(',' , @rv) : "-";
716 }
717
718 # create_swap(file, size, units)
719 # Calls dd and mkswap to setup a swap file
720 sub create_swap
721 {
722 local($out, $bl);
723 $bl = $_[1] * ($_[2] eq "g" ? 1024*1024 :
724                $_[2] eq "m" ? 1024 : 1);
725 $out = &backquote_logged("dd if=/dev/zero of=$_[0] bs=1024 count=$bl 2>&1");
726 if ($?) { return "dd failed : $out"; }
727 $out = &backquote_logged("mkswap $_[0] $bl 2>&1");
728 if ($?) { return "mkswap failed : $out"; }
729 &system_logged("sync >/dev/null 2>&1");
730 return 0;
731 }
732
733 # exports_list(host, dirarray, clientarray)
734 # Fills the directory and client array references with exports from some
735 # host. Returns an error string if something went wrong
736 sub exports_list
737 {
738 local($dref, $cref, $out, $_);
739 $dref = $_[1]; $cref = $_[2];
740 $out = &backquote_command("showmount -e ".quotemeta($_[0])." 2>&1", 1);
741 if ($?) { return $out; }
742 foreach (split(/\n/, $out)) {
743         if (/^(\/\S*)\s+(.*)$/) {
744                 push(@$dref, $1); push(@$cref, $2);
745                 }
746         }
747 return undef;
748 }
749
750 # broadcast_addr()
751 # Returns a useable broadcast address for finding NFS servers
752 sub broadcast_addr
753 {
754 local($out);
755 $out = &backquote_command("ifconfig -a 2>&1", 1);
756 if ($out =~ /broadcast\s+(\S+)\s+/) { return $1; }
757 return "255.255.255.255";
758 }
759
760 sub device_name
761 {
762 return $_[0];
763 }
764
765 sub files_to_lock
766 {
767 return ( $config{'fstab_file'} );
768 }
769
770 1;
771