Handle hostnames with upper-case letters
[webmin.git] / software / aix-lib.pl
1 # aix-lib.pl
2 # Functions for aix package management
3
4 sub list_package_system_commands
5 {
6 return ("lslpp", "geninstall", "installp");
7 }
8
9 # list_packages([package]*)
10 # Fills the array %packages with a list of all packages
11 sub list_packages
12 {
13         local($_, $list, $i, $file, %fileset);
14         $i = 0;
15         $list = join(' ', @_);
16         %packages = ( );
17         &open_execute_command(LSLPP, "lslpp -L -c $list 2>&1 | grep -v '#'", 1, 1);
18         while($file = <LSLPP>) {
19                 %fileset = &fileset_info($file); 
20                 if ($fileset{"type"} eq "R") {
21                         $packages{$i,'name'} = join("-", $fileset{"package_name"}, $fileset{"level"});
22                         $packages{$i,'class'} = $fileset{"package_name"};
23                         $packages{$i,'desc'} = $fileset{"description"};
24                 }
25                 else {
26                         $packages{$i,'name'} = $fileset{"fileset"};
27                         $packages{$i,'class'} = $fileset{"class"};
28                         $packages{$i,'desc'} = $fileset{"description"};
29                 }
30                 $i++;
31         }
32         close(LSLPP);
33         return $i;
34 }
35
36 # package_info(package)
37 # Returns an array of package information in the order
38 #  name, class, description, arch, version, vendor, installtime
39 sub package_info
40 {
41         local(@rv, @tmp, $d, $out, $archout, %fileset);
42
43         local $qm = quotemeta($_[0]);
44         $out = &backquote_command("lslpp -L -c $qm 2>&1 | grep -v '#'", 1);
45         %fileset = &fileset_info($out);
46         if ($out =~ /^lslpp:/) {
47                 &open_execute_command(RPM, "rpm -q $qm --queryformat \"%{NAME}-%{VERSION}\\n%{GROUP}\\n%{ARCH}\\n%{VERSION}\\n%{VENDOR}\\n%{INSTALLTIME}\\n\" 2>/dev/null", 1, 1);
48                 @tmp = <RPM>;
49                 chop(@tmp);
50                 if (!@tmp) { return (); }
51                 close(RPM);
52                 &open_execute_command(RPM, "rpm -q $qm --queryformat \"%{DESCRIPTION}\"", 1, 1);
53                 while(<RPM>) { $d .= $_; }
54                 close(RPM);
55                 return ($tmp[0], $tmp[1], $d, $tmp[2], $tmp[3], $tmp[4], &make_date($tmp[5]));
56         }
57         else {
58                 $archout = `uname -s`; 
59                 push(@rv, $_[0]);
60                 push(@rv, $fileset{"class"});
61                 push(@rv, $fileset{"description"});
62                 push(@rv, $archout);   
63                 push(@rv, $fileset{"level"});
64                 push(@rv, $text{'aix_unknown'});
65                 push(@rv, $text{'aix_unknown'});
66                 return @rv;
67         }
68 }
69
70 # is_package(file)
71 # Tests if some file is a valid package file
72 sub is_package
73 {
74         local($out, $name, $filetype);
75         local $qm = quotemeta($_[0]);
76         $out = &backquote_command("file $qm 2>&1", 1);
77         ($name, $filetype) = split(/:/, $out);
78         if ($filetype =~ /backup\/restore format file/i) { 
79                 $fileset{"filetype"} = "AIX";
80                 return 1;       
81         }
82         elsif ($filetype =~ /RPM v3 bin PowerPC/i) {
83                 $fileset{"filetype"} = "RPM";
84                 return 1;
85         }
86         else {  return 0; }
87 }
88
89 # file_packages(file)
90 # Returns a list of all packages in the given file, in the form
91 #  package description
92 sub file_packages
93 {
94         local($_, $line, $i, $j, $file, $out, $continue, @token, $firstline);
95         local(@rv, @output, $description, @vrmf, @field, $k, $l, $stub);
96         local $qm = quotemeta($_[0]);
97         local $real = &translate_filename($_[0]);
98         if (&is_package($_[0])) {
99                 @token = split(/\//, $_[0]);
100                 $i = @token;
101                 $file = $token[$i - 1];
102                 if ($fileset{"filetype"} eq "RPM") {
103                         $fileset{"fileset_name"} = "R:$file";
104                         if (-d $real) {
105                                 local @rv;
106                                 &open_execute_file(RPM, "cd $qm ; rpm -q -p *.rpm --queryformat \"%{NAME}-%{VERSION} %{SUMMARY}\\n\" 2>&1", 1, 1);
107                                 while(<RPM>) {
108                                         chop;
109                                         push(@rv, $_) if (!/does not appear|query of.*failed/);
110                                 }
111                                 close(RPM);
112                                 return @rv;
113                         }
114                         else {
115                                 local($out);
116                                 $out = &backquote_command("rpm -q -p $qm --queryformat \"%{NAME}-%{VERSION} %{SUMMARY}\" 2>&1", 1);
117                                 return ($out);
118                         }
119                 }
120                 elsif ($fileset{"filetype"} eq "AIX") {
121                         &open_tempfile(FILE, $_[0]);
122                         $line = <FILE>;
123                         $continue = 1;
124                         while ($continue) {
125                                 if ($line =~ /^\}/) { $continue = 0; }
126                                 elsif (($line =~ /lpp_name/) && ($line =~ / \{/)) { 
127                                         $firstline = $line; 
128                                         $line = <FILE>;
129                                         $out = $out . $line;
130                                 }
131                                 elsif ($line =~ /^\]/) {
132                                         $line = <FILE>;
133                                         if ($line =~ /^\}/) { $continue = 0; }
134                                         else { $out = $out . $line; }
135                                 }       
136                                 $line = <FILE>; 
137                         }
138                         close(FILE);
139                         @field = split(/\s/, $firstline);
140                         $j = @field;
141                         for ($i = 0; $i < $j; $i++) {
142                                 if ($field[$i] =~ /\{/) {
143                                         $fileset{"fileset_name"} = $field[$i - 1] =~ /\>|\s+/ ? $file : 
144                                                                    $field[$i - 1];
145                                 }
146                         }
147                         @output = split(/\n/, $out);
148                         $j = @output;
149                         for ($i = 0; $i < $j; $i++) {
150                                 if ($output[$i] !~ /\{|\}|\*/) {
151                                         @field = split(/\s/, $output[$i]);
152                                         $out = undef;
153                                         $out = "$fileset{fileset_name}  ";
154                                         $description = undef;
155                                         @vrmf = split(/\./, $field[1]);
156                                         $vrmf[0] =~ s/^0+//;
157                                         $vrmf[1] =~ s/^0+//; if ($vrmf[1] == "") { $vrmf[1] = "0"; }
158                                         $vrmf[2] =~ s/^0+//; if ($vrmf[2] == "") { $vrmf[2] = "0"; } 
159                                         $vrmf[3] =~ s/^0+//; if ($vrmf[3] == "") { $vrmf[3] = "0"; }
160                                         if ($vrmf[0] != "") {
161                                                 $k = @field;
162                                                 for ($l = 6; $l <= $k; $l++) {
163                                                         $description = $description . " " . $field[$l];
164                                                 }
165                                                 $out = $out . "$field[0], $vrmf[0].$vrmf[1].$vrmf[2].$vrmf[3], $description";
166                                         }       
167                                 }
168                                 push(@rv, $out);
169                         }
170                         return @rv;
171                 }
172         }
173         else {  return undef; }
174 }
175
176 # install_options(file, package)
177 # Outputs HTML for choosing install options
178 sub install_options
179 {
180         local(@token, $command, $i, $j, $file, $directory);
181         @token = split(/\//, $_[0]);
182         $i = @token;
183         for ( $j = 1; $j < $i - 1; $j++) {
184                 $directory = join("/", $directory, $token[$j]);
185         }
186
187         $file = $token[$i-1];
188
189         print "<script language=\"JavaScript\">\n";
190         print "   function changeRadio(formName, radiobutton, disable) {\n";
191         print "      for( var i=0; i<formName.elements.length; i++) {\n";
192         print "         if (formName.elements[i].name == radiobutton) {\n";
193         print "            formName.elements[i].checked = disable;\n";
194         print "         }\n";
195         print "      }\n";
196         print "   }\n";
197         print "</script>\n";
198
199         print "<tr>\n";
200         print "<td>", &hlink("<b>$text{'aix_device'}</b>", "aix_device"), "</td>\n";
201         print "<td>$directory</td>\n";
202         print "</tr>\n";
203
204         print "<tr>\n";
205         print "<td>", &hlink("<b>$text{'aix_software'}</b>", "aix_software"), "</td>\n";
206         print "<td>$file</td>\n";
207         print "</tr>\n";
208
209         print "<tr>\n";
210         print "<td>", &hlink("<b>$text{'aix_preview'}</b>", "aix_preview"), "</td>\n";
211         print "<td><input type=radio name=preview value=1> $text{'yes'}\n";
212         print "<input type=radio name=preview value=0 checked> $text{'no'}</td>\n";
213         print "</tr>\n";
214
215         print "<tr>\n";
216         print "<td>", &hlink("<b>$text{'aix_commit'}</b>", "aix_commit"), "</td>\n";
217         print "<td><input type=radio name=commit value=1 checked> $text{'yes'}\n"; 
218         print "<input type=radio name=commit value=0 \n";
219         print "     onClick=\"changeRadio(this.form, 'save', true)\"> $text{'no'}</td>\n";
220         print "</tr>\n";
221
222         print "<tr>\n";
223         print "<td>", &hlink("<b>$text{'aix_save'}</b>", "aix_save"), "</td>\n";
224         print "<td><input type=radio name=save value=1> $text{'yes'}\n";
225         print "<input type=radio name=save value=0 checked> $text{'no'}</td>\n";
226         print "</tr>\n";
227
228         print "<tr>\n";
229         print "<td>", &hlink("<b>$text{'aix_auto'}</b>", "aix_auto"), "</td>\n";
230         print "<td><input type=radio name=auto value=1 \n";
231         print "     onClick=\"changeRadio(this.form, 'overwrite', false)\" checked> $text{'yes'}\n";
232         print "<input type=radio name=auto value=0> $text{'no'}</td>\n";
233         print "</tr>\n";
234
235         print "<tr>\n";
236         print "<td>", &hlink("<b>$text{'aix_extend'}</b>", "aix_extend"), "</td>\n";
237         print "<td><input type=radio name=extend value=1 checked> $text{'yes'}\n";
238         print "<input type=radio name=extend value=0> $text{'no'}</td>\n";
239         print "</tr>\n";
240
241         print "<tr>\n";
242         print "<td>", &hlink("<b>$text{'aix_overwrite'}</b>", "aix_overwrite"), "</td>\n";
243         print "<td><input type=radio name=overwrite value=1 \n";
244         print "     onClick=\"changeRadio(this.form, 'auto', false)\"> $text{'yes'}\n";
245         print "<input type=radio name=overwrite value=0 checked > $text{'no'}</td>\n";
246         print "</tr>\n";
247
248         print "<tr>\n";
249         print "<td>", &hlink("<b>$text{'aix_verify'}</b>", "aix_verify"), "</td>\n";
250         print "<td><input type=radio name=verify value=1> $text{'yes'}\n";
251         print "<input type=radio name=verify value=0 checked> $text{'no'}</td>\n";
252         print "</tr>\n";
253
254 #        print "<tr>\n";
255 #        print "<td>", &hlink("<b>$text{'aix_include'}</b>", "aix_include"), "</td>\n";
256 #        print "<td><input type=radio name=include value=1> $text{'yes'}\n";
257 #        print "<input type=radio name=include value=0 checked> $text{'no'}</td>\n";
258 #        print "</tr>\n";
259
260         print "<tr>\n";
261         print "<td>", &hlink("<b>$text{'aix_detail'}</b>", "aix_detail"), "</td>\n";
262         print "<td><input type=radio name=detail value=1> $text{'yes'}\n";
263         print "<input type=radio name=detail value=0 checked> $text{'no'}</td>\n";
264         print "</tr>\n";
265
266         print "<tr>\n";
267         print "<td>", &hlink("<b>$text{'aix_process'}</b>", "aix_process"), "</td>\n";
268         print "<td><input type=radio name=process value=1 checked> $text{'yes'}\n";
269         print "<input type=radio name=process value=0> $text{'no'}</td>\n";
270         print "</tr>\n";
271
272         print "<tr>\n";
273         print "<td>", &hlink("<b>$text{'aix_accept'}</b>", "aix_accept"), "</td>\n";
274         print "<td><input type=radio name=accept value=1> $text{'yes'}\n";
275         print "<input type=radio name=accept value=0 checked> $text{'no'}</td>\n";
276         print "</tr>\n";
277
278         print "<tr>\n";
279         print "<td>", &hlink("<b>$text{'aix_license'}</b>", "aix_license"), "</td>\n";
280         print "<td><input type=radio name=license value=1> $text{'yes'}\n";
281         print "<input type=radio name=license value=0 checked> $text{'no'}</td>\n";
282         print "</tr>\n";
283
284         print "<tr>\n";
285         print "<td>", &hlink("<b>$text{'aix_clean'}</b>", "aix_clean"), "</td>\n";
286         print "<td><input type=radio name=clean value=1 \n";
287         print "     onClick=\"changeRadio(this.form, 'preview', false),\n";
288         print "               changeRadio(this.form, 'commit', false),\n";
289         print "               changeRadio(this.form, 'save', false),\n";
290         print "               changeRadio(this.form, 'auto', false),\n";
291         print "               changeRadio(this.form, 'extend', false),\n";
292         print "               changeRadio(this.form, 'overwrite', false),\n";
293         print "               changeRadio(this.form, 'verify', false),\n";
294 #       print "               changeRadio(this.form, 'include', false),\n";
295         print "               changeRadio(this.form, 'detail', false),\n";
296         print "               changeRadio(this.form, 'process', false),\n";
297         print "               changeRadio(this.form, 'accept', false),\n";
298         print "               changeRadio(this.form, 'license', false)\"> $text{'yes'}\n";
299         print "<input type=radio name=clean value=0\n";
300         print "     onClick=\"reset()\" checked> $text{'no'}</td>\n";
301         print "</tr>\n";
302 }
303
304 # install_package(file, package)
305 # Installs the package in the given file, with options from %in
306 sub install_package
307 {
308         local(@token, $command, $directory, $out);
309         @token = split(/\//, $_[0]);
310         $i = @token;
311         for ( $j = 1; $j < $i - 1; $j++) {
312                 $directory = join("/", $directory, $token[$j]);
313         }
314
315         local $args = ($in{"preview"}   ? "p"  : "")   .
316                       ($in{"commit"}    ? "c"  : "")   .
317                       ($in{"save"}      ? ""   : "N")  .
318                       ($in{"auto"}      ? "g"  : "")   .
319                       ($in{"extend"}    ? "X"  : "")   .
320                       ($in{"overwrite"} ? "F"  : "")   .
321                       ($in{"verify"}    ? "v"  : "")   .
322 #                     ($in{"include"}   ? "G"  : "")   .
323                       ($in{"detail"}    ? "V2" : "")   .
324                       ($in{"process"}   ? ""   : "S")  .
325                       ($in{"accept"}    ? "Y"  : "")   .
326                       ($in{"license"}   ? "E"  : "");
327
328         $command = "geninstall -I \"-a$args\" -d '$directory' '$fileset{fileset_name}' 2>&1";
329         if ($in{"clean"}) {
330                 $args = "-C";
331                 $command = "installp $args 2>&1";
332         }
333
334         local $out = &backquote_logged($command);
335                 if (($?) || ($in{"preview"}) || ($in{"clean"})) { 
336                         return "<pre>$command<br>$out</pre>";
337         }
338         return undef;
339 }
340
341 # check_files(package)
342 # Fills in the %files array with information about the files belonging
343 # to some package. Values in %files are path type user group mode size error link
344 sub check_files
345 {
346         local($_, $list, $i, $_, @w, %errs, %myfile, $epath, $path, $fileset, $file);
347         local $qm = quotemeta($_[0]);
348         $i = 0;
349         $list = join(' ', @_);
350         &open_execute_command(LSLPP, "lslpp -f -c $qm 2>&1 | grep -v '#'", 1, 1);
351         $out = <LSLPP>;
352         if ($out =~ /lslpp:/) { 
353                 &open_execute_command(RPM, "rpm -V $qm", 1, 1);
354                 while(<RPM>) {
355                         /^(.{8}) (.) (.*)$/;
356                         if ($1 eq "missing ") { $errs{$3} = "Missing"; }
357                         else {
358                                 $epath = $3;
359                                 @w = grep { $_ ne "." } split(//, $1);
360                                 $errs{$epath} =
361                                         join("\n", map { "Failed $etype{$_} check" } @w);
362                         }
363                 }
364                 close(RPM);
365                 &open_execute_command(RPM, "rpm -q $qm -l --dump", 1, 1);
366                 while(<RPM>) {
367                         chop;
368                         if ($_ =~ /(contains no files)/) { return $i; }
369                         @w = split(/ /);
370                         $files{$i,'path'} = $w[0];
371                         if ($w[10] ne "X") { $files{$i,'link'} = $w[10]; }
372                         $files{$i,'type'} = $w[10] ne "X" ? 3 :
373                                             (-d &translate_filename($w[0]))? 1 :
374                                             $w[7]         ? 5 : 0;
375                         $files{$i,'user'} = $w[5];
376                         $files{$i,'group'} = $w[6];
377                         $files{$i,'size'} = $w[1];
378                         $files{$i,'error'} = $w[7]        ? "" : $errs{$w[0]};
379                         $i++;
380                 }
381                 close(RPM);
382         }
383         else {
384                 while($fileinfo = <LSLPP>) {
385                         chop($fileinfo);
386                         #Path:Fileset:File
387                         ($path, $fileset, $file) = split(/:/, $fileinfo);
388                         %myfile = &file_info($file);
389                         $files{$i,'path'}  = $myfile{"path"};
390                         $files{$i,'type'}  = $myfile{"type"}; 
391                         $files{$i,'user'}  = $myfile{"uid"}; 
392                         $files{$i,'group'} = $myfile{"gid"};
393                         $files{$i,'mode'}  = $myfile{"mode"}; 
394                         $files{$i,'size'}  = $myfile{"size"}; 
395                         $files{$i,'link'}  = $myfile{"link"};
396                         $files{$i,'error'} = $myfile{"err"};
397                         $i++;
398                 }
399         }
400         close(LSLPP);
401         return $i;
402 }
403
404 # installed_file(file)
405 # Given a filename, fills %file with details of the given file and returns 1.
406 # If the file is not known to the package system, returns 0
407 # Usable values in %file are  path type user group mode size packages
408 sub installed_file
409 {
410         local(%myfile);
411         local $qm = quotemeta($_[0]);
412         $out = &backquote_command("lslpp -wc $qm 2>&1 | grep -v '#'", 1);
413         if ($?) {
414                 local($pkg, @w, $_);
415                 undef(%file);
416                 $pkg = &backquote_command("rpm -q -f $qm --queryformat \"%{NAME}-%{VERSION}\\n\" 2>&1", 1);
417
418                 if ($pkg =~ /not owned/ || $?) { return 0; }
419                 @pkgs = split(/\n/, $pkg);
420                 &open_execute_command(RPM, "rpm -q $pkgs[0] -l --dump", 1);
421                 while(<RPM>) {
422                         chop;
423                         @w = split(/ /);
424                         if ($w[0] eq $_[0]) {
425                                 $file{'packages'} = join(' ', @pkgs);
426                                 $file{'path'} = $w[0];
427                                 if ($w[10] ne "X") { $files{$i,'link'} = $w[10]; }
428                                 $file{'type'} = $w[10] ne "X" ? 3 :
429                                         (-d &translate_filename($w[0])) ? 1 :
430                                                 $w[7]         ? 5 : 0;
431                                 $file{'user'} = $w[5];
432                                 $file{'group'}= $w[6];
433                                 $file{'mode'} = substr($w[4], -4);
434                                 $file{'size'} = $w[1];
435                                 last;
436                         }
437                 }
438                 close(RPM);
439         }
440         else {
441                 %myfile = &file_info($_[0]);
442                 $file{'path'}     = $myfile{"path"};
443                 $file{'type'}     = $myfile{"type"};
444                 $file{'user'}     = $myfile{"uid"};
445                 $file{'group'}    = $myfile{"gid"};
446                 $file{'mode'}     = $myfile{"mode"};
447                 $file{'size'}     = $myfile{"size"};
448                 $file{'link'}     = $myfile{"link"};
449                 $file{'packages'} = $myfile{"package"};
450         }
451         return 1;
452 }
453
454 # delete_package(package)
455 # Totally remove some package
456 sub delete_package
457 {
458         local(%fileset, $file, $out, $rv);
459         local $temp = &transname();
460         local $qm = quotemeta($_[0]);
461
462         $file = &backquote_command("lslpp -L -c $qm 2>&1 | grep -v '#'", 1);
463         %fileset = &fileset_info($file);
464
465         $rv = &system_logged("geninstall -u $_[0] >$temp 2>&1");
466         local $out = &backquote_command("cat $temp");
467         &unlink_file($temp);
468         
469         if ($rv) { return "<pre>$out</pre>"; }
470         return undef; 
471 }
472
473 sub fileset_info
474 {
475         local($_, $out, %fileset, $package_name, $fileset, $level, $state, $ptf_id, 
476               $fix_state, $type, $description, $destination_dir, $uninstaller, 
477               $msg_cat, $msg_set, $msg_num, $parent, $class);
478         %fileset = ();
479         ($package_name, $fileset, $level, $state, $ptf_id, $fix_state,
480          $type, $description, $destination_dir, $uninstaller, $msg_cat,
481          $msg_set, $msg_num, $parent) = split(/:/, $_[0]);
482         ($class, $stub)             = split(/\./, $package_name);
483         $fileset{"class"}           = $class;
484         $fileset{"package_name"}    = $package_name;
485         $fileset{"fileset"}         = $fileset;
486         $fileset{"level"}           = $level;
487         $fileset{"state"}           = $state;
488         $fileset{"ptf_id"}          = $ptf_id;
489         $fileset{"fix_state"}       = $fix_state;
490         $fileset{"type"}            = $type;
491         $fileset{"description"}     = $description;
492         $fileset{"destination_dir"} = $destination_dir;
493         $fileset{"uninstaller"}     = $uninstaller;
494         $fileset{"msg_cat"}         = $msg_cat;
495         $fileset{"msg_set"}         = $msg_set;
496         $fileset{"msg_num"}         = $msg_num;
497         $fileset{"parent"}          = $parent;
498         return(%fileset);
499 }
500
501 sub file_info
502 {
503         local($_, %file, @out, $filename, $fileset, $type,  
504               $dev, $ino, $mode, $nlink, $uid, $gid, @args, $rdev,
505               $size, $atime, $mtime, $ctime, $blksize, $blocks);
506         %file = ();     
507         local $real;
508         
509         if ($_[0] =~ /->/) {
510                 ($filename, $symlink) = split(/->/, $_[0]);
511                 $real = &translate_filename($filename);
512                 chop($filename);
513                 ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
514                  $atime, $mtime, $ctime, $blksize, $blocks) = lstat($real);
515         }
516         else {
517                 $filename = $_[0];
518                 $real = &translate_filename($filename);
519                 ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
520                  $atime, $mtime, $ctime, $blksize, $blocks) = stat($real);
521         }
522         
523         local $qm = quotemeta($filename);
524         @out = &backquote_command("lslpp -wc $qm 2>&1", 1);
525         ($stub, $fileset, $type) = split(/:/, $out[1]);
526
527         $file{"path"}    = $filename;   
528         $file{"dev"}     = sprintf "%d,%d", $dev/256, $dev%256;
529         $file{"ino"}     = $ino;
530         $file{"mode"}    = sprintf "%o", $mode & 07777;
531         $file{"nlink"}   = $nlink;
532         $file{"uid"}     = getpwuid($uid);
533         $file{"gid"}     = getgrgid($gid);
534         $file{"rdev"}    = readlink($rdev);
535         $file{"size"}    = $size        ? $size : 0;
536         $file{"atime"}   = scalar(localtime($atime));
537         $file{"mtime"}   = scalar(localtime($mtime));
538         $file{"ctime"}   = scalar(localtime($ctime));
539         $file{"blksize"} = $blksize;
540         $file{"blocks"}  = $blocks;
541         $file{"link"}    = readlink($real);
542         $file{"package"} = $fileset;
543         $file{"err"}     = -e $real  ? 0 : "Error";
544         $file{"type"}    = -l $real ? 3 :
545                            -d $real ? 1 :
546                            0;
547         return(%file);
548 }
549
550 sub package_system
551 {
552         return $text{'aix_manager'}; 
553 }
554
555 sub package_help
556 {
557         return "installp lslpp";
558 }
559
560 1;
561