install.pl 8.95 KB
Newer Older
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
1
2
3
4
5
6
7
8
9
#!/usr/bin/perl

use 5.24.0;
use strict;
use warnings;
use Carp qw/croak/;
use Cwd qw(cwd);
use File::Path;
use File::Copy;
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
10
use File::Basename;
11
use Getopt::Long	qw(:config bundling);
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
12
use FindBin '$RealBin';
13
14

#--------------------------------------------------------------------
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
15
#  DATA
16
#--------------------------------------------------------------------
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
17
18
19
20

my $printers = {
    'copy3a' => {
        'model'    => 'TA4505ci',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
21
        'location' => 'Building A, 3th floor kitchen',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
22
23
    },
    'lj5c' => {
Martin Klimes (k11m1)'s avatar
cleanup    
Martin Klimes (k11m1) committed
24
        'model'    => 'hplj600',
25
        'location' => 'Building C, 5th floor',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
26
27
    },
    'lj4c' => {
Martin Klimes (k11m1)'s avatar
cleanup    
Martin Klimes (k11m1) committed
28
        'model'    => 'hplj600',
29
        'location' => 'Building C, 4th floor',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
30
31
    },
    'lj4p' => {
Martin Klimes (k11m1)'s avatar
cleanup    
Martin Klimes (k11m1) committed
32
        'model'    => 'hpljp4015x',
33
        'location' => 'Building B, 4th floor',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
34
35
    },
    'lj4a' => {
Martin Klimes (k11m1)'s avatar
cleanup    
Martin Klimes (k11m1) committed
36
        'model'    => 'hplj600',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
37
        'location' => 'Building A, 4th floor kitchen',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
38
39
    },
    'copy4a' => {
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
40
        'model'    => 'TA4505ci',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
41
42
43
44
        'location' => 'Building A, 4th floor kitchen',
    },
    'copy2a' => {
        'model'    => 'TA4505ci',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
45
        'location' => 'Building A, 2nd floor kitchen',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
46
47
    },
    'lj3a' => {
Martin Klimes (k11m1)'s avatar
cleanup    
Martin Klimes (k11m1) committed
48
        'model'    => 'hplj600',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
49
50
51
        'location' => 'Building A, 3th floor kitchen',
    },
    'lj2a' => {
Martin Klimes (k11m1)'s avatar
cleanup    
Martin Klimes (k11m1) committed
52
        'model'    => 'hplj600',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
53
        'location' => 'Building A, 2nd floor kitchen',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
54
55
56
    },
    'copy5c' => {
        'model'    => 'TA4505ci',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
57
        'location' => 'Building C, 5th floor',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
58
59
    },
    'lj3b' => {
Martin Klimes (k11m1)'s avatar
cleanup    
Martin Klimes (k11m1) committed
60
        'model'    => 'hpljp4515x',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
61
        'location' => 'Building B, 3th floor, kitchen',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
62
63
    },
    'lj-a302' => {
Martin Klimes (k11m1)'s avatar
cleanup    
Martin Klimes (k11m1) committed
64
        'model'    => 'hplj600',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
65
66
67
68
        'location' => 'Building A, 3th floor A302 LaSArIS',
    },
    'copy4c' => {
        'model'    => 'TA4505ci',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
69
        'location' => 'Building C, 4th floor',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
70
71
    },
    'lj2b' => {
Martin Klimes (k11m1)'s avatar
cleanup    
Martin Klimes (k11m1) committed
72
        'model'    => 'hpljp3015',
73
        'location' => 'Building B, 2nd floor kitchen',
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
74
75
76
77
78
    }
};

my $models = {
    'TA5007ci' => {
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
79
80
81
82
        'filters' => [
            '/usr/lib/cups/filter/kyofilter_pre_E',
            '/usr/lib/cups/filter/kyofilter_E',
        ],
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
83
84
    },
    'TA4505ci' => {
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
85
86
        'filters' => ['/usr/libexec/cups/filter/kyofilter_B',],
        'options' => ['Option19=One', 'Option21=True', 'Option17=DF730',],
87
    },
Martin Klimes (k11m1)'s avatar
cleanup    
Martin Klimes (k11m1) committed
88
    'hplj600' => {
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
89
        'options' => ['HPOption_Duplexer=True',],
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
90
91
    }
};
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
92

Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
93
94
95
96
#--------------------------------------------------------------------
#  Option processing
#--------------------------------------------------------------------

Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
97
98
99
100
101
102
my $options = {};

GetOptions($options, qw(update cron help|h|?));

if ($options->{usage} || (@ARGV != 1 && !$options->{cron})) {
    usage();
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
103
104
}

105
106
check_env();

Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
107
if ($options->{cron}) {
108
109
110
111
    check_cron();
    exit;
}

Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
112
113
114
#--------------------------------------------------------------------
#  Helper functions
#--------------------------------------------------------------------
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
115
116
117

sub get_description {
    my ($printer_name) = @_;
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
118
    return "$printer_name (FI MUNI)";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
119
120
121
}

sub prompt_username {
122
    print "Enter username: ";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
123
    chomp(my $username = <STDIN>);
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
124
    return $username;
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
125
126
127
}

sub prompt_password {
128
    print "Enter password: ";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
129
    system("stty -echo");
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
130
    chomp(my $password1 = <STDIN>);
Martin Klimes (k11m1)'s avatar
cleanup    
Martin Klimes (k11m1) committed
131
    system("stty echo");
132
    print "\nRepeat password: ";
Martin Klimes (k11m1)'s avatar
cleanup    
Martin Klimes (k11m1) committed
133
    system("stty -echo");
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
134
    chomp(my $password2 = <STDIN>);
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
135
136
    system("stty echo");
    print "\n";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
137

Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
138
    if ($password1 ne $password2) {
139
        die "[ERROR] Passwords do not match!";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
140
    }
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
141
    return $password1;
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
142
}
Martin Klimeš's avatar
Martin Klimeš committed
143
144
145
146
147
sub encode_uri {
    my ($source) = @_;
    $source =~ s/([^^A-Za-z0-9])/ sprintf "%%%02x", ord $1 /eg;
    return $source
}
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
148
149
sub get_url {
    my ($printer_name) = @_;
Martin Klimeš's avatar
Martin Klimeš committed
150
    my $user           = encode_uri(prompt_username());
151
    say "Warning! Password will be stored in plain text in /etc/cups/printers.conf";
152
    say "This is a limitation of the CUPS/SMB method. To exit press Ctrl + c.";
Martin Klimeš's avatar
Martin Klimeš committed
153
154
    my $password       = encode_uri(prompt_password());
    $printer_name = encode_uri($printer_name);
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
155

Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
156
    return "smb://NTFI\\${user}:${password}\@print.fi.muni.cz/$printer_name";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
157
158
}

Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
159
sub install_printer {
160
161
162
163
    my ($printer_name) = @_;
    my $url = get_url($printer_name);

    my $command = qq(lpadmin \\
Martin Klimeš's avatar
Martin Klimeš committed
164
    -p "${printer_name}\@fi" \\
165
166
167
168
169
170
171
    -D "${printer_name} (FI MUNI)" \\
    -L "$printers->{$printer_name}->{'location'}" \\
    -E \\
    -v "${url}" \\
    -P "ppds/${printer_name}.ppd" \\
    -o media-default=iso_a4_210x297mm \\
    -o sides-default=two-sided-long-edge \\
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
172
    -o auth-info-required=username,password);
173

174
    for my $option (
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
175
        @{$models->{$printers->{$printer_name}->{'model'}}->{'options'}})
176
    {
177
        $command .= " -o $option ";
178
179
    }

180
    system($command);
181
182
183
    if ($? != 0) {
        die "[ERROR] Could not install the printer via lpadmin";
    }
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
184
185

    return;
186
187
}

188
sub update_ppd {
189
    my ($printer_name) = @_;
190

191
    my $command = qq(lpadmin \\
Martin Klimeš's avatar
Martin Klimeš committed
192
    -p "${printer_name}\@fi" \\
193
    -P "ppds/${printer_name}.ppd" );
194

195
    system($command);
196
197
198
    if ($? != 0) {
        die "[ERROR] Could not update the ppd via lpadmin";
    }
199

200
    return;
201
202
}

Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
203
sub copy_filter {
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
204
    my ($path) = @_;
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
205

Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
206
    my ($filter, $destination, $suffix) = fileparse($path);
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
207
208

    # my $destination = "/usr/lib/cups/filter/";
209

Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
210
    if (!-d $destination) {
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
211
        my $dirs = eval { mkpath($destination) };
212
        die "[ERROR] Failed to create $destination $@\n" unless $dirs;
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
213
214
    }

Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
215
    copy("filters/" . $filter, $destination)
216
      or die "[ERROR] Failed to copy $filter: $!\n";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
217
218
    say "[OK] Copied $filter.";

Martin Klimes (k11m1)'s avatar
cleanup    
Martin Klimes (k11m1) committed
219
    chmod 0755, $destination . $filter;
220

Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
221
222
    return;
}
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
223

224
sub print_printers {
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
225
    say "Available printers:";
226
227
    printf "%-14s | %-12s| %s\n", "Printer name", "Model", "Location";
    say "-" x 70;
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
228
    for (sort keys %$printers) {
229
230
        printf "%-14s | %-12s| %s\n", $_, $printers->{$_}->{'model'},
          $printers->{$_}->{'location'};
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
231
    }
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
232
    return;
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
233
234
}

235
sub usage {
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
236
237
    print <<END;
Script for installing faculty printers on Linux via Samba print server.
238
usage: $0 {--cron | [--update] <printer-name>}
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
239
240
241
242
243
244
245
246

Requires local CUPS server running and Samba client installed.
Must be run as root.
Option --update only updates installed printer.
Option --cron only prompts for cron installation.

END

Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
247
248
249
250
251
252
    print_printers();

    exit 1;
}

sub check_python {
253
    my $regex  = qr/^Python 2\.7*/;
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
254
    my $output = qx/python -V 2>&1/;
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
255

Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
256
    if ($? == 0 && $output =~ $regex) {
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
257
        say "[OK] Python 2.7 is present.";
258
        return "python";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
259
    }
260
261
262
263

    say "[ERROR] Python 2.7 is not present";

    my $s_output = qx/python2 -V 2>&1/;
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
264
    if ($? == 0 && $s_output =~ $regex) {
265
        say "[OK] Python 2.7 is present as python2";
266
        return "python2";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
267
    }
268
269

    die "[ERROR] Python 2.7 Not Found and is needed for TA5007ci\n";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
270
271
272
}

sub python_package {
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
273
    my ($package_name, $python) = @_;
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
274

275
    say "[INFO] Installing $package_name...";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
276
    my $status = chdir "$package_name";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
277
    if ($status == 0) {
278
        die "[ERROR] folder $package_name is not present!";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
279
280
    }
    my $output = system("${python} setup.py install");
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
281
    if ($? != 0) {
282
        die "[ERROR] $package_name exited with different exit code than 0!";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
283
284
    }
    $status = chdir '..';
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
285
    if ($status == 0) {
286
        die "[ERROR] Could not return to the working directory!";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
287
    }
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
288
    return;
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
289
290
}

291
sub pre_TA5007ci {
292
    my $python = check_python();
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
293
294
    python_package("PyPDF2-1.26.0", $python);
    python_package("reportlab",     $python);
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
295
    return;
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
296
297
}

Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
298
sub check_cron {
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
299
    if (! -e "/etc/cron.weekly/fi_printers_cron") {
300
        print "Do you want to enable automatic updates via cron? [Y/n] ";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
301
302
303

        chomp(my $answer = <STDIN>);
        if ($answer eq 'Y' || $answer eq 'y' || $answer eq '') {
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
304
            print "[INFO] Installing cron.\n";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
305
306
307
308

            copy("$RealBin/cron.pl", "/etc/cron.weekly/fi_printers_cron")
                or die "[ERROR] Could not copy cron script\n";
            chmod 0700, "/etc/cron.weekly/fi_printers_cron";
309
            say "[INFO] Cron installed";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
310
        }
311
312
313
314
315
316
317
318
319
    } else {
        say "[INFO] Cron is already installed.";
    }
}

sub check_env {
    # Check for smbclient
    my $output = `which smbclient &>/dev/null`;
    if ($? != 0) {
320
        die "[ERROR] Samba client seems not to be installed. (smbclient)";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
321
    }
322
323
324

    # Check if we don't have Root
    die "[ERROR] Must be run with root privileges\n" if $> != 0;
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
325
}
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
326
327
328
#--------------------------------------------------------------------
#  Start of the script
#--------------------------------------------------------------------
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
329

Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
330
my ($printer_name) = @ARGV;
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
331

Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
332
if (not(exists($printers->{$printer_name}))) {
333
    say "[ERROR] Printer $printer_name is not supported.";
334
    print_printers();
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
335
    exit 1;
336
}
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
337
338
339


my $model = $printers->{$printer_name}->{'model'};
340
say "[INFO] Selected model is $model";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
341

342
#TA5007ci requires python2 reportlab and PyPDF2
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
343
if ($model eq "TA5007ci") {
Martin Klimes (k11m1)'s avatar
cleanup    
Martin Klimes (k11m1) committed
344
    pre_TA5007ci;
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
345
346
}

Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
347
348
for my $filter (@{($models->{$model} // {})->{filters} // []}) {
    copy_filter($filter);
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
349
}
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
350
if ($options->{update}) {
351
352
    update_ppd("$printer_name");
    say "[INFO] Update of $printer_name is completed.";
353
354
}
else {
355
356
    install_printer("$printer_name");
    say "[INFO] Installation of $printer_name is completed.";
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
357
    check_cron();
358
}
Martin Klimes (k11m1)'s avatar
Martin Klimes (k11m1) committed
359