3 # Save or create a mount. When saving an existing mount, at lot of different
6 require './mount-lib.pl';
7 &error_setup($text{'save_err'});
11 if ($in{'advanced'}) {
12 # Return to mount form, but force advanced mount option mode
13 if ($in{'old'} eq '') {
14 &redirect("edit_mount.cgi?type=$in{'type'}&advanced=1");
17 &redirect("edit_mount.cgi?temp=$in{'temp'}&index=$in{'old'}&advanced=1");
23 if ($in{type} ne "swap") {
24 if ($in{directory} !~ /^\//) {
25 if (@access_fs && $in{directory}) {
26 # Assume relative to allowed dir
27 $in{directory} = $access_fs[0]."/".$in{directory};
30 &error(&text('save_edirname', $in{'directory'}));
33 if (-r $in{'directory'} && !(-d $in{'directory'})) {
34 &error(&text('save_edir', $in{'directory'}));
36 # non-existant directories get created later
39 # for swap files, set the directory to 'swap'
40 $in{directory} = "swap";
42 &can_edit_fs($in{'directory'}, undef, $in{'type'}, undef, 1) &&
43 !$access{'only'} || &error($text{'edit_ecannot'});
44 $access{'create'} || defined($in{'old'}) || &error($text{'edit_ecannot2'});
47 @mmodes = &mount_modes($in{type});
48 $msave = ($mmodes[0]==0 ? 0 : $in{msave});
49 $mnow = ($mmodes[1]==0 ? $msave : $in{mmount});
50 $access{'simopts'} = 0 if ($in{'nosimopts'});
52 foreach $f (&files_to_lock()) {
55 if (defined($in{old}) && !$access{'simple'}) {
56 # Saving an existing mount
57 if ($in{temp}) { @mlist = &list_mounted(); }
58 else { @mlist = &list_mounts(); }
59 @mold = @{$mlist[$in{old}]};
61 if (!$mnow && !$in{oldmnow} && !$msave) {
62 # Not mounted, so remove from fstab without checking
66 # Changing an existing mount
67 $dev = &check_location($in{'type'});
68 &parse_options($mold[2], $mold[3]);
69 $opts = &check_options($in{'type'}, $dev, $in{'directory'});
70 @minfo = ($in{'directory'}, $dev, $in{'type'}, $opts,
71 $mmodes[2] ? $in{'order'} : "-",
72 $in{'msave'}==2||$mmodes[0]==1 ? "yes" : "no");
75 # Check for change in device
76 if ($mold[1] ne $dev) {
77 # Device has changed..check it
78 if (!&multiple_mount($minfo[2]) && &get_mounted("*", $dev)>=0) {
79 &error(&text('save_ealready', $dev));
81 if (!&multiple_mount($minfo[2]) && &get_mount("*", $dev) != -1){
82 &error(&text('save_ealready2', $dev));
87 # Check for change in directory
88 if ($in{type} ne "swap" && $mold[0] ne $in{directory}) {
89 # Directory has changed.. check it too
90 if (&get_mounted($in{directory}, "*")>=0) {
91 &error(&text('save_ealready3', $in{'directory'}));
93 if (&get_mount($in{directory}, "*") != -1) {
94 &error(&text('save_ealready4', $in{'directory'}));
98 if (!(-d $in{directory})) {
99 # Create the new directory
100 &lock_file($in{directory});
101 &make_dir($in{directory}, 0755) ||
102 &error(&text('save_emkdir',
103 $in{'directory'}, $!));
104 &unlock_file($in{directory});
109 # Check for change in current mount status
110 if ($in{'oldmnow'} && $mmodes[3] == 1) {
111 # Mounted, and cannot be unmounted
113 elsif ($in{'oldmnow'} && !$mnow) {
114 # Just been unmounted..
115 if ($error = &unmount_dir($mold[0], $mold[1], $in{'type'},
116 $mold[3], $in{'force'})) {
118 $error =~ /busy|Invalid argument/ &&
119 defined(&can_force_unmount_dir) &&
120 &can_force_unmount_dir(@mold)) {
121 # Mount is busy.. most likely because it is
122 # currently in use. Offer the user a choice to
124 &ui_print_header(undef, $text{'edit_title'}, "");
125 print &text('save_force', "<tt>$mold[0]</tt>"),
127 print "<form action=save_mount.cgi>\n";
128 print "<input type=hidden name=force ",
130 foreach $k (keys %in) {
131 print "<input type=hidden name=$k ",
132 "value=\"$in{$k}\">\n";
135 print &ui_submit($text{'save_fapply'}),"\n";
139 &ui_print_footer("", $text{'index_return'});
143 &error(&text('save_eumount', $error));
146 @tlog = ( "umount", "dir", $mold[0],
147 { 'dir' => $mold[0], 'dev' => $mold[1],
148 'type' => $mold[2], 'opts' => $mold[3] } );
150 elsif ($mnow && !$in{oldmnow}) {
151 # Just been mounted..
152 if ($error = &mount_dir(@minfo)) {
153 &error(&text('save_emount', $error));
155 @tlog = ( "mount", "dir", $minfo[0],
156 { 'dir' => $minfo[0], 'dev' => $minfo[1],
157 'type' => $minfo[2], 'opts' => $minfo[3] } );
159 elsif (!$mnow && !$in{oldmnow}) {
160 # Not mounted, and doesn't need to be
162 elsif ($mold[0] eq $minfo[0] && $mold[1] eq $minfo[1] &&
163 &diff_opts($mold[3], $minfo[3]) && !$in{'perm_only'} &&
164 defined(&os_remount_dir)) {
165 # Only options have changed .. just call remount
166 if ($error = &remount_dir(@minfo)) {
167 &error(&text('save_eremount', $error));
169 @tlog = ( "remount", "dir", $minfo[0],
170 { 'dir' => $minfo[0], 'dev' => $minfo[1],
171 'type' => $minfo[2], 'opts' => $minfo[3] } );
173 elsif (($mold[0] ne $minfo[0] || $mold[1] ne $minfo[1] ||
174 &diff_opts($mold[3], $minfo[3])) && !$in{'perm_only'}) {
175 # Need to unmount/mount to apply new options
176 if ($error = &unmount_dir($mold[0], $mold[1], $in{type})) {
177 if ($error =~ /busy|Invalid argument/ && $msave) {
178 # Mount is busy.. most likely because it is
179 # currently in use. Offer the user a choice
180 # to update only the fstab file, rather than
182 &ui_print_header(undef, $text{'edit_title'}, "");
183 print &text('save_perm', "<tt>$mold[0]</tt>"),
185 print "<form action=save_mount.cgi>\n";
186 print "<input type=hidden name=perm_only ",
188 foreach $k (keys %in) {
189 print "<input type=hidden name=$k ",
190 "value=\"$in{$k}\">\n";
193 print &ui_submit($text{'save_apply'}),"\n";
197 &ui_print_footer("", $text{'index_return'});
200 else { &error(&text('save_eremount', $error)); }
202 if ($error = &mount_dir(@minfo)) {
203 &error(&text('save_eremount', $error));
205 @tlog = ( "remount", "dir", $minfo[0],
206 { 'dir' => $minfo[0], 'dev' => $minfo[1],
207 'type' => $minfo[2], 'opts' => $minfo[3] } );
210 # Check for change in permanence
211 if ($in{oldmsave} && !$msave) {
212 # Delete from mount table
213 &delete_mount($in{old});
214 @plog = ( "delete", "dir", $in{'directory'},
215 { 'dir' => $mold[0], 'dev' => $mold[1],
216 'type' => $mold[2], 'opts' => $mold[3] } );
218 elsif ($msave && !$in{oldmsave}) {
220 &create_mount(@minfo);
221 @plog = ( "create", "dir", $in{'directory'},
222 { 'dir' => $minfo[0], 'dev' => $minfo[1],
223 'type' => $minfo[2], 'opts' => $minfo[3] } );
225 elsif (!$msave && !$in{oldmsave}) {
228 elsif ($mold[0] ne $minfo[0] || $mold[1] ne $minfo[1] ||
229 $mold[4] != $minfo[4] || $mold[5] ne $minfo[5] ||
230 &diff_opts($mold[3], $minfo[3])) {
231 # Apply any changes in mount options
232 &change_mount($in{old}, @minfo);
233 @plog = ( "modify", "dir", $in{'directory'},
234 { 'dir' => $minfo[0], 'dev' => $minfo[1],
235 'type' => $minfo[2], 'opts' => $minfo[3] } );
238 # If no longer mounted, remove the dir
239 if (&get_mounted(@mold) < 0) {
240 &delete_unmounted(@mold);
243 elsif (defined($in{'old'})) {
244 # Doing a simple modification to a mount
246 @mlist = &list_mounted();
250 @mlist = &list_mounts();
252 $now = 1 if ($in{'oldmnow'});
254 @mold = @{$mlist[$in{old}]};
257 # Just unmount the filesystem
258 if ($error = &unmount_dir($mold[0], $mold[1], $in{type})) {
259 &error(&text('save_eumount', $error));
261 &delete_unmounted(@mold);
264 elsif ($in{'mount'}) {
265 # Just mount the filesystem
266 if ($error = &mount_dir(@mold)) {
267 &error(&text('save_emount', $error));
271 elsif ($in{'perm'}) {
272 # Add to permanent mount list
273 &create_mount($mold[0], $mold[1], $mold[2], $mold[3],
277 elsif ($in{'delete'}) {
278 if ($in{'oldmnow'}) {
280 if ($error = &unmount_dir($mold[0], $mold[1],
282 &error(&text('save_eumount', $error));
286 # Remove from permanent list
287 &delete_mount($in{'old'});
288 &delete_unmounted(@mold);
292 # Updating the mount in some way ..
293 # Check the mount source
294 $dev = &check_location($in{'type'});
295 &parse_options($mold[2], $mold[3]);
296 if (defined($access{'opts'}) &&
297 $access{'opts'} !~ /$in{'type'}/) {
298 # Just use existing options
300 foreach $k (keys %options) {
301 if ($options{$k} eq '') { push(@opts, $k); }
302 else { push(@opts, "$k=$options{$k}"); }
304 $opts = @opts ? join(",", @opts) : "-";
307 # Get options from the user
308 $opts = &check_options($in{'type'}, $dev,
311 @minfo = ($in{'directory'}, $dev, $in{'type'}, $opts, 2, 'yes');
313 # Check for change in device
314 if ($mold[1] ne $dev) {
315 # Device has changed..check it
316 if (!&multiple_mount($minfo[2]) &&
317 &get_mounted("*", $dev)>=0) {
318 &error(&text('save_ealready', $dev));
320 if (!&multiple_mount($minfo[2]) &&
321 &get_mount("*", $dev) != -1){
322 &error(&text('save_ealready2', $dev));
327 # Check for change in directory
328 if ($in{type} ne "swap" && $mold[0] ne $in{directory}) {
329 # Directory has changed.. check it too
330 if (&get_mounted($in{directory}, "*")>=0) {
331 &error(&text('save_ealready3',
334 if (&get_mount($in{directory}, "*") != -1) {
335 &error(&text('save_ealready4',
340 if (!(-d $in{directory})) {
341 # Create the new directory
342 &lock_file($in{directory});
343 &make_dir($in{directory}, 0755) ||
344 &error(&text('save_emkdir',
345 $in{'directory'}, $!));
346 &unlock_file($in{directory});
351 if ($in{'oldmnow'} && ($mold[0] ne $minfo[0] ||
352 $mold[1] ne $minfo[1] || &diff_opts($mold[3], $minfo[3]))) {
353 # Need to unmount/mount to apply new options
354 if ($error=&unmount_dir($mold[0], $mold[1], $in{type})){
355 &error(&text('save_eremount', $error));
357 if ($error = &mount_dir(@minfo)) {
358 &error(&text('save_eremount', $error));
362 if ($in{'oldmsave'}) {
363 # Change entry in fstab
364 &change_mount($in{'old'}, @minfo);
368 elsif ($access{'simple'}) {
369 # Create and mounting from the simple interface
370 $dev = &check_location($in{type});
371 if (!defined($access{'opts'}) || $access{'opts'} =~ /$in{'type'}/) {
372 $opts = &check_options($in{'type'}, $dev, $in{'directory'});
377 @minfo = ($in{directory}, $dev, $in{type}, $opts, 2, 'yes');
379 # Check if the device is in use
380 if (!&multiple_mount($minfo[2]) && &get_mounted("*", $dev)>=0) {
381 &error(&text('save_ealready', $dev));
383 if (!&multiple_mount($minfo[2]) && &get_mount("*", $dev) != -1) {
384 &error(&text('save_ealready2', $dev));
387 # Check if the directory is in use
388 if ($in{type} ne "swap") {
389 if (&get_mounted($in{directory}, "*")>=0) {
390 &error(&text('save_ealready2', $in{'directory'}));
392 if (&get_mount($in{directory}, "*") != -1) {
393 &error(&text('save_ealready3', $in{'directory'}));
397 # Create the directory
398 if ($in{type} ne "swap" && !(-d $in{directory})) {
399 &lock_file($in{directory});
400 &make_dir($in{directory}, 0755) ||
401 &error(&text('save_emkdir', $in{'directory'}, $!));
402 &unlock_file($in{directory});
407 if ($error = &mount_dir($minfo[0], $minfo[1],
408 $minfo[2], $minfo[3])) {
409 if ($made_dir) { rmdir($in{directory}); }
410 &error(&text('save_emount', $error));
414 &create_mount(@minfo);
419 # Creating a new mount, complex interface
420 $dev = &check_location($in{type});
421 &parse_options($minfo[3]);
422 $opts = &check_options($in{type}, $dev, $in{'directory'});
423 @minfo = ($in{directory}, $dev, $in{type}, $opts,
424 $mmodes[2] ? $in{order} : "-",
425 $in{msave}==2||$mmodes[0]==1 ? "yes" : "no");
427 # Check if anything is being done
428 if (!$msave && !$mnow) {
429 &error($text{'save_enone'});
432 # Check if the device is in use
433 if (!&multiple_mount($minfo[2]) && &get_mounted("*", $dev)>=0) {
434 &error(&text('save_ealready', $dev));
436 if (!&multiple_mount($minfo[2]) && &get_mount("*", $dev) != -1) {
437 &error(&text('save_ealready2', $dev));
440 # Check if the directory is in use
441 if ($in{type} ne "swap") {
442 if (&get_mounted($in{directory}, "*")>=0) {
443 &error(&text('save_ealready2', $in{'directory'}));
445 if (&get_mount($in{directory}, "*") != -1) {
446 &error(&text('save_ealready3', $in{'directory'}));
450 # Create the directory
451 if ($in{type} ne "swap" && !(-d $in{directory})) {
452 &lock_file($in{directory});
453 &make_dir($in{directory}, 0755) ||
454 &error(&text('save_emkdir', $in{'directory'}, $!));
455 &unlock_file($in{directory});
459 # If mounting now, attempt to do it
461 # If the mount fails, give up totally
462 if ($error = &mount_dir($minfo[0], $minfo[1],
463 $minfo[2], $minfo[3])) {
464 if ($made_dir) { rmdir($in{directory}); }
465 &error(&text('save_emount', $error));
467 @tlog = ( "mount", "dir", $in{'directory'},
468 { 'dir' => $minfo[0], 'dev' => $minfo[1],
469 'type' => $minfo[2], 'opts' => $minfo[3] } );
472 # If saving, save now
474 &create_mount(@minfo);
475 @plog = ( "create", "dir", $in{'directory'},
476 { 'dir' => $minfo[0], 'dev' => $minfo[1],
477 'type' => $minfo[2], 'opts' => $minfo[3] } );
480 foreach $f (&files_to_lock()) {
483 &webmin_log(@plog) if (@plog);
484 %tpmap = ( 'create', 'mount', 'delete', 'umount', 'modify', 'remount' );
485 if (@tlog && $tpmap{$plog[0]} ne $tlog[0]) {
489 # Mark this mount and owned by this current user
490 $users = &get_filesystem_users();
491 if ($msave || $mnow) {
492 $users->{$in{'directory'}} ||= $remote_user;
495 delete($users->{$in{'directory'}});
497 &save_filesystem_users($users);
499 &redirect($in{'return'});
502 # Put back any changes to the fstab file
505 if ($in{temp} && $in{mboot}) {
506 # a mount was made permanent.. undo by deleting it
509 elsif (!$in{temp} && !$in{mboot}) {
510 # a permanent mount was made temporary.. undo by making it permanent
511 &create_mount(@mold);
514 # some mount options were changed.. undo by changing back
515 &change_mount($in{old}, @mold);
518 # A directory for mounting was created.. delete it
519 rmdir($in{directory});
523 # diff_opts(string1, string2)
526 local $o1 = join(",", sort { $a cmp $b } split(/,/, $_[0]));
527 local $o2 = join(",", sort { $a cmp $b } split(/,/, $_[1]));