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
11sub list_mounts
12{
13local(@rv, @p, @o, $_, $i, $j); $i = 0;
14
15# Get /etc/fstab mounts
16open(FSTAB, "<".$config{'fstab_file'});
17while(<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	}
36close(FSTAB);
37return @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
43sub create_mount
44{
45local(@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];
51if ($_[5] eq "no") {
52	$opts = join(',' , (split(/,/ , $opts) , "noauto"));
53	}
54if ($opts eq "") { &print_tempfile(FSTAB, "  defaults"); }
55else { &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
64sub change_mount
65{
66local($i, @fstab, $line, $opts, $j, @amd);
67$i = 0;
68
69# Update fstab file
70open(FSTAB, "<".$config{'fstab_file'});
71@fstab = <FSTAB>;
72close(FSTAB);
73&open_tempfile(FSTAB, ">$config{'fstab_file'}");
74foreach (@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
98sub delete_mount
99{
100local($i, @fstab, $line, $opts, $j, @amd);
101$i = 0;
102
103# Update fstab file
104open(FSTAB, "<".$config{'fstab_file'});
105@fstab = <FSTAB>;
106close(FSTAB);
107&open_tempfile(FSTAB, ">$config{'fstab_file'}");
108foreach (@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
127sub list_mounted
128{
129# get the list of mounted filesystems
130local(@rv, $_);
131local $cmd = $uname_release =~ /^[3456789]\.[0-9]/ ? "netbsd-mounts-3" :
132	     $uname_release =~ /^2\.[0-9]/ ? "netbsd-mounts-2" :
133					     "netbsd-mounts";
134&compile_program($cmd);
135open(CMD, "$module_config_directory/$cmd |");
136while(<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	}
141close(CMD);
142
143# add output from swapinfo
144&open_execute_command(SWAP, "swapinfo", 1, 1);
145while(<SWAP>) {
146	if (/^(\/\S+)\s+\d+\s+\d+/) {
147		push(@rv, [ "swap", $1, "swap", "-" ]);
148		}
149	}
150close(SWAP);
151return @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
158sub mount_dir
159{
160local($out, $opts, $shar, %options, %smbopts);
161if ($_[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	}
166else {
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	}
173return 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
180sub unmount_dir
181{
182local($out, %smbopts, $dir);
183if ($_[2] eq "swap") {
184	# Not possible!
185	&error("Swap space cannot be removed");
186	}
187else {
188	$out = &backquote_logged("umount $_[0] 2>&1");
189	if ($?) { return "<pre>$out</pre>"; }
190	}
191return 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
216sub mount_modes
217{
218if ($_[0] eq "swap")
219	{ return (2, 1, 0, 1); }
220elsif ($_[0] eq "ffs")
221	{ return (2, 1, 1, 0); }
222else
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.
230sub disk_space
231{
232if (&get_mounted($_[1], "*") < 0) { return (); }
233if ($_[0] eq "proc" || $_[0] eq "swap") { return (); }
234if (&backquote_command("df -k ".quotemeta($_[1]), 1) =~
235    /Mounted on\n\S+\s+(\S+)\s+\S+\s+(\S+)/) {
236	return ($1, $2);
237	}
238return ( );
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.
246sub list_fstypes
247{
248local @rv = ("ffs", "nfs", "cd9660", "msdos", "swap");
249push(@rv, "ext2fs") if (&has_command("mount_ext2fs"));
250return @rv;
251}
252
253
254# fstype_name(type)
255# Given a short filesystem type, return a human-readable name for it
256sub fstype_name
257{
258local(%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");
266return $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
272sub multiple_mount
273{
274return $_[0] eq "nfs";
275}
276
277
278# generate_location(type, location)
279# Output HTML for editing the mount location of some filesystem.
280sub generate_location
281{
282local ($type, $loc) = @_;
283if ($type eq "nfs") {
284	# NFS mount from some host and directory
285        local ($host, $dir) = $loc =~ /^([^:]+):(.*)$/ ? ( $1, $2 ) : ( );
286        print &ui_table_row(&hlink($text{'linux_nfshost'}, "nfshost"),
287                &ui_textbox("nfs_host", $host, 30).
288                &nfs_server_chooser_button("nfs_host").
289                "&nbsp;".
290                "<b>".&hlink($text{'linux_nfsdir'}, "nfsdir")."</b> ".
291                &ui_textbox("nfs_dir",
292                            ($type eq "nfs4") && ($dir eq "") ? "/" : $dir, 30).
293                &nfs_export_chooser_button("nfs_host", "nfs_dir"));
294	}
295else {
296	local $msg;
297        if ($type eq "swap") {
298                # Swap file or device
299		$msg = $text{'linux_swapfile'};
300                }
301        else {
302                # Disk-based filesystem
303                $msg = &fstype_name($type);
304                }
305	local ($disk_dev, $ide_t, $ide_s, $ide_p, $scsi_t, $scsi_s, $scsi_p);
306	if ($loc =~ /^\/dev\/wd(\d)s(\d)([a-z]*)$/) {
307		$disk_dev = 0; $ide_t = $1; $ide_s = $2; $ide_p = $3;
308		}
309	elsif ($loc =~ /^\/dev\/sd(\d)s(\d)([a-z]*)$/) {
310		$disk_dev = 1; $scsi_t = $1; $scsi_s = $2; $scsi_p = $3;
311		}
312	else { $disk_dev = 2; }
313
314        print &ui_table_row($msg,
315                &ui_radio_table("disk_dev", $disk_dev,
316                  [ [ 0, $text{'freebsd_ide'},
317                      $text{'freebsd_device'}." ".
318                        &ui_textbox("ide_t", $ide_t, 4)." ".
319                      $text{'freebsd_slice'}." ".
320                        &ui_textbox("ide_s", $ide_s, 4)." ".
321                      $text{'freebsd_part'}." ".
322                        &ui_textbox("ide_p", $ide_p, 4) ],
323                    [ 1, $text{'freebsd_scsi'},
324                      $text{'freebsd_device'}." ".
325                        &ui_textbox("scsi_t", $scsi_t, 4)." ".
326                      $text{'freebsd_slice'}." ".
327                        &ui_textbox("scsi_s", $scsi_s, 4)." ".
328                      $text{'freebsd_part'}." ".
329                        &ui_textbox("scsi_p", $scsi_p, 4) ],
330                    [ 2, $text{'freebsd_other'},
331                      &ui_textbox("dev_path", $disk_dev == 2 ? $loc : "", 40).
332                      " ".&file_chooser_button("dev_path", 0) ] ]));
333	}
334}
335
336
337# generate_options(type, newmount)
338# Output HTML for editing mount options for a particular filesystem
339# under this OS
340sub generate_options
341{
342if ($_[0] ne "swap") {
343	# These options are common to all filesystems
344	print "<tr> <td><b>Read-only?</b></td>\n";
345	printf "<td nowrap><input type=radio name=bsd_ro value=1 %s> Yes\n",
346		defined($options{"rdonly"}) || defined($options{"ro"})
347			? "checked" : "";
348	printf "<input type=radio name=bsd_ro value=0 %s> No</td>\n",
349		defined($options{"rdonly"}) || defined($options{"ro"})
350			? "" : "checked";
351
352	print "<td><b>Buffer writes to filesystem?</b></td>\n";
353	printf"<td nowrap><input type=radio name=bsd_sync value=0 %s> Yes\n",
354		defined($options{"sync"}) ? "" : "checked";
355	printf "<input type=radio name=bsd_sync value=1 %s> No</td> </tr>\n",
356		defined($options{"sync"}) ? "checked" : "";
357
358	print "<tr> <td><b>Allow device files?</b></td>\n";
359	printf "<td nowrap><input type=radio name=bsd_nodev value=0 %s> Yes\n",
360		defined($options{"nodev"}) ? "" : "checked";
361	printf "<input type=radio name=bsd_nodev value=1 %s> No</td>\n",
362		defined($options{"nodev"}) ? "checked" : "";
363
364	print "<td><b>Allow execution of binaries?</b></td>\n";
365	printf"<td nowrap><input type=radio name=bsd_noexec value=0 %s> Yes\n",
366		defined($options{"noexec"}) ? "" : "checked";
367	printf "<input type=radio name=bsd_noexec value=1 %s> No</td> </tr>\n",
368		defined($options{"noexec"}) ? "checked" : "";
369
370	print "<tr> <td><b>Disallow setuid programs?</b></td>\n";
371	printf "<td nowrap><input type=radio name=bsd_nosuid value=1 %s> Yes\n",
372		defined($options{"nosuid"}) ? "checked" : "";
373	printf "<input type=radio name=bsd_nosuid value=0 %s> No</td>\n",
374		defined($options{"nosuid"}) ? "" : "checked";
375
376	print "<td><b>Update access times?</b></td>\n";
377	printf"<td nowrap><input type=radio name=bsd_noatime value=0 %s> Yes\n",
378		defined($options{"noatime"}) ? "" : "checked";
379	printf "<input type=radio name=bsd_noatime value=1 %s> No</td> </tr>\n",
380		defined($options{"noatime"}) ? "checked" : "";
381
382	}
383
384if ($_[0] eq "ffs") {
385	# FFS filesystems support quotas
386	print "<tr> <td><b>User quotas at boot</b></td> <td colspan=3>\n";
387	printf "<input type=radio name=ffs_userquota value=0 %s> Disabled\n",
388		defined($options{'userquota'}) ? "" : "checked";
389	printf "<input type=radio name=ffs_userquota value=1 %s> Enabled\n",
390		defined($options{'userquota'}) && $options{'userquota'} eq ""
391			? "checked" : "";
392	printf "<input type=radio name=ffs_userquota value=2 %s>\n",
393		$options{'userquota'} ? "checked" : "";
394	print "Enabled, use file\n";
395	printf "<input name=ffs_userquota_file size=30 value=\"%s\">\n",
396		$options{'userquota'};
397	print "</td> </tr>\n";
398
399	print "<tr> <td><b>Group quotas at boot</b></td> <td colspan=3>\n";
400	printf "<input type=radio name=ffs_groupquota value=0 %s> Disabled\n",
401		defined($options{'groupquota'}) ? "" : "checked";
402	printf "<input type=radio name=ffs_groupquota value=1 %s> Enabled\n",
403		defined($options{'groupquota'}) && $options{'groupquota'} eq ""
404			? "checked" : "";
405	printf "<input type=radio name=ffs_groupquota value=2 %s>\n",
406		$options{'groupquota'} ? "checked" : "";
407	print "Enabled, use file\n";
408	printf "<input name=ffs_groupquota_file size=30 value=\"%s\">\n",
409		$options{'groupquota'};
410	print "</td> </tr>\n";
411	}
412elsif ($_[0] eq "nfs") {
413	# NFS filesystems have lots more options
414	print "<tr> <td><b>Retry mounts in background?</b></td>\n";
415	printf "<td nowrap><input type=radio name=nfs_b value=1 %s> Yes\n",
416		defined($options{"-b"}) ? "checked" : "";
417	printf "<input type=radio name=nfs_b value=0 %s> No</td>\n",
418		defined($options{"-b"}) ? "" : "checked";
419
420	print "<td><b>Return error on timeouts?</b></td>\n";
421	printf "<td nowrap><input type=radio name=nfs_s value=1 %s> Yes\n",
422		defined($options{"-s"}) ? "checked" : "";
423	printf "<input type=radio name=nfs_s value=0 %s> No</td> </tr>\n",
424		defined($options{"-s"}) ? "" : "checked";
425
426	print "<tr> <td><b>Timeout</b></td>\n";
427	printf "<td nowrap><input type=radio name=nfs_t_def value=1 %s> Default\n",
428		defined($options{"-t"}) ? "" : "checked";
429	printf "<input type=radio name=nfs_t_def value=0 %s>\n",
430		defined($options{"-t"}) ? "checked" : "";
431	printf "<input size=5 name=nfs_t value=\"$options{'-t'}\"></td>\n";
432
433	print "<td><b>Number of Retransmissions</b></td>\n";
434	printf "<td nowrap><input type=radio name=nfs_x_def value=1 %s> Default\n",
435		defined($options{"-x"}) ? "" : "checked";
436	printf "<input type=radio name=nfs_x_def value=0 %s>\n",
437		defined($options{"-x"}) ? "checked" : "";
438	print "<input size=5 name=nfs_x value=\"$options{'-x'}\"></td> </tr>\n";
439
440	print "<tr> <td><b>NFS version</b></td> <td nowrap>\n";
441	local $v = defined($options{"-2"}) ? 2 :
442		   defined($options{"-3"}) ? 3 : 0;
443	printf "<input type=radio name=nfs_ver value=0 %s> Auto\n",
444		$v ? "" : "checked";
445	printf "<input type=radio name=nfs_ver value=2 %s> V2\n",
446		$v == 2 ? "checked" : "";
447	printf "<input type=radio name=nfs_ver value=3 %s> V3</td>\n",
448		$v == 3 ? "checked" : "";
449
450	print "<td><b>Mount retries</b></td>\n";
451	printf "<td nowrap><input type=radio name=nfs_r_def value=1 %s> Default\n",
452		defined($options{"-R"}) ? "" : "checked";
453	printf "<input type=radio name=nfs_r_def value=0 %s>\n",
454		defined($options{"-R"}) ? "checked" : "";
455	print "<input size=5 name=nfs_r value=\"$options{'-R'}\"></td> </tr>\n";
456
457	print "<tr> <td><b>Read-ahead blocks</b></td>\n";
458	printf "<td nowrap><input type=radio name=nfs_a_def value=1 %s> Default\n",
459		defined($options{"-a"}) ? "" : "checked";
460	printf "<input type=radio name=nfs_a_def value=0 %s>\n",
461		defined($options{"-a"}) ? "checked" : "";
462	print "<input size=5 name=nfs_a value=\"$options{'-a'}\"></td> </tr>\n";
463
464	print "<tr> <td><b>RPC Protocol</b></td>\n";
465	printf "<td nowrap><input type=radio name=nfs_t2 value=1 %s> TCP\n",
466		defined($options{"-T"}) ? "checked" : "";
467	printf "<input type=radio name=nfs_t2 value=0 %s> UDP</td> </tr>\n",
468		defined($options{"-T"}) ? "" : "checked";
469	}
470elsif ($_[0] eq "msdos"){
471	# MS-DOS filesystems options deal with filling in
472	# missing unix functionality
473	print "<tr> <td><b>User files are owned by</b></td>\n";
474	printf "<td><input name=msdos_u size=8 value=\"%s\">\n",
475		defined($options{"-u"}) ? getpwuid($options{"-u"}) : "";
476	print &user_chooser_button("msdos_u", 0),"</td>\n";
477
478	print "<td><b>Group files are owned by</b></td>\n";
479	printf "<td><input name=msdos_g size=8 value=\"%s\">\n",
480		defined($options{"-g"}) ? getgrgid($options{"-g"}) : "";
481	print &group_chooser_button("msdos_g", 0),"</td>\n";
482
483	print "<tr> <td><b>File permissions mask</b></td>\n";
484	printf "<td><input type=radio name=msdos_m_def value=1 %s> Default\n",
485		defined($options{"-m"}) ? "" : "checked";
486	printf "<input type=radio name=msdos_m_def value=0 %s>\n",
487		defined($options{"-m"}) ? "checked" : "";
488	print "<input size=5 name=msdos_m value=\"$options{'-m'}\"></td>\n";
489	}
490elsif ($_[0] eq "cd9660") {
491	# CDROM filesystem
492	print "<tr> <td><b>Ignore Unix Attributes?</b></td>\n";
493	printf "<td><input type=radio name=cd9660_r value=1 %s> Yes\n",
494		defined($options{"-r"}) ? "checked" : "";
495	printf "<input type=radio name=cd9660_r value=0 %s> No</td>\n",
496		defined($options{"-r"}) ? "" : "checked";
497
498	print "<td><b>Show version numbers?</b></td>\n";
499	printf "<td><input type=radio name=cd9660_g value=1 %s> Yes\n",
500		defined($options{"-g"}) ? "checked" : "";
501	printf "<input type=radio name=cd9660_g value=0 %s> No</td> </tr>\n",
502		defined($options{"-g"}) ? "" : "checked";
503
504	print "<tr> <td><b>Use extended attributes?</b></td>\n";
505	printf "<td><input type=radio name=cd9660_e value=1 %s> Yes\n",
506		defined($options{"-e"}) ? "checked" : "";
507	printf "<input type=radio name=cd9660_e value=0 %s> No</td> </tr>\n",
508		defined($options{"-e"}) ? "" : "checked";
509	}
510elsif ($_[0] eq "swap") {
511	# Swap has no options..
512	print "<tr> <td><i>No Options Available</i></td> </tr>\n";
513	}
514}
515
516
517# check_location(type)
518# Parse and check inputs from %in, calling &error() if something is wrong.
519# Returns the location string for storing in the fstab file
520sub check_location
521{
522if ($_[0] eq "nfs") {
523	local($out, $temp, $mout, $dirlist);
524
525	if ($config{'nfs_check'}) {
526		# Use ping and showmount to see if the host exists and is up
527		if ($in{nfs_host} !~ /^\S+$/) {
528			&error("'$in{nfs_host}' is not a valid hostname");
529			}
530		$out = &backquote_command("ping -c 1 '$in{nfs_host}' 2>&1");
531		if ($out =~ /unknown host/i) {
532			&error("The host '$in{nfs_host}' does not exist");
533			}
534		elsif ($out =~ /100\% packet loss/) {
535			&error("The host '$in{nfs_host}' is down");
536			}
537		$out = &backquote_command("showmount -e '$in{nfs_host}' 2>&1");
538		if ($out =~ /Unable to receive/) {
539			&error("The host '$in{nfs_host}' does not support NFS");
540			}
541		elsif ($?) {
542			&error("Failed to get mount list : $out");
543			}
544		}
545
546	# Validate directory name
547	foreach (split(/\n/, $out)) {
548		if (/^(\/\S+)/) { $dirlist .= "$1\n"; }
549		}
550	if ($in{nfs_dir} !~ /^\/\S+$/) {
551		&error("'$in{nfs_dir}' is not a valid directory name. The ".
552		       "available directories on $in{nfs_host} are:".
553		       "<pre>$dirlist</pre>");
554		}
555
556	# Try a test mount to see if filesystem is available
557	$temp = &transname();
558	&make_dir($temp, 0755);
559	$mout = &backquote_command("mount $in{nfs_host}:$in{nfs_dir} $temp 2>&1");
560	if ($mout =~ /No such file or directory/) {
561		&error("The directory '$in{nfs_dir}' does not exist on the ".
562		       "host $in{nfs_host}. The available directories are:".
563		       "<pre>$dirlist</pre>");
564		}
565	elsif ($mout =~ /Permission denied/) {
566		&error("This host is not allowed to mount the directory ".
567		       "$in{nfs_dir} from $in{nfs_host}");
568		}
569	elsif ($?) {
570		&error("NFS Error - $mout");
571		}
572	# It worked! unmount
573	&execute_command("umount $temp");
574	&unlink_file($temp);
575	return "$in{nfs_host}:$in{nfs_dir}";
576	}
577else {
578	# This is some kind of disk-based filesystem.. get the device name
579	if ($in{'disk_dev'} == 0) {
580		$in{'ide_t'} =~ /^\d+$/ ||
581			&error("'$in{ide_t}' is not a valid device number");
582		$in{'ide_s'} =~ /^\d+$/ ||
583			&error("'$in{ide_s}' is not a valid slice number");
584		$in{'ide_p'} =~ /^[a-z]*$/ ||
585			&error("'$in{ide_p}' is not a valid partition letter");
586		$dv = "/dev/wd$in{ide_t}s$in{ide_s}$in{ide_p}";
587		}
588	elsif ($in{'disk_dev'} == 1) {
589		$in{'scsi_t'} =~ /^\d+$/ ||
590			&error("'$in{scsi_t}' is not a valid device number");
591		$in{'scsi_s'} =~ /^\d+$/ ||
592			&error("'$in{scsi_s}' is not a valid slice number");
593		$in{'scsi_p'} =~ /^[a-z]*$/ ||
594			&error("'$in{scsi_p}' is not a valid partition letter");
595		$dv = "/dev/sd$in{scsi_t}s$in{scsi_s}$in{scsi_p}";
596		}
597	else {
598		$dv = $in{'dev_path'};
599		}
600
601	# If the device entered is a symlink, follow it
602	if ($dvlink = readlink($dv)) {
603		if ($dvlink =~ /^\//) { $dv = $dvlink; }
604		else {	$dv =~ /^(.*\/)[^\/]+$/;
605			$dv = $1.$dvlink;
606			}
607		}
608
609	# Check if the device actually exists and uses the right filesystem
610	(-r $dv) || &error("The device file '$dv' does not exist");
611	return $dv;
612	}
613}
614
615# check_options(type, device, directory)
616# Read options for some filesystem from %in, and use them to update the
617# %options array. Options handled by the user interface will be set or
618# removed, while unknown options will be left untouched.
619sub check_options
620{
621local($k, @rv);
622
623# Parse the common options first..
624if ($_[0] ne "swap") {
625	delete($options{"ro"}); delete($options{"rw"});
626	delete($options{"rdonly"});
627	if ($in{'bsd_ro'}) { $options{'ro'} = ''; }
628	else { $options{'rw'} = ""; }
629
630	delete($options{"sync"}); delete($options{"async"});
631	if ($in{'bsd_sync'}) { $options{'sync'} = ''; }
632
633	delete($options{'nodev'});
634	if ($in{'bsd_nodev'}) { $options{'nodev'} = ''; }
635
636	delete($options{'noexec'});
637	if ($in{'bsd_noexec'}) { $options{'noexec'} = ''; }
638
639	delete($options{'nosuid'});
640	if ($in{'bsd_nosuid'}) { $options{'nosuid'} = ''; }
641
642	delete($options{'noatime'});
643	if ($in{'bsd_noatime'}) { $options{'noatime'} = ''; }
644
645	}
646else {
647	# Swap always has the sw option
648	$options{'sw'} = "";
649	}
650
651if ($_[0] eq "ffs") {
652	# Parse FFS quota options
653	delete($options{'userquota'}) if ($in{'ffs_userquota'} == 0);
654	$options{'userquota'} = "" if ($in{'ffs_userquota'} == 1);
655	$options{'userquota'} = $in{'ffs_groupquota_file'}
656		if ($in{'ffs_userquota'} == 2);
657
658	delete($options{'groupquota'}) if ($in{'ffs_groupquota'} == 0);
659	$options{'groupquota'} = "" if ($in{'ffs_groupquota'} == 1);
660	$options{'groupquota'} = $in{'ffs_groupquota_file'}
661		if ($in{'ffs_groupquota'} == 2);
662	}
663elsif ($_[0] eq "nfs") {
664	# NFS has a few specific options..
665	delete($options{'-b'});
666	$options{'-b'} = "" if ($in{'nfs_b'});
667
668	delete($options{'-s'});
669	$options{'-s'} = "" if ($in{'nfs_s'});
670
671	delete($options{'-t'});
672	$options{'-t'} = $in{'nfs_t'} if (!$in{'nfs_t_def'});
673
674	delete($options{'-x'});
675	$options{'-x'} = $in{'nfs_x'} if (!$in{'nfs_x_def'});
676
677	delete($options{'-2'}); delete($options{'-3'});
678	$options{'-2'} = "" if ($in{'nfs_ver'} == 2);
679	$options{'-3'} = "" if ($in{'nfs_ver'} == 3);
680
681	delete($options{'-R'});
682	$options{'-R'} = $in{'nfs_r'} if (!$in{'nfs_r_def'});
683
684	delete($options{'-a'});
685	$options{'-a'} = $in{'nfs_a'} if (!$in{'nfs_a_def'});
686
687	delete($options{'-T'});
688	$options{'-T'} = "" if ($in{'nfs_t2'});
689	}
690elsif ($_[0] eq "msdos") {
691	# MSDOS options for file ownership/perms
692	delete($options{"-u"}); delete($options{"-g"});
693	if ($in{'msdos_u'} ne "") { $options{'-u'} = getpwnam($in{'msdos_u'}); }
694	if ($in{'msdos_g'} ne "") { $options{'-g'} = getgrnam($in{'msdos_g'}); }
695
696	delete($options{"-m"});
697	if (!$in{'msdos_m_def'}) {
698		$in{'msdos_m'} =~ /^[0-7]{3}$/ ||
699			&error("'$in{'msdos_m'}' is not a valid octal mask");
700		$options{'-m'} = $in{'msdos_m'};
701		}
702	}
703elsif ($_[0] eq "cd9660") {
704	# Options for iso9660 cd-roms
705	delete($options{'-r'});
706	$options{'-r'} = "" if ($in{'cd9660_r'});
707
708	delete($options{'-g'});
709	$options{'-g'} = "" if ($in{'cd9660_g'});
710
711	delete($options{'-e'});
712	$options{'-e'} = "" if ($in{'cd9660_e'});
713	}
714
715# Return options string
716foreach $k (keys %options) {
717	if ($options{$k} eq "") { push(@rv, $k); }
718	else { push(@rv, "$k=$options{$k}"); }
719	}
720return @rv ? join(',' , @rv) : "-";
721}
722
723# create_swap(file, size, units)
724# Calls dd and mkswap to setup a swap file
725sub create_swap
726{
727local($out, $bl);
728$bl = $_[1] * ($_[2] eq "t" ? 1024*1024*1024 :
729	       $_[2] eq "g" ? 1024*1024 :
730	       $_[2] eq "m" ? 1024 : 1);
731$out = &backquote_logged("dd if=/dev/zero of=$_[0] bs=1024 count=$bl 2>&1");
732if ($?) { return "dd failed : $out"; }
733$out = &backquote_logged("mkswap $_[0] $bl 2>&1");
734if ($?) { return "mkswap failed : $out"; }
735&system_logged("sync >/dev/null 2>&1");
736return 0;
737}
738
739# exports_list(host, dirarray, clientarray)
740# Fills the directory and client array references with exports from some
741# host. Returns an error string if something went wrong
742sub exports_list
743{
744local($dref, $cref, $out, $_);
745$dref = $_[1]; $cref = $_[2];
746$out = &backquote_command("showmount -e ".quotemeta($_[0])." 2>&1", 1);
747if ($?) { return $out; }
748foreach (split(/\n/, $out)) {
749	if (/^(\/\S*)\s+(.*)$/) {
750		push(@$dref, $1); push(@$cref, $2);
751		}
752	}
753return undef;
754}
755
756# broadcast_addr()
757# Returns a useable broadcast address for finding NFS servers
758sub broadcast_addr
759{
760local($out);
761$out = &backquote_command("ifconfig -a 2>&1", 1);
762if ($out =~ /broadcast\s+(\S+)\s+/) { return $1; }
763return "255.255.255.255";
764}
765
766sub device_name
767{
768return $_[0];
769}
770
771sub files_to_lock
772{
773return ( $config{'fstab_file'} );
774}
775
7761;
777
778