Handle hostnames with upper-case letters
[webmin.git] / smf / smf-lib.pl
1 #!/usr/local/bin/perl
2 # Common functions for managing smf services
3
4 BEGIN { push(@INC, ".."); };
5 use WebminCore;
6 &init_config();
7 require '../javascript-lib.pl';
8
9 do 'wizard.pl';
10
11 $lib = get_mod_lib();
12 if ($lib) {
13         do "$lib";
14         }
15
16 # Hash matching svc type to prefix
17 %svc_types = ("Network", "svc:/network/",
18         "System", "svc:/system/",
19         "Legacy", "lrc:/",
20         "Milestone", "svc:/milestone/",
21         "Platform-specific", "svc:/platform/",
22         "Application", "svc:/application/",
23         "Device-specific", "svc:/device/",
24         "Site-specific", "svc:/site/",
25         "All", "svc:/");
26
27 # Hash matching svc option to description
28 %svc_options = ("FMRI", "FMRI",
29         "STATE", "State",
30         "DESC", "Description",
31         "STIME", "StartTime",
32         "NSTATE", "NextState");
33
34 # defaults for main svc page
35 $default_svc_options = "FMRI,STATE,DESC";
36 $default_sortopt = "-SSTATE";
37 $default_include_disabled = 0;
38
39 # this hash associates smf states with colors
40 %state_colors = ("online", "green",
41         "offline", "yellow",
42         "maintenance", "red",
43         "legacy_run", "gray",
44         "disabled", "gray");
45
46 # this variable is used to record commands run. these are then
47 # displayed at bottom of page, in msg "this page was generated using
48 # commands $cmds_run".
49
50 $cmds_run = "";
51
52 $maxint = 65535;
53
54 # this array constitutes the specification of the smf service
55 # creation wizard
56 $wizard = "page=smfwizard_service.cgi,min=1,max=1; \
57         page=smfwizard_instance.cgi,min=1,max=$maxint; \
58         page=smfwizard_restarter.cgi,min=0,max=1; \
59         page=smfwizard_dependency.cgi,min=0,max=$maxint; \
60         page=smfwizard_dependent.cgi,min=0,max=$maxint; \
61         page=smfwizard_exec.cgi,min=0,max=$maxint; \
62         page=smfwizard_property_group.cgi,min=0,max=$maxint; \
63         page=smfwizard_property.cgi,min=0,max=$maxint; \
64         page=smfwizard_template.cgi,min=0,max=1; \
65         page=smfwizard_manpage.cgi,min=0,max=$maxint; \
66         submit=smfwizard_process_submit.cgi";
67
68 # Array of boolean values
69 @boolean_values = ("true", "false");
70
71 # Array of dependency/dependent types
72 @dep_types = ("service", "path");
73 # Array of restart_on values
74 @restart_on_values = ("none", "fault", "restart", "refresh", "error");
75 # Array of grouping values
76 @grouping_values = ("require_all", "require_any", "optional_all",
77         "exclude_all");
78 # Array of property value types
79 @propval_type_values = ("count", "integer", "opaque", "host", "hostname",
80 "net_address_v4", "net_address_v6", "time", "astring", "ustring", "boolean",
81 "fmri", "uri");
82
83 # Array of stability values
84 @stability_values = ("Evolving", "Unstable", "External", "-");
85
86 # Array of number of lines choices for logfile viewer
87 @logfile_numlines_values = ("20", "40", "80", "160", "all");
88
89 # subroutines used to run/check/log smf commands.
90
91 # Run all smf commands (separated by ";", check if expected retvals match
92 # (if needed) and return response(s)
93 #
94 # Paramters: cmdlist, [expected_retval]
95 #
96 sub run_smf_cmds()
97 {
98 local ($cmdlist, $expected_retval, @cmds, $errmsg, $response, $cmd,
99         $newresponse, $retval);
100 ($cmdlist, $expected_retval) = @_;
101 @cmds = split(/;/, "$cmdlist");
102 $errmsg = "";
103 $response = "";
104 foreach $cmd (@cmds) {
105         $newresponse = &backquote_logged("$cmd");
106         $retval = $?;
107         if ($response =~ /.+/) {
108                 # append to responses so far...
109                 $response = "$response ; $newresponse";
110         } else {
111                 $response = "$newresponse";
112                 }
113         # check retval
114         if (($expected_retval =~ /.+/) &&
115             ($expected_retval != $retval)) {
116                 $errmsg =
117 "${errmsg}Unexpected return value $retval from $cmd: $newresponse .";
118                 }
119         if ($cmds_run =~ /.+/) {
120                 $cmds_run = "$cmds_run ; $cmd";
121         } else {
122                 $cmds_run = "$cmd";
123                 }
124         }
125 if ($errmsg =~ /.+/) {
126         &error("$errmsg");
127         }
128 return $response;
129 }
130
131 # Import supplied manifest into repository, expect success
132 #
133 # Paramters: manifest
134 #
135 sub svc_import()
136 {
137 $manifest = $_[0];
138 &run_smf_cmds("/usr/sbin/svccfg import $manifest", 0);
139 }
140
141 # get dependencies/dependent listing for fmri
142 #
143 # Parameters: dependency_or_dependent, fmri
144 #
145 sub svc_dep_cmd()
146 {
147 local ($dependency_or_dependent, $fmri, $cmd);
148 ($dependency_or_dependent, $fmri) = @_;
149
150 if ($dependency_or_dependent eq "dependent") {
151         $cmd = "/usr/bin/svcs -H -oFMRI,STATE -D $fmri";
152 } else {
153         $cmd = "/usr/bin/svcs -H -oFMRI,STATE -d $fmri";
154         }
155 return (&run_smf_cmds("$cmd"));
156 }
157
158 # get grouping for child dependency on parent fmri using svcs -l
159 #
160 # Parameters: parent_fmri child_fmri
161 #
162 sub svc_grouping_cmd()
163 {
164 local ($parent_fmri, $child_fmri, $output, @output_lines, $line, $grouping);
165 ($parent_fmri, $child_fmri) = @_;
166 $output = &run_smf_cmds("/usr/bin/svcs -l $parent_fmri");
167 @output_lines = split(/\n/, $output);
168 foreach $line (@output_lines) {
169         chomp($line);
170         if ($line =~ /dependency\s+([^\/]+)\/\S+\s+$child_fmri/) {
171                 # found dependency at instance level
172                 $grouping = $1;
173                 return $grouping;
174                 }
175         }
176 # if no match at instance level, we try service level...
177 if ($child_fmri =~ /(svc:\/[^:]*):.*/) {
178         $child_fmri_svc = $1;
179         return (&svc_grouping_cmd($parent_fmri, $child_fmri_svc));
180 } else {        
181         return "";
182         }
183 }
184
185 # apply svc command to elts in fmri list
186 #
187 # Parameters: cmd, fmri
188 sub svc_state_cmd()
189 {
190 local ($cmd_name, $fmrilist_ref, $cmd, $cmdlist, $fmri);
191 ($cmd_name, $fmrilist_ref) = @_;
192 if ($cmd_name eq "$text{'state_enable'}") {
193         $cmd = "/usr/sbin/svcadm enable";
194 } elsif ($cmd_name eq "$text{'state_disable'}") {
195         $cmd = "/usr/sbin/svcadm disable";
196 } elsif ($cmd_name eq "$text{'state_refresh'}") {
197         $cmd = "/usr/sbin/svcadm refresh";
198 } elsif ($cmd_name eq "$text{'state_restart'}") {
199         $cmd = "/usr/sbin/svcadm restart";
200 } elsif ($cmd_name eq "$text{'state_maintenance'}") {
201         $cmd = "/usr/sbin/svcadm mark maintenance";
202 } elsif ($cmd_name eq "$text{'state_degraded'}") {
203         $cmd = "/usr/sbin/svcadm mark degraded";
204 } elsif ($cmd_name eq "$text{'state_clear'}") {
205         $cmd = "/usr/sbin/svcadm clear";
206 } elsif ($cmd_name eq "$text{'index_delete'}") {
207         $cmd = "/usr/sbin/svccfg delete -f";
208 } else {
209         &error("Unknown command $cmd_name!");
210         }
211 $cmdlist = "";
212 foreach $fmri (@$fmrilist_ref) {
213         $cmdlist = "${cmdlist}$cmd $fmri;";
214         }
215 return (&run_smf_cmds("$cmdlist", 0));
216 }
217
218 # get state for instance
219 #
220 # Parameters: fmri
221 #
222 sub svc_get_state_cmd()
223 {
224 local ($fmri, $state);
225 $fmri = $_[0];
226 $state = &run_smf_cmds("/usr/bin/svcs -H -oSTATE $fmri");
227 chomp($state);
228 return $state;
229 }
230
231 # add/delete/list propgroup/prop commands
232 #
233
234
235 # Add property group
236 #
237 # Parameters: fmri, service_or_instance, name, type
238 #
239 sub svc_addpg()
240 {
241 local($fmri, $sinst, $name, $type, $entity);
242 ($fmri, $sinst, $name, $type) = @_;
243 $entity = ($sinst eq "service") ? "$fmri" : "$fmri:$sinst";
244 &run_smf_cmds
245 ("/usr/bin/echo \"select $entity\naddpg $name $type\nquit\n\"  | /usr/sbin/svccfg", 0);
246 }
247
248 # Delete property group
249 #
250 # Parameters: fmri, service_or_instance, name
251 #
252 sub svc_delpg()
253 {
254 local($fmri, $sinst, $name, $entity);
255 ($fmri, $sinst, $name) = @_;
256 $entity = ($sinst eq "service") ? "$fmri" : "$fmri:$sinst";
257 &run_smf_cmds
258 ("/usr/bin/echo \"select $entity\ndelpg $name\nquit\n\"  | /usr/sbin/svccfg",
259         0);
260 }
261
262 # list property groups. we also determine if property group is at service
263 # or instance level and include this in listing.
264 #
265 # Parameters: fmri, service_or_instance
266 #
267 sub svc_listpg()
268 {
269 local ($fmri, $sinst, $entity, $pgroups, @pgroup_list, $i, $pgroup_info,
270         $name, $type, @listing);
271 ($fmri, $sinst) = @_;
272 $entity = ($sinst eq "service") ? "$fmri" : "$fmri:$sinst";
273 $pgroups = &run_smf_cmds
274     ("/usr/bin/echo \"select $entity\nlistpg\nquit\n\"  | /usr/sbin/svccfg", 0);
275 @pgroup_list = split(/\n/, $pgroups);
276 $i = 0;
277 foreach $pgroup_info (@pgroup_list) {
278         $pgroup_info =~ /([^\s]*)\s+(.*)/;
279         $name = $1;
280         $type = $2;
281         $listing[$i]{'pgroup_name'} = $1;
282         $listing[$i]{'pgroup_type'} = $2;
283         $listing[$i]{'sinst'} = $sinst;
284         $i = $i + 1;
285         }
286 return @listing;
287 }
288
289 # Set property (creates if doesnt yet exist)
290 #
291 # Parameters: fmri, service_or_instance, pgname, name, type, value
292 #
293 sub svc_setprop()
294 {
295 local($fmri, $sinst, $pgname, $pname, $type, $value, $entity);
296 ($fmri, $sinst, $pgname, $pname, $type, $value) = @_;
297 $entity = ($sinst eq "service") ? "$fmri" : "$fmri:$sinst";
298 &run_smf_cmds
299 ("/usr/bin/echo \"select $entity\nsetprop $pgname/$pname=$type:\\\"$value\\\"\nquit\n\" | /usr/sbin/svccfg", 0);
300 }
301
302 # Delete property 
303 #
304 # Parameters: fmri, service_or_instance, pgroup_name, name
305 #
306 sub svc_delprop()
307 {
308 local($fmri, $sinst, $pgname, $name, $entity);
309 ($fmri, $sinst, $pgname, $name) = @_;
310 $entity = ($sinst eq "service") ? "$fmri" : "$fmri:$sinst";
311 &run_smf_cmds
312 ("/usr/bin/echo \"select $entity\ndelprop $pgname/$name\nquit\n\" | /usr/sbin/svccfg", 0);
313 }
314
315 # list properties
316 #
317 # Parameters: fmri, service_or_instance, pgroup_name
318 #
319 sub svc_listprop()
320 {
321 local ($fmri, $sinst, $entity, $pgroup_name, $props, @prop_list, $i,
322         $prop_info, $name, $type, $value, @listing);
323 ($fmri, $sinst, $pgroup_name) = @_;
324 $entity = ($sinst eq "service") ? "$fmri" : "$fmri:$sinst";
325 $props = &run_smf_cmds
326     ("/usr/bin/echo \"select $entity\nlistprop $pgroup_name/\*\nquit\n\"  | /usr/sbin/svccfg", 0);
327 @prop_list = split(/\n/, $props);
328 $i = 0;
329 foreach $prop_info (@prop_list) {
330         $prop_info =~ /[^\/]*\/([^\s]+)\s+([^\s]*)\s+(.*)/;
331         $listing[$i]{'prop_name'} = $1;
332         $listing[$i]{'prop_type'} = $2;
333         $listing[$i]{'prop_value'} = $3;
334         $i = $i + 1;
335         }
336 return @listing;
337 }
338
339 # general subroutines: whats this links, converting links in text etc.
340 #
341
342 # wrapper for printing text and associated whats this link if required
343 #
344 # Parameters: text
345 #
346 sub text_and_whats_this()
347 {
348 local ($textname);
349 $textname = $_[0];
350 if ($config{'enable_whats_this'} == 1) {
351         print "$text{$textname} ", &hlink($text{'whats_this'}, $textname);
352         }
353 else {
354         print "$text{$textname}";
355         }
356 }
357
358 # Show what`s this? link, which opens new page with tip info. We pass in
359 # pagename and tipname, and the appropriate localized string, representing
360 # a concatenation of the two, is displayed.
361 #
362 # Parameters: tiparea, tipname
363 #
364 sub print_whats_this_link()
365 {
366 local($tipname);
367 $tipname = $_[0];
368 if ($config{'enable_whats_this'} == 1) {
369         print "<a href=\"whats_this.cgi?tipname=$tipname\" target=\"new\">$text{'whats_this'}</a>";
370         }
371 }
372
373 # convert manpage references to links, and http references to actual links
374 #
375 # Parameters: text
376 #
377 sub convert_links_in_text()
378 {
379 local($text);
380 $text = $_[0];
381 # convert http links,fmris,manpages and logfiles to links...
382 $text =~ s/See:\s+([^\(]*)\(([^\)]*)\)/See: <a href=\"\/man\/view_man.cgi?page=$1&sec=$2\">$1\($2\)<\/a>/g;
383 $text =~ s/http:\/\/(\S+)/<a href=\"http:\/\/$1\">http:\/\/$1<\/a>/g;
384 $text =~ s/(svc:\/\S+)/<a href=\"instance_viewer.cgi?fmri='$1'\">$1<\/a>/g;
385 $text =~
386   s/(\/var\/svc\/log\/\S+)/<a href=\"log_viewer.cgi?logfile='$1'\">$1<\/a>/g;
387 $text =~
388 s/(\/etc\/svc\/volatile\/\S+)/<a href=\"log_viewer.cgi?logfile='$1'\">$1<\/a>/g;
389 return $text;
390 }
391
392 # show selection
393 #
394 # Parameters: name, selected, selection_arrayref
395 #
396 sub print_selection()
397 {
398 local($name, $selected, $selection_arrayref, @array, $elt, $select);
399 ($name, $selected, $selection_arrayref) = @_;
400 print "<select name=\"$name\" size=1>\n";
401 @array = @$selection_arrayref;
402 foreach $elt (@array) {
403         $select = "";
404         if ($elt eq $selected) {
405                 $select = "selected";
406                 }
407         print "<option $select>$elt</option>\n";
408         }
409 print "</select>\n";
410 }
411
412 # shows commands run in generating page...
413 #
414 # Parameters:
415 #
416 sub print_cmds_run()
417 {
418 local ($cmds_run_clipped);
419 $cmds_run_clipped = substr($cmds_run, 0, 240);
420 print "<hr>\n";
421 print "<p>$text{'cmds_run'}:<\p>\n";
422 print "<p>${cmds_run_clipped}...</p>\n";
423 }
424
425 # show buttons to enable/disable etc
426 #
427 # Parameters:
428 #
429 sub print_state_buttons()
430 {
431 print "<input type=submit name=\"change_state\" value=\"$text{'state_enable'}\">&nbsp;\n";
432 print "<input type=submit name=\"change_state\" value=\"$text{'state_disable'}\">&nbsp;\n";
433 print "<input type=submit name=\"change_state\" value=\"$text{'state_refresh'}\">&nbsp;\n";
434 print "<input type=submit name=\"change_state\" value=\"$text{'state_restart'}\">&nbsp;\n";
435 print "<input type=submit name=\"change_state\" value=\"$text{'state_maintenance'}\">&nbsp;\n";
436 print "<input type=submit name=\"change_state\" value=\"$text{'state_degraded'}\">&nbsp;\n";
437 print "<input type=submit name=\"change_state\" value=\"$text{'state_clear'}\">&nbsp;\n";
438 }
439
440 # show svc chooser button
441 #
442 # Parameters: prop_name, form_index, button_value, type, add
443 #
444 sub print_svc_chooser()
445 {
446 ($prop_name, $form_index, $button_value, $type, $add) = @_;
447 print "<input type=button onClick='ifield = document.forms[$form_index].$prop_name; chooser= window.open(\"svc_chooser.cgi?type=$type&add=$add\", \"chooser\", \"toolbar=no,menubar=no,scrollbar=no,width=500,height=400\"); chooser.ifield = ifield; window.ifield = ifield' value=\"$button_value\">\n";
448 }
449
450 # show path chooser button
451 #
452 # Parameters: prop_name, form_index, button_value, add
453 #
454 sub print_path_chooser()
455 {
456 ($prop_name, $form_index, $button_value, $add) = @_;
457 print "<input type=button onClick='ifield = document.forms[$form_index].$prop_name; chooser= window.open(\"path_chooser.cgi?add=$add\", \"chooser\", \"toolbar=no,menubar=no,scrollbar=no,width=500,height=400\"); chooser.ifield = ifield; window.ifield = ifield' value=\"$button_value\">\n";
458 }
459
460 # subroutines used by index page
461
462 # gather required information from svcs, storing as
463 # array of hashes indexed by property...
464
465 # Parameters: filter, comma_separated_optlist
466 #
467 sub svcs_listing()
468 {
469 local ($filter, $opts, $opt, @optlist, @sinfo, $sinf, @sinf_array, $i);
470 ($filter, $sortopt) = @_;
471 $filter = "$filter\*";
472 $allopts = "FMRI,STATE,NSTATE,STIME,DESC";
473 $sinfo = &run_smf_cmds("/usr/bin/svcs -H -o $allopts $sortopt $filter");
474 @sinfo_list = split(/\n/, $sinfo);
475 foreach $sinf (@sinfo_list) {
476         chomp($sinf);
477         if ($sinf =~ /(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)/) {
478                 $listing[$i]{'FMRI'} = $1;
479                 $listing[$i]{'STATE'} = $2;
480                 $listing[$i]{'NSTATE'} = $3;
481                 $listing[$i]{'STIME'} = $4;
482                 $listing[$i]{'DESC'} = $5;
483                 $i = $i + 1;
484                 }
485         }
486 return @listing;
487 }
488
489 # subroutines used in wizard-based service creation
490
491 # subfunction to create smf manifest from wizard datafiles.
492 #
493 # Parameters:
494
495 sub create_smf_manifest()
496 {
497 local (%service_info, $manifest, @find_replace_array, @datafiles, $i);
498 $manifest = $_[0];
499 unlink($manifest);
500 # add service information to manifest
501 %service_info = &wizard_get_data("smfwizard_service.cgi", "0");
502 @find_replace_array = ("SERVICE_NAME/$service_info{'service_name'}",
503         "SERVICE_VERSION/$service_info{'service_version'}");
504 &fill_manifest_template("service_template.xml", $manifest,
505         \@find_replace_array);
506 # restarter
507 %service_info = &wizard_get_data("smfwizard_restarter.cgi", "0");
508 if ($service_info{'restarter_fmri'} =~ /.+/) {
509         @find_replace_array =
510   ("RESTARTER_FMRI/<service_fmri value=\'$service_info{'restarter_fmri'}\' />");
511         &fill_manifest_template("restarter_template.xml", $manifest,
512                 \@find_replace_array);
513         }
514 &add_service_or_instance_info($manifest, "service");
515 @datafiles = &list_wizard_datafiles("smfwizard_instance.cgi");
516 for ($i = 0; $i < @datafiles; $i++) {
517         %service_info = &wizard_get_data("smfwizard_instance.cgi", $i);
518         @find_replace_array = ("INSTANCE_NAME/$service_info{'instance_name'}",
519                 "INSTANCE_ENABLED/$service_info{'instance_enabled'}");
520         &fill_manifest_template("instance_template.xml", $manifest,
521                 \@find_replace_array);
522         &add_service_or_instance_info($manifest,
523                 "$service_info{'instance_name'}");
524         @find_replace_array = ();
525         &fill_manifest_template("instance_template_end.xml", $manifest,
526                 \@find_replace_array);
527         }
528 # template info
529 %service_info = &wizard_get_data("smfwizard_template.cgi", "0");
530 @find_replace_array =
531         ("TEMPLATE_COMMON_NAME/$service_info{'template_common_name'}",
532         "TEMPLATE_DESCRIPTION/$service_info{'template_description'}");
533 if (($service_info{'template_common_name'} =~ /.+/) &&
534     ($service_info{'template_description'} =~ /.+/)) {
535         &fill_manifest_template("template_template.xml", $manifest,
536                 \@find_replace_array);
537         @datafiles = &list_wizard_datafiles("smfwizard_manpage.cgi");
538         for ($i = 0; $i < @datafiles; $i++) {
539                 %service_info = &wizard_get_data("smfwizard_manpage.cgi", $i);
540                 @find_replace_array =
541                 ("MANPAGE_TITLE/$service_info{'manpage_title'}",
542                 "MANPAGE_SECTION/$service_info{'manpage_section'}",
543                 "MANPAGE_MANPATH/$service_info{'manpage_manpath'}");
544                 &fill_manifest_template("manpage_template.xml", $manifest,
545                         \@find_replace_array);
546                 }
547         @find_replace_array = ();
548         &fill_manifest_template("template_template_end.xml", $manifest,
549                 \@find_replace_array);
550         }
551 @find_replace_array = ();
552 &fill_manifest_template("service_template_end.xml", $manifest,
553         \@find_replace_array);
554 }
555
556 # subfunction to add dependecy/dependent/exec method/propgroup/prop
557 # information to manifest. if at service level, we look for sinst=service,
558 # otherwise, look for matches to instance name
559 #
560 sub add_service_or_instance_info()
561 {
562 local ($manifest, $sinst, @datafiles, $i, %service_info, $stability,
563         @find_replace_array, $stability, $cred, $pgroup_name, $pgroup_type,
564         $j, @propfiles, %prop_info);
565 ($manifest, $sinst) = @_;
566 @datafiles = &list_wizard_datafiles("smfwizard_dependency.cgi");
567 for ($i = 0; $i < @datafiles; $i++) {
568         %service_info = &wizard_get_data("smfwizard_dependency.cgi", $i);
569         # does sinst match?
570         if ("$service_info{'sinst'}" eq "$sinst") {
571                 # add dep'y
572                 if ($service_info{'dependency_stability'} eq "-") {
573                         $stability = "";
574                 } else {
575                         $stability =
576                 "<stability value='$service_info{'dependency_stability'}'/>";
577                         }
578                 @find_replace_array =
579                     ("DEP_NAME/$service_info{'dependency_name'}",
580                      "DEP_TYPE/$service_info{'dependency_type'}",
581                      "DEP_GROUPING/$service_info{'dependency_grouping'}",
582                      "DEP_RESTART_ON/$service_info{'dependency_restart_on'}",
583         "DEP_FMRI/<service_fmri value=\'$service_info{'dependency_fmri'}\' />",
584                      "DEP_STABILITY/$stability");
585                 &fill_manifest_template("dependency_template.xml", $manifest,
586                         \@find_replace_array);
587                 }
588         }
589 @datafiles = &list_wizard_datafiles("smfwizard_dependent.cgi");
590 for ($i = 0; $i < @datafiles; $i++) {
591         %service_info = &wizard_get_data("smfwizard_dependent.cgi", $i);
592         # does sinst match?
593         if ("$service_info{'sinst'}" eq "$sinst") {
594                 # add dep't
595                 if ($service_info{'dependent_stability'} eq "-") {
596                         $stability = "";
597                 } else {
598                         $stability =
599                 "<stability value='$service_info{'dependent_stability'}'/>";
600                         }
601                 @find_replace_array =
602                     ("DEP_NAME/$service_info{'dependent_name'}",
603                      "DEP_TYPE/$service_info{'dependent_type'}",
604                      "DEP_GROUPING/$service_info{'dependent_grouping'}",
605                      "DEP_RESTART_ON/$service_info{'dependent_restart_on'}",
606         "DEP_FMRI/<service_fmri value=\'$service_info{'dependent_fmri'}\' />",
607                         "DEP_STABILITY/$stability");
608                 &fill_manifest_template("dependent_template.xml", $manifest,
609                         \@find_replace_array);
610                 }
611         }
612 @datafiles = &list_wizard_datafiles("smfwizard_exec.cgi");
613 for ($i = 0; $i < @datafiles; $i++) {
614         %service_info = &wizard_get_data("smfwizard_exec.cgi", $i);
615         # does sinst match?
616         if ("$service_info{'sinst'}" eq "$sinst") {
617                 # add exec method
618                 # method context
619                 if (("$service_info{'exec_user'}" =~ /.+/) ||
620                     ("$service_info{'exec_group'}" =~ /.+/) ||
621                     ("$service_info{'exec_privileges'}" =~ /.+/)) {
622                         $cred = "<method_context><method_credential ";
623                         if ("$service_info{'exec_user'}" =~ /.+/) {
624                                 $cred =
625                                    "$cred user=\'$service_info{'exec_user'}\' ";
626                                 }
627                         if ("$service_info{'exec_group'}" =~ /.+/) {
628                                 $cred =
629                                  "$cred group=\'$service_info{'exec_group'}\' ";
630                                 }
631                         if ("$service_info{'exec_privileges'}" =~ /.+/) {
632                                 $cred =
633                         "$cred privileges=\'$service_info{'exec_privileges'}\' ";
634                                 }
635                         $cred = "$cred /> </method_context>";
636                 } else {
637                         $cred = "";
638                         }
639                 @find_replace_array =
640                     ("EXEC_NAME/$service_info{'exec_name'}",
641                      "EXEC_TIMEOUT_SECONDS/$service_info{'exec_timeout'}",
642                      "EXEC_EXEC/$service_info{'exec_exec'}",
643                      "EXEC_METHOD_CREDENTIAL/$cred");
644                 &fill_manifest_template("exec_template.xml", $manifest,
645                         \@find_replace_array);
646                 }
647         }
648 # for property group/properties, we cycle through property groups, then
649 # for each pgroup we see if each property is a member of the group AND
650 # applies at the appropriate service/instance level
651
652 @datafiles = &list_wizard_datafiles("smfwizard_property_group.cgi");
653 for ($i = 0; $i < @datafiles; $i++) {
654         %service_info = &wizard_get_data("smfwizard_property_group.cgi", $i);
655         $pgroup_name = "$service_info{'property_group_name'}";
656         $pgroup_type = "$service_info{'property_group_type'}";
657         if ($service_info{'property_group_stability'} eq "-") {
658                 $stability = "";
659         } else {
660                 $stability =
661         "<stability value='$service_info{'property_group_stability'}'/>";
662                 }
663         @find_replace_array =
664                 ("PGROUP_NAME/$pgroup_name", "PGROUP_TYPE/$pgroup_type",
665                  "PGROUP_STABILITY/$stability");
666         &fill_manifest_template("property_group_template.xml",
667                 $manifest, \@find_replace_array);
668         @propfiles = &list_wizard_datafiles("smfwizard_property.cgi");
669         for ($j = 0; $j < @propfiles; $j++) {
670                 # does sinst/pgroup match??
671                 %prop_info = &wizard_get_data("smfwizard_property.cgi", $j);
672                 if (("$sinst" eq "$prop_info{'sinst'}") &&
673                     ("$pgroup_name" eq "$prop_info{'pgroup'}")) {
674                         # matched sinst/pgroup, display prop...
675                         @find_replace_array =
676                             ("PROP_NAME/$prop_info{'property_name'}",
677                              "PROP_TYPE/$prop_info{'property_type'}",
678                              "PROP_VALUE/$prop_info{'property_value'}");
679                         &fill_manifest_template("property_template.xml",
680                                  $manifest, \@find_replace_array);
681                         }
682                 }
683         @find_replace_array = ();
684         &fill_manifest_template("property_group_template_end.xml", $manifest,
685                 \@find_replace_array);
686         }
687 }
688
689 # subfunction to read in manifest template (for exec method, dependency
690 # etc), and replace keywords with desired values. the keywords/desired
691 # values are passed in as an array, each elt is a find/replace string.
692 # template values may be replace multiple times (e.g. service_fmris
693 # for deps
694 #
695 # Parameters: template_file target_file find_replace_arrayref
696 #
697 sub fill_manifest_template()
698 {
699 local ($template, $target, $find_replace_arrayref, @template_data,
700         $find_replace_expr, @tdata, $find, $replace, $linenum, $line,
701         @replace_data, $i);
702 ($template, $target, $find_replace_arrayref) = @_;
703 open(TEMPLATE, "$module_root_directory/$template");
704 @template_data = <TEMPLATE>;
705 close(TEMPLATE);
706 foreach $find_replace_expr (@$find_replace_arrayref) {
707         @tdata = @template_data;
708         # split find/replace into components...
709         $find_replace_expr =~ /([^\/]*)\/(.*)/;
710         $find = $1;
711         $replace = $2;
712         $linenum = 0;
713         foreach $line (@tdata) {
714                 if ($line =~ s/$find/$replace/) {
715                         $replace_data[$linenum] =
716                                 "$replace_data[$linenum]$line\n";
717                         }
718                 $linenum++;
719                 }
720         }
721 # now append to target file
722 if (-e $target) {
723         open(TARGET, ">>$target");
724 } else {
725         open(TARGET, ">$target");
726         }
727 for ($i = 0; $i < @template_data; $i++) {
728         # if we have a "replace" line, write it, otherwise write original
729         # template line
730         if ($replace_data[$i] =~ /.+/) {
731                 print TARGET "$replace_data[$i]";
732         } else {
733                 print TARGET "$template_data[$i]";
734                 }
735         }
736 close(TARGET);
737 }
738
739 # subroutines used in properties page
740
741 #
742 # subroutines used by dep_viewer page
743 #
744
745 # Builds dependency/dependent tree starting from fmri.
746 # Uses hash with fmris as keys to contain tree info. This way,
747 # we don't expand a particular branch multiple times when we recurse...
748 #
749 # Parameters: dependency_or_dependent, tree_ref, fmri, level, expand_listref
750 #
751 sub build_dep_tree()
752 {
753 local ($dependency_or_dependent, $tree_ref, $fmri, $level,
754         $expand_listref, $state, $grouping, $allow_expand, $expand_fmri, $deps,
755         @dep_info, $dep_inf, $dep_fmri, $dep_state, $parent, $child,
756         $dep_grouping);
757 ($dependency_or_dependent, $tree_ref, $fmri, $level, $expand_listref,
758 $state, $grouping) = @_;
759 $allow_expand = 0;
760 # if fmri is on expand list passed in, we allow expansion.
761 foreach $expand_fmri (@$expand_listref) {
762         if ($expand_fmri eq $fmri) {
763                 $allow_expand = 1;
764                 break;
765                 }
766         }
767 if ($tree_ref->{"$fmri"}->{'exists'} != 1) {
768         # new hash element
769         $tree_ref->{"$fmri"}->{'exists'} = 1;
770         # state information, if passed in...
771         if ($state =~ /.+/) {
772                 $tree_ref->{"$fmri"}->{'state'} = $state;
773                 }
774         if ($grouping =~ /.+/) {
775                 $tree_ref->{"$fmri"}->{'grouping'} = $grouping;
776                 }
777         # do we expand tree here (i.e. recurse?)
778         $tree_ref->{"$fmri"}->{'expand'} = $allow_expand;
779         @{$tree_ref->{"$fmri"}->{'children'}} = ();
780         $tree_ref->{"$fmri"}->{'haschildren'} = 0;
781         $deps = &svc_dep_cmd($dependency_or_dependent, $fmri);
782         @dep_info = split(/\n/, $deps);
783         foreach $dep_inf (@dep_info) {
784                 # dependency info consists of fmri and state
785                 $dep_inf =~ /(\S+)\s+(\S+)/;
786                 $dep_fmri = $1;
787                 $dep_state = $2;
788                 # we need to find out what grouping is (using svcs -l).
789                 # for dep'y we call svcs -l $fmri, looking for line
790                 # specifying $dep_fmri. for dep't we call svcs -l
791                 # $dep_fmri, looking for line specifying $fmri.
792                 if ($dependency_or_dependent eq "dependency") {
793                         $parent = $fmri;
794                         $child = $dep_fmri;
795                 } else {
796                         $parent = $dep_fmri;
797                         $child = $fmri;
798                         }
799                 $dep_grouping = &svc_grouping_cmd($parent, $child);
800                 # we need to determine if dep has children, in order
801                 # to disable the expand button if not. however, we
802                 # dont recurse if it does unless it was on expand list
803                 $tree_ref->{"$fmri"}->{'haschildren'} = 1;
804                 chomp($dep_fmri);
805                 push(@{$tree_ref->{"$fmri"}->{'children'}},
806                         $dep_fmri);
807                 if ($allow_expand == 1) {
808                         &build_dep_tree($dependency_or_dependent, $tree_ref,
809                                 $dep_fmri, $level + 1, $expand_listref,
810                                 $dep_state, $dep_grouping);
811                         }
812                 }       
813         }
814 }
815
816 # Displays dependency/dependent tree using depth-first recursion:
817 # get fmris children, the print each childs children etc.
818 # However, if a fmri has expand == 0, we don`t recurse for it.
819 # For expanded fmris, we show the contract (-) button, and for
820 # unexpanded, we show the expand button (if they have children).
821 #
822 # Parameters: dependency_or_dependent, tree_ref, fmri, level
823 #
824 sub print_dep_tree()
825 {
826 local ($dependency_or_dependent, $tree_ref, $fmri, $level, $fmriinfo,
827         $indent, $child_fmri, $tab, $i, $color);
828 ($dependency_or_dependent, $tree_ref, $fmri, $level) = @_;
829 $fmriinfo = $fmri;
830 # indent according to level of tree
831 $indent = 8*$level;
832 $tab = "";
833 for ($i = 0; $i < $indent; $i++) {
834         $tab="$tab&nbsp;";
835         }
836 print "<p>$tab";
837 if ($tree_ref->{"$fmri"}->{'expand'} == 1) {
838         $fmriinfo = &contractbutton($dependency_or_dependent, $tree_ref,
839                 $fmri);
840 } else {
841         $fmriinfo = &expandbutton($dependency_or_dependent, $tree_ref,
842                 $fmri);
843         }
844 # show expand/contract button...
845 if ($level > 0) {
846         print "$fmriinfo";
847         }
848 # apply-to checkbox
849 print "&nbsp;<input type=checkbox name=\"applyto\" value=\"$fmri\">\n";
850 # fmri, link to state editor page for fmri
851 print "&nbsp;<a href=\"dep_viewer.cgi?fmri='$fmri'\">$fmri</a>";
852 if ($tree_ref->{"$fmri"}->{'state'} =~ /.+/) {
853         $color = "$state_colors{$tree_ref->{$fmri}->{'state'}}";
854         print
855           "&nbsp;<font color=$color>$tree_ref->{$fmri}->{'state'}</font>";
856         }
857 if ($tree_ref->{"$fmri"}->{'grouping'} =~ /.+/) {
858         print "&nbsp;($tree_ref->{$fmri}->{'grouping'})";
859         }
860 print "</p>\n";
861 if ($tree_ref->{"$fmri"}->{'expand'} == 1) {
862         # we can expand
863         foreach $child_fmri (@{$tree_ref->{"$fmri"}->{'children'}}) {
864                 &print_dep_tree($dependency_or_dependent, $tree_ref,
865                         $child_fmri, $level + 1);
866                 }
867         }
868 }
869
870 sub contractbutton()
871 {
872 local ($dependency_or_dependent, $tree_ref, $fmri, $disable);
873 ($dependency_or_dependent, $tree_ref, $fmri) = @_;
874 $disable = "";
875 # for elements with no children, disable button...
876 if ($tree_ref->{"$fmri"}->{'haschildren'} == 0) {
877         $disable = "disabled=\"disabled\"";
878         }
879 return "<input type=submit name=\"${dependency_or_dependent}_contract_$fmri\" value=\"-\" $disable><input type=\"hidden\" name=\"${dependency_or_dependent}_expandlist\" value=\"$fmri\">";
880 }
881
882 sub expandbutton()
883 {
884 local ($dependency_or_dependent, $tree_ref, $fmri, $disable);
885 ($dependency_or_dependent, $tree_ref, $fmri) = @_;
886 $disable = "";
887 if ($tree_ref->{"$fmri"}->{'haschildren'} == 0) {
888         $disable = "disabled=\"disabled\"";
889         }
890 return "<input type=submit name=\"${dependency_or_dependent}_expand_$fmri\" value=\"+\" $disable>";
891 }
892
893