#!/usr/bin/env perl # graveman.wrapper - "Setup" program for "graveman" # License: Creative Commons Attribution-NonCommercial-ShareALike 2.5 # Revision: 070713 # Note: License applies to wrapper only. "graveman" itself is a sep- # arate package that's distributed under the GNU General Public Lic- # ense, version 2 (June 1991). #--------------------------------------------------------------------- # license information #--------------------------------------------------------------------- # This section may not be modified except as approved by the author or # licensor, or to make non-content changes such as adjustments to par- # agraph formatting or white space. # This version of this software is distributed under the following # license: # # Creative Commons Attribution-NonCommercial-ShareAlike 2.5 # You may use, modify, and redistribute this software without fees or # royalties, but only under the terms and conditions set forth by the # license. In particular, copies and derived works cannot be used for # commercial purposes. Additionally, the license propagates to copies # and derived works. Furthermore, you must provide attribution "in the # manner specified by the author or licensor". The latter point is # discussed below. # The author [and licensor] hereby specifies that attribution must be # handled in the following manner: a. If the software is interactive, # any About or Credits dialog boxes, windows, or output text provided # by the original version must be preserved and readily accessible to # the end user at runtime. b. If the software is non-interactive, or # if it does not provide About or Credits dialog boxes, windows, or # output text, the operating system and/or desktop environment used # must provide attribution that is visible and/or readily accessible # to the end user at runtime. # The following techniques do not meet the attribution requirements: # Attribution through text files, attribution through printed docu- # mentation, verbal attribution, or postings on external web sites # [i.e., web sites that are not an intrinsic local component of the # operating system or desktop environment used]. These examples are # provided for illustrative purposes only. # It should be noted that trademarks are an additional issue. If this # software uses any trademarks, trademark-related restrictions may # apply. # This is not a complete explanation of the terms and conditions in- # volved. For more information, see the Creative Commons Attribution- # NonCommercial-ShareAlike 2.5 license. #--------------------------------------------------------------------- # overview #--------------------------------------------------------------------- # 1. This script is a wrapper for "graveman" 0.3.12-5. It'll probably # require changes for other releases. #--------------------------------------------------------------------- # 2. This script performs some setup operations. Presently, the fol- # lowing steps are implemented: # # a. Switch to user's "home" directory. # # b. Use a fast method to identify CD/DVD devices presently avail- # able on the system. # # Note: The approach used is much faster than "graveman's" # "cdrecord"-based approach [possibly several hundred times # faster]. As a tradeoff, the fast approach doesn't detect cer- # tain features [such as "burn free" capability]. This may be # corrected at a later date. # # c. Modify the user's "graveman" configuration file to reflect # the CD/DVD device list discussed previously. Note: If the # file doesn't already exist, this script creates it. # # d. Make other changes to the configuration file, if necessary. # # e. Chain to the target program [passing any/all relevant argu- # ments]. #--------------------------------------------------------------------- # 3. Requirements [not including "graveman" and related dependencies # such as "wodim"]: # # a. Most importantly, this wrapper is distro-specific. This ver- # sion assumes that it's running on a distro that maintains a # directory named "/dev/cdroms". The directory in question con- # tains one symbolic link for each CD/DVD device in the system. # The link has a human-readable name and points to a conven- # tional CD/DVD device node. # # b. Additionally, this wrapper needs Perl, "zenity", and Linux # kernel 2.6. # # c. This wrapper doesn't use "sox" directly. However, it assumes # that "sox" has been compiled with MP3 and Ogg Vorbis sup- # port. #--------------------------------------------------------------------- # standard module setup #--------------------------------------------------------------------- require 5.6.1; use strict; use Carp; use warnings; # Trap warnings $SIG {__WARN__} = sub { die @_; }; #--------------------------------------------------------------------- # basic constants #--------------------------------------------------------------------- use constant ZERO => 0; # Zero use constant ONE => 1; # One use constant FALSE => 0; # Boolean FALSE use constant TRUE => 1; # Boolean TRUE #--------------------------------------------------------------------- # program parameters #--------------------------------------------------------------------- # $IE specifies an internal-error message prefix string. # $PREFIX specifies an absolute path for "graveman's" "install" tree. # Note: The path shouldn't end with a slash. # $PROGNAME should be equal to this wrapper's filename, minus any # path component. # $REVISION specifies a wrapper-revision string. # $TARGET_PROGRAM specifies an absolute path for the target executa- # ble. # Presently, $TARGET_PROGRAM should be equal to a directory path [end- # ing with a forward slash], plus $PROGNAME, plus the filename exten- # sion ".bin". If these conventions are changed, the filename speci- # fied by $TARGET_PROGRAM [disregarding the path component] must be # different than the name of this script, or infinite loops may oc- # cur. my $IE = 'Internal error'; my $PREFIX = '__META_PREFIX__'; my $PROGNAME = 'graveman'; my $REVISION = '070616'; my $TARGET_PROGRAM = "$PREFIX/bin/$PROGNAME.bin"; #--------------------------------------------------------------------- # "graveman"-related constants #--------------------------------------------------------------------- # These are "graveman" DVD-capability numbers. The numbers used here # are compatible with "graveman" 0.3.12-5. They may require changes # for other releases. my $_READ_CDR = 1; my $_WRITE_CDR = 2; my $_WRITE_CDRW = 4; my $_READ_DVD = 16; my $_WRITE_DVD = 32; #--------------------------------------------------------------------- # "graveman" configuration-file template #--------------------------------------------------------------------- # This template is compatible with "graveman" 0.3.12-5. It may require # changes for other releases. # Notes on a few key settings: # # datarockridge=1 # Enable Rockridge extensions # datajoliet=1 # Enable Joliet extensions # tmpdir=/var/tmp # vs. a default setting of "/tmp" # sox_support_mp3=1 # Requires "sox" built with MP3 support # sox_support_ogg=1 # Requires "sox" built with Ogg support #--------------------------------------------------------------------- # This is part one of two. my $CONF_PART_ONE = << 'END'; [general] confversion=0.3.12-5 dataisolevel=2 mkisofs_support_isov2=1 dvd+rw-format=__META_BINDIR__/dvd+rw-format nbrcddata=1 charsetdata=DEFAULT dstothercombo= fastblank=1 cdrdaopara= sox=__META_BINDIR__/sox statusbar=1 confversion=0.3.12-5 dvd+rw-mediainfopara= datajoliet=1 dvddatasimul=0 srccopycombo= x=163 eject=1 soxpara= dstaudiocombo= nbrdvddata=1 dvddatanotfix=0 y=154 dstaudiospeed= theme=default saveconfig=1 flacpara= dvd+rw-mediainfo=__META_BINDIR__/dvd+rw-mediainfo dataformat=data height=393 mkisofs=__META_BINDIR__/mkisofs datanotfix=0 dstdvddatacombo= lastdir= autoblank=1 dstdvddataspeed= overburn=1 cdrecordpara= datamodburn=dao audiodao=1 width=666 version=1 flac=__META_BINDIR__/flac sox_support_ogg=1 dstdatacombo= dstdataspeed= tmpdir=/var/tmp audionotfix=0 datarockridge=1 datamulti=0 dvd+rw-formatpara= growisofspara= cdrdao=__META_BINDIR__/cdrdao tooltips=1 sox_support_mp3=1 readcdpara= datasimul=0 nbrcdcopy=1 copysimul=0 dstcopycombo= growisofs=__META_BINDIR__/growisofs dstcopyspeed= readcd=__META_BINDIR__/readcd audiosimul=0 cdrecord=__META_BINDIR__/cdrecord mkisofspara= iconsize=48 scan_drives=0 nbrcdaudio=1 END #--------------------------------------------------------------------- # This is part two of two. my $CONF_PART_TWO = << 'END'; [charsets] code=cp10081 label=Macintosh Turkish (CP10081) [charsets] code=cp10079 label=Macintosh Icelandic (CP10079) [charsets] code=cp10029 label=Macintosh Central European (CP10029) [charsets] code=cp10007 label=Macintosh Cyrillic (CP10007) [charsets] code=cp10006 label=Macintosh Greek (CP10006) [charsets] code=cp10000 label=Macintosh Roman (CP10000) [charsets] code=koi8-u label=Ukrainian (KOI8-U) [charsets] code=koi8-r label=Russian (KOI8-R) [charsets] code=cp1251 label=Windows Cyrillic (CP1251) [charsets] code=cp1250 label=Windows Central European (CP1250) [charsets] code=cp874 label=MS-DOS Thai (CP874) [charsets] code=cp869 label=MS-DOS Modern Greek (CP869) [charsets] code=cp866 label=MS-DOS Russian (CP866) [charsets] code=cp865 label=MS-DOS Nordic (CP865) [charsets] code=cp864 label=MS-DOS Arabic (CP864) [charsets] code=cp863 label=MS-DOS Canadian French (CP863) [charsets] code=cp862 label=MS-DOS Hebrew (CP862) [charsets] code=cp861 label=MS-DOS Icelandic (CP861) [charsets] code=cp860 label=MS-DOS Portugese (CP860) [charsets] code=cp857 label=MS-DOS Turkish (CP857) [charsets] code=cp855 label=MS-DOS Cyrillic (CP855) [charsets] code=cp852 label=MS-DOS Slavic (CP852) [charsets] code=cp850 label=MS-DOS Multilingual Latin1 (CP852) [charsets] code=cp775 label=MS-DOS Baltic (CP774) [charsets] code=cp737 label=MS-DOS Greek (CP737) [charsets] code=cp437 label=MS-DOS US (CP437) [charsets] code=iso8859-15 label=Latin/Occidental+euro alphabet (ISO 8859-15) [charsets] code=iso8859-14 label=Latin/Celtic alphabet (ISO 8859-14) [charsets] code=iso8859-9 label=Latin alphabet No. 5 (ISO 8859-9) [charsets] code=iso8859-8 label=Latin/Hebrew alphabet (ISO 8859-8) [charsets] code=iso8859-7 label=Latin/Greek alphabet (ISO 8859-7) [charsets] code=iso8859-6 label=Latin/Arabic alphabet (ISO 8859-6) [charsets] code=iso8859-5 label=Latin/Cyrillic alphabet (ISO 8859-5) [charsets] code=iso8859-4 label=Latin alphabet No. 4 (ISO 8859-4) [charsets] code=iso8859-3 label=Latin alphabet No. 3 (ISO 8859-3) [charsets] code=iso8859-2 label=Latin alphabet No. 2 (ISO 8859-2) [charsets] code=iso8859-1 label=Latin/Occidental alphabet (ISO 8859-1) END #--------------------------------------------------------------------- # support routines #--------------------------------------------------------------------- # Future change: Document this routine. sub ErrorExit { my ($msg) = @_; $msg = "" if !defined $msg; $msg =~ s@\s+\z@@s; $msg = $IE unless length $msg; $msg = "graveman wrapper: $msg"; system "zenity --error --text=\"$msg\""; exit ONE; } #--------------------------------------------------------------------- # Future change: Document this routine. sub IntError { my ($msg) = @_; $msg = "" if !defined $msg; $msg =~ s@\s+\z@@s; $msg = '???' unless length $msg; $msg =~ s@#(\d)@#$REVISION-$1@; $msg = "$IE $msg\n\nThis is probably a bug"; &ErrorExit ($msg); } #--------------------------------------------------------------------- # Future change: Document this routine. sub ExpectFlag { my ($msg, $str) = @_; $str = "" if !defined $str; $str =~ s@^\s+@@s; $str =~ s@\s+\z@@s; &IntError ($msg) unless $str =~ m@^[01]\z@; $str; } #--------------------------------------------------------------------- # Future change: Document this routine. sub BuildDeviceEntries { my $data; # Data buffer my $path; # Pathname my $ModelName; # Human-readable model name my $ref_list; # Pointer to an array my $str; # Scratch #--------------------------------------------------------------------- # $basedev holds base device names; i.e., device names such as "hda" # or "sr0" without the usual "/dev/" part. my $basedev; # Base device name #--------------------------------------------------------------------- # %DeviceToModel maps device names of the form "hda" or "sr0" [i.e., # without the "/dev/" part] to human-readable model names. my %DeviceToModel = (); #--------------------------------------------------------------------- # Linux 2.6 kernels provide a pseudo-file named "/proc/sys/dev/cdrom/ # info". The file in question contains a 2D CD/DVD information table. # The table contains one row per line [disregarding a header line and # blank lines]. Every row starts with a field name, which consists of # arbitrary text followed by a colon. # "InfoFieldMap" maps field names [excluding leading/trailing white # space and colons] to array references [i.e., pointers]. Each array # reference points to an array that lists the values associated with # individual devices for the corresponding field. For more informa- # tion, see the source code. my %InfoFieldMap = (); #--------------------------------------------------------------------- # Build %DeviceToModel table [described previously]. # This code is distro-specific. For more information, see the notes at # the start of this file. opendir (DIR, "/dev/cdroms") || &ErrorExit ("/dev/cdroms directory is missing"); while (defined ($_ = readdir (DIR))) { next if m@^\.@; $ModelName = $_; $path = "/dev/cdroms/$_"; next unless -l $path; $path = readlink $path; next unless defined ($path) && ($path =~ m@^/dev/(\w+)\z@); $DeviceToModel {$1} = $ModelName; } closedir DIR; #--------------------------------------------------------------------- # Read standard Linux 2.6 CD/DVD info table. $str = '/proc/sys/dev/cdrom/info'; open (IFD, "<$str") || &ErrorExit ("Can't read system data file:\n$str"); undef $/; $data = ; $data = "" if !defined $data; close IFD; #---------------------------------------------------------------------- # Build %InfoFieldMap table [described previously]. $data =~ y/\011\040/ /s; my @InfoFieldNames = ( 'drive name' , 'drive speed' , 'Can write CD-R' , 'Can write CD-RW' , 'Can read DVD' , 'Can write DVD-R' ); for my $field_name (@InfoFieldNames) { &IntError ('#0001') unless $data =~ m@(^|\n)$field_name: (\S[^\012]*)@; $str = $2; $str =~ s@^\s+@@s; $str =~ s@\s+\z@@s; my @list = split (/\s+/, $str); $InfoFieldMap {$field_name} = \@list; } #---------------------------------------------------------------------- # Build "graveman"-format CD/DVD definitions. $ref_list = $InfoFieldMap {'drive name'}; &IntError ('#0002') unless defined $ref_list; my @basedev = @$ref_list; my $outbuf = ""; for my $ii (ZERO..$#basedev) { $basedev = $basedev [$ii]; $ModelName = $DeviceToModel {$basedev}; $ref_list = $InfoFieldMap {'drive speed' }; my $speed = $$ref_list [$ii]; &IntError ('#0003') if !defined $basedev; &IntError ('#0004') if !defined $ModelName; &IntError ('#0005') if !defined ($speed) || ($speed !~ m@^\d+\z@); $ref_list = $InfoFieldMap {'Can write CD-R' }; my $can_write_cd_r = &ExpectFlag ('#0006', $$ref_list [$ii]); $ref_list = $InfoFieldMap {'Can write CD-RW' }; my $can_write_cd_rw = &ExpectFlag ('#0007', $$ref_list [$ii]); $ref_list = $InfoFieldMap {'Can read DVD' }; my $can_read_dvd = &ExpectFlag ('#0008', $$ref_list [$ii]); $ref_list = $InfoFieldMap {'Can write DVD-R' }; my $can_write_dvd_r = &ExpectFlag ('#0009', $$ref_list [$ii]); my $type; $type = $_READ_CDR; $type += $_WRITE_CDR if $can_write_cd_r; $type += $_WRITE_CDRW if $can_write_cd_rw; $type += $_READ_DVD if $can_read_dvd; $type += $_WRITE_DVD if $can_write_dvd_r; my $dev = "/dev/$basedev"; $ModelName =~ s@([a-z])-([a-z])@$1 $2@i; $outbuf .= << "END"; [lecteur] dev=$dev actu=0 name=$ModelName type=$type vitesse=$speed vitessedvd=0 manual=0 END } #---------------------------------------------------------------------- # Wrap it up. $outbuf; # Return "graveman"-format entries } #--------------------------------------------------------------------- # configuration-file processor #--------------------------------------------------------------------- # Future change: Document this routine. sub UpdateConfigFile { my $HOME; # Absolute path for "home" directory my $data; # Data buffer my $orig_data; # Copy of original data my $str; # Scratch #--------------------------------------------------------------------- # Initial setup. $HOME = $ENV {HOME}; # Identify "home" directory # Safety measure &ErrorExit ("Can't identify your home directory") unless defined $HOME; chdir $HOME; # Go to "home" directory #--------------------------------------------------------------------- # Construct new configuration data. # Configuration-file directory my $CFGDIR = "$HOME/.config/graveman"; # Configuration-file pathname my $CFGFILE = "$CFGDIR/graveman.conf"; my $NewFile = TRUE; # New-file flag # $part1 contains everything that goes before the first [lecteur] # block in a configuration file. $part2 contains everything that # goes after the last [lecteur] block. The next statement sets $part1 # and $part2 to appropriate default values. my ($part1, $part2) = ($CONF_PART_ONE, $CONF_PART_TWO); # Open old configuration file if (open (IFD, "<$CFGFILE")) { # Successful - Read entire file undef $/; $data = ; $data = "" if !defined $data; close IFD; $orig_data = $data; # Save original data # The rest of the code in this "if" block extracts two segments from # the configuration-file data. $part1 is set to the text that precedes # the first [lecteur] block. $part2 is set to the text that follows # the last one. # If the configuration file doesn't contain any [lecteur] blocks, # $part1 is set to everything preceding the point where the first # [lecteur] block would go and $part2 is set to everything after the # point where the last [lecteur] block would end. $data =~ y/\000//d; if ($data !~ m@\[lecteur\]@) { $data =~ s@(\[charsets\])@[lecteur]\nkludge=1\n$1@; } while ($data =~ s@\[lecteur\][^\[\]]*@\000@gis) {} $data =~ s@\000+@\000@g; my @parts = split (/\000/, $data); if (scalar (@parts) == 2) { ($part1, $part2) = ($parts [ZERO], $parts [ONE]); } $NewFile = FALSE; } $part1 =~ s@\s*\z@\n@; # Make some white-space adjustments $part2 =~ s@^\s+@@; # Build a complete configuration file my $CFGDATA = $part1 . &BuildDeviceEntries() . $part2; #--------------------------------------------------------------------- # Misc. adjustment[s]. $CFGDATA =~ s@(\n[a-z]+combo=)/dev/[^012]+@$1@g; #--------------------------------------------------------------------- # Update configuration file. # Are there any changes? if (defined ($orig_data) && ($CFGDATA eq $orig_data)) { # No - We're done print "No changes to graveman config file required\n"; return; } unlink $CFGFILE; # Safety measure - This takes care of # symbolic links system "mkdir -p $CFGDIR"; # If directory isn't there, create it # Verify that directory is present &ErrorExit ("Couldn't create configuration directory:\n$CFGDIR") unless -d $CFGDIR; # Open the file for writing &ErrorExit ("Couldn't create configuration file:\n$CFGFILE") unless open (OFD, ">$CFGFILE"); print OFD $CFGDATA; # Write data to file # Close the file &ErrorExit ("Couldn't write to configuration file:\n$CFGFILE") unless close OFD; # Print a status message $str = $NewFile ? 'Created' : 'Updated'; print "$str graveman config file\n"; undef; } #--------------------------------------------------------------------- # main routine #--------------------------------------------------------------------- sub Main { &UpdateConfigFile(); # Update configuration file # Chain to target program exec $TARGET_PROGRAM, @ARGV; exit ONE; # Shouldn't be reached } #--------------------------------------------------------------------- # main program #--------------------------------------------------------------------- &Main(); # Call the main routine exit ONE; # Shouldn't be reached