Imported Upstream version 3.3.3
[debian/amanda] / perl / Amanda / Interactivity / tty.pm
1 # Copyright (c) 2010-2012 Zmanda, Inc.  All Rights Reserved.
2 #
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful, but
9 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11 # for more details.
12 #
13 # You should have received a copy of the GNU General Public License along
14 # with this program; if not, write to the Free Software Foundation, Inc.,
15 # 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 #
17 # Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
18 # Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
19
20 package Amanda::Interactivity::tty;
21
22 use strict;
23 use warnings;
24 use POSIX qw( :errno_h );
25 use vars qw( @ISA );
26 @ISA = qw( Amanda::Interactivity );
27
28 use Amanda::Paths;
29 use Amanda::Util;
30 use Amanda::Debug qw( debug );
31 use Amanda::Changer;
32 use Amanda::MainLoop qw( :GIOCondition );
33
34 =head1 NAME
35
36 Amanda::Interactivity::tty -- Interactivity class to read user request from /dev/tty
37
38 =head1 SYNOPSIS
39
40 Amanda::Interactivity class to write user request on /dev/tty and read reply
41 from /dev/tty.
42
43 =cut
44
45 sub new {
46     my $class = shift;
47     my $property = shift;
48
49     my $input;
50     my $output;
51     my $abort_message;
52
53     my $r = open($input, '<', "/dev/tty");
54     if (!$r) {
55         $abort_message = "Failed to open /dev/tty: $!";
56     } else {
57         $r = open($output, '>', "/dev/tty");
58         if (!$r) {
59             $abort_message = "Failed to open /dev/tty: $!";
60             close $input;
61             $input = undef;
62         }
63     }
64     my $self = {
65         input_src     => undef,
66         input         => $input,
67         output        => $output,
68         property      => $property,
69         abort_message => $abort_message,
70     };
71     return bless ($self, $class);
72 }
73
74 sub DESTROY {
75     my $self = shift;
76
77     close($self->{'input'})  if $self->{'input'};
78     close($self->{'output'}) if $self->{'output'};
79 }
80
81 sub abort {
82     my $self = shift @_;
83
84     if ($self->{'input_src'}) {
85         $self->{'input_src'}->remove();
86         $self->{'input_src'} = undef;
87     }
88 }
89
90 sub user_request {
91     my $self = shift @_;
92     my %params = @_;
93     my $buffer = "";
94
95     my $message    = $params{'message'};
96     my $label      = $params{'label'};
97     my $new_volume = $params{'new_volume'};
98     my $err        = $params{'err'};
99     my $chg_name   = $params{'chg_name'};
100
101     my $data_in = sub {
102         my $b;
103         my $n_read = POSIX::read(fileno($self->{'input'}), $b, 1);
104         if (!defined $n_read) {
105             return if ($! == EINTR);
106             $self->abort();
107             return $params{'request_cb'}->(
108                         Amanda::Changer::Error->new('fatal',
109                                 message => "Fail to read from /dev/tty"));
110         } elsif ($n_read == 0) {
111             $self->abort();
112             return $params{'request_cb'}->(
113                         Amanda::Changer::Error->new('fatal',
114                                 message => "Aborted by user"));
115         } else {
116             $buffer .= $b;
117             if ($b eq "\n") {
118                 my $line = $buffer;
119                 chomp $line;
120                 $buffer = "";
121                 $self->abort();
122                 return $params{'request_cb'}->(undef, $line);
123             }
124         }
125     };
126
127     if ($self->{'abort_message'}) {
128         return $params{'request_cb'}->(
129                         Amanda::Changer::Error->new('fatal',
130                                 message => $self->{'abort_message'}));
131     }
132
133     print {$self->{'output'}} "$err\n";
134     if ($label && $new_volume) {
135         print {$self->{'output'}} "Insert volume labeled '$label' or a new volume in $chg_name\n";
136     } elsif ($label) {
137         print {$self->{'output'}} "Insert volume labeled '$label' in $chg_name\n";
138     } else {
139         print {$self->{'output'}} "Insert a new volume in $chg_name\n";
140     }
141     print {$self->{'output'}} "and press <enter> enter, or ^D to abort.\n";
142
143     $self->{'input_src'} = Amanda::MainLoop::fd_source(
144                                                 fileno($self->{'input'}),
145                                                 $G_IO_IN|$G_IO_HUP|$G_IO_ERR);
146     $self->{'input_src'}->set_callback($data_in);
147     return;
148 }
149
150 1;