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