Handle hostnames with upper-case letters
[webmin.git] / mount / mount-lib.pl
1 # mount-lib.pl
2 # Functions for handling the /etc/[v]fstab file. Some functions are defined in
3 # here, and some in OS-specific files named <os_type>-lib.pl
4
5 BEGIN { push(@INC, ".."); };
6 use WebminCore;
7 &init_config();
8 %access = &get_module_acl();
9 $filesystem_users_file = "$module_config_directory/filesystem-users";
10 @access_fs = split(/\s+/, $access{'fs'});
11
12 # get_mount(directory|'swap', device)
13 # Returns the index of this mount, or -1 if not known
14 sub get_mount
15 {
16 local(@mlist, $p, $d, $i);
17 @mlist = &list_mounts();
18 for($i=0; $i<@mlist; $i++) {
19         $p = $mlist[$i];
20         if ($_[0] eq "*" && $p->[1] eq $_[1]) {
21                 # found by match on device
22                 return $i;
23                 }
24         elsif ($_[1] eq "*" && $p->[0] eq $_[0]) {
25                 # found by match on directory
26                 return $i;
27                 }
28         elsif ($p->[0] eq $_[0] && $p->[1] eq $_[1]) {
29                 # found by match on both
30                 return $i;
31                 }
32         }
33 return -1;
34 }
35
36
37 # get_mounted(directory|'swap', device)
38 # Returns the index of this current mount, or -1 if not known
39 sub get_mounted
40 {
41 local(@mlist, $p, $d, $i);
42 @mlist = &list_mounted();
43 for($i=0; $i<@mlist; $i++) {
44         $p = $mlist[$i];
45         if ($_[0] eq "*" && $p->[1] eq $_[1]) {
46                 # found by match on device
47                 return $i;
48                 }
49         elsif ($_[1] eq "*" && $p->[0] eq $_[0]) {
50                 # found by match on directory
51                 return $i;
52                 }
53         elsif ($p->[0] eq $_[0] && $p->[1] eq $_[1]) {
54                 # found by match on both
55                 return $i;
56                 }
57         }
58 return -1;
59 }
60
61
62 # parse_options(type, options)
63 # Convert an options string for some filesystem into the associative
64 # array %options
65 sub parse_options
66 {
67 local($_);
68 undef(%options);
69 if ($_[1] ne "-") {
70         foreach (split(/,/, $_[1])) {
71                 if (/^([^=]+)=(.*)$/) { $options{$1} = $2; }
72                 else { $options{$_} = ""; }
73                 }
74         }
75 return \%options;
76 }
77
78 # join_options(type, [&hash])
79 # Returns a string constructed from the %options hash
80 sub join_options
81 {
82 local $h = $_[1] || \%options;
83 local (@rv, $k);
84 foreach $k (keys %$h) {
85         push(@rv, $h->{$k} eq "" ? $k : $k."=".$h->{$k});
86         }
87 return @rv ? join(",", @rv) : "-";
88 }
89
90 # swap_form(path)
91 # This function should be called by os-specific code to display a form
92 # asking for the size of a swap file to create. The form will be submitted
93 # to a creation program, and then redirected back to the original mount cgi
94 sub swap_form
95 {
96 &ui_print_header(undef, "Create Swap File", "");
97 print "<form action=create_swap.cgi>\n";
98 foreach $k (keys %in) {
99         print "<input type=hidden name=\"$k\" value=\"$in{$k}\">\n";
100         }
101 print "<input type=hidden name=cswap_file value=\"$_[0]\">\n";
102 print "The swap file <tt>$_[0]</tt> does not exist.<p>\n";
103 print "Create and mount a swap file with size <input name=cswap_size size=6>\n";
104 print "<select name=cswap_units>\n";
105 print "<option value=k> kB\n";
106 print "<option value=m selected> MB\n";
107 print "<option value=g> GB\n";
108 print "</select>\n";
109 print "<input type=submit value=\"Create\"></form>\n";
110 &ui_print_footer("", "mount list");
111 exit;
112 }
113
114 # nfs_server_chooser_button(input, [form])
115 sub nfs_server_chooser_button
116 {
117 local($form);
118 $form = @_ > 1 ? $_[1] : 0;
119 if ($access{'browse'}) {
120         print "<input type=button onClick='ifield = document.forms[$form].$_[0]; nfs_server = window.open(\"../$module_name/nfs_server.cgi\", \"nfs_server\", \"toolbar=no,menubar=no,scrollbars=yes,width=400,height=300\"); nfs_server.ifield = ifield; window.ifield = ifield' value=\"...\">\n";
121         }
122 }
123
124 # nfs_export_chooser_button(serverinput, exportinput, [form])
125 sub nfs_export_chooser_button
126 {
127 local($form);
128 $form = @_ > 2 ? $_[2] : 0;
129 if ($access{'browse'}) {
130         print "<input type=button onClick='if (document.forms[$form].$_[0].value != \"\") { ifield = document.forms[$form].$_[1]; nfs_export = window.open(\"../$module_name/nfs_export.cgi?server=\"+document.forms[$form].$_[0].value, \"nfs_export\", \"toolbar=no,menubar=no,scrollbars=yes,width=500,height=200\"); nfs_export.ifield = ifield; window.ifield = ifield }' value=\"...\">\n";
131         }
132 }
133
134 # smb_server_chooser_button(serverinput, [form])
135 sub smb_server_chooser_button
136 {
137 local($form);
138 $form = @_ > 1 ? $_[1] : 0;
139 if (&has_command($config{'smbclient_path'}) && $access{'browse'}) {
140         print "<input type=button onClick='ifield = document.forms[$form].$_[0]; smb_server = window.open(\"../$module_name/smb_server.cgi\", \"smb_server\", \"toolbar=no,menubar=no,scrollbars=yes,width=400,height=300\"); smb_server.ifield = ifield; window.ifield = ifield' value=\"...\">\n";
141         }
142 }
143
144 # smb_share_chooser_button(serverinput, shareinput, [form])
145 sub smb_share_chooser_button
146 {
147 local($form);
148 $form = @_ > 2 ? $_[2] : 0;
149 if (&has_command($config{'smbclient_path'}) && $access{'browse'}) {
150         print "<input type=button onClick='if (document.forms[$form].$_[0].value != \"\") { ifield = document.forms[$form].$_[1]; smb_share = window.open(\"../$module_name/smb_share.cgi?server=\"+document.forms[$form].$_[0].value, \"smb_share\", \"toolbar=no,menubar=no,scrollbars=yes,width=400,height=300\"); smb_share.ifield = ifield; window.ifield = ifield }' value=\"...\">\n";
151         }
152 }
153
154 # Include the correct OS-specific functions file
155 if ($gconfig{'os_type'} =~ /^\S+\-linux$/) {
156         do "linux-lib.pl";
157         }
158 else {
159         do "$gconfig{'os_type'}-lib.pl";
160         }
161
162 # can_edit_fs(dir, device, type, options, [is-new])
163 # Returns 1 if a filesystem can be edited, 0 otherwise
164 sub can_edit_fs
165 {
166 local $ok = 1;
167 if (@access_fs) {
168         local $d;
169         foreach $d (@access_fs) {
170                 $ok = 0 if (!&is_under_directory($d, $_[0]));
171                 }
172         }
173 $ok = 0 if (!&can_fstype($_[2]));
174 if ($access{'user'} && !$_[4]) {
175         local $users = &get_filesystem_users();
176         $ok = 0 if ($users->{$_[0]} ne $remote_user);
177         }
178 return $ok;
179 }
180
181 # can_fstype(type)
182 sub can_fstype
183 {
184 return 1 if (!$access{'types'});
185 local @types = split(/\s+/, $access{'types'});
186 return &indexof($_[0], @types) >= 0;
187 }
188
189 # compile_program(name, default-arch)
190 # Ensures that some C program is compiled and copied to /etc/webmin . Uses the
191 # supplied native versions if possible
192 sub compile_program
193 {
194 return if (-r "$module_config_directory/$_[0]" &&
195    &execute_command("$module_config_directory/$_[0]", undef, undef, undef, 0, 1) == 0);
196 local $arch = &backquote_command("uname -m");
197 $arch =~ s/\r|\n//g;
198 local $re = $_[1];
199 if ($re && $arch =~ /^$re$/i && -r "$module_root_directory/$_[0]" &&
200     &execute_command("$module_root_directory/$_[0]", undef, undef, undef, 0, 1) == 0) {
201         # Compiled program for this architecture already exists and is working,
202         # so can just copy
203         &execute_command("cp $module_root_directory/$_[0] $module_config_directory/$_[0]");
204         }
205 else {
206         # Need to compile
207         local ($cc) = (&has_command("gcc") || &has_command("cc") ||
208                        &has_command("gcc-4.0") || &has_command("gcc-3.3"));
209         $cc || &error($text{'egcc'});
210         local $out = &backquote_logged("$cc -o $module_config_directory/$_[0] $module_root_directory/$_[0].c 2>&1");
211         if ($?) {
212                 &error(&text('ecompile', "<pre>$out</pre>"));
213                 }
214         }
215 &set_ownership_permissions(undef, undef, 0755,"$module_config_directory/$_[0]");
216 }
217
218 # get_filesystem_users()
219 # Returns a mapping between filesystems and their owners
220 sub get_filesystem_users
221 {
222 local %users;
223 &read_file($filesystem_users_file, \%users);
224 return \%users;
225 }
226
227 # save_filesystem_users(&usermap)
228 # Saves the filesystem owner mapping
229 sub save_filesystem_users
230 {
231 &write_file($filesystem_users_file, $_[0]);
232 }
233
234 # can_delete_directory(mount-point)
235 # Returns 1 if some directory should be deleted when un-mounting
236 sub can_delete_directory
237 {
238 local @dirs = split(/\s+/, $config{'delete_under'});
239 return 0 if (!@dirs);
240 return 0 if ($_[0] eq "swap");
241 local $d;
242 foreach $d (@dirs) {
243         return 1 if (&is_under_directory($d, $_[0]));
244         }
245 return 0;
246 }
247
248 # delete_unmounted(dir, device)
249 # If some directory is no longer in the permanent mount list, delete it if it
250 # is under the list of dirs to auto-delete
251 sub delete_unmounted
252 {
253 if (&can_delete_directory($_[0]) &&
254     &get_mount($_[0], $_[1]) < 0) {
255         &system_logged("rmdir ".quotemeta($_[0]));
256         }
257 }
258
259 # remount_dir(directory, device, type, options)
260 # Adjusts the options for some mounted filesystem
261 sub remount_dir
262 {
263 if (defined(&os_remount_dir)) {
264         return &os_remount_dir(@_);
265         }
266 else {
267         local $err = &unmount_dir(@_);
268         return $err if ($err);
269         return &mount_dir(@_);
270         }
271 }
272
273 # filesystem_for_dir(dir)
274 # Give a directory, returns the details filesystem it is on (dir, device,
275 # type, options)
276 sub filesystem_for_dir
277 {
278 local @stdir = stat($_[0]);
279 foreach my $m (&list_mounted()) {
280         local @stm = stat($m->[0]);
281         if ($stm[0] == $stdir[0]) {
282                 # Save device number!
283                 return @$m;
284                 }
285         }
286 return ( );
287 }
288
289 # local_disk_space([&always-count])
290 # Returns the total local and free disk space on the system.
291 sub local_disk_space
292 {
293 my ($always) = @_;
294 my ($total, $free) = (0, 0);
295 my @mounted = &mount::list_mounted();
296 my %donezone;
297 my %donevzfs;
298 foreach $m (@mounted) {
299         if ($m->[2] =~ /^ext/ ||
300             $m->[2] eq "reiserfs" || $m->[2] eq "ufs" ||
301             $m->[2] eq "zfs" || $m->[2] eq "simfs" || $m->[2] eq "vzfs" ||
302             $m->[2] eq "xfs" || $m->[2] eq "jfs" ||
303             $m->[1] =~ /^\/dev\// ||
304             &indexof($m->[1], @$always) >= 0) {
305                 if ($m->[1] =~ /^zones\/([^\/]+)/ &&
306                     $m->[2] eq "zfs" && $donezone{$1}++) {
307                         # Don't double-count zones
308                         next;
309                         }
310                 my ($t, $f) = &mount::disk_space($m->[2], $m->[0]);
311                 if (($m->[2] eq "simfs" || $m->[2] eq "vzfs" ||
312                      $m->[0] eq "/dev/vzfs") &&
313                     $donevzfs{$t,$f}++) {
314                         # Don't double-count VPS filesystems
315                         next;
316                         }
317                 $total += $t*1024;
318                 $free += $f*1024;
319                 }
320         }
321 return ($total, $free);
322 }
323
324 1;
325