X-Git-Url: https://git.gag.com/?a=blobdiff_plain;ds=sidebyside;f=perl%2FAmanda%2FDevice.pm;h=11a3c89a5bce06554a690f7c2f82863c7379cfee;hb=fd48f3e498442f0cbff5f3606c7c403d0566150e;hp=432d2f3847165ca93391b88656457eddb08febe2;hpb=96f35b20267e8b1a1c846d476f27fcd330e0b018;p=debian%2Famanda diff --git a/perl/Amanda/Device.pm b/perl/Amanda/Device.pm index 432d2f3..11a3c89 100644 --- a/perl/Amanda/Device.pm +++ b/perl/Amanda/Device.pm @@ -7,7 +7,7 @@ package Amanda::Device; use base qw(Exporter); use base qw(DynaLoader); -require Amanda::Types; +require Amanda::Header; package Amanda::Devicec; bootstrap Amanda::Device; package Amanda::Device; @@ -50,8 +50,48 @@ sub this { package Amanda::Device; +*unaliased_name = *Amanda::Devicec::unaliased_name; +*rait_device_open_from_children = *Amanda::Devicec::rait_device_open_from_children; *IS_WRITABLE_ACCESS_MODE = *Amanda::Devicec::IS_WRITABLE_ACCESS_MODE; +############# Class : Amanda::Device::DirectTCPConnection ############## + +package Amanda::Device::DirectTCPConnection; +use vars qw(@ISA %OWNER %ITERATORS %BLESSEDMEMBERS); +@ISA = qw( Amanda::Device ); +%OWNER = (); +%ITERATORS = (); +sub DESTROY { + return unless $_[0]->isa('HASH'); + my $self = tied(%{$_[0]}); + return unless defined $self; + delete $ITERATORS{$self}; + if (exists $OWNER{$self}) { + Amanda::Devicec::delete_DirectTCPConnection($self); + delete $OWNER{$self}; + } +} + +*close = *Amanda::Devicec::DirectTCPConnection_close; +sub new { + my $pkg = shift; + my $self = Amanda::Devicec::new_DirectTCPConnection(@_); + bless $self, $pkg if defined($self); +} + +sub DISOWN { + my $self = shift; + my $ptr = tied(%$self); + delete $OWNER{$ptr}; +} + +sub ACQUIRE { + my $self = shift; + my $ptr = tied(%$self); + $OWNER{$ptr} = 1; +} + + ############# Class : Amanda::Device::queue_fd_t ############## package Amanda::Device::queue_fd_t; @@ -132,6 +172,14 @@ sub DESTROY { *seek_block = *Amanda::Devicec::Device_seek_block; *read_block = *Amanda::Devicec::Device_read_block; *read_to_fd = *Amanda::Devicec::Device_read_to_fd; +*erase = *Amanda::Devicec::Device_erase; +*eject = *Amanda::Devicec::Device_eject; +*directtcp_supported = *Amanda::Devicec::Device_directtcp_supported; +*listen = *Amanda::Devicec::Device_listen; +*accept = *Amanda::Devicec::Device_accept; +*use_connection = *Amanda::Devicec::Device_use_connection; +*write_from_connection = *Amanda::Devicec::Device_write_from_connection; +*read_to_connection = *Amanda::Devicec::Device_read_to_connection; *property_list = *Amanda::Devicec::Device_property_list; *property_get = *Amanda::Devicec::Device_property_get; *property_set = *Amanda::Devicec::Device_property_set; @@ -143,6 +191,7 @@ sub DESTROY { *device_name = *Amanda::Devicec::Device_device_name; *access_mode = *Amanda::Devicec::Device_access_mode; *is_eof = *Amanda::Devicec::Device_is_eof; +*is_eom = *Amanda::Devicec::Device_is_eom; *volume_label = *Amanda::Devicec::Device_volume_label; *volume_time = *Amanda::Devicec::Device_volume_time; *status = *Amanda::Devicec::Device_status; @@ -220,6 +269,7 @@ package Amanda::Device; @EXPORT_OK = (); %EXPORT_TAGS = (); + =head1 NAME Amanda::Device - interact with Amanda data-storage devices @@ -232,117 +282,708 @@ Amanda::Device - interact with Amanda data-storage devices if ($dev->read_label() == $DEVICE_STATUS_SUCCESS) { print "Label on $device_name is '$dev->volume_label'\n"; } - -See http://wiki.zmanda.com/index.php/Device_API for details on how Devices are used. -=head1 API STATUS +=head1 DATA MODEL + +A volume is a container for data which can be "loaded" into a particular +device. For tape devices, a volume is a tape, but most other devices do not +deal with such physical objects. Each volume has a volume header giving, among +other things, the label of the volume and the timestamp on which it was +written. The header may also indicate that the volume is not an Amanda volume. +Aside from the header, a volume contains a sequence of files, numbered starting +at 1. While writing, devices number files sequentially, but devices that +support partial volume recycling may have "holes" in the sequence of file +numbers where files have been deleted. The C method, below, +describes how the API represents this situation. Each file has a header, too, +which contains lots of information about the file. See L for +the full list. After the header, a file is just a sequence of bytes. + +Reads and writes to devices take place in blocks. Unlike a typical +operating-system file, in which any block boundaries are lost after the file is +written, devices must be read back with the block sizes that were used to read. +See C for more in block sizes, and the read_block and +write_block sections, below, for more information. + +=head1 USING THE DEVICE API + +The Device API is object-oriented, so the first task in using the API is to +make a Device object: + + $dev = Amanda::Device->new("tape:/dev/nst0"); + +This function takes a device name (possibly a device alias) and returns a +device object. This function always returns a Device, although it may be a Null +device with an error condition. Any C call should be followed by a check +of the device's status: + + $dev = Amanda::Device->new($device_name); + if ($dev->status() != $Amanda::Device::DEVICE_STATUS_SUCCESS) { + die "Could not open '$device_name': " . $dev->error(); + } + +This function does not access the underlying hardware or any other external +systems in any way: that doesn't happen until C or C. An +Amanda configuration must be loaded when this function is called, as it +searches the configuation for device definitions. The member variable +C is set when this function has returned. + +It is unusual for higher-level code to call C<< Amanda::Device->new >>. +Intead, use L to load a volume and reserve access to it; the +resulting reservation will contain an already-created Device object. + +While Amanda proivdes multiple implementations of the Device class, they are +not distinguishable via the usual Perl methods (C or C<< $dev->isa >>). + +Device users generally call device methods in the following order for reading: + + read_label (optional) + start + seek_file (optional) + read_block (repeated) + +or, when writing or appending: + + read_label (optional) + start + start_file + write_block (repeated) + finish_file + finish + +=head2 Alternate Constructor + +To create a new RAIT device from a collection of device objects, call +C<< Amanda::Device->new_rait_from_children($child1, $child2, ..) >>. +If one of the child objects is C, the resulting RAIT device +will operate in degraded mode. + +=head2 Error Handling + +Device methods return a particular value to signal the presence of an error +condition. In many cases, this is simply false (exceptions are listed below). + +When a device signals an error, C<< $dev->status >> and C<< $dev->error >> +contain details of what went wrong. Status is a bitfield where each bit that is +set indicates a possible problem. Unfortunately, some devices are unable to +distinguish states due to limitations of an external system. For example, the +tape device often cannot distinguish an empty drive +(C<$DEVICE_STATUS_VOLUME_MISSING>) from a hard device error +(C<$DEVICE_STATUS_DEVICE_ERROR>), leading to the status +C<$DEVICE_STATUS_VOLUME_MISSING>|C<$DEVICE_STATUS_DEVICE_ERROR>. To be clear: +as few as one of the status bits may represent a actual problem. If +C<$DEVICE_STATUS_VOLUME_UNLABELED> is set along with other bits, it is I +safe to assume that an unlabeled volume is available. However, if the bit is +not set, then it is safe to assume there is no unlabeled volume present. + +=over 2 + +=item C<$DEVICE_STATUS_SUCCESS> + +All OK (no bits set) + +=item C<$DEVICE_STATUS_DEVICE_ERROR> -Stable +The device is in an unresolvable error state, and further retries are unlikely +to change the status -=head1 Amanda::Device Objects +=item C<$DEVICE_STATUS_DEVICE_BUSY> -See the wiki for descriptions of these functions. Note that C instance variables -are represented by accessor functions of the same name. +The device is in use, and should be retried later -=over +=item C<$DEVICE_STATUS_VOLUME_MISSING> -=item C +The device itself is OK, but has no media loaded. This may change if media is +loaded by the user or a changer -=item C +=item C<$DEVICE_STATUS_VOLUME_UNLABELED> -=item C +The device is OK and media is laoded, but there is no Amanda header or an +invalid header on the media. -=item C +=item C<$DEVICE_STATUS_VOLUME_ERROR> -=item C +The device is OK, but there was an unresolvable error loading the header from +the media, so subsequent reads or writes will probably fail. -where C<$jobinfo> is a C (see L) +=back + +At the risk of being repetitive, never test a device's status with C<==>, +unless it is to C<$DEVICE_STATUS_SUCCESS>. Furthermore, never try to parse the +device error messages -- they are only for user consumption, and may differ +from device to device. + +In addition to the status bitfield, a Device also provides a +user-comprehensible error message, available from the methods C +(returning the error message), C (returning the string form of +the status), or C (returning the error message if one is set, +otherwise the string form of the status). None of these functions will ever +return C. + +=head2 Properties + +Device properties provide a bidirectional means of communication between +devices and their users. A device provides values for some properties, which +other parts of Amanda can use to adjust their behavior to suit the device. For +example, Amanda will only attempt to append to a volume if the device's +properties indicate that it supports this activity. Some devices have +additional properties that can be set to control its activity. For example, the +S3 Device requires that the users' keys be given via properties. + +See C for more information on device properties and their +meanings. + +The methods C and C are used to get and set +properties, respectively. If the indicated property simply does not exist, +these functions return an error indication (FALSE), but the device's status +remains C<$DEVICE_STATUS_SUCCESS>. If a more serious error occurs, then the +device's status is set appropriately. + +Device properties are easy to handle, as the Perl-to-C glue takes care of all +necessary type conversions: + + $success = $device->property_set("BLOCK_SIZE", $blocksize); + $blocksize = $device->property_get("BLOCK_SIZE"); + +If C is called in an array context, it returns the property +value, its surety, and its source, in that order. If there is an error +fetching the property, C returns C. + +The C method returns a list of all properties: + + my @props = $device->property_list(); + +its return is an array of hashes: + + ( { 'access' => $access_flags, + 'name' => $property_name, + 'description' => $property_description }, + ... + ) + +=head3 Surety and Source + +All properties have a source - where the value came from - and surety - a level +of confidence in the value. This can be used to decide which of two potentially +contradictory properties to believe. For example, the RAIT device examines the +source and surety of child devices' block sizes, prefering properties set by +the user (C<$PROPERTY_SOURCE_USER>) over others. + +Set a property's source and surety with C: + $dev->property_set_ex("my_prop", 13, $PROPERTY_SURETY_BAD, $PROPERTY_SOURCE_DEFAULT); +The surety and source are returned after the property value in list context: + my ($val, $sur, $sou) = $dev->property_get("my_prop"); + +The available sureties are: + + $PROPERTY_SURETY_GOOD + $PROPERTY_SURETY_BAD + +and the sources are: + + $PROPERTY_SOURCE_DEFAULT + $PROPERTY_SOURCE_DETECTED + $PROPERTY_SOURCE_USER + +=head2 Concurrency + +Some devices can perform more than one operation simultaneously, while others +are more limited. For example, a tape device is exclusive to a single process +while it is in use, while a VFS device can support concurrent reads and writes +on the same volume. + +As of this writing, device locking is not correctly implemented in many +devices; consult the source code and check with the Amanda developers before +depending on concurrent operation of devices. + +=head2 EOM and EOF + +When writing to a volume, an EOM (end-of-media) condition occurs when no more +space is available on the volume. Some devices (currently only those +supporting DirectTCP) distinguish a logical EOM (LEOM) from a physical EOM +(PEOM). The logical EOM comes some distance before the physical EOM, with +enough space left to finish a data block and write any additional bookkeeping +data before PEOM. -=item C +In such devices, the C attribute is set once LEOM is detected. Such +detection can happen in any method that writes to the volume, including +C, C, C, and C. API users that +understand LEOM should take this as a signal to complete writing to the device +and move on before hitting PEOM. -Note that Perl code is not expected to handle on-device data, so there -is currently no way to provide data to this function from Perl. This may -change in future revisions. +Devices which do not support EOM simply return a VOLUME_ERROR when the volume +is full. If this occurs during a C operation, then the volume may +or may not contain the block - the situation is indeterminate. -=item C +=head2 Device Resources -where C<$fd> is an integer file descriptor, not a filehandle +Some device types have a "locking" mechanism that prevents other parts of the +system from accessing the underlying resource while an operation is in +progress. For example, a typical UNIX tape driver cannot be opened by two +processes at once. -=item C +Amanda Devices will lock the underlying resource when C or C +is called, and unlock the resource either when the Device object is +garbage-collected or in the C method. Thus in a calling sequence such as -=item C + read_label + start + seek_file + ... + finish -=item C +the underlying resource remains locked for the entire sequence, even between +read_label and finish. -=item C +It is unwise to rely on Perl's garbage-collection to automatically release +resources. Instead, always explicitly release resources with a C call. +The Changer API is careful to do this in its C method. -=item C +=head2 Member Variables -where C<$fd> is an integer file descriptor, not a filehandle +All member variables are implemented using accessor methods, rather than the +more common hashref technique. Use -Note that Perl code is not expected to handle on-device data, so there -is currently no way to access the data this function returns. This may -change in future revisions. + print $dev->device_name, "\n"; -=item C +instead of -returns a list of properties, each represented as a hash: + print $dev->{'device_name'}, "\n"; - { 'access' => $access_flags, - 'name' => $property_name, - 'description' => $property_description } +The member variables are: -=item C +=over 4 -returns the property, with the appropriate Perl type, or undef. In array -context, returns the list C<($value, $surety, $source)>. +=item C -=item C +the current file number, if any -=item C +=item C -where C<$value> is of an appropriate type for the given property, C<$surety> is -a C<$PROPERTY_SURETY_*> constant, and C<$source> is a C<$PROPERTY_SOURCE_*> -constant. +the current block number, if any -=item C +=item C -=item C (accessor function) +true if the device is in the middle of reading or writing a file -=item C (accessor function) +=item C -=item C (accessor function) +the name with which the device was constructed; note that this is not set until after open_device is finished -- it is an error to access this variable in an open_device implementation -=item C (accessor function) +=item C -=item C (accessor function) +the current access mode (C<$ACCESS_NULL>, or that supplied to start) -=item C (accessor function) +=item C -=item C (accessor function) +true if an EOF occurred while reading; also used by C -=item C (accessor function) +=item C -=item C (accessor function) +true if a write operation reached the end of the volume (end-of-medium) -=item C (accessor function) +=item C -=item C (accessor function) +the label of the current volume, set by start and read_label -=item C (accessor function) +=item C + +the timestamp of the current volume, set by start and read_label + +=item C + +the header of the current volume, set by read_label + +=item C + +the device's error status (bit flags) as an integer + +=item C + +the device's error status (bit flags) as a string + +=item C + +the device's error message + +=item C + +the device's error message, if set, otherwise the same as C -- +use this to display error messages from devices + +=item C + +the device's currently configured block size. This is also available via the +BLOCK_SIZE property. Writers should use block_size-byte blocks, and readers +should initially use block_size, and expand buffers as directed by +C. + +=item C + +minimum allowed block size for this device + +=item C + +maximum allowed block size for this device =back -=head1 CONSTANTS +=head2 Object Methods + +=head3 configure($use_global_config) + + $dev->configure(1); + +Once you have a new device, you should configure it. This sets properties on +the device based on the user's configuation. If C<$use_global_config> is true, +then any global C parameters are processed, along with +tapetype and other relevant parameters. Otherwise, only parameters from the +device definition (if the device was opened via an alias) are processed. + +This method is I. All access to Devices should be via the Changer +API (see L), which implements its own, more advanced method of +configuring devices. The C method may be removed in a future +release. + +=head3 read_label + + $status = $dev->read_label(); + +This function reads the tape header of the current volume, returning the +Device's status (see "Error Handling", above). Since this is often the first +function to accses the underlying hardware, its error status is the one most +often reported to the user. In fact, C is little more than a +wrapper around read_label. + +The method sets the following member variables: -This module defines a large number of constants. Again, consult the -wiki or C for the details on their meaning. These constants -are available from the package namespace (e.g., -C), or imported with the C<:constant> -import tag. +=over 4 + +=item C + +if any header data was read from the volume, it is represented here. The +header's type may be F_WEIRD if the header was not recognized by Amanda. + +=item C + +if read_label read the header successfully, then volume_label contains the +label + +=item C + +smililarly, if read_label read the header successfully, then volume_time +contains the timestamp from the header + +=back + +=head3 start + + $succss = $dev->start($ACCESS_WRITE, $label, $timestamp); + +Start starts the device and prepares it for the use described by its second +parameter. This function can be called regardless of whether C has +already been called. + +If the access mode is C<$ACCESS_WRITE>, then the label and timestamp must be +supplied (although leaving the timestamp undef will use the current time), and +they will be used to write a new volume header. Otherwise, these parameters +should be undef. + +On completion, start leaves the device's C, C and +C member variables set, by reading the tape header if necessary. +Note that in mode C<$ACCESS_APPEND>, the C member variable is not set +until after C has been called. + +=head3 start_file + + $success = $dev->start_file($header); + +This method prepares the device to write data into a file, beginning by writing +the supplied header to the volume. On successful completion, the device's +C is set to the current file number, C is zero, and C is +true. If the volume is out of space, the C member is set to true and +the method returns false with status C. + +=head3 write_block + + # (not available from Perl) + success = device_write_block(dev, blocksize, buf); + +This method writes a single block of data to the volume. It is only available +from C -- Perl code should not be handling raw data, as it is far too slow. +Use the transfer architecture (L) for that purpose. + +The C must be the device's block size, unless +this is a short write. A short write must be the last block +of a file. Some devices will zero-pad a short write to a full +blocksize. This method returns false on error. If the volume is +out of space, C is set and the method returns false with +status C. Note that not all devices can +differentiate an EOM condition from other errors; these devices will +set C whenever the situation is ambiguous. + +This function ensures that C is correct on exit. Even in an +error condition, it does not finish the current file for the caller. + +=head3 write_from_fd (DEPRECATED) + + my $qfd = Amanda::Device::queue_fd_t->new(fileno($fh)); + if (!$dev->write_from_fd($fd)) { + print STDERR $qfd->{errmsg}, "\n" if ($qfd->{errmsg}); + print STDERR $dev->status_or_error(), "\n" if ($dev->status()); + } + +This method reads from the given file descriptor until EOF, writing the data to +a Device file which should already be started, and not returning until the +operation is complete. The file is not automatically finished. This method is +deprecated; the better solution is to use the transfer architecture +(L). + +This is a virtual method, but the default implementation in the Device class +uses C, so there is no need for subclasses to override it. + +=head3 finish_file + + $success = $dev->finish_file(); + +Once an entire file has been written, finish_file performs any +cleanup required on the volume, such as writing filemarks. On exit, +C is false. If the device runs out of space while finishing +(e.g., the filemark does not fit), then this method returns false +with status C and C is set. + +This function should not be used while reading -- instead, just seek +to the next file. + +=head3 seek_file + + $header = $dev->seek_file($fileno); + +In C<$ACCESS_READ>, C sets up the device to read from file +C<$fileno>. This function is not available in C<$ACCESS_WRITE> and +C<$ACCESS_APPEND>. It returns the header from the requested file on success, or +undef on error. + +If the requested file doesn't exist, as might happen when a volume has had +files recycled, then C will seek to the next file that does exist. The +file this function selected is indicated by the C member variable on exit. +If the requested file number is exactly one more than the last valid file, this +function returns a C<$F_TAPEEND> header. + +As an example, on a volume with only files 1 and 3: + + $dev->seek_file(1) returns header for file 1, $dev->file == 1 + $dev->seek_file(2) returns header for file 3, $dev->file == 3 + $dev->seek_file(3) returns header for file 3, $dev->file == 3 + $dev->seek_file(4) returns a tapend header, $dev->file == 4 + $dev->seek_file(5) returns NULL/undef + +On exit, C is false, C is true unless no file was found (tapeend or NULL), C is the discovered file, and C is zero. + +=head3 seek_block + + $success = $dev->seek_block($block); + +After seeking to a file, the caller can optionally seek to a particular block +in the file. This function will set C appropriately. Note that it may +not be possible to detect EOF, so this function may fail to set C even +though a subsequent C will return no data. + +=head3 read_block + + # (not available from Perl) + bytes_read = device_read_block(dev, buffer, *blocksize); + +This method is the complement of C, and reads the next block from +the device, or returns -1 on error. Pass a buffer and its size. If the buffer +is not big enough, no read is performed, the parameter C is set to +the required blocksize, and the method returns 0. As a special case, passing a +C buffer and C<*blocksize == 0> is treated as a request for the required block +size. It is not an error to pass a buffer that is too large (and, in fact, this +is precisely the effect of setting the C configuration +parameter). + +On EOF, this method returns -1, but sets C and leaves the device's +status set to C<$DEVICE_STATUS_SUCCESS>. Some devices may be able to detect EOF +while reading the last block, and will set C at that time. Others must +wait for the next read to fail. It is never an error to call C +after an EOF, so there is no need to check C except when C +returns -1. + +=head3 read_to_fd (DEPRECATED) + + queue_fd_t *qfd = queue_fd_new(fd, NULL); + my $qfd = Amanda::Device::queue_fd_t->new(fileno($fh)); + if (!$dev->read_to_fd($fd)) { + print STDERR $qfd->{errmsg}, "\n" if ($qfd->{errmsg}); + print STDERR $dev->status_or_error(), "\n" if ($dev->status()); + } + +This method reads the current file from the device and writes to the given file +descriptor, not returning until the operation is complete. This method is +deprecated; new uses of devices use the transfer architecture +(L). + +This is a virtual method, but the default implementation in the Device class +uses C, so there is no need for subclasses to override it. + +=head3 finish + + $success = $dev->finish(); + +This undoes the effects of start, returning the device to a neutral state +(C<$ACCESS_NULL>). It will also release any resources acquired by +C, even if C was not called. After C, it is not an +error to call C again, even with a different mode. + +=head3 recycle_file + + $success = $dev->recycle_file(fileno); + +On devices that support it, this removes the indicated file from the volume, +presumably freeing its space to be used for other files. File numbers of +existing files will not change, so this operation may leave "holes" in the +sequence of file numbers. See C to see how this is handled. + +This method cannot be called while in a file, nor while in C<$ACCESS_READ> +mode. + +=head3 erase + + $success = $dev->erase(fileno); + +On devices that support it, this erases all data from the volume, presumably +freeing the space. This method must be called before start and after finish -- +that is, while the device is in a neutral state (C<$ACCESS_NULL>). You can +detect whether or not this operation is supported using the C +property. + +=head3 eject + + $success = $dev->eject(); + +On devices that support it, this eject the volume. This method can be called +before start and after finish. + +=head3 directtcp_supported + + $supp = $dev->directtcp_supported(); + +This method returns TRUE if the DirectTCP-related methods (C, +C, C, and C) are implemented +by this device. + +=head3 listen + + $addrs = $dev->listen($for_writing); + +The C method starts the device listening for an incoming DirectTCP +connection. The method returns a set of IP:PORT pairs to which a TCP +connection can be made. The boolean C is TRUE if +this connection will be used to write to the device. + +This method can be called at any time, but between the time C is called +and when C returns, no other methods of the device should be called. + +The return value might look like: + + $addrs = [ [ "127.0.0.1", 9382 ] ] + +In C, the memory for these addresses remains the responsibility of the device, +and will remain unchanged until C returns. + +=head3 accept + + $conn = $dev->accept(); + +This method accepts a connection to one of the addresses returned by C, +returning an established DirectTCPConnection object (see below). It returns +C on failure. Note that this method may block indefinitely if no +connection ever occurs. The C implementation returns an already-referenced +connection object, so the caller should call C when the +connection is no longer needed. + +=head3 use_connection + + my $ok = $dev->use_connection($conn); + +Call this method to use a DirectTCPConnection object created with another +device. The method must be called before the device is started (so +C is C<$ACCESS_NULL>), as some devices cannot support switching +connections without rewinding. Any subsequent C or +C calls will use this connection. + +=head3 write_from_connection + + ($ok, $actual_size) = $dev->write_from_connection($size); + +This method reads data from the DirectTCPConnection specified with +C or returned from C and writes it to the volume. It +writes at most C<$size> bytes, and returns the number of bytes written in +C<$actual_size>. On error, C<$ok> is false. + +When an EOF is received over the connection, signalling the end of the data +stream, then this method returns without error (C<$ok> is true), with +C<$actual_size> indicating the number of bytes written to the device (which may +be zero). In this case, the C attribute is true on return. + +Similarly, when the device encounters logical EOM in this method, it returns +the total bytes transferred in C<$actual_size>, with C<$ok> true, and the +C attribute true. No data is lost. If writes continue until physical +EOM, data may be lost. + +=head3 read_to_connection + + ($ok, $actual_size) = $dev->read_to_connection($size); + +This method is similar to C but the data flows in the +opposite direction. It reads at most C<$size> bytes, and returns the total +number of bytes read in C<$actual_size>. + +When the method encounters an EOF, it stops early and returns successfully with +the number of bytes actually read (which may be zero). + +=head3 property_get + +Get a property value, where the property is specified by name. See "Properties", above. + +=head3 property_set + +Set a simple property value. See "Properties", above. + +=head3 property_set_ex + +Set a property value with surety and source. See "Properties", above. + +=head2 CONSTANTS + +This module defines a large number of constant scalars. These constants are +available from the package namespace (e.g., C<$Amanda::Device::ACCESS_WRITE>), +or imported with the C<:constant> import tag. + +=head2 DirectTCPConnection objects + +The C method returns an object to represent the ongoing DirectTCP +connection. This object is mostly useful as a "token" to be passed to +C and C. In particular, a +connection created by one device can be used with another device; this is how +DirectTCP dumps are spanned over multiple volumes. + +The class does have one critical method, though: + + $conn->close(); + +This method closes the connection, releasing all resources allocated to it. It +can be called at any time, whether the remote side has closed the connection +already or not. =cut + +sub new_rait_from_children { + my $class = shift; # strip the $class from the arguments + return rait_device_open_from_children([@_]); +} + push @EXPORT_OK, qw(DeviceAccessMode_to_strings); push @{$EXPORT_TAGS{"DeviceAccessMode"}}, qw(DeviceAccessMode_to_strings); @@ -850,7 +1491,7 @@ $_PropertySource_VALUES{"SOURCE_USER"} = $PROPERTY_SOURCE_USER; push @{$EXPORT_TAGS{"constants"}}, @{$EXPORT_TAGS{"PropertySource"}}; -# SWIG produces a sub-package for the Device "class", in this case named +# SWIG produces a sub-package for the Device "class", in this case named # Amanda::Device::Device. For user convenience, we allow Amanda::Device->new(..) to # do the same thing. This is a wrapper function, and not just a typeglob assignment, # because we want to get the right blessing.