1# linux-lib.pl
2# Mount table functions for linux
3
4if (!$no_check_support) {
5	my %support;
6	my $fsfile = &read_file_contents("/proc/filesystems");
7	foreach my $l (split(/\r?\n/, $fsfile)) {
8		my @w = split(/\s+/, $l);
9		my $fs = pop(@w);
10		$support{$fs} = 1;
11		}
12	if (&has_command("amd")) {
13		local $amd = &read_amd_conf();
14		$amd_support = $amd =~ /\[\s*global\s*\]/i ? 2 : 1;
15		}
16	$autofs_support = &has_command("automount");
17	if (&has_command("mount.cifs")) {
18		$cifs_support = 4;
19		}
20	if (&has_command("mount.smbfs")) {
21		$smbfs_support = &backquote_command("mount.smbfs -v 2>&1", 1) =~ /username=/i ? 4 : 3;
22		$smbfs_fs = "smbfs";
23		}
24	elsif (&has_command("mount.smb")) {
25		$smbfs_support = &backquote_command("mount.smb -v 2>&1", 1) =~ /username=/i ? 4 : 3;
26		$smbfs_fs = "smb";
27		}
28	elsif (&has_command("smbmount")) {
29		$smbfs_support = &backquote_command("smbmount -v 2>&1", 1) =~ /Version\s+2/i ? 2 : 1;
30		$smbfs_fs = "smbfs";
31		}
32	$swaps_support = -r "/proc/swaps";
33	$tmpfs_support = 1;
34	$ext3_support = 1;
35	$no_mount_check = 1;
36	$bind_support = 1;
37	if ($support{'ext4'}) {
38		$ext4_support = 1;
39		}
40	if ($support{'xfs'} || &has_command("mkfs.xfs")) {
41		$xfs_support = 1;
42		}
43	if ($support{'jfs'} || &has_command("mkfs.jfs")) {
44		$jfs_support = 1;
45		}
46	if ($support{'btrfs'} || &has_command("mkfs.btrfs")) {
47		$btrfs_support = 1;
48		}
49	}
50
51# We always need to check this, to fix up LABEL= mounts
52if (&has_command("e2label")) {
53	$has_e2label = 1;
54	}
55if (&has_command("xfs_db")) {
56	$has_xfs_db = 1;
57	}
58if (&has_command("vol_id")) {
59	$has_volid = 1;
60	}
61if (&has_command("reiserfstune")) {
62	$has_reiserfstune = 1;
63	}
64$uuid_directory = "/dev/disk/by-uuid";
65
66# Return information about a filesystem, in the form:
67#  directory, device, type, options, fsck_order, mount_at_boot
68# If a field is unused or ignored, a - appears instead of the value.
69# Swap-filesystems (devices or files mounted for VM) have a type of 'swap',
70# and 'swap' in the directory field
71sub list_mounts
72{
73return @list_mounts_cache if (@list_mounts_cache);
74local(@rv, @p, @o, $_, $i, $j);
75$i = 0;
76
77# Get /etc/fstab mounts
78open(FSTAB, "<".$config{fstab_file});
79while(<FSTAB>) {
80	local(@o, $at_boot);
81	chop; s/#.*$//g;
82	if (!/\S/ || /\signore\s/) { next; }
83	if (/\t+[^\t]+\t+[^\t+]\t+/) {
84		# Contains at least 3 tabs .. assume tab separation
85		@p = split(/\t+/, $_);
86		}
87	else {
88		@p = split(/\s+/, $_);
89		}
90	$p[0] =~ s/\\040/ /g;
91	$p[1] =~ s/\\040/ /g;
92	if ($p[2] eq "proc") { $p[0] = "proc"; }
93	elsif ($p[2] eq "auto") { $p[2] = "*"; }
94	elsif ($p[2] eq "swap") { $p[1] = "swap"; }
95	elsif ($p[2] eq $smbfs_fs || $p[2] eq "cifs") {
96		$p[0] =~ s/\\040/ /g;
97		$p[0] =~ s/\//\\/g;
98		}
99	$p[1] = &simplify_path($p[1]);
100	$rv[$i] = [ $p[1], $p[0], $p[2] ];
101	$rv[$i]->[5] = "yes";
102	@o = split(/,/ , $p[3] eq "defaults" ? "" : $p[3]);
103	if (($j = &indexof("noauto", @o)) >= 0) {
104		# filesytem is not mounted at boot
105		splice(@o, $j, 1);
106		$rv[$i]->[5] = "no";
107		}
108	if (($j = &indexof("bind", @o)) >= 0) {
109		# Special bind option, which indicates a loopback filesystem
110		splice(@o, $j, 1);
111		$rv[$i]->[2] = "bind";
112		}
113	$rv[$i]->[3] = (@o ? join(',' , @o) : "-");
114	$rv[$i]->[4] = (@p >= 5 ? $p[5] : 0);
115	$i++;
116	}
117close(FSTAB);
118
119if ($amd_support == 1) {
120	# Get old automounter configuration, as used by redhat
121	local $amd = &read_amd_conf();
122	if ($amd =~ /MOUNTPTS='(.*)'/) {
123		@p = split(/\s+/, $1);
124		for($j=0; $j<@p; $j+=2) {
125			$rv[$i++] = [ $p[$j], $p[$j+1], "auto",
126				      "-", 0, "yes" ];
127			}
128		}
129	}
130elsif ($amd_support == 2) {
131	# Guess what? There's now a *new* amd config file format, introduced
132	# in redhat 6.1 and caldera 2.3
133	local @amd = &parse_amd_conf();
134	local @sp = split(/:/, $amd[0]->{'opts'}->{'search_path'});
135	local ($am, $sp);
136	foreach $am (@amd) {
137		local $mn = $am->{'opts'}->{'map_name'};
138		if ($mn !~ /^\//) {
139			foreach $sp (@sp) {
140				if (-r "$sp/$mn") {
141					$mn = "$sp/$mn";
142					last;
143					}
144				}
145			}
146		$rv[$i++] = [ $am->{'dir'}, $mn,
147			      "auto", $am->{'opts'}, 0, "yes" ]
148			if ($am->{'dir'} ne 'global');
149		}
150	}
151
152# Get kernel automounter configuration
153if ($autofs_support) {
154	open(AUTO, "<".$config{'autofs_file'});
155	while(<AUTO>) {
156		chop;
157		s/#.*$//g;
158		if (/^\s*(\S+)\s+(\S+)\s*(.*)$/) {
159			$rv[$i++] = [ $1, $2, "autofs",
160				      ($3 ? &autofs_options($3) : "-"),
161				      0, "yes" ];
162			}
163		}
164	close(AUTO);
165	}
166
167@list_mounts_cache = @rv;
168return @rv;
169}
170
171
172# create_mount(directory, device, type, options, fsck_order, mount_at_boot)
173# Add a new entry to the fstab file, old or new automounter file
174sub create_mount
175{
176local(@mlist, @amd, $_, $opts);
177
178if ($_[2] eq "auto") {
179	if ($amd_support == 1) {
180		# Adding an old automounter mount
181		local $amd = &read_amd_conf();
182		local $m = "$_[0] $_[1]";
183		if ($amd =~ /MOUNTPTS=''/) {
184			$amd =~ s/MOUNTPTS=''/MOUNTPTS='$m'/;
185			}
186		else {
187			$amd =~ s/MOUNTPTS='(.*)'/MOUNTPTS='$1 $m'/;
188			}
189		&write_amd_conf($amd);
190		}
191	elsif ($amd_support == 2) {
192		# Adding a new automounter mount
193		local @amfs = split(/\s+/, $config{'auto_file'});
194		&open_tempfile(AMD, ">>$amfs[0]");
195		&print_tempfile(AMD, "\n");
196		&print_tempfile(AMD, "[ $_[0] ]\n");
197		&print_tempfile(AMD, "map_name = $_[1]\n");
198		&close_tempfile(AMD);
199		}
200	}
201elsif ($_[2] eq "autofs") {
202	# Adding a new automounter mount
203	&open_tempfile(AUTO, ">> $config{'autofs_file'}");
204	&print_tempfile(AUTO, "$_[0]  $_[1]");
205	if ($_[3]) {
206		&print_tempfile(AUTO, "  ",&autofs_args($_[3]));
207		}
208	&print_tempfile(AUTO, "\n");
209	&close_tempfile(AUTO);
210	}
211else {
212	# Adding a normal mount to the fstab file
213	local $dev = $_[1];
214	if ($_[2] eq $smbfs_fs || $_[2] eq "cifs") {
215		$dev =~ s/\\/\//g;
216		}
217	$dev =~ s/ /\\040/g;
218	local $mp = $_[0];
219	$mp =~ s/ /\\040/g;
220	&open_tempfile(FSTAB, ">> $config{fstab_file}");
221	&print_tempfile(FSTAB, $dev."\t".$mp."\t".$_[2]);
222	local @opts = $_[3] eq "-" ? ( ) : split(/,/, $_[3]);
223	if ($_[5] eq "no") {
224		push(@opts, "noauto");
225		}
226	else {
227		@opts = grep { $_ !~ /^(auto|noauto)$/ } @opts;
228		}
229	if ($_[2] eq "bind") {
230		push(@opts, "bind");
231		}
232	if (!@opts) { &print_tempfile(FSTAB, "\t"."defaults"); }
233	else { &print_tempfile(FSTAB, "\t".join(",", @opts)); }
234	&print_tempfile(FSTAB, "\t"."0"."\t");
235	&print_tempfile(FSTAB, $_[4] eq "-" ? "0\n" : "$_[4]\n");
236	&close_tempfile(FSTAB);
237	}
238undef(@list_mounts_cache);
239}
240
241
242# change_mount(num, directory, device, type, options, fsck_order, mount_at_boot)
243# Change an existing permanent mount
244sub change_mount
245{
246local($i, @fstab, $line, $opts, $j, @amd);
247$i = 0;
248
249# Update fstab file
250open(FSTAB, "<".$config{fstab_file});
251@fstab = <FSTAB>;
252close(FSTAB);
253&open_tempfile(FSTAB, "> $config{fstab_file}");
254foreach (@fstab) {
255	chop; ($line = $_) =~ s/#.*$//g;
256	if ($line =~ /\S/ && $line !~ /\signore\s/ && $i++ == $_[0]) {
257		# Found the line to replace
258		local $dev = $_[2];
259		if ($_[3] eq $smbfs_fs || $_[3] eq "cifs") {
260			$dev =~ s/\\/\//g;
261			}
262		$dev =~ s/ /\\040/g;
263		local $mp = $_[1];
264		$mp =~ s/ /\\040/g;
265		&print_tempfile(FSTAB, $dev."\t".$mp."\t".$_[3]);
266		local @opts = $_[4] eq "-" ? ( ) : split(/,/, $_[4]);
267		if ($_[6] eq "no") {
268			push(@opts, "noauto");
269			}
270		else {
271			@opts = grep { $_ !~ /^(auto|noauto)$/ } @opts;
272			}
273		if ($_[3] eq "bind") {
274			push(@opts, "bind");
275			}
276		if (!@opts) { &print_tempfile(FSTAB, "\t"."defaults"); }
277		else { &print_tempfile(FSTAB, "\t".join(",", @opts)); }
278		&print_tempfile(FSTAB, "\t"."0"."\t");
279		&print_tempfile(FSTAB, $_[5] eq "-" ? "0\n" : "$_[5]\n");
280		}
281	else { &print_tempfile(FSTAB, $_,"\n"); }
282	}
283&close_tempfile(FSTAB);
284
285if ($amd_support == 1) {
286	# Update older amd configuration
287	local $amd = &read_amd_conf();
288	if ($amd =~ /MOUNTPTS='(.*)'/) {
289		# found mount points line..
290		local @mpts = split(/\s+/, $1);
291		for($j=0; $j<@mpts; $j+=2) {
292			if ($i++ == $_[0]) {
293				$mpts[$j] = $_[1];
294				$mpts[$j+1] = $_[2];
295				}
296			}
297		local $mpts = join(" ", @mpts);
298		$amd =~ s/MOUNTPTS='(.*)'/MOUNTPTS='$mpts'/;
299		}
300	&write_amd_conf($amd);
301	}
302elsif ($amd_support == 2) {
303	# Update new amd configuration
304	local @amd = &parse_amd_conf();
305	foreach $am (@amd) {
306		next if ($am->{'dir'} eq 'global');
307		if ($i++ == $_[0]) {
308			local $lref = &read_file_lines($am->{'file'});
309			local @nl = ( "[ $_[1] ]" );
310			local %opts = %{$am->{'opts'}};
311			$opts{'map_name'} = $_[2];
312			foreach $o (keys %opts) {
313				push(@nl, "$o = $opts{$o}");
314				}
315			splice(@$lref, $am->{'line'},
316			       $am->{'eline'} - $am->{'line'} + 1, @nl);
317			&flush_file_lines();
318			}
319		}
320	}
321
322# Update autofs configuration
323if ($autofs_support) {
324	open(AUTO, "<".$config{'autofs_file'});
325	@auto = <AUTO>;
326	close(AUTO);
327	&open_tempfile(AUTO, "> $config{'autofs_file'}");
328	foreach (@auto) {
329		chop; ($line = $_) =~ s/#.*$//g;
330		if ($line =~ /\S/ && $i++ == $_[0]) {
331			&print_tempfile(AUTO, "$_[1]  $_[2]");
332			if ($_[4]) {
333				&print_tempfile(AUTO, "  ",&autofs_args($_[4]));
334				}
335			&print_tempfile(AUTO, "\n");
336			}
337		else {
338			&print_tempfile(AUTO, $_,"\n");
339			}
340		}
341	&close_tempfile(AUTO);
342	}
343undef(@list_mounts_cache);
344}
345
346
347# delete_mount(index)
348# Delete an existing permanent mount
349sub delete_mount
350{
351local($i, @fstab, $line, $opts, $j, @amd);
352$i = 0;
353
354# Update fstab file
355open(FSTAB, "<".$config{fstab_file});
356@fstab = <FSTAB>;
357close(FSTAB);
358&open_tempfile(FSTAB, ">$config{fstab_file}");
359foreach (@fstab) {
360	chop; ($line = $_) =~ s/#.*$//g;
361	if ($line !~ /\S/ || $line =~ /\signore\s/ || $i++ != $_[0]) {
362		# Don't delete this line
363		&print_tempfile(FSTAB, $_,"\n");
364		}
365	}
366&close_tempfile(FSTAB);
367
368if ($amd_support == 1) {
369	# Update older amd configuration
370	local $foundamd = 0;
371	local $amd = &read_amd_conf();
372	if ($amd =~ /MOUNTPTS='(.*)'/) {
373		# found mount points line..
374		local @mpts = split(/\s+/, $1);
375		for($j=0; $j<@mpts; $j+=2) {
376			if ($i++ == $_[0]) {
377				splice(@mpts, $j, 2);
378				$foundamd = 1;
379				}
380			}
381		local $mpts = join(" ", @mpts);
382		$amd =~ s/MOUNTPTS='(.*)'/MOUNTPTS='$mpts'/;
383		}
384	&write_amd_conf($amd) if ($foundamd);
385	}
386elsif ($amd_support == 2) {
387	# Update new amd configuration
388	local @amd = &parse_amd_conf();
389	foreach $am (@amd) {
390		next if ($am->{'dir'} eq 'global');
391		if ($i++ == $_[0]) {
392			local $lref = &read_file_lines($am->{'file'});
393			splice(@$lref, $am->{'line'},
394			       $am->{'eline'} - $am->{'line'} + 1);
395			&flush_file_lines();
396			}
397		}
398	}
399
400# Update AMD file
401if ($amd_support) {
402	open(AMD, "<".$config{auto_file});
403	@amd = <AMD>;
404	close(AMD);
405	&open_tempfile(AMD, ">$config{auto_file}");
406	foreach (@amd) {
407		if (/MOUNTPTS='(.*)'/) {
408			# found mount points line..
409			@mpts = split(/\s+/, $1);
410			for($j=0; $j<@mpts; $j+=2) {
411				if ($i++ != $_[0]) {
412					push(@nmpts, $mpts[$j]);
413					push(@nmpts, $mpts[$j+1]);
414					}
415				}
416			&print_tempfile(AMD, "MOUNTPTS='".join(' ', @nmpts)."'\n");
417			}
418		else { &print_tempfile(AMD, $_); }
419		}
420	&close_tempfile(AMD);
421	}
422
423# Update autofs file
424if ($autofs_support) {
425	open(AUTO, "<".$config{'autofs_file'});
426	@auto = <AUTO>;
427	close(AUTO);
428	&open_tempfile(AUTO, ">$config{'autofs_file'}");
429	foreach (@auto) {
430		chop; ($line = $_) =~ s/#.*$//g;
431		if ($line !~ /\S/ || $i++ != $_[0]) {
432			# keep this line
433			&print_tempfile(AUTO, $_,"\n");
434			}
435		}
436	&close_tempfile(AUTO);
437	}
438undef(@list_mounts_cache);
439}
440
441
442# list_mounted([no-label])
443# Return a list of all the currently mounted filesystems and swap files.
444# The list is in the form:
445#  directory device type options
446sub list_mounted
447{
448return @list_mounted_cache
449	if (@list_mounted_cache && $list_mounted_cache_mode == $_[0]);
450local(@rv, @p, @o, $mo, $_, %smbopts);
451
452# Do any filesystems use labels that we need to resolve?
453local @mounts = &list_mounts();
454local $anylabel = 0;
455local $anyuuid = 0;
456foreach my $m (@mounts) {
457	if ($m->[1] =~ /^LABEL=/) {
458		$anylabel++;
459		}
460	if ($m->[1] =~ /^UUID=/) {
461		$anyuuid++;
462		}
463	}
464
465&read_smbopts();
466open(MTAB, "</etc/mtab");
467while(<MTAB>) {
468	chop;
469	s/#.*$//g;
470	if (!/\S/) { next; }
471	@p = split(/\s+/, $_);
472	next if ($p[0] eq "rootfs");	# Bogus pseudo-fs
473	$p[1] = &simplify_path($p[1]);
474	if ($p[2] eq "auto" || $p[0] =~ /^\S+:\(pid\d+\)$/) {
475		# Automounter map.. turn the map= option into the device
476		@o = split(/,/ , $p[3]);
477		($mo) = grep {/^map=/} (@o);
478		$mo =~ /^map=(.*)$/; $p[0] = $1;
479		$p[3] = join(',' , grep {!/^map=/} (@o));
480		$p[2] = "auto";
481		}
482	elsif ($p[2] eq "autofs") {
483		# Kernel automounter map.. use the pid to find the map
484		$p[0] =~ /automount\(pid(\d+)\)/ || next;
485		$out = &backquote_command("ps hwwww $1", 1);
486		$out =~ /automount\s+(.*)\s*(\S+)\s+(file|program|yp)(,\S+)?\s+(\S+)/ || next;
487		$p[0] = $5;
488		$p[3] = $1 ? &autofs_options($1) : "-";
489		}
490	elsif ($p[2] eq $smbfs_fs || $p[2] eq "cifs") {
491		# Change from //FOO/BAR to \\foo\bar
492		$p[0] = &lowercase_share_path($p[0]);
493		$p[3] = $smbopts{$p[1]};
494		}
495	elsif ($p[2] eq "proc") {
496		# The source for proc mounts is always proc
497		$p[0] = "proc";
498		}
499	if (!$_[0] && $anylabel) {
500		# Check for a label on this partition, and there is one
501		# and this filesystem is in fstab with the label, change
502		# the device.
503		local $label = &get_filesystem_label(@p);
504		if (defined($label)) {
505			foreach my $m (@mounts) {
506				if ($m->[0] eq $p[1] &&
507				    $m->[1] eq "LABEL=$label") {
508					$p[0] = "LABEL=$label";
509					last;
510					}
511				}
512			}
513		}
514
515	# Check for a UUID on this partition, and if there is one
516	# and the filesystem is in fstab with the label, change
517	# the device.
518	if (!$_[0] && $anyuuid) {
519		local $uuid = &device_to_uuid($p[0], \@mounts);
520		if ($uuid) {
521			$p[0] = "UUID=$uuid";
522			}
523		}
524
525	# check fstab for a mount on the same dir which is a symlink
526	# to the device
527	local @st = stat($p[0]);
528	foreach $m (@mounts) {
529		if ($m->[0] eq $p[1]) {
530			local @fst = stat($m->[1]);
531			if ($fst[0] == $st[0] && $fst[1] == $st[1]) {
532				# symlink to the same place!
533				$p[0] = $m->[1];
534				last;
535				}
536			}
537		}
538
539	if ($p[3] =~ s/,bind,// || $p[3] =~ s/^bind,// ||
540	    $p[3] =~ s/,bind$// || $p[3] =~ s/^bind$//) {
541		# Special bind option, which indicates a loopback filesystem
542		$p[2] = "bind";
543		}
544
545	push(@rv, [ $p[1], $p[0], $p[2], $p[3] ]);
546	}
547close(MTAB);
548open(SWAPS, "</proc/swaps");
549while(<SWAPS>) {
550	chop;
551	if (/^(\/\S+)\s+/) {
552		local $sf = $1;
553
554		# check fstab for a mount on a device which is a symlink
555		# to the path in /proc/swaps
556		local @st = stat($sf);
557		foreach $m (@mounts) {
558			local @fst = stat($m->[1]);
559			if ($m->[2] eq 'swap' && $fst[0] == $st[0] &&
560			    $fst[1] == $st[1]) {
561				$sf = $m->[1];
562				last;
563				}
564			}
565
566		# Convert to UUID format if used in fstab
567		if (!$_[0]) {
568			local $uuid = &device_to_uuid($sf, \@mounts);
569			if ($uuid) {
570				$sf = "UUID=$uuid";
571				}
572			}
573		push(@rv, [ "swap", $sf, "swap", "-" ]);
574		}
575	}
576close(SWAPS);
577@list_mounted_cache = @rv;
578$list_mounted_cache_mode = $_[0];
579return @rv;
580}
581
582# device_to_uuid(device, [&mounts])
583# Given a device name like /dev/sda1, return the UUID for it.
584# If a list of mounts are given, only match if found in mount list.
585sub device_to_uuid
586{
587local ($device, $mounts) = @_;
588local $uuid;
589if ($device =~ /^\Q$uuid_directory\E\/([^\/]+)$/) {
590	# Device is already under the UUID directory, so ID can be found
591	# immediately from the path
592	$uuid = $1;
593	}
594elsif ($device =~ /^\/dev\// && ($has_volid || -d $uuid_directory)) {
595	# Device is like /dev/sda1, so try to find the UUID for it by either
596	# looking in /dev/disk/by-uuid or using the volid command
597	if (-d $uuid_directory) {
598		# Use UUID mapping directory
599		opendir(DIR, $uuid_directory);
600		foreach my $f (readdir(DIR)) {
601			local $linkdest = &simplify_path(
602				&resolve_links("$uuid_directory/$f"));
603			if ($linkdest eq $device) {
604				$uuid = $f;
605				last;
606				}
607			}
608		closedir(DIR);
609		}
610	else {
611		# Use vol_id command
612		local $out = &backquote_command(
613				"vol_id ".quotemeta($device)." 2>&1", 1);
614		if ($out =~ /ID_FS_UUID=(\S+)/) {
615			$uuid = $1;
616			}
617		}
618	}
619if ($uuid && @$mounts) {
620	my $found;
621	foreach my $m (@$mounts) {
622		if ($m->[1] eq "UUID=$uuid") {
623			$found++;
624			last;
625			}
626		}
627	$uuid = undef if (!$found);
628	}
629return $uuid;
630}
631
632# mount_dir(directory, device, type, options)
633# Mount a new directory from some device, with some options. Returns 0 if ok,
634# or an error string if failed
635sub mount_dir
636{
637local($out, $opts, $shar, %options, %smbopts);
638local @opts = $_[3] eq "-" || $_[3] eq "" ? ( ) :
639		grep { $_ ne "noauto" } split(/,/, $_[3]);
640if ($_[2] eq "bind") {
641	push(@opts, "bind");
642	}
643$opts = @opts ? "-o ".quotemeta(join(",", @opts)) : "";
644&parse_options($_[2], $_[3]);
645
646# Work out args for label or UUID
647local $devargs;
648if ($_[1] =~ /LABEL=(.*)/) {
649	$devargs = "-L ".quotemeta($1);
650	}
651elsif ($_[1] =~ /UUID=(\S+)/) {
652	$devargs = "-U ".quotemeta($1);
653	}
654else {
655	$devargs = quotemeta($_[1]);
656	}
657
658if ($_[2] eq "swap") {
659	# Use swapon to add the swap space..
660	local $priarg = $options{'pri'} ne "" ? "-p $options{'pri'}" : "";
661	$out = &backquote_logged("swapon $priarg $devargs 2>&1");
662	if ($out =~ /Invalid argument/) {
663		# looks like this swap partition isn't ready yet.. set it up
664		$out = &backquote_logged("mkswap $devargs 2>&1");
665		if ($?) { return "mkswap failed : <pre>$out</pre>"; }
666		$out = &backquote_logged("swapon $devargs 2>&1");
667		}
668	if ($?) { return "<pre>$out</pre>"; }
669	}
670elsif ($_[2] eq "auto") {
671	# Old automounter filesystem
672	$out = &backquote_logged("amd $_[0] $_[1] >/dev/null 2>/dev/null");
673	if ($?) { return $text{'linux_eamd'}; }
674	}
675elsif ($_[2] eq "autofs") {
676	# New automounter filesystem
677	$opts = &autofs_args($_[3]);
678	$type = $_[1] !~ /^\// ? "yp" :
679		(-x $_[1]) ? "program" : "file";
680	$out = &backquote_logged("automount $opts $_[0] $type $_[1] 2>&1");
681	if ($?) { return &text('linux_eauto', "<pre>$out</pre>"); }
682	}
683elsif ($_[2] eq $smbfs_fs || $_[2] eq "cifs") {
684	local $shar = $_[1];
685	$shar =~ s/\\/\//g if ($shar =~ /^\\/);
686	local $support = $_[2] eq $smbfs_fs ? $smbfs_support : $cifs_support;
687	return uc($_[2])." not supported" if (!$support);
688	local $qshar = quotemeta($shar);
689	if ($support >= 3) {
690		# SMB filesystem mounted with mount command
691		local $temp = &transname();
692		local $ex = &system_logged("mount -t $_[2] $opts $qshar $_[0] >$temp 2>&1 </dev/null");
693		local $out = &read_file_contents($temp);
694		unlink($temp);
695		if ($ex || $out =~ /failed|error/i) {
696			&system_logged("umount $_[0] >/dev/null 2>&1");
697			return "<pre>$out</pre>";
698			}
699		}
700	elsif ($support == 2) {
701		# SMB filesystem mounted with version 2.x smbmount
702		$opts =
703		    ($options{'user'} ? "-U $options{'user'} " : "").
704		    ($options{'passwd'} ? "" : "-N ").
705		    ($options{'workgroup'} ? "-W $options{'workgroup'} " : "").
706		    ($options{'clientname'} ? "-n $options{'clientname'} " : "").
707		    ($options{'machinename'} ? "-I $options{'machinename'} " : "");
708		&foreign_require("proc");
709		local ($fh, $fpid) = &proc::pty_process_exec_logged(
710			"sh -c 'smbmount $shar $_[0] -d 0 $opts'");
711		if ($options{'passwd'}) {
712			local $w = &wait_for($fh, "word:");
713			if ($w < 0) {
714				&system_logged("umount $_[0] >/dev/null 2>&1");
715				return $text{'linux_esmbconn'};
716				}
717			local $p = "$options{'passwd'}\n";
718			syswrite($fh, $p, length($p));
719			}
720		local $got;
721		while(<$fh>) {
722			$got .= $_;
723			}
724		if ($got =~ /failed/) {
725			&system_logged("umount $_[0] >/dev/null 2>&1");
726			return "<pre>$got</pre>\n";
727			}
728		close($fh);
729		}
730	elsif ($support == 1) {
731		# SMB filesystem mounted with older smbmount
732		$shortname = &get_system_hostname();
733		if ($shortname =~ /^([^\.]+)\.(.+)$/) { $shortname = $1; }
734		$opts =
735		   ($options{servername} ? "-s $options{servername} " : "").
736		   ($options{clientname} ? "-c $options{clientname} "
737					 : "-c $shortname ").
738		   ($options{machinename} ? "-I $options{machinename} " : "").
739		   ($options{user} ? "-U $options{user} " : "").
740		   ($options{passwd} ? "-P $options{passwd} " : "-n ").
741		   ($options{uid} ? "-u $options{uid} " : "").
742		   ($options{gid} ? "-g $options{gid} " : "").
743		   ($options{fmode} ? "-f $options{fmode} " : "").
744		   ($options{dmode} ? "-d $options{dmode} " : "");
745		$out = &backquote_logged("smbmount $shar $_[0] $opts 2>&1 </dev/null");
746		if ($out) {
747			&system_logged("umount $_[0] >/dev/null 2>&1");
748			return "<pre>$out</pre>";
749			}
750		}
751	&read_smbopts();
752	$smbopts{$_[0]} = $_[3] eq "-" ? "dummy=1" : $_[3];
753	&write_smbopts();
754	}
755else {
756	# some filesystem supported by mount
757	local $fs = $_[2] eq "*" ? "auto" : $_[2];
758	$cmd = "mount -t $fs $opts $devargs ".quotemeta($_[0]);
759	$out = &backquote_logged("$cmd 2>&1 </dev/null");
760	if ($?) { return "<pre>$out</pre>"; }
761	}
762undef(@list_mounted_cache);
763return 0;
764}
765
766# os_remount_dir(directory, device, type, options)
767# Adjusts the options for some mounted filesystem, by re-mounting
768sub os_remount_dir
769{
770if ($_[2] eq "swap" || $_[2] eq "auto" || $_[2] eq "autofs" ||
771    $_[2] eq $smbfs_fs || $_[2] eq "cifs") {
772	# Cannot use remount
773	local $err = &unmount_dir(@_);
774	return $err if ($err);
775	return &mount_dir(@_);
776	}
777else {
778	# Attempt to use remount
779	local @opts = $_[3] eq "-" || $_[3] eq "" ? ( ) :
780			grep { $_ ne "noauto" } split(/,/, $_[3]);
781	push(@opts, "remount");
782	local $opts = @opts ? "-o ".quotemeta(join(",", @opts)) : "";
783	local $fs = $_[2] eq "*" ? "auto" : $_[2];
784	if ($_[1] =~ /LABEL=(.*)/) {
785		$cmd = "mount -t $fs -L $1 $opts $_[0]";
786		}
787	elsif ($_[1] =~ /UUID=(\S+)/) {
788		$cmd = "mount -t $fs -U $1 $opts $_[0]";
789		}
790	else {
791		$cmd = "mount -t $fs $opts $_[1] $_[0]";
792		}
793	$out = &backquote_logged("$cmd 2>&1 </dev/null");
794	if ($?) { return "<pre>$out</pre>"; }
795	undef(@list_mounted_cache);
796	return undef;
797	}
798}
799
800# unmount_dir(directory, device, type, options, [force])
801# Unmount a directory that is currently mounted. Returns 0 if ok,
802# or an error string if failed
803sub unmount_dir
804{
805local($out, %smbopts, $dir);
806if ($_[2] eq "swap") {
807	# Use swapoff to remove the swap space..
808	$out = &backquote_logged("swapoff $_[1]");
809	if ($?) { return "<pre>$out</pre>"; }
810	}
811elsif ($_[2] eq "auto") {
812	# Kill the amd process
813	$dir = $_[0];
814	if (&backquote_command("cat /etc/mtab") =~ /:\(pid([0-9]+)\)\s+$dir\s+(auto|nfs)\s+/) {
815		&kill_logged('TERM', $1) || return $text{'linux_ekillamd'};
816		}
817	sleep(2);
818	}
819elsif ($_[2] eq "autofs") {
820	# Kill the automount process
821	$dir = $_[0];
822	&backquote_command("cat /etc/mtab") =~ /automount\(pid([0-9]+)\)\s+$dir\s+autofs\s+/;
823	&kill_logged('TERM', $1) || return $text{'linux_ekillauto'};
824	sleep(2);
825	}
826else {
827	local $fflag = $_[4] ? "-l" : "";
828	$out = &backquote_logged("umount $fflag $_[0] 2>&1");
829	if ($?) { return "<pre>$out</pre>"; }
830	if ($_[2] eq $smbfs_fs || $_[2] eq "cifs") {
831		# remove options from list
832		&read_smbopts();
833		delete($smbopts{$_[0]});
834		&write_smbopts();
835		&execute_command("rmmod smbfs");
836		&execute_command("rmmod cifs");
837		}
838	}
839undef(@list_mounted_cache);
840return 0;
841}
842
843# can_force_unmount_dir(directory, device, type)
844# Returns 1 if some directory can be forcibly un-mounted
845sub can_force_unmount_dir
846{
847if ($_[2] ne "swap" && $_[2] ne "auto" && $_[2] ne "autofs") {
848	# All filesystems using the normal 'mount' command can be
849	return 1;
850	}
851else {
852	return 0;
853	}
854}
855
856# mount_modes(type)
857# Given a filesystem type, returns 4 numbers that determine how the file
858# system can be mounted, and whether it can be fsck'd
859#  0 - cannot be permanently recorded
860#	(smbfs under linux before 2.2)
861#  1 - can be permanently recorded, and is always mounted at boot
862#	(swap under linux)
863#  2 - can be permanently recorded, and may or may not be mounted at boot
864#	(most normal filesystems)
865# The second is:
866#  0 - mount is always permanent => mounted when saved
867#	(swap under linux before 2.2, or any filesystem that is always
868#	 mounted at boot by some script)
869#  1 - doesn't have to be permanent
870#	(normal fs types)
871# The third is:
872#  0 - cannot be fsck'd at boot time
873#  1 - can be be fsck'd at boot
874# The fourth is:
875#  0 - can be unmounted
876#  1 - cannot be unmounted
877# The (optional) fourth is:
878#  0 - can be edited
879#  1 - cannot be edited (because is always mounted at boot by some script)
880sub mount_modes
881{
882if ($_[0] eq "swap")
883	{ return (1, $swaps_support ? 1 : 0, 0, 0); }
884elsif ($_[0] eq "auto" || $_[0] eq "autofs")
885	{ return (1, 1, 0, 0); }
886elsif ($_[0] eq $smbfs_fs)
887	{ return ($smbfs_support >= 3 ? 2 : 0, 1, 0, 0); }
888elsif ($_[0] eq "cifs") { return (2, 1, 0, 0); }
889elsif ($_[0] =~ /^ext\d+$/ || $_[0] eq "minix" ||
890       $_[0] eq "xiafs" || $_[0] eq "xfs" || $_[0] eq "jfs" || $_[0] eq "btrfs")
891	{ return (2, 1, 1, 0); }
892else
893	{ return (2, 1, 0, 0); }
894}
895
896
897# disk_space(type, directory)
898# Returns the amount of total and free space for some filesystem, or an
899# empty array if not appropriate.
900sub disk_space
901{
902if (&get_mounted($_[1], "*") < 0) { return (); }
903if ($_[0] eq "proc" || $_[0] eq "swap" ||
904    $_[0] eq "auto" || $_[0] eq "autofs") { return (); }
905&clean_language();
906local $out = &backquote_command("df -k ".quotemeta($_[1]), 1);
907&reset_environment();
908if ($out =~ /Mounted on\n\S+\s+(\S+)\s+\S+\s+(\S+)/) {
909	return ($1, $2);
910	}
911return ( );
912}
913
914# inode_space(type, directory)
915# Returns the total and free number of inodes for some filesystem.
916sub inode_space
917{
918if (&get_mounted($_[1], "*") < 0) { return (); }
919&clean_language();
920local $out = &backquote_command("df -i $_[1]", 1);
921&reset_environment();
922if ($out =~ /Mounted on\n\S+\s+(\S+)\s+\S+\s+(\S+)/) {
923	return ($1, $2);
924	}
925return ( );
926}
927
928# list_fstypes()
929# Returns an array of all the supported filesystem types. If a filesystem is
930# found that is not one of the supported types, generate_location() and
931# generate_options() will not be called for it.
932sub list_fstypes
933{
934local @sup = ("ext2", "msdos", "nfs", "nfs4", "iso9660", "ext",
935	      "hpfs", "fat", "vfat", "umsdos", "sysv", "reiserfs",
936	      "ntfs", "hfs", "fatx");
937push(@sup, $smbfs_fs) if ($smbfs_support);
938push(@sup, "cifs") if ($cifs_support);
939push(@sup, "auto") if ($amd_support);
940push(@sup, "autofs") if ($autofs_support);
941push(@sup, "tmpfs") if ($tmpfs_support);
942push(@sup, "ext3") if ($ext3_support);
943push(@sup, "ext4") if ($ext4_support);
944push(@sup, "xfs") if ($xfs_support);
945push(@sup, "btrfs") if ($btrfs_support);
946push(@sup, "jfs") if ($jfs_support);
947push(@sup, "bind") if ($bind_support);
948push(@sup, "swap");
949return @sup;
950}
951
952
953# fstype_name(type)
954# Given a short filesystem type, return a human-readable name for it
955sub fstype_name
956{
957local(%fsmap);
958%fsmap = ("ext2","Old Linux Native Filesystem",
959	  "ext3","Linux Native Filesystem",
960	  "ext4","New Linux Native Filesystem",
961	  "minix","Minix Filesystem",
962	  "msdos","MS-DOS Filesystem",
963	  "nfs","Network Filesystem",
964	  "nfs4","Network Filesystem v4",
965	  $smbfs_fs,"Windows Networking Filesystem",
966	  "cifs","Common Internet Filesystem",
967	  "iso9660","ISO9660 CD-ROM",
968	  "ext","Old EXT Linux Filesystem",
969	  "xiafs","Old XIAFS Linux Filesystem",
970	  "hpfs","OS/2 Filesystem",
971	  "fat","MS-DOS Filesystem",
972	  "vfat","Windows Filesystem",
973	  "umsdos","Linux on top of MS-DOS Filesystem",
974	  "sysv","System V Filesystem",
975	  "swap","Virtual Memory",
976	  "proc","Kernel Filesystem",
977	  "sysfs","Kernel Filesystem",
978	  "devpts","Pseudoterminal Device Filesystem",
979	  "auto",($autofs_support ? "Old " : "")."Automounter Filesystem",
980	  "reiserfs","Reiser Filesystem",
981	  "autofs","New Automounter Filesystem",
982	  "usbdevfs","USB Devices",
983	  "shm","SysV Shared Memory",
984	  "tmpfs","RAM/Swap Disk",
985	  "devtmpfs","RAM/Swap Disk",
986	  "ramfs","RAM Disk",
987	  "btrfs","Oracle B-Tree Filesystem",
988	  "ocfs2","Oracle Clustering Filesystem",
989	  "gfs2","RedHat Clustering Filesystem",
990	  "xfs","Linux XFS Filesystem",
991	  "jfs","IBM Journalling Filesystem",
992	  "ntfs","Windows NT Filesystem",
993	  "bind","Loopback Filesystem",
994	  "hfs","Apple Filesystem",
995	  "fatx","XBOX Filesystem",
996	  "btrfs","BTR Filesystem",
997	  );
998return $config{long_fstypes} && $fsmap{$_[0]} ? $fsmap{$_[0]} : uc($_[0]);
999}
1000
1001
1002# multiple_mount(type)
1003# Returns 1 if filesystems of this type can be mounted multiple times, 0 if not
1004sub multiple_mount
1005{
1006return ($_[0] eq "nfs" || $_[0] eq "nfs4" || $_[0] eq "auto" ||
1007	$_[0] eq "autofs" || $_[0] eq "bind" || $_[0] eq "tmpfs");
1008}
1009
1010
1011# generate_location(type, location)
1012# Output HTML for editing the mount location of some filesystem.
1013sub generate_location
1014{
1015local ($type, $loc) = @_;
1016if ($type eq "nfs" || $type eq "nfs4") {
1017	# NFS mount from some host and directory
1018	local ($host, $dir) = $loc =~ /^([^:]+):(.*)$/ ? ( $1, $2 ) : ( );
1019	print &ui_table_row(&hlink($text{'linux_nfshost'}, "nfshost"),
1020		&ui_textbox("nfs_host", $host, 30).
1021		&nfs_server_chooser_button("nfs_host").
1022		"&nbsp;".
1023		"<b>".&hlink($text{'linux_nfsdir'}, "nfsdir")."</b> ".
1024		&ui_textbox("nfs_dir",
1025	       		    ($type eq "nfs4") && ($dir eq "") ? "/" : $dir, 30).
1026		&nfs_export_chooser_button("nfs_host", "nfs_dir"));
1027	}
1028elsif ($type eq "auto") {
1029	# Using some automounter map
1030	print &ui_table_row($text{'linux_map'},
1031		&ui_textbox("auto_map", $loc, 30)." ".
1032		&file_chooser_button("auto_map", 0));
1033	}
1034elsif ($type eq "autofs") {
1035	# Using some kernel automounter map
1036	print &ui_table_row($text{'linux_map'},
1037		&ui_textbox("autofs_map", $loc, 30)." ".
1038		&file_chooser_button("autofs_map", 0));
1039	}
1040elsif ($type eq "swap") {
1041	# Swap file or device
1042	&foreign_require("fdisk");
1043	local @opts;
1044	local ($found, $ufound, $lnx_dev);
1045
1046	# Show partitions input
1047	local $sel = &fdisk::partition_select("lnx_disk", $loc, 3, \$found);
1048	push(@opts, [ 0, $text{'linux_disk'}, $sel ]);
1049	$lnx_dev = 0 if ($found);
1050
1051	# Show UUID input
1052	if ($has_volid || -d $uuid_directory) {
1053		local $u = $loc =~ /UUID=(\S+)/ ? $1 : undef;
1054		local $usel = &fdisk::volid_select("lnx_uuid", $u, \$ufound);
1055		if ($usel) {
1056			push(@opts, [ 5, $text{'linux_usel'}, $usel ]);
1057			$lnx_dev = 5 if ($ufound);
1058			}
1059		}
1060
1061	# Show other file input
1062	$lnx_dev = 1 if (!$found && !$ufound);
1063	push(@opts, [ 1, $text{'linux_swapfile'},
1064			 &ui_textbox("lnx_other", $loc, 40)." ".
1065			 &file_chooser_button("lnx_other") ]);
1066	print &ui_table_row($text{'linux_swapfile'},
1067		&ui_radio_table("lnx_dev", $lnx_dev, \@opts));
1068	}
1069elsif ($type eq $smbfs_fs || $type eq "cifs") {
1070	# Windows filesystem
1071	local ($server, $share) = $loc =~ /^\\\\([^\\]*)\\(.*)$/ ?
1072					($1, $2) : ( );
1073	print &ui_table_row($text{'linux_smbserver'},
1074		&ui_textbox("smbfs_server", $server, 30)." ".
1075		&smb_server_chooser_button("smbfs_server")." ".
1076		"&nbsp;".
1077		"<b>$text{'linux_smbshare'}</b> ".
1078		&ui_textbox("smbfs_share", $share, 30)." ".
1079		&smb_share_chooser_button("smbfs_server", "smbfs_share"));
1080	}
1081elsif ($type eq "tmpfs") {
1082	# RAM disk (no location needed)
1083	}
1084elsif ($type eq "bind") {
1085	# Loopback filesystem, mounted from some other directory
1086	print &ui_table_row($text{'linux_bind'},
1087		&ui_textbox("bind_dir", $loc, 40)." ".
1088		&file_chooser_button("bind_dir", 1));
1089	}
1090else {
1091	# This is some linux disk-based filesystem
1092	&foreign_require("fdisk");
1093	local ($found, $rfound, $lfound, $vfound, $ufound, $rsel, $c);
1094	local ($lnx_dev, @opts);
1095
1096	# Show regular partition input
1097	local $sel = &fdisk::partition_select("lnx_disk", $loc, 0, \$found);
1098	push(@opts, [ 0, $text{'linux_disk'}, $sel ]);
1099	$lnx_dev = 0 if ($found);
1100
1101	# Show RAID input
1102	if (&foreign_check("raid")) {
1103		&foreign_require("raid");
1104		local $conf = &raid::get_raidtab();
1105		local @ropts;
1106		foreach $c (@$conf) {
1107			if ($c->{'active'}) {
1108				$c->{'value'} =~ /(\d+)$/;
1109				push(@ropts, [ $c->{'value'},
1110					       &text('linux_rdev', "$1") ]);
1111				$rfound++ if ($loc eq $c->{'value'});
1112				}
1113			}
1114		$lnx_dev = 2 if ($rfound);
1115		if (@ropts) {
1116			push(@opts, [ 2, $text{'linux_raid'},
1117				&ui_select("lnx_raid", $loc, \@ropts) ]);
1118			}
1119		}
1120
1121	# Show LVM input
1122	if (&foreign_check("lvm")) {
1123		&foreign_require("lvm");
1124		local @vgs = &lvm::list_volume_groups();
1125		local @lvs;
1126		foreach $v (@vgs) {
1127			push(@lvs, &lvm::list_logical_volumes($v->{'name'}));
1128			}
1129		local @lopts;
1130		foreach $l (@lvs) {
1131			local $sf = &same_file($loc, $l->{'device'});
1132			push(@lopts, [ $l->{'device'},
1133			    &text('linux_ldev', $l->{'vg'}, $l->{'name'}) ]);
1134			$vfound = $l->{'device'} if ($sf);
1135			}
1136		$lnx_dev = 4 if ($vfound);
1137		if (@lopts) {
1138			push(@opts, [ 4, $text{'linux_lvm'},
1139				&ui_select("lnx_lvm", $vfound, \@lopts) ]);
1140			}
1141		}
1142
1143	# Show label input
1144	if ($has_e2label || $has_xfs_db || $has_reiserfstune) {
1145		local $l = $_[1] =~ /LABEL=(.*)/ ? $1 : undef;
1146		local $esel = &fdisk::label_select("lnx_label", $l, \$lfound);
1147		if ($esel) {
1148			push(@opts, [ 3, $text{'linux_lsel'}, $esel ]);
1149			$lnx_dev = 3 if ($lfound);
1150			}
1151		}
1152
1153	# Show UUID input
1154	if ($has_volid || -d $uuid_directory) {
1155		local $u = $loc =~ /UUID=(\S+)/ ? $1 : undef;
1156		local $usel = &fdisk::volid_select("lnx_uuid", $u, \$ufound);
1157		if ($usel) {
1158			push(@opts, [ 5, $text{'linux_usel'}, $usel ]);
1159			$lnx_dev = 5 if ($ufound);
1160			}
1161		}
1162
1163	# Show other device input
1164	local $anyfound = $found || $rfound || $lfound || $vfound || $ufound;
1165	$lnx_dev = 1 if (!$anyfound);
1166	push(@opts, [ 1, $text{'linux_other'},
1167		      &ui_textbox("lnx_other", $anyfound ? "" : $loc, 40).
1168		      " ".&file_chooser_button("lnx_other") ]);
1169
1170	print &ui_table_row(&fstype_name($_[0]),
1171		&ui_radio_table("lnx_dev", $lnx_dev, \@opts));
1172	}
1173}
1174
1175
1176# generate_options(type, newmount)
1177# Output HTML for editing mount options for a particular filesystem
1178# under this OS
1179sub generate_options
1180{
1181local ($type, $newmount) = @_;
1182if ($type ne "swap" && $type ne "auto" &&
1183    $type ne "autofs" && $type ne $smbfs_fs && $type ne "cifs") {
1184	# Lots of options are common to all linux filesystems
1185	print &ui_table_row(&hlink($text{'linux_ro'}, "linux_ro"),
1186		&ui_yesno_radio("lnx_ro", defined($options{"ro"})));
1187
1188	print &ui_table_row(&hlink($text{'linux_sync'}, "linux_sync"),
1189		&ui_yesno_radio("lnx_sync", defined($options{"sync"}), 0, 1));
1190
1191	print &ui_table_row(&hlink($text{'linux_user'}, "linux_user"),
1192		&ui_yesno_radio("lnx_user", defined($options{"user"})));
1193
1194	print &ui_table_row(&hlink($text{'linux_nodev'}, "linux_nodev"),
1195		&ui_radio("lnx_nodev", defined($options{"nodev"}) ? 1 :
1196				       defined($options{"dev"}) ? 0 : 2,
1197			  [ [ 1, $text{'yes'} ],
1198			    [ 0, $text{'no'} ],
1199			    [ 2, $text{'linux_ifuser'} ] ]));
1200
1201	print &ui_table_row(&hlink($text{'linux_noexec'}, "linux_noexec"),
1202		&ui_radio("lnx_noexec", defined($options{"noexec"}) ? 1 :
1203				       defined($options{"dev"}) ? 0 : 2,
1204			  [ [ 1, $text{'yes'} ],
1205			    [ 0, $text{'no'} ],
1206			    [ 2, $text{'linux_ifuser'} ] ]));
1207
1208	print &ui_table_row(&hlink($text{'linux_nosuid'}, "linux_nosuid"),
1209		&ui_radio("lnx_nosuid", defined($options{"nosuid"}) ? 1 :
1210				       defined($options{"dev"}) ? 0 : 2,
1211			  [ [ 1, $text{'yes'} ],
1212			    [ 0, $text{'no'} ],
1213			    [ 2, $text{'linux_ifuser'} ] ]));
1214
1215	print &ui_table_row(&hlink($text{'linux_noatime'}, "linux_noatime"),
1216		&ui_yesno_radio("lnx_noatime", defined($options{"noatime"})));
1217
1218	print &ui_table_row(&hlink($text{'linux_netdev'}, "linux_netdev"),
1219		&ui_yesno_radio("lnx_netdev", defined($options{"_netdev"})));
1220
1221	print &ui_table_row(&hlink($text{'linux_nofail'}, "linux_nofail"),
1222		&ui_yesno_radio("lnx_nofail", defined($options{"nofail"})));
1223	}
1224
1225if ($type =~ /^ext\d+$/) {
1226	# Ext2+ has lots more options..
1227	print &ui_table_hr();
1228
1229	if ($no_mount_check) {
1230		print &ui_table_row($text{'linux_df'},
1231		    &ui_yesno_radio("ext2_df", defined($options{"minixdf"})));
1232		}
1233	else {
1234		print &ui_table_row($text{'linux_check'},
1235			&ui_select("ext2_check",
1236			    $options{"check"} eq "" ? "normal" :
1237			    defined($options{"nocheck"}) ? "none" :
1238						       $options{"check"},
1239			    [ [ "normal", $text{'linux_normal'} ],
1240			      [ "strict", $text{'linux_strict'} ],
1241			      [ "none", $text{'linux_none'} ] ]));
1242		}
1243
1244	print &ui_table_row($text{'linux_errors'},
1245		&ui_select("ext2_errors",
1246			!defined($options{"errors"}) ? "default" :
1247			$options{"errors"},
1248			[ [ "default", $text{'default'} ],
1249			  [ "continue", $text{'linux_continue'} ],
1250			  [ "remount-ro", $text{'linux_remount_ro'} ],
1251			  [ "panic", $text{'linux_panic'} ] ]));
1252
1253	print &ui_table_row($text{'linux_grpid'},
1254		&ui_yesno_radio("ext2_grpid", defined($options{"grpid"}) ||
1255					      defined($options{"bsdgroups"})));
1256
1257	my $usrquota = defined($options{"usrquota"}) ||
1258			defined($options{"usrjquota"});
1259	my $grpquota = defined($options{"grpquota"}) ||
1260			defined($options{"grpjquota"});
1261	print &ui_table_row($text{'linux_quotas'},
1262		&ui_select("ext2_quota", $usrquota && $grpquota ? 3 :
1263					 $grpquota ? 2 :
1264					 $usrquota ? 1 : 0,
1265			   [ [ 0, $text{'no'} ],
1266			     [ 1, $text{'linux_usrquota'} ],
1267			     [ 2, $text{'linux_grpquota'} ],
1268			     [ 3, $text{'linux_usrgrpquota'} ] ]));
1269
1270	print &ui_table_row($text{'linux_quotaj'},
1271		&ui_radio("ext2_quotaj",
1272			  defined($options{"usrjquota"}) ||
1273			   defined($options{"grpjquota"}) ? 1 : 0,
1274			  [ [ 1, $text{'linux_quotaj1'} ],
1275			    [ 0, $text{'linux_quotaj0'} ] ]));
1276
1277	print &ui_table_row($text{'linux_resuid'},
1278		&ui_user_textbox("ext2_resuid", defined($options{"resuid"}) ?
1279				   getpwuid($options{"resuid"}) : ""));
1280
1281	print &ui_table_row($text{'linux_resgid'},
1282		&ui_group_textbox("ext2_resgid", defined($options{"resgid"}) ?
1283				   getgrgid($options{"resgid"}) : ""));
1284	}
1285elsif ($type eq "nfs" || $type eq "nfs4") {
1286	# Linux nfs has some more options...
1287	print &ui_table_hr();
1288
1289	print &ui_table_row(&hlink($text{'linux_port'}, "linux_port"),
1290		&ui_opt_textbox("nfs_port", $options{"port"}, 6,
1291				$text{'default'}));
1292
1293	print &ui_table_row(&hlink($text{'linux_bg'}, "linux_bg"),
1294		&ui_yesno_radio("nfs_bg", defined($options{"bg"})));
1295
1296	print &ui_table_row(&hlink($text{'linux_soft'}, "linux_soft"),
1297		&ui_yesno_radio("nfs_soft", defined($options{"soft"})));
1298
1299	print &ui_table_row(&hlink($text{'linux_timeo'}, "linux_timeo"),
1300		&ui_opt_textbox("nfs_timeo", $options{"timeo"}, 6,
1301				$text{'default'}));
1302
1303	print &ui_table_row(&hlink($text{'linux_retrans'}, "linux_retrans"),
1304		&ui_opt_textbox("nfs_retrans", $options{"restrans"}, 6,
1305				$text{'default'}));
1306
1307	print &ui_table_row(&hlink($text{'linux_intr'}, "linux_intr"),
1308		&ui_yesno_radio("nfs_intr", defined($options{"intr"})));
1309
1310	local $proto = defined($options{"udp"}) ? "udp" :
1311		       defined($options{"tcp"}) ? "tcp" : "";
1312	print &ui_table_row(&hlink($text{'linux_transfert'}, "linux_transfert"),
1313		&ui_select("nfs_transfert", $proto,
1314			   [ [ '', $text{'default'} ],
1315			     [ 'tcp', 'TCP' ],
1316			     [ 'udp', 'UDP' ] ]));
1317
1318	print &ui_table_row(&hlink($text{'linux_rsize'}, "linux_rsize"),
1319		&ui_opt_textbox("nfs_rsize", $options{"rsize"}, 6,
1320				$text{'default'}));
1321
1322	print &ui_table_row(&hlink($text{'linux_wsize'}, "linux_wsize"),
1323		&ui_opt_textbox("nfs_wsize", $options{"wsize"}, 6,
1324				$text{'default'}));
1325
1326	my ($auth, $sec) = $options{"sec"} =~ /^(ntlmssp|ntlmv2|ntlm|spkm|lkey|krb5|sys)(p|i|)/ ? ($1, $2) : ( );
1327	print &ui_table_row(&hlink($text{'linux_auth'}, "linux_auth"),
1328		&ui_radio("nfs_auth", $auth,
1329			  [ [ '', 'sys' ],
1330			    [ 'krb5', 'krb5 (Kerberos 5)' ],
1331			    [ 'lkey', 'lkey' ],
1332			    [ 'spkm', 'spkm-3' ],
1333			    [ 'ntlm', 'ntlm (NTLM)' ],
1334			    [ 'ntmlv2', 'ntmlv2 (NTLM version 2)' ],
1335			    [ 'ntlmssp', 'ntlmssp (NTLMv2 in NTLMSSP)' ] ]));
1336
1337	print &ui_table_row(&hlink($text{'linux_sec'}, "linux_sec"),
1338		&ui_radio("nfs_sec", $sec,
1339			  [ [ '', $text{'config_none'} ],
1340			    [ 'i', $text{'linux_integrity'} ],
1341			    [ 'p', $text{'linux_privacy'} ] ]));
1342
1343	print &ui_table_row(&hlink($text{'linux_nfsvers'}, "linux_nfsvers"),
1344		&ui_select("nfs_nfsvers", $options{"nfsvers"},
1345			   [ [ "", $text{'linux_nfsdefault'} ],
1346			     2, 3, 4, 4.1 ]));
1347	}
1348elsif ($type eq "fat" || $type eq "vfat" || $type eq "msdos" ||
1349       $type eq "umsdos" || $type eq "fatx"){
1350	# All dos-based filesystems share some options
1351	print &ui_table_hr();
1352
1353	print &ui_table_row($text{'linux_uid'},
1354		&ui_user_textbox("fat_uid", defined($options{'uid'}) ?
1355					      getpwuid($options{'uid'}) : ""));
1356
1357	print &ui_table_row($text{'linux_gid'},
1358		&ui_group_textbox("fat_gid", defined($options{'gid'}) ?
1359					      getgrgid($options{'gid'}) : ""));
1360
1361	print &ui_table_row($text{'linux_rules'},
1362		&ui_select("fat_check", substr($options{"check"}, 0, 1),
1363			   [ [ '', $text{'default'} ],
1364			     [ 'r', $text{'linux_relaxed'} ],
1365			     [ 'n', $text{'linux_normal'} ],
1366			     [ 's', $text{'linux_strict'} ] ]));
1367
1368	$conv = substr($options{"conv"}, 0, 1);
1369	$conv = '' if ($conv eq 'b');
1370	print &ui_table_row($text{'linux_conv'},
1371		&ui_select("fat_conv", $conv,
1372			   [ [ 'b', $text{'linux_none'} ],
1373			     [ 't', $text{'linux_allfiles'} ],
1374			     [ 'a', $text{'linux_textfiles'} ] ]));
1375
1376	print &ui_table_row($text{'linux_umask'},
1377		&ui_opt_textbox("fat_umask", $options{"umask"}, 6,
1378				$text{'default'}));
1379
1380	print &ui_table_row($text{'linux_quiet'},
1381		&ui_yesno_radio("fat_quiet", defined($options{"quiet"}), 0, 1));
1382
1383
1384	if ($_[0] eq "vfat") {
1385		# vfat has some extra options beyond fat
1386		print &ui_table_row($text{'linux_uni_xlate'},
1387			&ui_yesno_radio("fat_uni_xlate",
1388					defined($options{"uni_xlate"})));
1389
1390		print &ui_table_row($text{'linux_posix'},
1391			&ui_yesno_radio("fat_posix",
1392					defined($options{"posix"})));
1393		}
1394	}
1395elsif ($type eq "hpfs") {
1396	# OS/2 filesystems has some more options..
1397	print &ui_table_hr();
1398
1399	print &ui_table_row($text{'linux_uid'},
1400		&ui_user_textbox("hpfs_uid", defined($options{'uid'}) ?
1401					      getpwuid($options{'uid'}) : ""));
1402
1403	print &ui_table_row($text{'linux_gid'},
1404		&ui_group_textbox("hpfs_gid", defined($options{'gid'}) ?
1405					      getgrgid($options{'gid'}) : ""));
1406
1407	print &ui_table_row($text{'linux_umask'},
1408		&ui_opt_textbox("hpfs_umask", $options{"umask"}, 6,
1409				$text{'default'}));
1410
1411	print &ui_table_row($text{'linux_conv2'},
1412		&ui_select("hpfs_conv", substr($options{"conv"}, 0, 1) || "b",
1413			   [ [ 'b', $text{'linux_none'} ],
1414			     [ 't', $text{'linux_allfiles'} ],
1415			     [ 'a', $text{'linux_textfiles'} ] ]));
1416	}
1417elsif ($type eq "iso9660") {
1418	# CD-ROM filesystems have some more options..
1419	print &ui_table_hr();
1420
1421	print &ui_table_row($text{'linux_uid'},
1422		&ui_user_textbox("iso9660_uid", defined($options{'uid'}) ?
1423					      getpwuid($options{'uid'}) : ""));
1424
1425	print &ui_table_row($text{'linux_gid'},
1426		&ui_group_textbox("iso9660_gid", defined($options{'gid'}) ?
1427					      getgrgid($options{'gid'}) : ""));
1428
1429	print &ui_table_row($text{'linux_rock'},
1430		&ui_yesno_radio("iso9660_norock", defined($options{"norock"})));
1431
1432	print &ui_table_row($text{'linux_mode'},
1433		&ui_textbox("iso9660_mode", defined($options{"mode"}) ?
1434				$options{"mode"} : "444", 10));
1435	}
1436elsif ($type eq "auto") {
1437	# Don't know how to set options for auto filesystems yet..
1438	print &ui_table_span("<i>$text{'linux_noopts'}</i>");
1439	}
1440elsif ($_[0] eq "autofs") {
1441	print &ui_table_span("<b>$text{'edit_autofs_opt'}</b>");
1442
1443	print &ui_table_row($text{'linux_timeout'},
1444		&ui_opt_textbox("autofs_timeout", $options{'timeout'}, 6,
1445				$text{'default'}));
1446
1447	print &ui_table_row($text{'linux_pid_file'},
1448		&ui_opt_textbox("autofs_pid-file", $options{'pid-file'}, 40,
1449				$text{'no'}, $text{'yes'})." ".
1450		&file_chooser_button("autofs_pid-file", 0), 3);
1451	}
1452elsif ($type eq "swap") {
1453	# Swap has no options..
1454	print &ui_table_row($text{'linux_swappri'},
1455		&ui_opt_textbox("swap_pri", $options{'pri'}, 6,
1456				     $text{'default'}));
1457	}
1458elsif ($type eq $smbfs_fs || $type eq "cifs") {
1459	# SMB filesystems have a few options..
1460	$support = $_[0] eq $smbfs_fs ? $smbfs_support : $cifs_support;
1461	if (keys(%options) == 0 && !$_[1]) {
1462		print &ui_table_span("<i>$text{'linux_smbwarn'}</i>");
1463		}
1464
1465	print &ui_table_row($text{'linux_username'},
1466		&ui_textbox("smbfs_user",
1467		$support == 4 ? $options{'username'} : $options{'user'}, 20));
1468
1469	print &ui_table_row($text{'linux_password'},
1470		&ui_password("smbfs_passwd",
1471		$support == 4 ? $options{'password'} : $options{'passwd'}, 20));
1472
1473	if ($support == 4) {
1474		print &ui_table_row($text{'linux_credentials'},
1475			&ui_textbox("smbfs_creds", $options{"credentials"}, 30).
1476			" ".
1477			($access{'browse'} ?
1478			  &file_chooser_button("smbfs_creds", 0) : ""));
1479		}
1480
1481	if ($support != 2) {
1482		print &ui_table_row($text{'linux_uid'},
1483			&ui_user_textbox("smbfs_uid",
1484			  defined($options{'uid'}) ? getpwuid($options{'uid'})
1485						   : ""));
1486
1487		print &ui_table_row($text{'linux_gid'},
1488			&ui_group_textbox("smbfs_gid",
1489			  defined($options{'gid'}) ? getgrgid($options{'gid'})
1490						   : ""));
1491		}
1492
1493	if ($support == 1) {
1494		print &ui_table_row($text{'linux_sname'},
1495			&ui_opt_textbox("smbfs_sname", $options{"servername"},
1496					20, $text{'linux_auto'}));
1497		}
1498	elsif ($support == 2) {
1499		print &ui_table_row($text{'linux_wg'},
1500			&ui_opt_textbox("smbfs_wg", $options{"workgroup"},
1501					20, $text{'linux_auto'}));
1502		}
1503
1504	if ($support < 3) {
1505		print &ui_table_row($text{'linux_cname'},
1506			&ui_opt_textbox("smbfs_cname", $options{"clientname"},
1507					20, $text{'linux_auto'}));
1508
1509		print &ui_table_row($text{'linux_mname'},
1510			&ui_opt_textbox("smbfs_mname", $options{"machinename"},
1511					20, $text{'linux_auto'}));
1512		}
1513
1514	if ($support == 1) {
1515		print &ui_table_row($text{'linux_fmode'},
1516		    &ui_textbox("smbfs_fmode",
1517			defined($options{'fmode'}) ? $options{'fmode'} : "755",
1518			5));
1519
1520		print &ui_table_row($text{'linux_dmode'},
1521		    &ui_textbox("smbfs_dmode",
1522			defined($options{'dmode'}) ? $options{'dmode'} : "755",
1523			5));
1524		}
1525	elsif ($support >= 3) {
1526		print &ui_table_row($text{'linux_fmode'},
1527			&ui_opt_textbox("smbfs_file_mode",
1528					$options{'file_mode'}, 5,
1529					$text{'default'}));
1530
1531		print &ui_table_row($text{'linux_dmode'},
1532			&ui_opt_textbox("smbfs_dir_mode",
1533					$options{'dir_mode'}, 5,
1534					$text{'default'}));
1535
1536		print &ui_table_row($text{'linux_ro'},
1537			&ui_yesno_radio("smbfs_ro", defined($options{"ro"})));
1538		}
1539	if ($support == 4) {
1540		print &ui_table_row($text{'linux_user'},
1541		    &ui_yesno_radio("smbfs_user2", defined($options{"user"})));
1542
1543		print &ui_table_row($text{'linux_cname'},
1544			&ui_opt_textbox("smbfs_cname", $options{"netbiosname"},
1545					40, $text{'linux_auto'}), 3);
1546
1547		print &ui_table_row($text{'linux_mname'},
1548			&ui_opt_textbox("smbfs_mname", $options{"ip"},
1549					40, $text{'linux_auto'}), 3);
1550
1551		print &ui_table_row($text{'linux_wg'},
1552			&ui_opt_textbox("smbfs_wg", $options{"workgroup"},
1553					10, $text{'linux_auto'}));
1554
1555		}
1556
1557	if ($type eq "cifs") {
1558		# Show cifs-only options
1559		print &ui_table_row($text{'linux_codepage'},
1560			&ui_opt_textbox("smbfs_codepage",
1561			    $options{'codepage'}, 10, $text{'default'}));
1562
1563		print &ui_table_row($text{'linux_iocharset'},
1564			&ui_opt_textbox("smbfs_iocharset",
1565			    $options{'iocharset'}, 10, $text{'default'}));
1566
1567		print &ui_table_row($text{'linux_nounix'},
1568			&ui_yesno_radio("smbfs_nounix",
1569					defined($options{"nounix"})));
1570
1571		print &ui_table_row($text{'linux_cvers'},
1572			&ui_opt_textbox("smbfs_vers", $options{"vers"},
1573					5, $text{'linux_auto'}));
1574
1575		print &ui_table_row($text{'linux_noserverino'},
1576			&ui_yesno_radio("smbfs_noserverino",
1577					defined($options{"noserverino"})));
1578		}
1579	}
1580elsif ($type eq "reiserfs") {
1581	# Reiserfs is a new super-efficient filesystem
1582	print &ui_table_hr();
1583
1584	print &ui_table_row($text{'linux_notail'},
1585		&ui_yesno_radio("lnx_notail", defined($options{"notail"})));
1586	}
1587elsif ($type eq "tmpfs") {
1588	# Tmpfs has some size options
1589	print &ui_table_hr();
1590
1591	print &ui_table_row($text{'linux_tmpsize'},
1592		&ui_opt_textbox("lnx_tmpsize", $options{"size"}, 10,
1593				$text{'linux_unlimited'})." bytes");
1594
1595	print &ui_table_row($text{'linux_nr_blocks'},
1596		&ui_opt_textbox("lnx_nr_blocks", $options{"nr_blocks"}, 10,
1597				$text{'linux_unlimited'}));
1598
1599	print &ui_table_row($text{'linux_nr_inodes'},
1600		&ui_opt_textbox("lnx_nr_inodes", $options{"nr_inodes"}, 10,
1601				$text{'linux_unlimited'}));
1602
1603	print &ui_table_row($text{'linux_tmpmode'},
1604		&ui_opt_textbox("lnx_tmpmode", $options{"mode"}, 3,
1605				$text{'default'}));
1606	}
1607elsif ($type eq "xfs") {
1608	# Show options for XFS
1609	print &ui_table_hr();
1610
1611	print &ui_table_row($text{'linux_usrquotas'},
1612		&ui_radio("xfs_usrquota",
1613			defined($options{"quota"}) ||
1614			  defined($options{"usrquota"}) ? 1 :
1615			defined($options{"uqnoenforce"}) ? 2 : 0,
1616			[ [ 1, $text{'yes'} ],
1617			  [ 2, $text{'linux_noenforce'} ],
1618			  [ 0, $text{'no'} ] ]));
1619
1620	print &ui_table_row($text{'linux_grpquotas'},
1621		&ui_radio("xfs_grpquota",
1622			defined($options{"quota"}) ||
1623			  defined($options{"grpquota"}) ? 1 :
1624			defined($options{"uqnoenforce"}) ? 2 : 0,
1625			[ [ 1, $text{'yes'} ],
1626			  [ 2, $text{'linux_noenforce'} ],
1627			  [ 0, $text{'no'} ] ]));
1628	}
1629elsif ($type eq "jfs") {
1630	# No other JFS options yet!
1631	}
1632elsif ($type eq "ntfs") {
1633	# Windows NT/XP/2000 filesystem
1634	print &ui_table_hr();
1635
1636	print &ui_table_row($text{'linux_uid'},
1637		&ui_user_textbox("ntfs_uid", defined($options{'uid'}) ?
1638					      getpwuid($options{'uid'}) : ""));
1639
1640	print &ui_table_row($text{'linux_gid'},
1641		&ui_group_textbox("ntfs_gid", defined($options{'gid'}) ?
1642					      getgrgid($options{'gid'}) : ""));
1643	}
1644}
1645
1646
1647# check_location(type)
1648# Parse and check inputs from %in, calling &error() if something is wrong.
1649# Returns the location string for storing in the fstab file
1650sub check_location
1651{
1652if (($_[0] eq "nfs") || ($_[0] eq "nfs4")) {
1653	local($out, $temp, $mout, $dirlist, @dirlist);
1654
1655	if (&has_command("showmount") && $config{'nfs_check'}) {
1656		# Use ping and showmount to see if the host exists and is up
1657		if ($in{nfs_host} !~ /^\S+$/) {
1658			&error(&text('linux_ehost', $in{'nfs_host'}));
1659			}
1660		$out = &backquote_command(
1661			"ping -c 1 ".quotemeta($in{nfs_host})." 2>&1");
1662		if ($out =~ /unknown host/) {
1663			&error(&text('linux_ehost2', $in{'nfs_host'}));
1664			}
1665		elsif ($out =~ /100\% packet loss/) {
1666			&error(&text('linux_edown', $in{'nfs_host'}));
1667			}
1668		$out = &backquote_command(
1669			"showmount -e ".quotemeta($in{nfs_host})." 2>&1");
1670		if ($out =~ /Unable to receive/) {
1671			&error(&text('linux_enfs', $in{'nfs_host'}));
1672			}
1673		elsif ($?) {
1674			&error(&text('linux_elist', $out));
1675			}
1676		}
1677
1678	# Validate directory name for NFSv3 (in v4 '/' exists)
1679	foreach (split(/\n/, $out)) {
1680		if (/^(\/\S+)/) {
1681			$dirlist .= "$1\n";
1682			push(@dirlist, $1);
1683			}
1684		}
1685
1686	if ($_[0] ne "nfs4" && $in{'nfs_dir'} !~ /^\/.*$/ &&
1687	    &indexof($in{'nfs_dir'}, @dirlist) < 0) {
1688		&error(&text('linux_enfsdir', $in{'nfs_dir'},
1689			     $in{'nfs_host'}, "<pre>$dirlist</pre>"));
1690		}
1691
1692	# Try a test mount to see if filesystem is available
1693	$temp = &tempname();
1694	&make_dir($temp, 0755);
1695	&execute_command("mount -t $_[0] ".
1696			 quotemeta("$in{nfs_host}:$in{nfs_dir}")." ".
1697			 quotemeta($temp),
1698			 undef, \$mout, \$mout);
1699	if ($mout =~ /No such file or directory/i) {
1700		&error(&text('linux_enfsdir', $in{'nfs_dir'},
1701			     $in{'nfs_host'}, "<pre>$dirlist</pre>"));
1702		}
1703	elsif ($mout =~ /Permission denied/i) {
1704		&error(&text('linux_enfsperm', $in{'nfs_dir'}, $in{'nfs_host'}));
1705		}
1706	elsif ($?) {
1707		&error(&text('linux_enfsmount', "<tt>$mout</tt>"));
1708		}
1709	# It worked! unmount
1710	local $umout;
1711	&execute_command("umount ".quotemeta($temp), undef, \$umout, \$umout);
1712	if ($?) {
1713		&error(&text('linux_enfsmount', "<tt>$umout</tt>"));
1714		}
1715	rmdir(&translate_filename($temp));	# Don't delete mounted files!
1716
1717	return "$in{nfs_host}:$in{nfs_dir}";
1718	}
1719elsif ($_[0] eq "auto") {
1720	# Check if the automounter map exists..
1721	(-r $in{auto_map}) || &error(&text('linux_eautomap', $in{'auto_map'}));
1722	return $in{auto_map};
1723	}
1724elsif ($_[0] eq "autofs") {
1725	# Check if the map exists (if it is a file)
1726	if ($in{'autofs_map'} =~ /^\// && !(-r $in{'autofs_map'})) {
1727		&error(&text('linux_eautomap', $in{'autofs_map'}));
1728		}
1729	return $in{autofs_map};
1730	}
1731elsif ($_[0] eq $smbfs_fs || $_[0] eq "cifs") {
1732	# No real checking done
1733	$in{'smbfs_server'} =~ /\S/ || &error($text{'linux_eserver'});
1734	$in{'smbfs_share'} =~ /\S/ || &error($text{'linux_eshare'});
1735	return &lowercase_share_path(
1736		"\\\\".$in{'smbfs_server'}."\\".$in{'smbfs_share'});
1737	}
1738elsif ($_[0] eq "tmpfs") {
1739	# No location needed
1740	return "tmpfs";
1741	}
1742elsif ($_[0] eq "bind") {
1743	# Just check the directory
1744	-d $in{'bind_dir'} || &error($text{'linux_ebind'});
1745	return $in{'bind_dir'};
1746	}
1747else {
1748	# This is some kind of disk-based linux filesystem.. get the device name
1749	if ($in{'lnx_dev'} == 0) {
1750		$dv = $in{'lnx_disk'};
1751		}
1752	elsif ($in{'lnx_dev'} == 2) {
1753		$dv = $in{'lnx_raid'};
1754		}
1755	elsif ($in{'lnx_dev'} == 3) {
1756		$dv = "LABEL=".$in{'lnx_label'};
1757		}
1758	elsif ($in{'lnx_dev'} == 4) {
1759		$dv = $in{'lnx_lvm'};
1760		}
1761	elsif ($in{'lnx_dev'} == 5) {
1762		$dv = "UUID=".$in{'lnx_uuid'};
1763		}
1764	else {
1765		$dv = $in{'lnx_other'};
1766		$dv || &error($text{'linux_edev'});
1767		}
1768
1769	# If the device entered is a symlink, follow it
1770	#if ($dvlink = readlink($dv)) {
1771	#	if ($dvlink =~ /^\//) { $dv = $dvlink; }
1772	#	else {	$dv =~ /^(.*\/)[^\/]+$/;
1773	#		$dv = $1.$dvlink;
1774	#		}
1775	#	}
1776
1777	# Check if the device actually exists and uses the right filesystem
1778	if (!-r $dv && $dv !~ /LABEL=/ && $dv !~ /UUID=/) {
1779		if ($_[0] eq "swap" && $dv !~ /\/dev/) {
1780			&swap_form($dv);
1781			}
1782		else {
1783			&error(&text('linux_edevfile', $dv));
1784			}
1785		}
1786	return $dv;
1787	}
1788}
1789
1790# check_options(type, device, directory)
1791# Read options for some filesystem from %in, and use them to update the
1792# %options array. Options handled by the user interface will be set or
1793# removed, while unknown options will be left untouched.
1794sub check_options
1795{
1796local($k, @rv);
1797
1798# Parse the common options first..
1799if ($_[0] ne "swap" && $_[0] ne "auto" &&
1800    $_[0] ne "autofs" && $_[0] ne $smbfs_fs && $_[0] ne "cifs") {
1801	delete($options{"ro"}); delete($options{"rw"});
1802	if ($in{lnx_ro}) { $options{"ro"} = ""; }
1803
1804	delete($options{"sync"}); delete($options{"async"});
1805	if ($in{lnx_sync}) { $options{"sync"} = ""; }
1806
1807	delete($options{"dev"}); delete($options{"nodev"});
1808	if ($in{lnx_nodev} == 1) { $options{"nodev"} = ""; }
1809	elsif ($in{lnx_nodev} == 0) { $options{"dev"} = ""; }
1810
1811	delete($options{"exec"}); delete($options{"noexec"});
1812	if ($in{lnx_noexec} == 1) { $options{"noexec"} = ""; }
1813	elsif ($in{lnx_noexec} == 0) { $options{"exec"} = ""; }
1814
1815	delete($options{"suid"}); delete($options{"nosuid"});
1816	if ($in{lnx_nosuid} == 1) { $options{"nosuid"} = ""; }
1817	elsif ($in{lnx_nosuid} == 0) { $options{"suid"} = ""; }
1818
1819	delete($options{"user"}); delete($options{"nouser"});
1820	if ($in{lnx_user}) { $options{"user"} = ""; }
1821
1822	delete($options{"noatime"});
1823	$options{"noatime"} = "" if ($in{'lnx_noatime'});
1824	delete($options{"relatime"}) if ($in{'lnx_noatime'});
1825
1826	delete($options{"_netdev"});
1827	$options{"_netdev"} = "" if ($in{'lnx_netdev'});
1828
1829	delete($options{"nofail"});
1830	$options{"nofail"} = "" if ($in{'lnx_nofail'});
1831	}
1832
1833if (($_[0] eq "nfs") || ($_[0] eq "nfs4")) {
1834	# NFS has a few specific options..
1835	delete($options{"bg"}); delete($options{"fg"});
1836	if ($in{nfs_bg}) { $options{"bg"} = ""; }
1837
1838	delete($options{"soft"}); delete($options{"hard"});
1839	if ($in{nfs_soft}) { $options{"soft"} = ""; }
1840
1841	delete($options{"timeo"});
1842	if (!$in{nfs_timeo_def}) {
1843		$in{nfs_timeo} =~ /^\d+$/ && $in{nfs_timeo} > 0 ||
1844			&error($text{'linux_etimeo'});
1845		$options{"timeo"} = $in{nfs_timeo};
1846		}
1847
1848	delete($options{"retrans"});
1849	if (!$in{nfs_retrans_def}) { $options{"retrans"} = $in{nfs_retrans}; }
1850
1851	delete($options{"port"});
1852	if (!$in{nfs_port_def}) { $options{"port"} = $in{nfs_port}; }
1853
1854	delete($options{"intr"}); delete($options{"nointr"});
1855	if ($in{nfs_intr}) { $options{"intr"} = ""; }
1856
1857	delete($options{"tcp"}); delete($options{"udp"});
1858	if ($in{nfs_transfert} eq "tcp") {
1859		$options{"tcp"} = "";
1860		}
1861	elsif ($in{nfs_transfert} eq "udp") {
1862		$options{"udp"} = "";
1863		}
1864
1865	delete($options{"wsize"});
1866	if (!$in{nfs_wsize_def}) { $options{"wsize"} = $in{nfs_wsize}; }
1867
1868	delete($options{"rsize"});
1869	if (!$in{nfs_rsize_def}) { $options{"rsize"} = $in{nfs_rsize}; }
1870
1871	delete($options{"sec"});
1872
1873	# Only sys and krb5 for the moment
1874	if ($in{nfs_auth}) {
1875	    $options{"sec"} = $in{"nfs_auth"}.$in{"nfs_sec"};
1876	}
1877
1878	if ($in{'nfs_nfsvers'}) {
1879		$options{'nfsvers'} = $in{'nfs_nfsvers'};
1880	} else {
1881		delete($options{'nfsvers'});
1882	}
1883    }
1884elsif ($_[0] =~ /^ext\d+$/) {
1885	# More options for ext2..
1886	if ($no_mount_check) {
1887		delete($options{"bsddf"}); delete($options{"minixdf"});
1888		$options{"minixdf"} = "" if ($in{'ext2_df'});
1889		}
1890	else {
1891		delete($options{"check"}); delete($options{"nocheck"});
1892		if ($in{ext2_check} ne "normal") {
1893			$options{"check"} = $in{ext2_check};
1894			}
1895		}
1896
1897	delete($options{"errors"});
1898	if ($in{ext2_errors} ne "default") {
1899		$options{"errors"} = $in{ext2_errors};
1900		}
1901
1902	delete($options{"grpid"}); delete($options{"bsdgroups"});
1903	delete($options{"sysvgroups"}); delete($options{"nogrpid"});
1904	if ($in{ext2_grpid}) {
1905		$options{"grpid"} = "";
1906		}
1907
1908	delete($options{"resuid"}); delete($options{"resgid"});
1909	if ($in{'ext2_resuid'})
1910		{ $options{"resuid"} = getpwnam($in{'ext2_resuid'}); }
1911	if ($in{'ext2_resgid'})
1912		{ $options{"resgid"} = getgrnam($in{'ext2_resgid'}); }
1913
1914	my $jufile = $options{"usrjquota"};
1915	my $jgfile = $options{"grpjquota"};
1916	delete($options{"quota"}); delete($options{"noquota"});
1917	delete($options{"usrquota"}); delete($options{"grpquota"});
1918	delete($options{"usrjquota"}); delete($options{"grpjquota"});
1919	my ($u, $g) = ("usrquota", "grpquota");
1920	if ($in{'ext2_quotaj'}) {
1921		($u, $g) = ("usrjquota", "grpjquota");
1922		$jufile ||= "aquota.user";
1923		$jgfile ||= "aquota.group";
1924		$options{"jqfmt"} = "vfsv0";
1925		}
1926	else {
1927		$jufile = "";
1928		$jgfile = "";
1929		delete($options{"jqfmt"});
1930		}
1931	if ($in{'ext2_quota'} == 1) { $options{$u} = $jufile; }
1932	elsif ($in{'ext2_quota'} == 2) { $options{$g} = $jgfile; }
1933	elsif ($in{'ext2_quota'} == 3) { $options{$u} = $jufile; $options{$g} = $jgfile; }
1934	}
1935elsif ($_[0] eq "fat" || $_[0] eq "vfat" ||
1936       $_[0] eq "msdos" || $_[0] eq "umsdos" || $_[0] eq "fatx") {
1937	# All dos-based filesystems have similar options
1938	delete($options{"uid"}); delete($options{"gid"});
1939	if ($in{fat_uid} ne "") { $options{"uid"} = getpwnam($in{'fat_uid'}); }
1940	if ($in{fat_gid} ne "") { $options{"gid"} = getgrnam($in{'fat_gid'}); }
1941
1942	delete($options{"check"});
1943	if ($in{fat_check} ne "") { $options{"check"} = $in{fat_check}; }
1944
1945	delete($options{"conv"});
1946	if ($in{fat_conv} ne "") { $options{"conv"} = $in{fat_conv}; }
1947
1948	delete($options{"umask"});
1949	if (!$in{fat_umask_def}) {
1950		$in{fat_umask} =~ /^[0-7]{3}$/ ||
1951			&error(&text('linux_emask', $in{'fat_umask'}));
1952		$options{"umask"} = $in{fat_umask};
1953		}
1954
1955	delete($options{"quiet"});
1956	if ($in{fat_quiet}) {
1957		$options{"quiet"} = "";
1958		}
1959
1960	if ($_[0] eq "vfat") {
1961		# Parse extra vfat options..
1962		delete($options{"uni_xlate"});
1963		if ($in{fat_uni_xlate}) { $options{"uni_xlate"} = ""; }
1964
1965		delete($options{"posix"});
1966		if ($in{fat_posix}) { $options{"posix"} = ""; }
1967		}
1968	}
1969elsif ($_[0] eq "hpfs") {
1970	# OS/2 filesystem options..
1971	delete($options{"uid"}); delete($options{"gid"});
1972	if ($in{hpfs_uid} ne "") { $options{"uid"} = getpwnam($in{hpfs_uid}); }
1973	if ($in{hpfs_gid} ne "") { $options{"gid"} = getgrnam($in{hpfs_gid}); }
1974
1975	delete($options{"umask"});
1976	if (!$in{hpfs_umask_def}) {
1977		$in{hpfs_umask} =~ /^[0-7]{3}$/ ||
1978			&error(&text('linux_emask', $in{'hpfs_umask'}));
1979		$options{"umask"} = $in{hpfs_umask};
1980		}
1981
1982	delete($options{"conv"});
1983	if ($in{hpfs_conv} ne "") { $options{"conv"} = $in{hpfs_conv}; }
1984	}
1985elsif ($_[0] eq "iso9660") {
1986	# Options for iso9660 cd-roms
1987	delete($options{"uid"}); delete($options{"gid"});
1988	if ($in{iso9660_uid} ne "")
1989		{ $options{"uid"} = getpwnam($in{iso9660_uid}); }
1990	if ($in{iso9660_gid} ne "")
1991		{ $options{"gid"} = getgrnam($in{iso9660_gid}); }
1992
1993	delete($options{"norock"});
1994	if ($in{iso9660_norock}) { $options{"norock"} = ""; }
1995
1996	delete($options{"mode"});
1997	$in{iso9660_mode} =~ /^[0-7]{3}$/ ||
1998		&error(&text('linux_emask', $in{'iso9660_mode'}));
1999	$options{"mode"} = $in{iso9660_mode};
2000	}
2001elsif ($_[0] eq "autofs") {
2002	# Options for automounter filesystems
2003	delete($options{'timeout'});
2004	if (!$in{'autofs_timeout_def'}) {
2005		$in{'autofs_timeout'} =~ /^\d+$/ ||
2006			&error(&text('linux_etimeout', $in{'autofs_timeout'}));
2007		$options{'timeout'} = $in{'autofs_timeout'};
2008		}
2009	delete($options{'pid-file'});
2010	if (!$in{'autofs_pid-file_def'}) {
2011		$in{'autofs_pid-file'} =~ /^\/\S+$/ ||
2012		       &error(&text('linux_epidfile', $in{'autofs_pid-file'}));
2013		$options{'pid-file'} = $in{'autofs_pid-file'};
2014		}
2015	}
2016elsif ($_[0] eq $smbfs_fs || $_[0] eq "cifs") {
2017	# Options for smb filesystems..
2018	local $support = $_[0] eq $smbfs_fs ? $smbfs_support : $cifs_support;
2019	delete($options{'user'}); delete($options{'username'});
2020	if ($in{smbfs_user}) {
2021		$options{$support == 4 ? 'username' : 'user'} = $in{smbfs_user};
2022		}
2023
2024	delete($options{'passwd'}); delete($options{'password'});
2025	if ($in{smbfs_passwd}) {
2026		$options{$support == 4 ? 'password' : 'passwd'} = $in{smbfs_passwd};
2027		}
2028
2029	if ($support == 4) {
2030		delete($options{'credentials'});
2031		if ($in{smbfs_creds}) {
2032			$options{'credentials'} = $in{smbfs_creds};
2033			}
2034		}
2035
2036	if ($support != 2) {
2037		delete($options{uid});
2038		if ($in{smbfs_uid} ne "") { $options{uid} = getpwnam($in{smbfs_uid}); }
2039
2040		delete($options{gid});
2041		if ($in{smbfs_gid} ne "") { $options{gid} = getgrnam($in{smbfs_gid}); }
2042		}
2043
2044	if ($support == 1) {
2045		delete($options{servername});
2046		if (!$in{smbfs_sname_def})
2047			{ $options{servername} = $in{smbfs_sname}; }
2048		}
2049	elsif ($support == 2 || $support == 4) {
2050		delete($options{workgroup});
2051		if (!$in{smbfs_wg_def})
2052			{ $options{workgroup} = $in{smbfs_wg}; }
2053		}
2054
2055	if ($support < 3) {
2056		delete($options{clientname});
2057		if (!$in{smbfs_cname_def})
2058			{ $options{clientname} = $in{smbfs_cname}; }
2059
2060		delete($options{machinename});
2061		if (!$in{smbfs_mname_def})
2062			{ $options{machinename} = $in{smbfs_mname}; }
2063		elsif (!&to_ipaddress($in{'smbfs_server'})) {
2064			# No hostname found for the server.. try to guess
2065			local($out, $sname);
2066			$sname = $in{'smbfs_server'};
2067			$out = &backquote_command("$config{'nmblookup_path'} -d 0 $sname 2>&1");
2068			if (!$? && $out =~ /^([0-9\.]+)\s+$sname\n/) {
2069				$options{machinename} = $1;
2070				}
2071			}
2072		}
2073	elsif ($support == 4) {
2074		delete($options{"netbiosname"});
2075		if (!$in{"smbfs_cname_def"}) {
2076			$in{"smbfs_cname"} =~ /^\S+$/ ||
2077				&error($text{'linux_ecname'});
2078			$options{"netbiosname"} = $in{"smbfs_cname"};
2079			}
2080		delete($options{"ip"});
2081		if (!$in{"smbfs_mname_def"}) {
2082			&to_ipaddress($in{"smbfs_mname"}) ||
2083				&error($text{'linux_emname'});
2084			$options{"ip"} = $in{"smbfs_mname"};
2085			}
2086		}
2087
2088	if ($support == 1) {
2089		delete($options{fmode});
2090		if ($in{smbfs_fmode} !~ /^[0-7]{3}$/) {
2091			&error(&text('linux_efmode', $in{'smbfs_fmode'}));
2092			}
2093		elsif ($in{smbfs_fmode} ne "755")
2094			{ $options{fmode} = $in{smbfs_fmode}; }
2095
2096		delete($options{dmode});
2097		if ($in{smbfs_dmode} !~ /^[0-7]{3}$/) {
2098			&error(&text('linux_edmode', $in{'smbfs_dmode'}));
2099			}
2100		elsif ($in{smbfs_dmode} ne "755")
2101			{ $options{dmode} = $in{smbfs_dmode}; }
2102		}
2103	elsif ($support >= 3) {
2104		if ($in{'smbfs_file_mode_def'}) {
2105			delete($options{'file_mode'});
2106			}
2107		else {
2108			$in{'smbfs_file_mode'} =~ /^0?[0-7]{3}$/ ||
2109			  &error(&text('linux_efmode', $in{'smbfs_file_mode'}));
2110			$options{'file_mode'} = $in{'smbfs_file_mode'};
2111			}
2112
2113		if ($in{'smbfs_dir_mode_def'}) {
2114			delete($options{'dir_mode'});
2115			}
2116		else {
2117			$in{'smbfs_dir_mode'} =~ /^0?[0-7]{3}$/ ||
2118		    	  &error(&text('linux_edmode', $in{'smbfs_dir_mode'}));
2119			$options{'dir_mode'} = $in{'smbfs_dir_mode'};
2120			}
2121
2122		delete($options{'ro'}); delete($options{'rw'});
2123		if ($in{'smbfs_ro'}) { $options{'ro'} = ''; }
2124		}
2125	if ($support == 4) {
2126		delete($options{'user'});
2127		if ($in{'smbfs_user2'}) { $options{'user'} = ''; }
2128		}
2129
2130	if ($_[0] eq "cifs") {
2131		# Parse CIFS-specific options
2132		delete($options{'codepage'});
2133		if (!$in{'smbfs_codepage_def'}) {
2134			$in{'smbfs_codepage'} =~ /^\S+$/ ||
2135				&error($text{'linux_ecodepage'});
2136			$options{'codepage'} = $in{'smbfs_codepage'};
2137			}
2138
2139		delete($options{'iocharset'});
2140		if (!$in{'smbfs_iocharset_def'}) {
2141			$in{'smbfs_iocharset'} =~ /^\S+$/ ||
2142				&error($text{'linux_eiocharset'});
2143			$options{'iocharset'} = $in{'smbfs_iocharset'};
2144			}
2145
2146		delete($options{'nounix'});
2147		if ($in{'smbfs_nounix'}) { $options{'nounix'} = ''; }
2148
2149		delete($options{'noserverino'});
2150		if ($in{'smbfs_noserverino'}) { $options{'noserverino'} = ''; }
2151
2152		delete($options{'vers'});
2153		if (!$in{'smbfs_vers_def'}) {
2154			$in{'smbfs_vers'} =~ /^[0-9\.]+$/ ||
2155				&error($text{'linux_ecvers'});
2156			$options{'vers'} = $in{'smbfs_vers'};
2157			}
2158		}
2159	}
2160elsif ($_[0] eq "reiserfs") {
2161	# Save reiserfs options
2162	delete($options{'notail'});
2163	$options{'notail'} = "" if ($in{'lnx_notail'});
2164
2165	if ($in{'lnx_user'} && !$in{'lnx_noexec'}) {
2166		# Have to force on the exec option
2167		$options{"exec"} = "";
2168		}
2169	}
2170elsif ($_[0] eq "tmpfs") {
2171	# Save tmpfs options
2172	if ($in{'lnx_tmpsize_def'}) {
2173		delete($options{'size'});
2174		}
2175	else {
2176		$in{'lnx_tmpsize'} =~ /^(\d+)([kmg]?)$/ ||
2177			&error($text{'lnx_etmpsize'});
2178		$options{'size'} = $in{'lnx_tmpsize'};
2179		}
2180
2181	if ($in{'lnx_nr_blocks_def'}) {
2182		delete($options{'nr_blocks'});
2183		}
2184	else {
2185		$in{'lnx_nr_blocks'} =~ /^\d+$/ ||
2186			&error($text{'lnx_enr_blocks'});
2187		$options{'nr_blocks'} = $in{'lnx_nr_blocks'};
2188		}
2189
2190	if ($in{'lnx_nr_inodes_def'}) {
2191		delete($options{'nr_inodes'});
2192		}
2193	else {
2194		$in{'lnx_nr_inodes'} =~ /^\d+$/ ||
2195			&error($text{'lnx_enr_inodes'});
2196		$options{'nr_inodes'} = $in{'lnx_nr_inodes'};
2197		}
2198
2199	if ($in{'lnx_tmpmode_def'}) {
2200		delete($options{'mode'});
2201		}
2202	else {
2203		$in{'lnx_tmpmode'} =~ /^[0-7]{3,4}$/ ||
2204			&error($text{'lnx_etmpmode'});
2205		$options{'mode'} = $in{'lnx_tmpmode'};
2206		}
2207	}
2208elsif ($_[0] eq "xfs") {
2209	# Save XFS options
2210	delete($options{'quota'});
2211	delete($options{'usrquota'});
2212	delete($options{'uqnoenforce'});
2213	$options{'usrquota'} = "" if ($in{'xfs_usrquota'} == 1);
2214	$options{'uqnoenforce'} = "" if ($in{'xfs_usrquota'} == 2);
2215
2216	delete($options{'grpquota'});
2217	delete($options{'gqnoenforce'});
2218	$options{'grpquota'} = "" if ($in{'xfs_grpquota'} == 1);
2219	$options{'gqnoenforce'} = "" if ($in{'xfs_grpquota'} == 2);
2220	}
2221elsif ($_[0] eq "ntfs") {
2222	# Save NTFS options
2223	delete($options{"uid"}); delete($options{"gid"});
2224	if ($in{ntfs_uid} ne "")
2225		{ $options{"uid"} = getpwnam($in{ntfs_uid}); }
2226	if ($in{ntfs_gid} ne "")
2227		{ $options{"gid"} = getgrnam($in{ntfs_gid}); }
2228	}
2229elsif ($_[0] eq "swap") {
2230	# Save SWAP options
2231	if ($in{'swap_pri_def'}) {
2232		delete($options{'pri'});
2233		}
2234	else {
2235		$in{'swap_pri'} =~ /^\d+$/ && $in{'swap_pri'} <= 32767 ||
2236			&error($text{'linux_eswappri'});
2237		$options{'pri'} = $in{'swap_pri'};
2238		}
2239	}
2240
2241# Add loop option if mounting a normal file
2242if ($_[0] ne "swap" && $_[0] ne "auto" && $_[0] ne "autofs" &&
2243    $_[0] ne $smbfs_fs && $_[0] ne "cifs" && $_[0] ne "nfs" &&
2244    $_[0] ne "nfs4" && $_[0] ne "tmpfs") {
2245	local(@st);
2246	@st = stat($_[1]);
2247	if (@st && ($st[2] & 0xF000) == 0x8000) {
2248		# a regular file.. add the loop option
2249		if (!$options{'loop'}) {
2250			$options{'loop'} = "";
2251			}
2252		}
2253	}
2254
2255# Return options string
2256foreach $k (sort { ($b eq "user" ? 1 : 0) <=> ($a eq "user" ? 1 : 0) } (keys %options)) {
2257	if ($options{$k} eq "") { push(@rv, $k); }
2258	else { push(@rv, "$k=$options{$k}"); }
2259	}
2260return @rv ? join(',' , @rv) : "-";
2261}
2262
2263
2264# Get the smbfs options from 'smbfs_opts' file in the current directory. This
2265# is sadly necessary because there is no way to get the current options for
2266# an existing smbfs mount... so webmin has to save them in a file when
2267# mounting. Blech.
2268sub read_smbopts
2269{
2270local($_);
2271open(SMBOPTS, "<$module_config_directory/smbfs");
2272while(<SMBOPTS>) {
2273	/^(\S+)\s+(\S+)$/;
2274	$smbopts{$1} = $2;
2275	}
2276close(SMBOPTS);
2277}
2278
2279sub write_smbopts
2280{
2281local($_);
2282&open_tempfile(SMBOPTS, "> $module_config_directory/smbfs");
2283foreach (keys %smbopts) {
2284	&print_tempfile(SMBOPTS, "$_\t$smbopts{$_}\n");
2285	}
2286&close_tempfile(SMBOPTS);
2287}
2288
2289
2290# create_swap(file, size, units)
2291# Calls dd and mkswap to setup a swap file
2292sub create_swap
2293{
2294local($out, $bl);
2295$bl = $_[1] * ($_[2] eq "t" ? 1024*1024*1024 :
2296	       $_[2] eq "g" ? 1024*1024 :
2297	       $_[2] eq "m" ? 1024 : 1);
2298$out = &backquote_logged("dd if=/dev/zero of=$_[0] bs=1024 count=$bl 2>&1");
2299if ($?) { return "dd failed : $out"; }
2300$out = &backquote_logged("mkswap $_[0] $bl 2>&1");
2301if ($?) { return "mkswap failed : $out"; }
2302&system_logged("sync >/dev/null 2>&1");
2303return 0;
2304}
2305
2306# exports_list(host, dirarray, clientarray)
2307# Fills the directory and client array references with exports from some
2308# host. Returns an error string if something went wrong
2309sub exports_list
2310{
2311local($dref, $cref, $out, $_);
2312$dref = $_[1]; $cref = $_[2];
2313$out = &backquote_command("showmount -e ".quotemeta($_[0])." 2>&1", 1);
2314if ($?) { return $out; }
2315
2316# Add '/' if the server is in NFSv4
2317if (nfs_max_version($_[0]) >= 4) {
2318    push(@$dref, "/"); push(@$cref, "*"); }
2319
2320foreach (split(/\n/, $out)) {
2321	if (/^(\/\S*)\s+(.*)$/) {
2322		push(@$dref, $1); push(@$cref, $2);
2323		}
2324	}
2325return undef;
2326}
2327
2328# nfs_max_version(host)
2329# Return the max NFS version allowed on a server
2330sub nfs_max_version
2331{
2332    local($_, $max, $out);
2333    $max = 0;
2334    $out = &backquote_command("/usr/sbin/rpcinfo -p ".quotemeta($_[0])." 2>&1", 1);
2335    if ($?) { return $out; }
2336    foreach (split(/\n/, $out)) {
2337	if ((/ +(\d) +.*nfs/) && ($1 > $max)) {
2338	    $max = $1; }
2339    }
2340    return $max;
2341}
2342
2343# broadcast_addr()
2344# Returns a useable broadcast address for finding NFS servers
2345sub broadcast_addr
2346{
2347local($out);
2348$out = &backquote_command("ifconfig -a 2>&1", 1);
2349if ($out =~ /(eth|tr)\d\s+.*\n.*Bcast:(\S+)\s+/) { return $2; }
2350return "255.255.255.255";
2351}
2352
2353# autofs_options(string)
2354# Converts a string of options line --timeout 60 to something like timeout=60
2355sub autofs_options
2356{
2357local(@options);
2358if ($_[0] =~ /--timeout\s+(\d+)/ || $_[0] =~ /-t\s+(\d+)/) {
2359	push(@options, "timeout=$1");
2360	}
2361if ($_[0] =~ /--pid-file\s+(\S+)/ || $_[0] =~ /-p\s+(\d+)/) {
2362	push(@options, "pid-file=$1");
2363	}
2364return join(',', @options);
2365}
2366
2367# autofs_args(string)
2368# Convert a comma-separated options string into args for automount
2369sub autofs_args
2370{
2371local(%options, $args);
2372&parse_options("autofs", $_[0]);
2373if (defined($options{'timeout'})) {
2374	$args .= " --timeout $options{'timeout'}";
2375	}
2376if (defined($options{'pid-file'})) {
2377	$args .= " --pid-file $options{'pid-file'}";
2378	}
2379return $args;
2380}
2381
2382# read_amd_conf()
2383# Returns the entire amd config file as a string
2384sub read_amd_conf
2385{
2386local $sl = $/;
2387$/ = undef;
2388local $rv;
2389foreach $f (split(/\s+/, $config{'auto_file'})) {
2390	open(AMD, "<".$f);
2391	$rv .= <AMD>;
2392	close(AMD);
2393	}
2394$/ = $sl;
2395return $rv;
2396}
2397
2398# write_amd_conf(text)
2399sub write_amd_conf
2400{
2401local @af = split(/\s+/, $config{'auto_file'});
2402&open_tempfile(AMD, ">$config{'auto_file'}");
2403&print_tempfile(AMD, $_[0]);
2404&close_tempfile(AMD);
2405}
2406
2407# parse_amd_conf()
2408# Parses a new-style amd.conf file into a hashtable
2409sub parse_amd_conf
2410{
2411local (@rv, $str);
2412foreach $f (split(/\s+/, $config{'auto_file'})) {
2413	local $lnum = 0;
2414	open(AMD, "<".$f);
2415	while(<AMD>) {
2416		s/\r|\n//g;
2417		s/#.*$//g;
2418		if (/\[\s*(\S+)\s*\]/) {
2419			$str = { 'dir' => $1,
2420				 'line' => $lnum,
2421				 'eline' => $lnum,
2422				 'file' => $f };
2423			push(@rv, $str);
2424			}
2425		elsif (/(\S+)\s*=\s*"(.*)"/ || /(\S+)\s*=\s*(\S+)/) {
2426			$str->{'opts'}->{$1} = $2;
2427			$str->{'eline'} = $lnum;
2428			}
2429		$lnum++;
2430		}
2431	close(AMD);
2432	}
2433return @rv;
2434}
2435
2436# device_name(device, [non-local])
2437# Converts a device name to a human-readable form
2438sub device_name
2439{
2440# First try to get name from fdisk module, as it knowns better about IDE
2441# and SCSI devices
2442if (&foreign_check("fdisk") && !$_[1]) {
2443	&foreign_require("fdisk");
2444	my @disks = &fdisk::list_disks_partitions();
2445	foreach my $d (@disks) {
2446		if ($d->{'device'} eq $_[0]) {
2447			return $d->{'desc'};
2448			}
2449		foreach my $p (@{$d->{'parts'}}) {
2450			if ($p->{'device'} eq $_[0]) {
2451				return $p->{'desc'};
2452				}
2453			}
2454		}
2455	}
2456
2457if (!$text{'select_part'}) {
2458	local %flang = &load_language('fdisk');
2459	foreach $k (keys %flang) {
2460		$text{$k} = $flang{$k} if ($k =~ /^select_/);
2461		}
2462	}
2463return $_[0] =~ /^\/dev\/(s|h|xv|v)d([a-z]+)(\d+)$/ ?
2464	&text('select_part', $1 eq 's' ? 'SCSI' : $1 eq 'xv' ? 'Xen' :
2465			     $1 eq 'v' ? 'VirtIO' : 'IDE',
2466			     uc($2), "$3") :
2467       $_[0] =~ /^\/dev\/(s|h|xv|v)d([a-z]+)$/ ?
2468	&text('select_device', $1 eq 's' ? 'SCSI' : $1 eq 'xv' ? 'Xen' :
2469			       $1 eq 'v' ? 'VirtIO' : 'IDE',
2470			       uc($2)) :
2471       $_[0] =~ /^\/dev\/mmcblk(\d+)p(\d+)$/ ?
2472	&text('select_part', "SD-Card", "$1", "$2") :
2473       $_[0] =~ /^\/dev\/mmcblk(\d+)$/ ?
2474	&text('select_device', "SD-Card", "$1") :
2475       $_[0] =~ /rd\/c(\d+)d(\d+)p(\d+)$/ ?
2476	&text('select_mpart', "$1", "$2", "$3") :
2477       $_[0] =~ /ida\/c(\d+)d(\d+)p(\d+)$/ ?
2478	&text('select_cpart', "$1", "$2", "$3") :
2479       $_[0] =~ /cciss\/c(\d+)d(\d+)p(\d+)$/ ?
2480	&text('select_smartpart', "$1", "$2", "$3") :
2481       $_[0] =~ /scsi\/host(\d+)\/bus(\d+)\/target(\d+)\/lun(\d+)\/part(\d+)/ ?
2482	&text('select_spart', "$1", "$2", "$3", "$4", "$5") :
2483       $_[0] =~ /scsi\/host(\d+)\/bus(\d+)\/target(\d+)\/lun(\d+)\/disc/ ?
2484	&text('select_scsi', "$1", "$2", "$3", "$4") :
2485       $_[0] =~ /ide\/host(\d+)\/bus(\d+)\/target(\d+)\/lun(\d+)\/part(\d+)/ ?
2486	&text('select_snewide', "$1", "$2", "$3", "$4", "$5") :
2487       $_[0] =~ /ide\/host(\d+)\/bus(\d+)\/target(\d+)\/lun(\d+)\/disc/ ?
2488	&text('select_newide', "$1", "$2", "$3", "$4") :
2489       $_[0] =~ /ataraid\/disc(\d+)\/part(\d+)$/ ?
2490	&text('select_ppart', "$1", "$2") :
2491       $_[0] =~ /fd(\d+)$/ ?
2492	&text('select_fd', "$1") :
2493       $_[0] =~ /md(\d+)$/ ?
2494	&text('linux_rdev', "$1") :
2495       $_[0] =~ /\/dev\/([^\/]+)\/([^\/]+)$/ && $1 ne "cdroms" ?
2496	&text('linux_ldev', "$1", "$2") :
2497       $_[0] =~ /LABEL=(\S+)/i ?
2498	&text('linux_label', "$1") :
2499       $_[0] =~ /UUID=(\S+)/i ?
2500	&text('linux_uuid', "$1") :
2501       $_[0] eq '/dev/cdrom' ?
2502	$text{'linux_cddev'} :
2503       $_[0] eq '/dev/burner' ?
2504	$text{'linux_burnerdev'} :
2505       $_[0] =~ /cdroms\/cdrom(\d+)$/ ?
2506	&text('linux_cddev2', "$1") :
2507	$_[0];
2508}
2509
2510sub files_to_lock
2511{
2512return ( $config{'fstab_file'}, $config{'autofs_file'},
2513	 split(/\s+/, $config{'auto_file'}) );
2514}
2515
2516# lowercase_share_path(path)
2517# Converts a share spec like //FOO/BAR/Smeg to //foo/bar/Smeg
2518sub lowercase_share_path
2519{
2520local ($path) = @_;
2521$path =~ s/\//\\/g;
2522if ($path =~ /^\\\\([^\\]+)\\([^\\]+)(\\.*)?/) {
2523	$path = "\\\\".lc($1)."\\".lc($2).$3;
2524	}
2525return $path;
2526}
2527
2528# get_filesystem_label(device, mount, type)
2529# Returns the label if there is one for this filesystem, or undef
2530sub get_filesystem_label
2531{
2532local @p = @_;
2533if (defined($get_filesystem_label_cache{$p[0]})) {
2534	return $get_filesystem_label_cache{$p[0]};
2535	}
2536local $rv = "";
2537if ($p[2] =~ /^ext\d+$/ && $has_e2label ||
2538    $p[2] eq "xfs" && $has_xfs_db ||
2539    $p[2] eq "reiserfs" && $has_reiserfstune) {
2540	local $label;
2541	if ($p[2] eq "xfs") {
2542		local $out = &backquote_command(
2543			"xfs_db -x -p xfs_admin -c label -r ".
2544			quotemeta($p[0])." 2>&1", 1);
2545		$label = $1 if ($out =~ /label\s*=\s*"(.*)"/ &&
2546				$1 ne '(null)');
2547		}
2548	elsif ($p[2] eq "reiserfs") {
2549		local $out = &backquote_command(
2550			"reiserfstune ".quotemeta($p[0])." 2>&1");
2551		if ($out =~ /LABEL:\s*(\S+)/) {
2552			$label = $1;
2553			}
2554		}
2555	else {
2556		$label = &backquote_command(
2557			"e2label ".quotemeta($p[0])." 2>&1", 1);
2558		chop($label);
2559		}
2560	$rv = $label if (!$?);
2561	}
2562$get_filesystem_label_cache{$p[0]} = $rv;
2563return $rv;
2564}
2565
25661;
2567
2568