Imported both gpgdir and gpgwrap projects.
[pgp-tools.git] / gpgdir / install.pl
1 #!/usr/bin/perl -w
2 #
3 ####################################################################
4 #
5 # File: install.pl
6 #
7 # Purpose: To install gpgdir on a Linux system.
8 #
9 # Author: Michael Rash (mbr@cipherdyne.org)
10 #
11 # Copyright (C) 2002-2008 Michael Rash (mbr@cipherdyne.org)
12 #
13 # License (GNU Public License):
14 #
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
19 #
20 # You should have received a copy of the GNU General Public License
21 # along with this program; if not, write to the Free Software
22 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 # USA
24 #
25 ####################################################################
26 #
27 # $Id: install.pl 311 2008-08-31 23:11:12Z mbr $
28 #
29
30 use Cwd;
31 use File::Copy;
32 use Getopt::Long;
33 use strict;
34
35 #======================= config =======================
36 my $install_dir = '/usr/bin';
37 my $libdir = '/usr/lib/gpgdir';
38 my $manpage = 'gpgdir.1';
39
40 ### only used it $ENV{'HOME'} is not set for some reason
41 my $config_homedir = '';
42
43 ### system binaries
44 my $gzipCmd = '/usr/bin/gzip';
45 my $perlCmd = '/usr/bin/perl';
46 my $makeCmd = '/usr/bin/make';
47 #===================== end config =====================
48
49 my $print_help = 0;
50 my $uninstall = 0;
51 my $force_mod_re = '';
52 my $exclude_mod_re = '';
53 my $skip_module_install = 0;
54 my $cmdline_force_install = 0;
55 my $locale = 'C'; ### default LC_ALL env variable
56 my $no_locale = 0;
57 my $deps_dir = 'deps';
58
59 my %cmds = (
60 'gzip' => $gzipCmd,
61 'perl' => $perlCmd,
62 'make' => $makeCmd
63 );
64
65 ### map perl modules to versions
66 my %required_perl_modules = (
67 'Class::MethodMaker' => {
68 'force-install' => 0,
69 'mod-dir' => 'Class-MethodMaker'
70 },
71 'GnuPG::Interface' => {
72 'force-install' => 0,
73 'mod-dir' => 'GnuPG-Interface'
74 },
75 'Term::ReadKey' => {
76 'force-install' => 0,
77 'mod-dir' => 'TermReadKey'
78 }
79 );
80
81 ### make Getopts case sensitive
82 Getopt::Long::Configure('no_ignore_case');
83
84 &usage(1) unless (GetOptions(
85 'force-mod-install' => \$cmdline_force_install, ### force install of all modules
86 'Force-mod-regex=s' => \$force_mod_re, ### force specific mod install with regex
87 'Exclude-mod-regex=s' => \$exclude_mod_re, ### exclude a particular perl module
88 'Skip-mod-install' => \$skip_module_install,
89 'home-dir=s' => \$config_homedir, ### force a specific home dir
90 'LC_ALL=s' => \$locale,
91 'locale=s' => \$locale,
92 'no-LC_ALL' => \$no_locale,
93 'no-locale' => \$no_locale, ### synonym
94 'uninstall' => \$uninstall, # Uninstall gpgdir.
95 'help' => \$print_help # Display help.
96 ));
97 &usage(0) if $print_help;
98
99 ### set LC_ALL env variable
100 $ENV{'LC_ALL'} = $locale unless $no_locale;
101
102 $force_mod_re = qr|$force_mod_re| if $force_mod_re;
103 $exclude_mod_re = qr|$exclude_mod_re| if $exclude_mod_re;
104
105 ### check to see if we are installing in a Cygwin environment
106 my $non_root_user = 0;
107 if (&is_cygwin()) {
108
109 print
110 "[+] It looks like you are installing gpgdir in a Cygwin environment.\n";
111 $non_root_user = 1;
112
113 } else {
114
115 unless ($< == 0 && $> == 0) {
116 print
117 "[+] It looks like you are installing gpgdir as a non-root user, so gpgdir\n",
118 " will be installed in your local home directory.\n\n";
119
120 $non_root_user = 1;
121 }
122 }
123
124 if ($non_root_user) {
125
126 ### we are installing as a normal user instead of root, so see
127 ### if it is ok to install within the user's home directory
128 my $homedir = '';
129 if ($config_homedir) {
130 $homedir = $config_homedir;
131 } else {
132 $homedir = $ENV{'HOME'} or die '[*] Could not get home ',
133 "directory, set the $config_homedir var.";
134 }
135
136 print
137 " gpgdir will be installed at $homedir/bin/gpgdir, and a few\n",
138 " perl modules needed by gpgdir will be installed in $homedir/lib/gpgdir/.\n\n",
139
140 mkdir "$homedir/lib" unless -d "$homedir/lib";
141 $libdir = "$homedir/lib/gpgdir";
142 $install_dir = "$homedir/bin";
143 }
144
145 ### make sure we can find the system binaries
146 ### in the expected locations.
147 &check_commands();
148
149 my $src_dir = getcwd() or die "[*] Could not get current working directory.";
150
151 ### create directories, make sure executables exist, etc.
152 &setup();
153
154 print "[+] Installing gpgdir in $install_dir\n";
155 &install_gpgdir();
156
157 ### install perl modules
158 unless ($skip_module_install) {
159 for my $module (keys %required_perl_modules) {
160 &install_perl_module($module);
161 }
162 }
163 chdir $src_dir or die "[*] Could not chdir $src_dir: $!";
164
165 print "[+] Installing man page.\n";
166 &install_manpage();
167
168 print "\n It is highly recommended to run the test suite in the test/\n",
169 " directory to ensure proper gpgdir operation.\n",
170 "\n[+] gpgdir has been installed!\n";
171
172 exit 0;
173 #===================== end main =======================
174
175 sub install_gpgdir() {
176 die "[*] gpgdir does not exist. Download gpgdir from " .
177 "http://www.cipherdyne.org/gpgdir" unless -e 'gpgdir';
178 copy 'gpgdir', "${install_dir}/gpgdir" or die "[*] Could not copy " .
179 "gpgdir to $install_dir: $!";
180
181 if ($non_root_user) {
182 open F, "< ${install_dir}/gpgdir" or die "[*] Could not open ",
183 "${install_dir}/gpgdir: $!";
184 my @lines = <F>;
185 close F;
186 open P, "> ${install_dir}/gpgdir.tmp" or die "[*] Could not open ",
187 "${install_dir}/gpgdir.tmp: $!";
188 for my $line (@lines) {
189 ### change the lib dir to new homedir path
190 if ($line =~ m|^\s*use\s+lib\s+\'/usr/lib/gpgdir\';|) {
191 print P "use lib '", $libdir, "';\n";
192 } else {
193 print P $line;
194 }
195 }
196 close P;
197 move "${install_dir}/gpgdir.tmp", "${install_dir}/gpgdir" or
198 die "[*] Could not move ${install_dir}/gpgdir.tmp -> ",
199 "${install_dir}/gpgdir: $!";
200
201 chmod 0700, "${install_dir}/gpgdir" or die "[*] Could not set " .
202 "permissions on gpgdir to 0755";
203 } else {
204 chmod 0755, "${install_dir}/gpgdir" or die "[*] Could not set " .
205 "permissions on gpgdir to 0755";
206 chown 0, 0, "${install_dir}/gpgdir" or
207 die "[*] Could not chown 0,0,${install_dir}/gpgdir: $!";
208 }
209 return;
210 }
211
212 sub install_perl_module() {
213 my $mod_name = shift;
214
215 chdir $src_dir or die "[*] Could not chdir $src_dir: $!";
216 chdir $deps_dir or die "[*] Could not chdir($deps_dir): $!";
217
218 die '[*] Missing force-install key in required_perl_modules hash.'
219 unless defined $required_perl_modules{$mod_name}{'force-install'};
220 die '[*] Missing mod-dir key in required_perl_modules hash.'
221 unless defined $required_perl_modules{$mod_name}{'mod-dir'};
222
223 if ($exclude_mod_re and $exclude_mod_re =~ /$mod_name/) {
224 print "[+] Excluding installation of $mod_name module.\n";
225 return;
226 }
227
228 my $version = '(NA)';
229
230 my $mod_dir = $required_perl_modules{$mod_name}{'mod-dir'};
231
232 if (-e "$mod_dir/VERSION") {
233 open F, "< $mod_dir/VERSION" or
234 die "[*] Could not open $mod_dir/VERSION: $!";
235 $version = <F>;
236 close F;
237 chomp $version;
238 } else {
239 print "[-] Warning: VERSION file does not exist in $mod_dir\n";
240 }
241
242 my $install_module = 0;
243
244 if ($required_perl_modules{$mod_name}{'force-install'}
245 or $cmdline_force_install) {
246 ### install regardless of whether the module may already be
247 ### installed
248 $install_module = 1;
249 } elsif ($force_mod_re and $force_mod_re =~ /$mod_name/) {
250 print "[+] Forcing installation of $mod_name module.\n";
251 $install_module = 1;
252 } else {
253 if (has_perl_module($mod_name)) {
254 print "[+] Module $mod_name is already installed in the ",
255 "system perl tree, skipping.\n";
256 } else {
257 ### install the module in the /usr/lib/gpgdir directory because
258 ### it is not already installed.
259 $install_module = 1;
260 }
261 }
262
263 if ($install_module) {
264 unless (-d $libdir) {
265 print "[+] Creating $libdir\n";
266 mkdir $libdir, 0755 or die "[*] Could not mkdir $libdir: $!";
267 }
268 print "[+] Installing the $mod_name $version perl " .
269 "module in $libdir/\n";
270 my $mod_dir = $required_perl_modules{$mod_name}{'mod-dir'};
271 chdir $mod_dir or die "[*] Could not chdir to ",
272 "$mod_dir: $!";
273 unless (-e 'Makefile.PL') {
274 die "[*] Your $mod_name source directory appears to be incomplete!\n",
275 " Download the latest sources from ",
276 "http://www.cipherdyne.org/\n";
277 }
278 system "$cmds{'make'} clean" if -e 'Makefile';
279 system "$cmds{'perl'} Makefile.PL PREFIX=$libdir LIB=$libdir";
280 system $cmds{'make'};
281 # system "$cmds{'make'} test";
282 system "$cmds{'make'} install";
283 chdir $src_dir or die "[*] Could not chdir $src_dir: $!";
284
285 print "\n\n";
286 }
287 chdir $src_dir or die "[*] Could not chdir $src_dir: $!";
288 return;
289 }
290
291 sub has_perl_module() {
292 my $module = shift;
293
294 # 5.8.0 has a bug with require Foo::Bar alone in an eval, so an
295 # extra statement is a workaround.
296 my $file = "$module.pm";
297 $file =~ s{::}{/}g;
298 eval { require $file };
299
300 return $@ ? 0 : 1;
301 }
302
303 sub install_manpage() {
304
305 if ($non_root_user) {
306 print
307 "[+] Because this is a non-root install, the man page will not be installed\n",
308 " but you can download it here: http://www.cipherdyne.org/gpgdir\n\n";
309 return;
310 }
311
312 die "[*] man page: $manpage does not exist. Download gpgdir " .
313 "from http://www.cipherdyne.org/gpgdir" unless -e $manpage;
314 ### default location to put the gpgdir man page, but check with
315 ### /etc/man.config
316 my $mpath = '/usr/share/man/man1';
317 if (-e '/etc/man.config') {
318 ### prefer to install $manpage in /usr/local/man/man1 if
319 ### this directory is configured in /etc/man.config
320 open M, '< /etc/man.config' or
321 die "[*] Could not open /etc/man.config: $!";
322 my @lines = <M>;
323 close M;
324 ### prefer the path "/usr/share/man"
325 my $found = 0;
326 for my $line (@lines) {
327 chomp $line;
328 if ($line =~ m|^MANPATH\s+/usr/share/man|) {
329 $found = 1;
330 last;
331 }
332 }
333 ### try to find "/usr/local/man" if we didn't find /usr/share/man
334 unless ($found) {
335 for my $line (@lines) {
336 chomp $line;
337 if ($line =~ m|^MANPATH\s+/usr/local/man|) {
338 $mpath = '/usr/local/man/man1';
339 $found = 1;
340 last;
341 }
342 }
343 }
344 ### if we still have not found one of the above man paths,
345 ### just select the first one out of /etc/man.config
346 unless ($found) {
347 for my $line (@lines) {
348 chomp $line;
349 if ($line =~ m|^MANPATH\s+(\S+)|) {
350 $mpath = $1;
351 last;
352 }
353 }
354 }
355 }
356 mkdir $mpath, 0755 unless -d $mpath;
357 my $mfile = "${mpath}/${manpage}";
358 print "[+] Installing $manpage man page as: $mfile\n";
359 copy $manpage, $mfile or die "[*] Could not copy $manpage to " .
360 "$mfile: $!";
361 chmod 0644, $mfile or die "[*] Could not set permissions on ".
362 "$mfile to 0644";
363 chown 0, 0, $mfile or
364 die "[*] Could not chown 0,0,$mfile: $!";
365 print "[+] Compressing man page: $mfile\n";
366 ### remove the old one so gzip doesn't prompt us
367 unlink "${mfile}.gz" if -e "${mfile}.gz";
368 system "$cmds{'gzip'} $mfile";
369 return;
370 }
371
372 ### check paths to commands and attempt to correct if any are wrong.
373 sub check_commands() {
374 my @path = qw(
375 /bin
376 /sbin
377 /usr/bin
378 /usr/sbin
379 /usr/local/bin
380 /usr/local/sbin
381 );
382 CMD: for my $cmd (keys %cmds) {
383 unless (-x $cmds{$cmd}) {
384 my $found = 0;
385 PATH: for my $dir (@path) {
386 if (-x "${dir}/${cmd}") {
387 $cmds{$cmd} = "${dir}/${cmd}";
388 $found = 1;
389 last PATH;
390 }
391 }
392 unless ($found) {
393 die "[*] Could not find $cmd anywhere!!! ",
394 "Please edit the config section to include the path to ",
395 "$cmd.\n";
396 }
397 }
398 unless (-x $cmds{$cmd}) {
399 die "[*] $cmd is located at ",
400 "$cmds{$cmd} but is not executable by uid: $<\n";
401 }
402 }
403 return;
404 }
405
406 sub is_cygwin() {
407
408 my $rv = 0;
409
410 ### get OS output from uname
411 open UNAME, "uname -o |" or return $rv;
412 while (<UNAME>) {
413 $rv = 1 if /Cygwin/;
414 }
415 close UNAME;
416
417 return $rv;
418 }
419
420
421 sub setup() {
422 unless (-d $libdir) {
423 mkdir $libdir, 0755 or die "[*] Could not create $libdir: $!"
424 }
425 return;
426 }
427
428 sub usage() {
429 my $exit_status = shift;
430 print <<_HELP_;
431
432 Usage: install.pl [options]
433
434 -u, --uninstall - Uninstall gpgdir.
435 -f, --force-mod-install - Force all perl modules to be installed
436 even if some already exist in the system
437 /usr/lib/perl5 tree.
438 -F, --Force-mod-regex <re> - Specify a regex to match a module name
439 and force the installation of such modules.
440 -E, --Exclude-mod-regex <re> - Exclude a perl module that matches this
441 regular expression.
442 -S, --Skip-mod-install - Do not install any perl modules.
443
444 -L, --LANG <locale> - Specify LANG env variable (actually the
445 LC_ALL variable).
446 -h --help - Prints this help message.
447
448 _HELP_
449 exit $exit_status;
450 }