Handle hostnames with upper-case letters
[webmin.git] / zones / forms-lib.pl
1 use Webmin::All;
2 use Socket;
3
4 # get_zone_form(&in, &zinfo)
5 # Returns a form for editing a zone
6 sub get_zone_form
7 {
8 local ($in, $zinfo) = @_;
9 local $form = new Webmin::Form("save_zone.cgi");
10 $form->set_input($in);
11 $form->add_hidden("zone", $zinfo->{'name'});
12 local $section = new Webmin::Section($text{'edit_common'}, 4, undef, "100%");
13 $form->add_section($section);
14
15 $section->add_row($text{'edit_name'}, "<tt>$in{'zone'}</tt>");
16 $section->add_row($text{'edit_status'}, &nice_status($zinfo->{'status'}));
17 $section->add_row($text{'edit_zonepath'}, "<tt>$zinfo->{'zonepath'}</tt>");
18 local $auto = new Webmin::Select("autoboot", $zinfo->{'autoboot'},
19                                  [ [ "true", $text{'yes'} ],
20                                    [ "false", $text{'no'} ] ]);
21 $section->add_input($text{'edit_autoboot'}, $auto);
22 local $pool = &pool_object("pool", $zinfo->{'pool'});
23 $section->add_input($text{'edit_pool'}, $pool);
24 $section->add_row($text{'edit_brand'}, "$zinfo->{'brand'}");
25
26 local @actions = &zone_status_actions($zinfo, 1);
27 $form->add_button(new Webmin::Submit($text{'save'}, "save"));
28 $form->add_button_spacer();
29 foreach my $a (@actions) {
30         $form->add_button(new Webmin::Submit($a->[1], $a->[0]));
31         }
32 $form->add_button_spacer() if (@actions);
33 $form->add_button(new Webmin::Submit($text{'edit_delete'}, "delete"));
34 return $form;
35 }
36
37 sub pool_object
38 {
39 local ($name, $value) = @_;
40 local $rv = new Webmin::OptTextbox($name, $value, 10, $text{'pool_none'});
41 $rv->set_validation_regexp('^\S+$', $text{'save_epool'});
42 return $rv;
43 }
44
45 # get_confirm_page(&in, type, &zinfo, from-list)
46 sub get_confirm_page
47 {
48 local ($in, $action, $zinfo, $list) = @_;
49 local $p = new Webmin::ConfirmPage(&zone_title($zinfo->{'name'}),
50                    $text{$action.'_title'},
51                    &text($action.'_rusure', "<tt>$zinfo->{'name'}</tt>"),
52                    "save_zone.cgi", $in, $text{'edit_'.$action}, $text{'ui_cancel'});
53 if ($list) {
54         $p->add_footer("index.cgi", $text{'index_return'});
55         }
56 else {
57         $p->add_footer("edit_zone.cgi?zone=$zinfo->{'name'}",
58                        $text{'edit_return'});
59         }
60 return $p;
61 }
62
63 # get_execute_page(action, &zinfo, from-list, action-args)
64 sub get_execute_page
65 {
66 local ($action, $zinfo, $list, $args) = @_;
67 local $p = new Webmin::Page(&zone_title($zinfo->{'name'}),
68                             $text{$action.'_title'});
69 local $d = new Webmin::DynamicWait(\&execute_action, [ $action, $zinfo, $args ]);
70 $p->add_form($d);
71 $d->set_message($text{$action.'_doing'});
72 $d->set_wait(1);
73 if ($list || $action eq "delete") {
74         $p->add_footer("index.cgi", $text{'index_return'});
75         }
76 else {
77         $p->add_footer("edit_zone.cgi?zone=$zinfo->{'name'}",
78                        $text{'edit_return'});
79         }
80 return $p;
81 }
82
83 sub execute_action
84 {
85 my ($d, $action, $zinfo, $args) = @_;
86 sleep(1);
87 local ($out, $ex);
88 if ($action eq "delete") {
89         # Halt and un-install before deleting
90         if ($zinfo->{'status'} ne 'configured') {
91                 if ($zinfo->{'status'} ne 'installed' &&
92                     $zinfo->{'status'} ne 'incomplete') {
93                         ($out, $ex) = &run_zone_command($zinfo, "halt");
94                         }
95                 if (!$ex) {
96                         ($out, $ex) = &run_zone_command($zinfo, "uninstall -F");
97                         }
98                 }
99         if (!$ex) {
100                 &delete_zone($zinfo);
101                 }
102         }
103 else {
104         # Just run zoneadm to execute action
105         ($out, $ex) = &run_zone_command($zinfo,
106                                       $action.($args ? " $args" : ""), 1);
107         }
108 $d->stop();
109 if ($ex) {
110         $p->add_error($text{'reboot_failed'}, $out);
111         }
112 else {
113         $p->add_message($text{'reboot_ok'});
114         if ($action eq "delete") {
115                 unlink(&zone_sysidcfg_file($zinfo->{'name'}));
116                 }
117         &webmin_log($action, "zone", $zinfo->{'name'});
118         }
119 }
120
121 # get_net_form(&in, &zinfo, &net)
122 sub get_net_form
123 {
124 local ($in, $zinfo, $net) = @_;
125 local ($new, $active, $address, $netmask);
126 local $form = new Webmin::Form("save_net.cgi", "post");
127 $form->add_hidden("zone", $zinfo->{'name'});
128 if ($net->{'address'}) {
129         $active = &get_active_interface($net);
130         ($address, $netmask) = &get_address_netmask($net, undef);
131         $form->add_hidden("old", $net->{'address'});
132         }
133 else {
134         $net = { 'physical' => &get_default_physical() };
135         $new = 1;
136         $form->add_hidden("new", 1);
137         }
138 $form->set_input($in);
139 local $section = new Webmin::Section($text{'net_header'}, 2);
140 $form->add_section($section);
141
142 local $ainput = new Webmin::Textbox("address", $address, 20);
143 $ainput->set_mandatory(1);
144 $ainput->set_validation_func(\&validate_address);
145 $section->add_input($text{'net_address'}, $ainput);
146
147 local $pinput = &physical_object("physical", $net->{'physical'});
148 $section->add_input($text{'net_physical'}, $pinput);
149
150 local $ninput = new Webmin::OptTextbox("netmask", $netmask, 20,
151                                        $text{'default'});
152 $ninput->set_validation_func(\&validate_netmask);
153 $section->add_input($text{'net_netmask'}, $ninput);
154
155 if ($active) {
156         $section->add_row($text{'net_broadcast'},
157                           "<tt>$active->{'broadcast'}</tt>");
158         }
159
160 if ($new) {
161         $form->add_button(new Webmin::Submit($text{'create'}, "create"));
162         }
163 else {
164         $form->add_button(new Webmin::Submit($text{'save'}, "save"));
165         $form->add_button(new Webmin::Submit($text{'delete'}, "delete"));
166         }
167 return $form;
168 }
169
170 # physical_object(name, value)
171 # Returns an input for selecting a real interface
172 sub physical_object
173 {
174 local ($name, $value) = @_;
175 return new Webmin::Select($name, $value,
176        [ map { [ $_->{'name'} ] } grep { $_->{'virtual'} eq '' }
177              &net::active_interfaces() ], 0, $value ? 1 : 0);
178 }
179
180 sub validate_address
181 {
182 return &check_ipaddress($_[0]) ? undef : $text{'net_eaddress'};
183 }
184
185 sub validate_netmask
186 {
187 return &check_ipaddress($_[0]) ? undef : $text{'net_enetmask'};
188 }
189
190 # get_pkg_form(&in, &zinfo, &pkg)
191 sub get_pkg_form
192 {
193 local ($in, $zinfo, $pkg) = @_;
194 local ($new);
195 local $form = new Webmin::Form("save_pkg.cgi", "post");
196 $form->set_input($in);
197 $form->add_hidden("zone", $zinfo->{'name'});
198 if ($pkg->{'dir'}) {
199         $form->add_hidden("old", $pkg->{'dir'});
200         }
201 else {
202         $new = 1;
203         $form->add_hidden("new", 1);
204         }
205 local $section = new Webmin::Section($text{'pkg_header'}, 2);
206 $form->add_section($section);
207
208 local $dinput = new Webmin::File("dir", $pkg->{'dir'}, 50, 1);
209 $dinput->set_mandatory(1);
210 $dinput->set_validation_func(\&validate_dir);
211 $section->add_input($text{'pkg_dir'}, $dinput);
212
213 if ($new) {
214         $form->add_button(new Webmin::Submit($text{'create'}, "create"));
215         }
216 else {
217         $form->add_button(new Webmin::Submit($text{'save'}, "save"));
218         $form->add_button(new Webmin::Submit($text{'delete'}, "delete"));
219         }
220 return $form;
221 }
222
223 sub validate_dir
224 {
225 return -d $_[0] ? undef : $text{'pkg_edir'};
226 }
227
228 # get_attr_form(&in, &zinfo, &attr)
229 sub get_attr_form
230 {
231 local ($in, $zinfo, $pkg) = @_;
232 local ($new);
233 local $form = new Webmin::Form("save_attr.cgi", "post");
234 $form->set_input($in);
235 $form->add_hidden("zone", $zinfo->{'name'});
236 if ($attr->{'name'}) {
237         $form->add_hidden("old", $attr->{'name'});
238         }
239 else {
240         $new = 1;
241         $form->add_hidden("new", 1);
242         }
243 local $section = new Webmin::Section($text{'attr_header'}, 2);
244 $form->add_section($section);
245
246 local $ninput = new Webmin::Textbox("name", $attr->{'name'}, 30);
247 $ninput->set_mandatory(1);
248 $ninput->set_validation_regexp('^\S+$', $text{'attr_ename'});
249 $section->add_input($text{'attr_name'}, $ninput);
250
251 local $tinput = new Webmin::Select("type", $attr->{'type'} || "string",
252                        [ map { [ $_, $text{'attr_'.$_} ] }
253                              &list_attr_types() ], 0, 1);
254 $section->add_input($text{'attr_type'}, $tinput);
255
256 local $vinput = new Webmin::Textbox("value", $attr->{'value'}, 30);
257 $vinput->set_validation_func(\&validate_value);
258 $vinput->set_mandatory(1);
259 $section->add_input($text{'attr_value'}, $vinput);
260
261 if ($new) {
262         $form->add_button(new Webmin::Submit($text{'create'}, "create"));
263         }
264 else {
265         $form->add_button(new Webmin::Submit($text{'save'}, "save"));
266         $form->add_button(new Webmin::Submit($text{'delete'}, "delete"));
267         }
268 return $form;
269 }
270
271 sub validate_value
272 {
273 local ($value, $name, $form) = @_;
274 if ($form->get_value("type") eq 'int') {
275         $value =~ /^\-?\d+$/ || return $text{'attr_eint'};
276         }
277 elsif ($form->get_value("type") eq 'uint') {
278         $value =~ /^\d+$/ || return $text{'attr_euint'};
279         }
280 elsif ($form->get_value("type") eq 'boolean') {
281         $value eq "true" || $value eq "false" ||
282                 return $text{'attr_uboolean'};
283         }
284 return undef;
285 }
286
287 # get_fs_form(in, &zinfo, &fs, type)
288 sub get_fs_form
289 {
290 local ($in, $zinfo, $fs, $type) = @_;
291 local ($new, $mount);
292 local $form = new Webmin::Form("save_fs.cgi", "post");
293 $form->set_input($in);
294 $form->add_hidden("zone", $zinfo->{'name'});
295 if ($fs->{'dir'}) {
296         $form->add_hidden("old", $fs->{'dir'});
297         $mount = &get_active_mount($zinfo, $fs);
298         }
299 else {
300         $new = 1;
301         $form->add_hidden("new", 1);
302         $form->add_hidden("type", $type);
303         }
304 local $section = new Webmin::Section($text{'fs_header'}, 2);
305 $form->add_section($section);
306
307 $section->add_row($text{'fs_type'},
308                   &mount::fstype_name($type)." (".uc($type).")");
309
310 if (!$new) {
311         if ($mount) {
312                 ($total, $free) = &mount::disk_space($mount->[2], $mount->[0]);
313                 $section->add_row($text{'fs_status'},
314                         $total ? &text('fs_mountedsp', &nice_size($total*1024),
315                                                        &nice_size($free*1024)) :
316                                  $text{'fs_mounted'});
317                 }
318         else {
319                 $section->add_row($text{'fs_status'}, $text{'fs_unmounted'});
320                 }
321         }
322 else {
323         $section->add_row($text{'fs_mount'},
324                       &ui_yesno_radio("mount", $zinfo->{'status'} eq 'running' ?
325                                                1 : 0));
326         }
327
328 local $dinput = new Webmin::File("dir", $fs->{'dir'}, 50);
329 $dinput->set_mandatory(1);
330 $dinput->set_validation_func(\&validate_fsdir);
331 $section->add_input($text{'fs_dir'}, $dinput);
332
333 if (&indexof($type, &mount::list_fstypes()) >= 0) {
334         # A supported filesystem, which means we can show nice options
335         local $shtml = 
336             "<table border width=100%><tr><td><table>".
337             &capture_function_output(\&mount::generate_location, $type,
338                                      $fs->{'special'}).
339             "</table></td></tr></table>";
340         $section->add_row($text{'fs_special'}, $shtml);
341
342         &mount::parse_options($type, $fs->{'options'});
343         local $ohtml =
344             "<table border width=100%><tr><td><table>".
345             &capture_function_output(\&mount::generate_options, $type,
346                                      $new ? 1 : 0).
347             "</table></td></tr></table>";
348         $section->add_row($text{'fs_options'}, $ohtml);
349         }
350 else {
351         # Un-supported, so show just text fields
352         local $sinput = new Webmin::Textbox("special", $fs->{'special'}, 40);
353         $sinput->set_mandatory(1);
354         $sinput->set_validation_func(\&validate_special);
355         $section->add_input($text{'fs_special'}, $sinput);
356
357         local $oinput = new Webmin::Textbox("options", $fs->{'options'}, 40);
358         $oinput->set_mandatory(1);
359         $oinput->set_validation_func(\&validate_options);
360         $section->add_input($text{'fs_options'}, $oinput);
361         }
362
363 if ($new) {
364         $form->add_button(new Webmin::Submit($text{'create'}, "create"));
365         }
366 else {
367         $form->add_button(new Webmin::Submit($text{'save'}, "save"));
368         $form->add_button(new Webmin::Submit($text{'delete'}, "delete"));
369         }
370 return $form;
371 }
372
373 sub validate_fsdir
374 {
375 return $_[0] =~ /^\/\S/ ? undef : $text{'fs_edir'};
376 }
377
378 sub validate_special
379 {
380 return $_[0] =~ /\S/ ? undef : $text{'fs_especial'};
381 }
382
383 sub validate_options
384 {
385 return $_[0] =~ /^\S*$/ ? undef : $text{'fs_eoptions'};
386 }
387
388 # get_rctl_form(&in, &zinfo, &rctl)
389 sub get_rctl_form
390 {
391 local ($in, $zinfo, $rctl) = @_;
392 local ($new, $mount);
393 local $form = new Webmin::Form("save_rctl.cgi", "post");
394 $form->set_input($in);
395 $form->add_hidden("zone", $zinfo->{'name'});
396 if ($rctl->{'name'}) {
397         $form->add_hidden("old", $rctl->{'name'});
398         }
399 else {
400         $new = 1;
401         $form->add_hidden("new", 1);
402         }
403 local $section = new Webmin::Section($text{'rctl_header'}, 2);
404 $form->add_section($section);
405
406 local $ninput = new Webmin::Select("name", $rctl->{'name'},
407                 [ map { [ $_ ] } grep { /^zone\./ } &list_rctls() ],
408                 0, $in{'new'} ? 0 : 1);
409 $section->add_input($text{'rctl_name'}, $ninput);
410
411 local $table = new Webmin::InputTable([ $text{'rctl_priv'},
412                                         $text{'rctl_limit'},
413                                         $text{'rctl_action'} ]);
414 $form->add_section($table);
415 local $pinput = new Webmin::Select("priv", undef,
416                    [ [ "", "&nbsp;" ],
417                      [ "privileged", $text{'rctl_privileged'} ] ]);
418 local $linput = new Webmin::Textbox("limit", undef, 20);
419 $linput->set_mandatory(1);
420 $linput->set_validation_func(\&validate_limit);
421 local $ainput = new Webmin::Select("action", undef,
422                            [ [ "none", $text{'rctl_none'} ],
423                              [ "deny", $text{'rctl_deny'} ] ]);
424 $table->set_inputs([ $pinput, $linput, $ainput ]);
425 local @values = split(/\0/, $rctl->{'value'});
426 foreach my $v (@values, "") {
427         ($priv, $limit, $action) = &get_rctl_value($v);
428         ($actionn, $actionv) = split(/=/, $action);
429         $table->add_values([ $priv, $limit, $actionn ]);
430         }
431 $table->set_emptymsg("No RCTLs defined yet");
432 $table->set_all_sortable(0);
433 $table->set_control(0);
434
435 if ($new) {
436         $form->add_button(new Webmin::Submit($text{'create'}, "create"));
437         }
438 else {
439         $form->add_button(new Webmin::Submit($text{'save'}, "save"));
440         $form->add_button(new Webmin::Submit($text{'delete'}, "delete"));
441         }
442 return $form;
443 }
444
445 sub validate_limit
446 {
447 return $_[0] =~ /^\d+$/ ? undef : $text{'rctl_elimit'};
448 }
449
450 sub get_create_form
451 {
452 local ($in) = @_;
453 local $form = new Webmin::Form("create_zone.cgi", "post");
454 $form->set_input($in);
455 local $section = new Webmin::Section($text{'create_header'}, 2);
456 $form->add_section($section);
457 &foreign_require("time", "time-lib.pl");
458
459 local $name = new Webmin::Textbox("name", undef, 20);
460 $name->set_mandatory(1);
461 $name->set_validation_func(\&validate_zone_name);
462 $section->add_input($text{'edit_name'}, $name);
463
464 local $path = new Webmin::OptTextbox("path", undef, 30,
465                 &text('create_auto', $config{'base_dir'}),
466                 $text{'create_sel'});
467 $path->set_validation_func(\&validate_zone_path);
468 $section->add_input($text{'create_path'}, $path);
469
470 local $brand = new Webmin::Select("brand",undef, [ &list_brands() ], 0, 0, $value ? 1 : 0);
471 $section->add_input($text{'create_brand'}, $brand);
472
473 local $address = new Webmin::OptTextbox("address", undef, 20,
474                                         $text{'create_noaddress'});
475 $address->set_validation_func(\&validate_address);
476 $section->add_input($text{'create_address'}, $address);
477
478 local $physical = &physical_object("physical", &get_default_physical());
479 $section->add_input($text{'net_physical'}, $physical);
480
481 local $install = new Webmin::Radios("install", 0, [ [ 1, $text{'yes'} ],
482                                                     [ 0, $text{'no'} ] ]);
483 $section->add_input($text{'create_install'}, $install);
484
485 local $webmin = new Webmin::Radios("webmin", 0, [ [ 1, $text{'yes'} ],
486                                                     [ 0, $text{'no'} ] ]);
487 $section->add_input($text{'create_webmin'}, $webmin);
488
489 local $inherit = new Webmin::Radios("inherit", 1, [ [ 1, $text{'pkg_inherit_yes'} ],
490                                                     [ 0, $text{'pkg_inherit_no'} ] ]);
491 $section->add_input($text{'pkg_inherit'}, $inherit);
492
493
494 local $pkgs = new Webmin::Multiline("pkgs", undef, 5, 50);
495 $section->add_input($text{'create_pkgs'}, $pkgs);
496
497 $section->add_separator();
498
499 local $cfg = new Webmin::Radios("cfg", 1, [ [ 1, $text{'create_cfgyes'} ],
500                                           [ 0, $text{'create_cfgno'} ] ]);
501 $section->add_input($text{'create_cfg'}, $cfg);
502
503 local $hostname = new Webmin::OptTextbox("hostname", undef, 20,
504                                          $text{'create_samehost'});
505 $hostname->set_validation_func(\&validate_zone_hostname);
506 $section->add_input($text{'create_hostname'}, $hostname);
507
508 local $root = new Webmin::OptTextbox("root", undef, 20,
509                                          $text{'create_same'});
510 $section->add_input($text{'create_root'}, $root);
511
512 local $currtz = &time::get_current_timezone();
513 local $timezone = new Webmin::OptTextbox("timezone", undef, 25,
514                                          &text('create_same2', $currtz));
515 $timezone->set_validation_func(\&validate_zone_timezone);
516 $section->add_input($text{'create_timezone'}, $timezone);
517
518 local $currlc = &get_global_locale();
519 local $locale = new Webmin::OptTextbox("locale", undef, 25,
520                                          &text('create_same2', $currlc));
521 $locale->set_validation_func(\&validate_zone_locale);
522 $section->add_input($text{'create_locale'}, $locale);
523
524 local $terminal = new Webmin::OptTextbox("terminal", undef, 25,
525                                          $text{'create_vt100'});
526 $terminal->set_validation_func(\&validate_zone_terminal);
527 $section->add_input($text{'create_terminal'}, $terminal);
528
529 local $dns = &net::get_dns_config();
530 local ($resolv) = grep { $_ ne "files" } split(/\s+/, $dns->{'order'});
531 $resolv ||= "none";
532 local $rinput = new Webmin::Radios("resolv", $resolv,
533                                   [ [ "none", $text{'create_none'} ],
534                                     [ "dns", $text{'create_dns'} ],
535                                     [ "nis", $text{'create_nis'} ],
536                                     [ "nis+", $text{'create_nis+'} ] ]);
537 $section->add_input($text{'create_name'}, $rinput);
538
539 local $domain = $resolv eq "dns" ? $dns->{'domain'}->[0] :
540           $resolv eq "nis" || $resolv eq "nis+" ? &net::get_domainname()
541                                                 : undef;
542 local $dinput = new Webmin::Textbox("domain", $domain, 20);
543 $dinput->set_validation_func(\&validate_zone_domain);
544 $dinput->set_disable_code("form.resolv[0].checked");
545 $section->add_input($text{'create_domain'}, $dinput);
546
547 local (@servers, $server);
548 if ($resolv eq "dns") {
549         @servers = map { &to_ipaddress($_) || &to_ip6address($_) || $_ }
550                          @{$dns->{'nameserver'}};
551         $server = join(" ", @servers);
552         }
553 elsif ($resolv eq "nis" || $resolv eq "nis+") {
554         $server = `ypwhich`;
555         chop($server);
556         }
557 local $server = new Webmin::Textbox("server", $server, 40);
558 $server->set_validation_func(\&validate_zone_server);
559 $server->set_disable_code("form.resolv[0].checked");
560 $section->add_input($text{'create_server'}, $server);
561
562 local ($router) = &net::get_default_gateway();
563 if (!$router) {
564         # Use active settings
565         foreach my $r (&net::list_routes()) {
566                 $router = $r->{'gateway'} if ($r->{'dest'} eq '0.0.0.0');
567                 }
568         }
569 local $rinput = new Webmin::OptTextbox("router", $router, 20,
570                                        $text{'create_none'});
571 $rinput->set_validation_func(\&validate_zone_router);
572 $section->add_input($text{'create_router'}, $rinput);
573
574 $form->add_button(new Webmin::Submit($text{'create_ok'}));
575 return $form;
576 }
577
578 sub validate_zone_name
579 {
580 return $text{'create_ename'} if ($_[0] !~ /^[a-z0-9\.\-\_]+$/i);
581 my ($clash) = grep { $_->{'name'} eq $in{'name'} } &list_zones();
582 return $text{'create_eclash'} if ($clash);
583 return undef;
584 }
585
586 sub validate_zone_path
587 {
588 return $_[0] =~ /^\// ? undef : $text{'create_epath'};
589 }
590
591 sub validate_zone_pkgs
592 {
593 my @pkgs = split(/[\r\n]+/, $in{'pkgs'});
594 foreach my $p (@pkgs) {
595         $p =~ /^\/\S/ || return &text('create_epkg', $p);
596         }
597 return undef;
598 }
599
600 sub validate_zone_hostname
601 {
602 return $_[0] =~ /^[a-z0-9\.\-\_]+$/ ? undef : $text{'create_ehostname'};
603 }
604
605 sub validate_zone_timezone
606 {
607 return $_[0] =~ /^\S+$/ ? undef : $text{'create_etimezone'};
608 }
609
610 sub validate_zone_locale
611 {
612 return $_[0] =~ /^\S+$/ ? undef : $text{'create_elocale'};
613 }
614
615 sub validate_zone_domain
616 {
617 return undef if ($_[2]->get_value("resolv") eq "none");
618 return $_[0] =~ /^[a-z0-9\.\-\_]+$/ ? undef : $text{'create_edomain'};
619 }
620
621 sub validate_zone_server
622 {
623 return undef if ($_[2]->get_value("resolv") eq "none");
624 local @servers = split(/\s+/, $in{'server'});
625 foreach my $n (@servers) {
626         return &text('create_eserver', $n) if (!&to_ipaddress($n));
627         }
628 return @servers ? undef : $text{'create_eservers'};
629 }
630
631 sub validate_zone_router
632 {
633 return &check_ipaddress($_[0]) ? undef : $text{'create_erouter'};
634 }
635
636 sub validate_zone_terminal
637 {
638 return $_[0] =~ /^\S+$/ ? undef : $text{'create_eterminal'};
639 }
640