This commit was generated by cvs2svn to compensate for changes in r6252,
[freeside.git] / rt / sbin / rt-setup-database.in
1 #!@PERL@ -w
2 # BEGIN BPS TAGGED BLOCK {{{
3
4 # COPYRIGHT:
5 #  
6 # This software is Copyright (c) 1996-2007 Best Practical Solutions, LLC 
7 #                                          <jesse@bestpractical.com>
8
9 # (Except where explicitly superseded by other copyright notices)
10
11
12 # LICENSE:
13
14 # This work is made available to you under the terms of Version 2 of
15 # the GNU General Public License. A copy of that license should have
16 # been provided with this software, but in any event can be snarfed
17 # from www.gnu.org.
18
19 # This work is distributed in the hope that it will be useful, but
20 # WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22 # General Public License for more details.
23
24 # You should have received a copy of the GNU General Public License
25 # along with this program; if not, write to the Free Software
26 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27 # 02110-1301 or visit their web page on the internet at
28 # http://www.gnu.org/copyleft/gpl.html.
29
30
31 # CONTRIBUTION SUBMISSION POLICY:
32
33 # (The following paragraph is not intended to limit the rights granted
34 # to you to modify and distribute this software under the terms of
35 # the GNU General Public License and is only of importance to you if
36 # you choose to contribute your changes and enhancements to the
37 # community by submitting them to Best Practical Solutions, LLC.)
38
39 # By intentionally submitting any modifications, corrections or
40 # derivatives to this work, or any other work intended for use with
41 # Request Tracker, to Best Practical Solutions, LLC, you confirm that
42 # you are the copyright holder for those contributions and you grant
43 # Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
44 # royalty-free, perpetual, license to use, copy, create derivative
45 # works based on those contributions, and sublicense and distribute
46 # those contributions and any derivatives thereof.
47
48 # END BPS TAGGED BLOCK }}}
49 use strict;
50 use vars qw($PROMPT $VERSION $Handle $Nobody $SystemUser $item);
51 use vars
52   qw(@Groups @Users @ACL @Queues @ScripActions @ScripConditions @Templates @CustomFields @Scrips @Attributes);
53
54 use lib "@LOCAL_LIB_PATH@";
55 use lib "@RT_LIB_PATH@";
56
57 #This drags in  RT's config.pm
58 # We do it in a begin block because RT::Handle needs to know the type to do its
59 # inheritance
60 use RT;
61 use Carp;
62 use RT::User;
63 use RT::CurrentUser;
64 use RT::Template;
65 use RT::ScripAction;
66 use RT::ACE;
67 use RT::Group;
68 use RT::User;
69 use RT::Queue;
70 use RT::ScripCondition;
71 use RT::CustomField;
72 use RT::Scrip;
73
74 RT::LoadConfig();
75 use Term::ReadKey;
76 use Getopt::Long;
77
78 my %args;
79
80 GetOptions(
81     \%args,
82     'prompt-for-dba-password', 'force', 'debug',
83     'action=s',                'dba=s', 'dba-password=s', 'datafile=s',
84     'datadir=s'
85 );
86
87 unless ( $args{'action'} ) {
88     help();
89     exit(-1);
90 }
91
92 $| = 1;    #unbuffer that output.
93
94 require RT::Handle;
95 my $Handle = RT::Handle->new($RT::DatabaseType);
96 $Handle->BuildDSN;
97 my $dbh;
98
99 if ( $args{'prompt-for-dba-password'} ) {
100     $args{'dba-password'} = get_dba_password();
101     chomp( $args{'dba-password'} );
102 }
103
104 if ( $args{'action'} eq 'init' ) {
105     $dbh = DBI->connect( get_system_dsn(), $args{'dba'}, $args{'dba-password'} )
106       || die "Failed to connect to " . get_system_dsn() . " as $args{'dba'}: $DBI::errstr";
107     print "Now creating a database for RT.\n";
108     if ( $RT::DatabaseType ne 'Oracle' || $args{'dba'} ne $RT::DatabaseUser ) {
109         create_db();
110     } else {
111         print "...skipped as ".$args{'dba'} ." is not " . $RT::DatabaseUser . " or we're working with Oracle.\n";
112     }
113
114     if ( $RT::DatabaseType eq "mysql" ) {
115         # Check which version we're running
116         my ($version) = $dbh->selectrow_hashref("show variables like 'version'")->{Value} =~ /^(\d\.\d+)/;
117         print "*** Warning: RT is unsupported on MySQL versions before 4.0.x\n" if $version < 4;
118
119         # MySQL must have InnoDB support
120         my $innodb = $dbh->selectrow_hashref("show variables like 'have_innodb'")->{Value};
121         if ( $innodb eq "NO" ) {
122             die "RT requires that MySQL be compiled with InnoDB table support.\n".
123               "See http://dev.mysql.com/doc/mysql/en/InnoDB.html\n";
124         } elsif ( $innodb eq "DISABLED" ) {
125             die "RT requires that MySQL InnoDB table support be enabled.\n".
126               ($version < 4
127                ? "Add 'innodb_data_file_path=ibdata1:10M:autoextend' to the [mysqld] section of my.cnf\n"
128                : "Remove the 'skip-innodb' line from your my.cnf file, restart MySQL, and try again.\n");
129         }
130     }
131
132     # SQLite can't deal with the disconnect/reconnect
133     unless ( $RT::DatabaseType eq 'SQLite' ) {
134
135         $dbh->disconnect;
136
137         if ( $RT::DatabaseType eq "Oracle" ) {
138             $RT::DatabasePassword = $RT::DatabasePassword; #Warning avidance
139             $dbh = DBI->connect( $Handle->DSN, ${RT::DatabaseUser}, ${RT::DatabasePassword} ) || die $DBI::errstr;
140         } else {        
141             $dbh = DBI->connect( $Handle->DSN, $args{'dba'}, $args{'dba-password'} ) || die $DBI::errstr;
142         }
143     }
144     print "Now populating database schema.\n";
145     insert_schema();
146     print "Now inserting database ACLs\n";
147     insert_acl() unless $RT::DatabaseType eq 'Oracle';
148     print "Now inserting RT core system objects\n";
149     insert_initial_data();
150     print "Now inserting RT data\n";
151     insert_data( $RT::EtcPath . "/initialdata" );
152 }
153 elsif ( $args{'action'} eq 'drop' ) {
154     unless ( $dbh =
155         DBI->connect( get_system_dsn(), $args{'dba'}, $args{'dba-password'} ) )
156     {
157         warn $DBI::errstr;
158         warn "Database doesn't appear to exist. Aborting database drop.";
159         exit;
160     }
161     drop_db();
162 }
163 elsif ( $args{'action'} eq 'insert_initial' ) {
164     insert_initial_data();
165 }
166 elsif ( $args{'action'} eq 'insert' ) {
167     insert_data( $args{'datafile'} || ($args{'datadir'}."/content") );
168 }
169 elsif ( $args{'action'} eq 'acl' ) {
170     $dbh = DBI->connect( $Handle->DSN, $args{'dba'}, $args{'dba-password'} )
171       || die "Failed to connect to " . get_system_dsn() . " as $args{'dba'}: $DBI::errstr";
172     insert_acl($args{'datadir'});
173 }
174 elsif ( $args{'action'} eq 'schema' ) {
175     $dbh = DBI->connect( $Handle->DSN, $args{'dba'}, $args{'dba-password'} )
176       || die "Failed to connect to " . get_system_dsn() . " as $args{'dba'}: $DBI::errstr";
177     insert_schema($args{'datadir'});
178 }
179 else {
180     print STDERR "$0 called with an invalid --action parameter\n";
181     exit(-1);
182 }
183
184 # {{{ sub insert_schema
185 sub insert_schema {
186     my $base_path = (shift || $RT::EtcPath);
187     my (@schema);
188     print "Creating database schema.\n";
189
190     my $schema_file = $base_path . "/schema." . $RT::DatabaseType;
191     if ( -f $schema_file ) {
192         open( SCHEMA, "<$schema_file"  ) or die "Can't open $schema_file: $!";
193         my @lines = <SCHEMA>;
194
195         my $local_schema_file = $RT::LocalEtcPath . "/schema." . $RT::DatabaseType;
196         if (-f $local_schema_file) {
197             open( SCHEMA_LOCAL, "<$local_schema_file" )
198                 or die "Can't open $local_schema_file: $!";
199             push @lines, ';;', <SCHEMA_LOCAL>;
200         }
201
202         my $statement = "";
203         foreach my $line (@lines) {
204             $line =~ s/\#.*//g;
205             $line =~ s/--.*//g;
206             $statement .= $line;
207             if ( $line =~ /;(\s*)$/ ) {
208                 $statement =~ s/;(\s*)$//g;
209                 push @schema, $statement;
210                 $statement = "";
211             }
212         }
213
214         local $SIG{__WARN__} = sub {};
215         my $is_local = 0; # local/etc/schema needs to be nonfatal.
216         $dbh->begin_work or die $dbh->errstr;
217         foreach my $statement (@schema) {
218             if ( $statement =~ /^\s*;$/ ) { $is_local = 1; next; }
219
220             print STDERR "SQL: $statement\n" if defined $args{'debug'};
221             my $sth = $dbh->prepare($statement) or die $dbh->errstr;
222             unless ( $sth->execute or $is_local ) {
223                 die "Problem with statement:\n $statement\n" . $sth->errstr;
224             }
225         }
226         $dbh->commit or die $dbh->errstr;
227     }
228     else {
229         die "Couldn't find schema file for " . $RT::DatabaseType . "\n";
230     }
231     print "Done setting up database schema.\n";
232 }
233
234 # }}}
235
236 # {{{ sub drop_db
237 sub drop_db {
238     if ( $RT::DatabaseType eq 'Oracle' ) {
239         print <<END;
240
241 To delete the tables and sequences of the RT Oracle database by running
242     \@etc/drop.Oracle
243 through SQLPlus.
244
245 END
246         return;
247     }
248     unless ( $args{'force'} ) {
249         print <<END;
250
251 About to drop $RT::DatabaseType database $RT::DatabaseName on $RT::DatabaseHost.
252 WARNING: This will erase all data in $RT::DatabaseName.
253
254 END
255         exit unless _yesno();
256
257     }
258
259     print "Dropping $RT::DatabaseType database $RT::DatabaseName.\n";
260
261     if ( $RT::DatabaseType eq 'SQLite' ) {
262         unlink $RT::DatabaseName or warn $!;
263         return;
264     }
265     $dbh->do("Drop DATABASE $RT::DatabaseName") or warn $DBI::errstr;
266 }
267
268 # }}}
269
270 # {{{ sub create_db
271 sub create_db {
272     print "Creating $RT::DatabaseType database $RT::DatabaseName.\n";
273     if ( $RT::DatabaseType eq 'SQLite' ) {
274         return;
275     }
276     elsif ( $RT::DatabaseType eq 'Pg' ) {
277         $dbh->do("CREATE DATABASE $RT::DatabaseName WITH ENCODING='UNICODE'");
278         if ( $DBI::errstr ) {
279             $dbh->do("CREATE DATABASE $RT::DatabaseName") || die $DBI::errstr;
280         }
281     }
282     elsif ( $RT::DatabaseType eq 'Oracle' ) {
283         insert_acl();
284     }
285     elsif ( $RT::DatabaseType eq 'Informix' ) {
286         $ENV{DB_LOCALE} = 'en_us.utf8';
287         $dbh->do("CREATE DATABASE $RT::DatabaseName WITH BUFFERED LOG");
288     }
289     else {
290         $dbh->do("CREATE DATABASE $RT::DatabaseName") or die $DBI::errstr;
291     }
292 }
293
294 # }}}
295
296 sub get_dba_password {
297     print "In order to create or update your RT database,";
298     print "this script needs to connect to your "
299       . $RT::DatabaseType
300       . " instance on "
301       . $RT::DatabaseHost . " as "
302       . $args{'dba'} . ".\n";
303     print "Please specify that user's database password below. If the user has no database\n";
304     print "password, just press return.\n\n";
305     print "Password: ";
306     ReadMode('noecho');
307     my $password = ReadLine(0);
308     ReadMode('normal');
309     print "\n";
310     return ($password);
311 }
312
313 # {{{ sub _yesno
314 sub _yesno {
315     print "Proceed [y/N]:";
316     my $x = scalar(<STDIN>);
317     $x =~ /^y/i;
318 }
319
320 # }}}
321
322 # {{{ insert_acls
323 sub insert_acl {
324     my $base_path = (shift || $RT::EtcPath);
325
326     if ( $RT::DatabaseType =~ /^oracle$/i ) {
327         do $base_path . "/acl.Oracle"
328           || die "Couldn't find ACLS for Oracle\n" . $@;
329     }
330     elsif ( $RT::DatabaseType =~ /^pg$/i ) {
331         do $base_path . "/acl.Pg" || die "Couldn't find ACLS for Pg\n" . $@;
332     }
333     elsif ( $RT::DatabaseType =~ /^mysql$/i ) {
334         do $base_path . "/acl.mysql"
335           || die "Couldn't find ACLS for mysql in $base_path\n" . $@;
336     }
337     elsif ( $RT::DatabaseType =~ /^Sybase$/i ) {
338         do $base_path . "/acl.Sybase"
339           || die "Couldn't find ACLS for Sybase in $base_path\n" . $@;
340     }
341     elsif ( $RT::DatabaseType =~ /^informix$/i ) {
342         do $base_path . "/acl.Informix"
343           || die "Couldn't find ACLS for Informix in $base_path\n" . $@;
344     }
345     elsif ( $RT::DatabaseType =~ /^SQLite$/i ) {
346         return;
347     }
348     else {
349         die "Unknown RT database type";
350     }
351
352     my @acl = acl($dbh);
353     foreach my $statement (@acl) {
354         print STDERR $statement if $args{'debug'};
355         my $sth = $dbh->prepare($statement) or die $dbh->errstr;
356         unless ( $sth->execute ) {
357             die "Problem with statement:\n $statement\n" . $sth->errstr;
358         }
359     }
360     print "Done setting up database ACLs.\n";
361 }
362
363 # }}}
364
365 =head2 get_system_dsn
366
367 Returns a dsn suitable for database creates and drops
368 and user creates and drops
369
370 =cut
371
372 sub get_system_dsn {
373
374     my $dsn = $Handle->DSN;
375
376     #with mysql, you want to connect sans database to funge things
377     if ( $RT::DatabaseType eq 'mysql' ) {
378         $dsn =~ s/dbname=$RT::DatabaseName//;
379
380         # with postgres, you want to connect to database1
381     }
382     elsif ( $RT::DatabaseType eq 'Pg' ) {
383         $dsn =~ s/dbname=$RT::DatabaseName/dbname=template1/;
384     }
385     elsif ( $RT::DatabaseType eq 'Informix' ) {
386         # with Informix, you want to connect sans database:
387         $dsn =~ s/Informix:$RT::DatabaseName/Informix:/;
388     }
389     return $dsn;
390 }
391
392 sub insert_initial_data {
393
394     RT::InitLogging();
395
396     #connect to the db, for actual RT work
397     require RT::Handle;
398     $RT::Handle = RT::Handle->new();
399     $RT::Handle->Connect();
400
401     #Put together a current user object so we can create a User object
402     my $CurrentUser = new RT::CurrentUser();
403
404     print "Checking for existing system user...";
405     my $test_user = RT::User->new($CurrentUser);
406     $test_user->Load('RT_System');
407     if ( $test_user->id ) {
408         print "found!\n\nYou appear to have a functional RT database.\n"
409           . "Exiting, so as not to clobber your existing data.\n";
410         exit(-1);
411
412     }
413     else {
414         print "not found.  This appears to be a new installation.\n";
415     }
416
417     print "Creating system user...";
418     my $RT_System = new RT::User($CurrentUser);
419
420     my ( $val, $msg ) = $RT_System->_BootstrapCreate(
421         Name     => 'RT_System',
422         RealName => 'The RT System itself',
423         Comments =>
424 'Do not delete or modify this user. It is integral to RT\'s internal database structures',
425         Creator => '1',
426         LastUpdatedBy => '1',
427     );
428
429     unless ( $val ) {
430         print "$msg\n";
431         exit(-1);
432     }
433     print "done.\n";
434     $RT::Handle->Disconnect() unless $RT::DatabaseType eq 'SQLite';
435
436 }
437
438 # load some sort of data into the database
439
440 sub insert_data {
441     my $datafile = shift;
442
443     #Connect to the database and get RT::SystemUser and RT::Nobody loaded
444     RT::Init;
445
446     my $CurrentUser = RT::CurrentUser->new();
447     $CurrentUser->LoadByName('RT_System');
448
449     if ( $datafile eq $RT::EtcPath . "/initialdata" ) {
450
451         print "Creating Superuser  ACL...";
452
453         my $superuser_ace = RT::ACE->new($CurrentUser);
454         $superuser_ace->_BootstrapCreate(
455                              PrincipalId => ACLEquivGroupId( $CurrentUser->Id ),
456                              PrincipalType => 'Group',
457                              RightName     => 'SuperUser',
458                              ObjectType    => 'RT::System',
459                              ObjectId      => '1' );
460
461         print "done.\n";
462     }
463
464     # Slurp in stuff to insert from the datafile. Possible things to go in here:-
465     # @groups, @users, @acl, @queues, @ScripActions, @ScripConditions, @templates
466
467     require $datafile
468       || die "Couldn't find initial data for import\n" . $@;
469
470     if ( @Groups ) {
471         print "Creating groups...";
472         foreach $item (@Groups) {
473             my $new_entry = RT::Group->new($CurrentUser);
474             my ( $return, $msg ) = $new_entry->_Create(%$item);
475             print "(Error: $msg)" unless $return;
476             print $return. ".";
477         }
478         print "done.\n";
479     }
480     if ( @Users ) {
481         print "Creating users...";
482         foreach $item (@Users) {
483             my $new_entry = new RT::User($CurrentUser);
484             my ( $return, $msg ) = $new_entry->Create(%$item);
485             print "(Error: $msg)" unless $return;
486             print $return. ".";
487         }
488         print "done.\n";
489     }
490     if ( @Queues ) {
491         print "Creating queues...";
492         for $item (@Queues) {
493             my $new_entry = new RT::Queue($CurrentUser);
494             my ( $return, $msg ) = $new_entry->Create(%$item);
495             print "(Error: $msg)" unless $return;
496             print $return. ".";
497         }
498         print "done.\n";
499     }
500     if ( @ACL ) {
501         print "Creating ACL...";
502         for my $item (@ACL) {
503
504             my ($princ, $object);
505
506             # Global rights or Queue rights?
507             if ( $item->{'Queue'} ) {
508                 $object = RT::Queue->new($CurrentUser);
509                 $object->Load( $item->{'Queue'} );
510             } else {
511                 $object = $RT::System;
512             }
513
514             # Group rights or user rights?
515             if ( $item->{'GroupDomain'} ) {
516                 $princ = RT::Group->new($CurrentUser);
517                 if ( $item->{'GroupDomain'} eq 'UserDefined' ) {
518                   $princ->LoadUserDefinedGroup( $item->{'GroupId'} );
519                 } elsif ( $item->{'GroupDomain'} eq 'SystemInternal' ) {
520                   $princ->LoadSystemInternalGroup( $item->{'GroupType'} );
521                 } elsif ( $item->{'GroupDomain'} eq 'RT::System-Role' ) {
522                   $princ->LoadSystemRoleGroup( $item->{'GroupType'} );
523                 } elsif ( $item->{'GroupDomain'} eq 'RT::Queue-Role' &&
524                           $item->{'Queue'} )
525                 {
526                   $princ->LoadQueueRoleGroup( Type => $item->{'GroupType'},
527                                               Queue => $object->id);
528                 } else {
529                   $princ->Load( $item->{'GroupId'} );
530                 }
531             } else {
532                 $princ = RT::User->new($CurrentUser);
533                 $princ->Load( $item->{'UserId'} );
534             }
535
536             # Grant it
537             my ( $return, $msg ) = $princ->PrincipalObj->GrantRight(
538                                                      Right => $item->{'Right'},
539                                                      Object => $object );
540
541             if ( $return ) {
542                 print $return. ".";
543             }
544             else {
545                 print $msg . ".";
546
547             }
548
549         }
550         print "done.\n";
551     }
552     if ( @CustomFields ) {
553         print "Creating custom fields...";
554         for $item (@CustomFields) {
555             my $new_entry = new RT::CustomField($CurrentUser);
556             my $values    = $item->{'Values'};
557             delete $item->{'Values'};
558             my ( $return, $msg ) = $new_entry->Create(%$item);
559             unless( $return ) {
560                 print "(Error: $msg)\n";
561                 next;
562             }
563
564             foreach my $value ( @{$values} ) {
565                 my ( $eval, $emsg ) = $new_entry->AddValue(%$value);
566                 print "(Error: $emsg)\n" unless $eval;
567             }
568
569             if ( $item->{LookupType} && !exists $item->{'Queue'} ) { # enable by default
570                 my $ocf = RT::ObjectCustomField->new($CurrentUser);
571                 $ocf->Create( CustomField => $new_entry->Id );
572             }
573
574             print "(Error: $msg)\n" unless $return;
575             print $return. ".";
576         }
577
578         print "done.\n";
579     }
580
581     if ( @ScripActions ) {
582         print "Creating ScripActions...";
583
584         for $item (@ScripActions) {
585             my $new_entry = RT::ScripAction->new($CurrentUser);
586             my ($return,$msg) = $new_entry->Create(%$item);
587             unless ($return) {
588                 print "(Error: $msg)\n";
589                 exit;
590             }
591             print $return. ".";
592         }
593
594         print "done.\n";
595     }
596
597     if ( @ScripConditions ) {
598         print "Creating ScripConditions...";
599
600         for $item (@ScripConditions) {
601             my $new_entry = RT::ScripCondition->new($CurrentUser);
602             my ($return,$msg) = $new_entry->Create(%$item);
603             unless ($return) {
604                 print "(Error: $msg)\n";
605                 exit;
606             }
607             print $return. ".";
608         }
609
610         print "done.\n";
611     }
612
613     if ( @Templates ) {
614         print "Creating templates...";
615
616         for $item (@Templates) {
617             my $new_entry = new RT::Template($CurrentUser);
618             my $return    = $new_entry->Create(%$item);
619             print $return. ".";
620         }
621         print "done.\n";
622     }
623     if ( @Scrips ) {
624         print "Creating scrips...";
625
626         for $item (@Scrips) {
627             my $new_entry = new RT::Scrip($CurrentUser);
628             my ( $return, $msg ) = $new_entry->Create(%$item);
629             if ( $return ) {
630                 print $return. ".";
631             }
632             else {
633                 print "(Error: $msg)\n";
634             }
635         }
636         print "done.\n";
637     }
638     if ( @Attributes ) {
639         print "Creating predefined searches...";
640         my $sys = RT::System->new($CurrentUser);
641
642         for $item (@Attributes) {
643             my $obj = delete $item->{Object}; # XXX: make this something loadable
644             $obj ||= $sys;
645             my ( $return, $msg ) = $obj->AddAttribute (%$item);
646             if ( $return ) {
647                 print $return. ".";
648             }
649             else {
650                 print "(Error: $msg)\n";
651             }
652         }
653         print "done.\n";
654     }
655     $RT::Handle->Disconnect() unless $RT::DatabaseType eq 'SQLite';
656     print "Done setting up database content.\n";
657 }
658
659 =head2 ACLEquivGroupId
660
661 Given a userid, return that user's acl equivalence group
662
663 =cut
664
665 sub ACLEquivGroupId {
666     my $username = shift;
667     my $user     = RT::User->new($RT::SystemUser);
668     $user->Load($username);
669     my $equiv_group = RT::Group->new($RT::SystemUser);
670     $equiv_group->LoadACLEquivalenceGroup($user);
671     return ( $equiv_group->Id );
672 }
673
674 sub help {
675
676     print <<EOF;
677
678 $0: Set up RT's database
679
680 --action        init    Initialize the database
681                 drop    Drop the database.
682                         This will ERASE ALL YOUR DATA
683                 insert_initial 
684                         Insert RT's core system objects
685                 insert  Insert data into RT's database. 
686                         By default, will use RT's installation data.
687                         To use a local or supplementary datafile, specify it
688                         using the '--datafile' option below.
689
690                 acl     Initialize only the database ACLs
691                         To use a local or supplementary datafile, specify it
692                         using the '--datadir' option below.
693
694                 schema  Initialize only the database schema
695                         To use a local or supplementary datafile, specify it
696                         using the '--datadir' option below.
697
698 --datafile /path/to/datafile
699 --datadir /path/to/              Used to specify a path to find the local
700                                 database schema and acls to be installed.
701
702
703 --dba                           dba's username
704 --dba-password                  dba's password
705 --prompt-for-dba-password       Ask for the database administrator's password interactively
706
707
708 EOF
709
710 }
711
712 1;