home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / boot / i386 / root / usr / sbin / isax < prev    next >
Text File  |  2006-11-29  |  31KB  |  1,117 lines

  1. #!/usr/bin/perl
  2. # Copyright (c) 1996 SuSE GmbH Nuernberg, Germany.  All rights reserved.
  3. #
  4. # Author: Marcus Schaefer <sax@suse.de>, 2000
  5. # isax.pl ( config writer/reader/adjuster using API data format )
  6. #
  7. # CVS ID:
  8. # --------
  9. # Status: Up-to-date
  10. #
  11. use strict;
  12. no strict "refs";
  13. no strict "subs";
  14.  
  15. use lib '/usr/share/sax/modules';
  16.  
  17. use Env;
  18. use XFree;
  19. use FBSet;
  20. use ParseConfig;
  21. use CreateSections;
  22. use ImportAPI;
  23. use HashMap;
  24. use Storable;
  25. use ExportAPI;
  26. use Getopt::Long;
  27.  
  28. use Storable qw(freeze thaw);
  29.  
  30. #=========================================
  31. # Globals...
  32. #-----------------------------------------
  33. my $Update;        # Option to update modelines [XFine cache]
  34. my $ListSection;   # Option list section X
  35. my $OutputFile;    # Option give output file name
  36. my $InputFile;     # Option give input api file name
  37. my $Modify;        # Option Modify yes/no
  38. my $Profile;       # Option profile file
  39. my $ProfileDevice; # Option profile device number
  40. my $PrintYCP;      # Option print as YCP if ListSection is active
  41. my $PlusYCP;       # Option print YCP [stderr] plus normal output [stdout]
  42. my $ImportBinary;  # Option import binary storable data
  43. my %init;          # init data hash
  44. my %save;          # save dialog data
  45. my %origin;        # original data during merging
  46. my @key;           # key list in HashMerge function
  47. my @cmd;           # command list in HashMerge function
  48.  
  49. our %import;       # ImportConfig information
  50. our %dialog;       # dialog data
  51.  
  52. #----[ init ]------#
  53. sub init {
  54. #----------------------------------------------------------
  55. # test for root privileges and get some options
  56. # create a secure directory and init the variables
  57. # used in other functions
  58. #
  59.     my $result = GetOptions(
  60.         "list|l=s"      => \$ListSection,
  61.         "config|c=s"    => \$OutputFile,
  62.         "file|f=s"      => \$InputFile,
  63.         "modify|m"      => \$Modify,
  64.         "profile|p=s"   => \$Profile,
  65.         "update|u"      => \$Update,
  66.         "device|d=i"    => \$ProfileDevice, 
  67.         "ycp|y"         => \$PrintYCP,
  68.         "plusycp"       => \$PlusYCP,
  69.         "binary|b:s"    => \$ImportBinary,
  70.         "help|h"        => \&usage,
  71.         "<>"            => \&usage
  72.     );
  73.     if ( $result != 1 ) {
  74.         usage();
  75.     }
  76.     if ( ! defined $ListSection ) {
  77.     if (qx(whoami) !~ /root/) {
  78.         die "ISaX: only root can do this";
  79.     }
  80.     }
  81.     if (defined $PrintYCP) {
  82.         $PrintYCP = "ycp";
  83.     }
  84.     if (defined $PlusYCP) {
  85.         $PrintYCP = "plusycp";
  86.     }
  87.     # verify option -f is required...
  88.     # --------------------------------
  89.     if ((! defined $InputFile) && (! defined $ListSection)) {
  90.         die "ISaX: no apifile specified";
  91.     }
  92.     # verify option -c is optional...
  93.     # --------------------------------
  94.     if (! defined $OutputFile) {
  95.         $OutputFile = "/etc/X11/xorg.conf";
  96.     }
  97.     $init{TmpDir}      = CreateSecureDir(); 
  98.     $init{Xmode}       = "/usr/sbin/xmode";
  99.     $init{ConfigFile}  = "/etc/X11/xorg.conf";
  100.     $init{BinaryFile}  = "/var/cache/sax/files/config";
  101.     $init{DbmNew}      = "/var/cache/sax/files/config.new";
  102.     $init{XFineCache}  = "/var/cache/xfine";
  103.     $init{ListFile}    = "$init{TmpDir}/apidata";
  104.     $init{ListSection} = $ListSection;
  105.     $init{OutputFile}  = $OutputFile;
  106.     $init{InputFile}   = $InputFile;
  107.     $init{Modify}      = $Modify;
  108.  
  109.     ApiInit();
  110.  
  111.     # import specifications...
  112.     # --------------------------
  113.     $import{ApiFile}   = $init{InputFile};
  114.     $import{Xmode}     = $init{Xmode};
  115. }
  116.  
  117. #----[ main ]----#
  118. sub main {
  119. #----------------------------------------------------------
  120. # main part: use ImportAPI functions to import api 
  121. # file, use xapi functions to create config file
  122. #
  123.     init();
  124.     # list sections...
  125.     # -----------------
  126.     if (defined $init{ListSection}) {
  127.         ListSection($init{ListSection},$PrintYCP);
  128.     }
  129.  
  130.     # create or modify the configuration...
  131.     # -------------------------------------
  132.     if (! defined $init{ListSection}) {
  133.     if (defined $init{Modify}) {
  134.         ModifyConfiguration();
  135.     } else {
  136.         CreateConfiguration();
  137.     }
  138.     }
  139.     RemoveSecureDir($init{TmpDir});
  140.  
  141.     # update modelines if set...
  142.     # ---------------------------
  143.     if (defined $Update) {
  144.     IncludeModelineChanges (
  145.         $init{OutputFile},$init{XFineCache}
  146.     );
  147.     }
  148.     exit 0;
  149. }
  150.  
  151.  
  152. #=========================================
  153. # Functions...
  154. #-----------------------------------------
  155. #---[ ImportConfig ]-----#
  156. sub ImportConfig {
  157. #----------------------------------------------------------
  158. # read the configuration file and create the
  159. # %dialog hash for further actions...
  160. #
  161.     my $serialized;
  162.  
  163.     if (! defined $ImportBinary) {
  164.     # /.../
  165.     # we will read the xorg.conf and merge all the
  166.     # information into the global hash structure
  167.     # -------------------------------------------
  168.     my $cp = XFree::ReadConfigFile($init{ConfigFile});
  169.     my $ee = XFree::GetFontPath($cp);
  170.     if ($ee eq "null") {
  171.         die "ISaX: could not import file: $init{ConfigFile}";
  172.     }
  173.     my %files   = ParseFileSection         ($cp);
  174.     my %sflags  = ParseServerFlagsSection  ($cp);
  175.     my %module  = ParseModuleSection       ($cp);
  176.     my %flags   = ParseServerLayoutSection ($cp);
  177.     my %input   = ParseInputDeviceSection  ($cp);
  178.     my %monitor = ParseMonitorSection      ($cp);
  179.     my %modes   = ParseModesSection        ($cp);
  180.     my %device  = ParseDeviceSection       ($cp);
  181.     my %screen  = ParseScreenSection       ($cp);
  182.     my %layout  = ParseServerLayoutSection ($cp);
  183.     my %extend  = ParseExtensionsSection   ($cp);
  184.  
  185.     %dialog = MergeParseResult(
  186.         \%files,\%module,\%flags ,\%input,\%monitor,
  187.         \%modes,\%device,\%screen,\%layout,\%sflags,\%extend
  188.     );
  189.     } else {
  190.     # /.../
  191.     # we have requested not to read the existing configuration
  192.     # file because --binary is set. We will include the SaX2
  193.     # written binary version of the detection information
  194.     # ----------------------------------------------------- 
  195.     if ($ImportBinary ne "") {
  196.         $init{BinaryFile} = $ImportBinary;
  197.     }
  198.     if (! -s $init{BinaryFile}) {
  199.         die "ISaX: could not import file: $init{BinaryFile}";
  200.     }
  201.     my $hashref = retrieve($init{BinaryFile});
  202.     if (! defined $hashref) {
  203.         die "ISaX: could not open tree: $init{BinaryFile}";
  204.     }
  205.     %dialog = %{$hashref};
  206.     %dialog = ConstructInputOptions (\%dialog);
  207.     }
  208.     PrepareLayoutDefaults();
  209.     PrepareLayout();
  210.  
  211.     # /.../
  212.     # include profile if given
  213.     # -------------------------
  214.     if (defined $Profile) {
  215.         $serialized = freeze (\%dialog);
  216.         %save   = %{thaw($serialized)};
  217.         %dialog = ImportProfile (
  218.             $Profile,$ProfileDevice,\%dialog
  219.         );
  220.     }
  221. }
  222.  
  223. #---[ PrepareLayoutDefaults ]----#
  224. sub PrepareLayoutDefaults {
  225. #----------------------------------------------------
  226. # this function is called to set default values to 
  227. # the ServerLayout section
  228. #
  229.     foreach my $id (keys %{$dialog{InputDevice}}) {
  230.         my $lid   = "all";
  231.         my $input = $dialog{InputDevice}{$id}{Identifier};
  232.         foreach my $layoutID (keys %{$dialog{ServerLayout}}) {
  233.         if (defined $dialog{ServerLayout}{$layoutID}{InputDevice}{$id}) {
  234.             $lid = $layoutID;
  235.             last;
  236.         }
  237.         }
  238.         if ($id % 2 == 0) {
  239.             #============================================
  240.             # this are keyboard devices
  241.             #--------------------------------------------
  242.             $dialog{ServerLayout}{$lid}{InputDevice}{$id}{usage}="CoreKeyboard";
  243.             $dialog{ServerLayout}{$lid}{InputDevice}{$id}{id}   =$input;
  244.         } else {
  245.             #============================================
  246.             # this are mouse devices
  247.             #--------------------------------------------
  248.             my $event  = "CorePointer";
  249.             if ($id != 1) {
  250.                 $event = "SendCoreEvents";
  251.             }
  252.             if (defined $dialog{ServerLayout}{$lid}{InputDevice}{$id}) {
  253.                 $dialog{ServerLayout}{$lid}{InputDevice}{$id}{usage} = $event;
  254.                 $dialog{ServerLayout}{$lid}{InputDevice}{$id}{id}    = $input;
  255.             }
  256.         }
  257.     }
  258.     # / ... /
  259.     # look up Xinerama/and Clone mode...
  260.     # -----------------------------------
  261.     foreach my $lid (keys %{$dialog{ServerLayout}}) {
  262.         if (! defined $dialog{ServerLayout}{$lid}{Option}{Xinerama}) {
  263.             $dialog{ServerLayout}{$lid}{Option}{Xinerama}     = "off";
  264.         }
  265.         if ($dialog{ServerLayout}{$lid}{Option}{Xinerama} eq "") {
  266.             $dialog{ServerLayout}{$lid}{Option}{Xinerama}     = "off";
  267.         }
  268.         if (! defined $dialog{ServerLayout}{$lid}{Option}{Clone}) {
  269.             $dialog{ServerLayout}{$lid}{Option}{Clone}        = "off";
  270.         }
  271.         if ($dialog{ServerLayout}{$lid}{Option}{Clone} eq "") {
  272.             $dialog{ServerLayout}{$lid}{Option}{Clone}        = "off";
  273.         }
  274.     }
  275. }
  276.  
  277. #---[ PrepareLayout ]---#
  278. sub PrepareLayout {
  279. #----------------------------------------------------------
  280. # prepare layout to know every neighbour within each screen 
  281. # line. This will create redundand information but is easier
  282. # to handle within SaX2 later
  283. #
  284.     my %layout;
  285.     foreach my $lid (keys %{$dialog{ServerLayout}}) {
  286.  
  287.         my %screen = %{$dialog{ServerLayout}{$lid}{Screen}};
  288.         foreach my $id (keys %screen) {
  289.             my $leftOf  = $screen{$id}{left};
  290.             my $rightOf = $screen{$id}{right};
  291.             my $above   = $screen{$id}{top};
  292.             my $beneath = $screen{$id}{bottom};
  293.  
  294.             if ($leftOf  =~ /Screen\[(.*)\]/) {
  295.                 $layout{$id}{right} = $1;
  296.                 $layout{$1}{left} = $id;
  297.             }
  298.             if ($rightOf =~ /Screen\[(.*)\]/) {
  299.                 $layout{$id}{left} = $1;
  300.                 $layout{$1}{right} = $id;
  301.             }
  302.             if ($above   =~ /Screen\[(.*)\]/) {
  303.                 $layout{$id}{bottom} = $1;
  304.                 $layout{$1}{top} = $id;
  305.             }
  306.             if ($beneath =~ /Screen\[(.*)\]/) {
  307.                 $layout{$id}{top} = $1;
  308.                 $layout{$1}{bottom} = $id;
  309.             }
  310.         }
  311.         foreach my $id (keys %screen) {
  312.             my $rel = $screen{$id}{relative};
  313.             $dialog{ServerLayout}{$lid}{Screen}{$id}{left}     = "<none>";
  314.             $dialog{ServerLayout}{$lid}{Screen}{$id}{right}    = "<none>";
  315.             $dialog{ServerLayout}{$lid}{Screen}{$id}{top}      = "<none>";
  316.             $dialog{ServerLayout}{$lid}{Screen}{$id}{bottom}   = "<none>";
  317.             $dialog{ServerLayout}{$lid}{Screen}{$id}{relative} = $rel;
  318.             if (defined $layout{$id}{left}) {
  319.                 my $n= $layout{$id}{left};
  320.                 $dialog{ServerLayout}{$lid}{Screen}{$id}{left}   = "Screen[$n]";
  321.             }
  322.             if (defined $layout{$id}{right}) {
  323.                 my $n= $layout{$id}{right};
  324.                 $dialog{ServerLayout}{$lid}{Screen}{$id}{right}  = "Screen[$n]";
  325.             }
  326.             if (defined $layout{$id}{top}) {
  327.                 my $n= $layout{$id}{top};
  328.                 $dialog{ServerLayout}{$lid}{Screen}{$id}{top}    = "Screen[$n]";
  329.             }
  330.             if (defined $layout{$id}{bottom}) {
  331.                 my $n= $layout{$id}{bottom};
  332.                 $dialog{ServerLayout}{$lid}{Screen}{$id}{bottom} = "Screen[$n]";
  333.             }
  334.         }
  335.     }
  336. }
  337.  
  338. #---[ CreateApiData ]-----#
  339. sub CreateApiData {
  340. #----------------------------------------------------------
  341. # create API interface file according to the
  342. # imported %dialog data
  343. #
  344.     my @input;    # InputDevice sections
  345.     my @device;   # Device sections
  346.     my @desktop;  # Monitor,Screen sections
  347.     my @layout;   # ServerLayout sections
  348.     my @extend;   # Extensions section
  349.  
  350.     open(FD,">$init{ListFile}") ||
  351.         die "could not create file $init{ListFile}: $!";
  352.     foreach my $section (keys %dialog) {
  353.     SWITCH: for ($section) {
  354.     # create Keyboard Path and Mouse sections...
  355.     # --------------------------------------------
  356.     /InputDevice/    && do {
  357.         @input   = KeyboardGetInputDevice(); print FD @input;
  358.         @input   = MouseGetInputDevice();    print FD @input;
  359.     last SWITCH;
  360.     };
  361.     # create Card section...
  362.     # ------------------------
  363.     /Device/         && do {
  364.         @device  = CardGetDevice();          print FD @device;
  365.     last SWITCH;
  366.     };
  367.     # create Monitor and Screen sections...
  368.     # --------------------------------------
  369.     /Screen/         && do {
  370.         @desktop = DesktopGetDesktop();      print FD @desktop;
  371.     last SWITCH;
  372.     };
  373.     # create Layout section...
  374.     # -------------------------
  375.     /ServerLayout/   && do {
  376.         @layout  = LayoutGetServerLayout();  print FD @layout;
  377.     last SWITCH;
  378.     };
  379.     # create Extensions section...
  380.     # ----------------------------
  381.     /Extensions/     && do {
  382.         @extend  = ExtensionsGetExtensions();print FD @extend;
  383.     };
  384.     }
  385.     }
  386.     close(FD);
  387. }
  388.  
  389. #---[ ListSection ]-----#
  390. sub ListSection {
  391. #----------------------------------------------------------
  392. # list the given section as YCP list or in human
  393. # readable format based on the %import hash with
  394. # a tree depth of 1
  395. #
  396.     my $item     = $_[0];
  397.     my $ycp      = $_[1];
  398.  
  399.     my @keylist; # list of id numbers and key values
  400.     my %result;  # result hash in numeric sort order
  401.     my $count;   # modeline counter
  402.     my $lastmode;# number of modelines 
  403.     my $modeline;# current modeline in loop
  404.     my @mlist;   # list of modelines
  405.     my @list;    # YCP list
  406.     my @timing;
  407.     my $k;
  408.     my $v;
  409.  
  410.     ImportConfig();
  411.     if ((defined $Profile) && ($ListSection ne "Layout")) {
  412.         %dialog = HDif (\%save,\%dialog);
  413.     }
  414.     CreateApiData();
  415.  
  416.     $import{ApiFile} = $init{ListFile};
  417.     %import = ApiRead();
  418.  
  419.     # /.../
  420.     # if the desktop section should be listed we will check 
  421.     # if the driver used is the fbdev driver... if yes get the
  422.     # currently used framebuffer resolution and color depth and
  423.     # build the Modes:<X> = <Y> line
  424.     # -------------------------------
  425.     if ($item eq "Desktop") {
  426.         %import = CheckFramebufferModes (\%import);
  427.     }
  428.  
  429.     foreach (keys %{$import{$item}}) {
  430.         @keylist = split(/ +/,$_);
  431.         $result{$keylist[0]}{$keylist[1]} = $import{$item}{$_};
  432.     }
  433.  
  434.     # /.../
  435.     # print out YCP or human readable or both
  436.     # ---
  437.     SWITCH: for ($PrintYCP) {
  438.         /^ycp/  && do {
  439.         doYCP (\%result,STDOUT,$item);
  440.         last SWITCH;
  441.         };
  442.  
  443.         /^plusycp/ && do {
  444.         doHumandReadable (\%result,STDERR);
  445.         doYCP (\%result,STDOUT,$item);
  446.         last SWITCH;
  447.         };
  448.  
  449.         # default...
  450.         # ----------
  451.         doHumandReadable (\%result,STDOUT);
  452.     }
  453.     unlink($init{ListFile});
  454. }
  455.  
  456. #---[ doHumandReadable ]------#
  457. sub doHumandReadable {
  458. #----------------------------------------------------------
  459. # print the given hash as human readable list to the 
  460. # given channel
  461. #
  462.     my %result  = %{$_[0]};
  463.     my $channel = $_[1];
  464.     my $id;     # section id
  465.     my $key;    # section key    
  466.  
  467.     foreach $id (sort keys %result) {
  468.     foreach $key (sort keys %{$result{$id}}) {
  469.         my $ISaXKey = $key;
  470.         if ($ISaXKey eq "DefaultDepth") { 
  471.             $ISaXKey = "ColorDepth"; 
  472.         }
  473.         my $line = sprintf ("%-2s: %-20s: %-40s\n",
  474.             $id,$ISaXKey,$result{$id}{$key}
  475.         );
  476.         print $channel $line;
  477.     }
  478.     }
  479. }
  480.  
  481. #---[ doYCP ]------#
  482. sub doYCP {
  483. #----------------------------------------------------------
  484. # print the given hash as YCP list to the given channel
  485. #
  486.     my %result   = %{$_[0]};
  487.     my $channel  = $_[1];
  488.     my $item     = $_[2];
  489.  
  490.     my @keylist; # list of id numbers and key values
  491.     my $id;      # section id
  492.     my $key;     # section key
  493.     my $count;   # modeline counter
  494.     my $lastmode;# number of modelines 
  495.     my $modeline;# current modeline in loop
  496.     my @mlist;   # list of modelines
  497.     my @list;    # YCP list
  498.     my @timing;
  499.     my $k;
  500.     my $v;
  501.  
  502.     @list = sort keys(%result);
  503.     my $lastid = pop(@list);
  504.  
  505.     print $channel "\$\[\n";
  506.     foreach $id (sort keys %result) {
  507.         my @list = sort keys(%{$result{$id}});
  508.         my $lastit = pop(@list);
  509.         print $channel "  $id : \$\[\n";
  510.         print $channel "   \"$item\" : \$\[\n";
  511.         foreach $key (sort keys %{$result{$id}}) {
  512.         $k = "\"$key\"";
  513.         $v = "\"$result{$id}{$key}\"";
  514.         if ($key eq "Modelines") {
  515.             # special key modelines needs a new YCP map
  516.             # ------------------------------------------
  517.             print $channel "     $k : \$[\n";
  518.             @mlist = split(/,/,$v);
  519.             $count = 0;
  520.             $lastmode = @mlist;
  521.             foreach $modeline (@mlist) {
  522.                 $modeline =~ s/^\"//;
  523.                 $modeline =~ s/\"$//;
  524.                 $modeline =~ s/^Modeline//;
  525.                 $modeline =~ s/\"(.*)\"/\"$1\" : \"Modeline \\\"$1\\\"/;
  526.                 @timing   = split(/:/,$modeline);
  527.                 my $line  = sprintf("     %-25s : %s",$timing[0],$timing[1]);
  528.                 print $channel $line;
  529.                 $count++;
  530.                 if ($count != $lastmode) {
  531.                     print $channel "\",\n";
  532.                 } else {
  533.                     print $channel "\"\n";
  534.                 }
  535.             }
  536.             print $channel "     \],\n";
  537.         } else {
  538.             # normal case...
  539.             # ---------------
  540.             # /.../
  541.             # if the value contains a \" sign we have to 
  542.             # escape this sign otherwhise YaST2 will 
  543.             # not accept the line 
  544.             # ---------------------
  545.             $v = $result{$id}{$key};
  546.             $v =~ s/\"/\\"/g;
  547.             $v = "\"$v\"";
  548.             if ($k eq "\"DefaultDepth\"") {
  549.                 $k = "\"ColorDepth\"";
  550.             }
  551.             if ($key ne $lastit) {
  552.                 my $line = sprintf("     %-25s : %s,\n",$k,$v);
  553.                 print $channel $line;
  554.             } else {
  555.                 my $line = sprintf("     %-25s : %s\n",$k,$v);
  556.                 print $channel $line;
  557.             }
  558.         }
  559.         }
  560.         print $channel "   \]\n";
  561.         if ($id ne $lastid) {
  562.             print $channel "  \],\n";
  563.         } else {
  564.             print $channel "  \]\n";
  565.         }
  566.     }
  567.     print $channel "\]\n";
  568. }
  569.  
  570. #---[ CreateConfigFile ]------#
  571. sub CreateConfigFile {
  572. #----------------------------------------------------------
  573. # create the configuration file according to the
  574. # imported API hash...
  575. #
  576.     my %input = %{$_[0]};
  577.     my %store = {};
  578.  
  579.     my @part0;   # header
  580.     my @part1;   # Files
  581.     my @part2;   # ServerFlags
  582.     my @part3;   # Module
  583.     my @part4;   # InputDevice (keyboard)
  584.     my @part5;   # InputDevice (mouse)
  585.     my @part6;   # Monitor
  586.     my @part7;   # Modes
  587.     my @part8;   # Screen
  588.     my @part9;   # Device
  589.     my @part10;  # ServerLayout
  590.     my @part11;  # DRI
  591.     my @part12;  # Extensions
  592.     my %config;  # section hash
  593.  
  594.     # Files,ServerFlags,Module...
  595.     # ---------------------------
  596.     %config = ApiImportPath(\%input);
  597.     %store  = HashMerge(\%store,\%config);
  598.     @part0  = CreateHeaderSection("ISaX");
  599.     @part1  = CreateFilesSection(\%config);
  600.     @part2  = CreateServerFlagsSection(\%config);
  601.     @part3  = CreateModuleSection(\%config);
  602.  
  603.     # InputDevice (Keyboard)...
  604.     # --------------------------
  605.     %config = ApiImportKeyboard(\%input);
  606.     %store  = HashMerge(\%store,\%config);
  607.     @part4  = CreateInputDeviceSection(\%config);
  608.  
  609.     # InputDevice (Mouse,Tablets,etc)...
  610.     # -----------------------------------
  611.     %config = ApiImportMouse(\%input);
  612.     %store  = HashMerge(\%store,\%config);
  613.     @part5  = CreateInputDeviceSection(\%config);
  614.  
  615.     # Monitor Modes, Screen...
  616.     # -------------------------
  617.     %config = ApiImportDesktop(\%input);
  618.     %store  = HashMerge(\%store,\%config);
  619.     @part6  = CreateMonitorSection(\%config);
  620.     @part7  = CreateModesSection(\%config);
  621.     @part8  = CreateScreenSection(\%config);
  622.  
  623.     # Devices...
  624.     # -----------
  625.     %config = ApiImportCard(\%input);
  626.     %store  = HashMerge(\%store,\%config);
  627.     @part9  = CreateDeviceSection(\%config);
  628.  
  629.     # ServerLayout...
  630.     # ----------------
  631.     %config = ApiImportLayout(\%input);
  632.     %store  = HashMerge(\%store,\%config);
  633.     @part10 = CreateServerLayoutSection(\%config);
  634.     @part11 = CreateDRISection(\%config);
  635.  
  636.     %config = ApiImportExtensions(\%input);
  637.     @part12 = CreateExtensionsSection(\%config);
  638.  
  639.     # /.../
  640.     # save new configuration as storable file
  641.     # this file may be used for later access
  642.     # ----
  643.     store (\%store,$init{DbmNew});
  644.  
  645.     # create configuration file
  646.     # --------------------------
  647.     open(HANDLE,">$init{OutputFile}") ||
  648.         die "ISaX: could not create $init{OutputFile}: $!\n";
  649.     print HANDLE @part0;  print HANDLE "\n";
  650.     print HANDLE @part1;  print HANDLE "\n";
  651.     print HANDLE @part2;  print HANDLE "\n";
  652.     print HANDLE @part3;  print HANDLE "\n";
  653.     print HANDLE @part4;  print HANDLE "\n";
  654.     print HANDLE @part5;  print HANDLE "\n";
  655.     print HANDLE @part6;  print HANDLE "\n";
  656.     print HANDLE @part7;  print HANDLE "\n";
  657.     print HANDLE @part8;  print HANDLE "\n";
  658.     print HANDLE @part9;  print HANDLE "\n";
  659.     print HANDLE @part10; print HANDLE "\n";
  660.     print HANDLE @part11; print HANDLE "\n";
  661.     print HANDLE @part12; print HANDLE "\n";
  662.     close(HANDLE);
  663.  
  664.     if (ImportXFineCache() eq "yes") {
  665.     IncludeModelineChanges (
  666.         $init{OutputFile},$init{XFineCache}
  667.     );
  668.     }
  669.     SaveAsHostConfig (
  670.         $init{OutputFile}
  671.     );
  672.     CreateChecksum (
  673.         $init{OutputFile}
  674.     );
  675. }
  676.  
  677. #---[ SaveAsHostConfig ]-------#
  678. sub SaveAsHostConfig {
  679. #-------------------------------------------------------
  680. # this function will save the given file as a machine
  681. # name based configuration file. On a diskless client
  682. # using the same NFS share you can use this version of
  683. # the configuration file to start your server
  684. #
  685.     my $basename = $_[0];
  686.     my $gethost  = "/bin/hostname";
  687.     if (-f $basename) {
  688.     if (-f $gethost) {
  689.         my $hostname = qx ($gethost);
  690.         $hostname = $basename."-".$hostname;
  691.         qx (cp $basename $hostname);
  692.     }
  693.     }
  694. }
  695.  
  696. #---[ CreateChecksum ]-------#
  697. sub CreateChecksum {
  698. #-------------------------------------------------------
  699. # this function will create a MD5 checksum from the
  700. # configuration file created
  701. #
  702.     my $file = $_[0];
  703.     my $md5  = "$file.md5";
  704.     my $sum = qx (/usr/bin/md5sum $file);
  705.     $sum = quotemeta ($sum);
  706.     if ($sum =~ /(.*) +/) {
  707.         $sum = $1;
  708.         open (FD,">$md5") || return;
  709.         print FD $sum;
  710.         close FD;
  711.     }    
  712. }
  713.  
  714. #---[ ModifyConfiguration ]-----#
  715. sub ModifyConfiguration {
  716. #----------------------------------------------------------
  717. # modify a existing configuration using the
  718. # given api modify file information...
  719. #
  720.     my %input;   # merged api file of merge and origin
  721.     my %merge;   # modification information
  722.     my $origin;  # original api file of existing config
  723.  
  724.     ImportConfig(); 
  725.     CreateApiData();
  726.  
  727.     $import{ApiFile} = $init{ListFile};
  728.     %origin = ApiRead();
  729.     %origin = CheckFramebufferModes (\%origin);
  730.  
  731.     $import{ApiFile} = $init{InputFile};
  732.     %merge  = ApiRead();
  733.     %input  = HashMerge(\%origin,\%merge);
  734.  
  735.     CreateConfigFile(\%input);
  736.     unlink($init{ListFile});
  737. }
  738.  
  739. #---[ CreateConfiguration ]-----#
  740. sub CreateConfiguration {
  741. #----------------------------------------------------------
  742. # create a configuration from scratch using the
  743. # given api file information...
  744. #
  745.     my %input = ApiRead();
  746.     CreateConfigFile(\%input);
  747. }
  748.  
  749. #---[ usage ]-------# 
  750. sub usage {
  751. #----------------------------------------------------------
  752. # how to use the ISaX...
  753. #
  754.     print "Linux ISaX Version 2.1 (2001-06-19)\n";
  755.     print "(C) Copyright 2001 SuSE GmbH\n";
  756.     print "\n";
  757.  
  758.     print "usage: ISaX -f <apifile> [ options ]\n";
  759.     print "options:\n";
  760.     print "[ -f | --file < apifile > ]\n";
  761.     print "  set name of the file containing the\n";
  762.     print "  config specifications/modifications \n";
  763.     print "[ -m | --modify ]\n";
  764.     print "  indicate the apifile to contain only\n";
  765.     print "  information about modifications\n";
  766.     print "[ -u | --update ]\n";
  767.     print "  include modeline patches to the configuration\n";
  768.     print "  file. The modeline cache is located in:\n";
  769.     print "  -- /var/cache/xfine --\n";
  770.     print "[ -l | --list < section > ]\n";
  771.     print "  list the current information about the\n";
  772.     print "  given configuration section. The following\n";
  773.     print "  sections are available:\n";
  774.     print "  /.../\n";
  775.     print "     Card       -> Section Device\n";
  776.     print "     Desktop    -> Section Monitor,Modes,Screen\n";
  777.     print "     Keyboard   -> Section InputDevice\n";
  778.     print "     Mouse      -> Section InputDevice\n";
  779.     print "     Path       -> Section Files,Module,ServerFlags\n";
  780.     print "     Layout     -> Section ServerLayout\n";
  781.     print "     Extensions -> Section Extensions\n";
  782.     print "  /.../\n";
  783.     print "[ -y | --ycp ]\n";
  784.     print "  suppress normal output of a list command\n";
  785.     print "  print a ycp list instead of a human readable\n";
  786.     print "  output\n";
  787.     print "[ -c | --config < output file > ]\n";
  788.     print "  set name of output file default is\n";
  789.     print "  /etc/X11/xorg.conf\n";
  790.     print "[ -p | --profile < file name > ]\n";
  791.     print "  set profile to include for this isax call\n";
  792.     print "  Note:\n";
  793.     print "  -----\n";
  794.     print "  only the differences between the section\n";
  795.     print "  with and without the profile are printed\n";
  796.     print "  The options -p and -d will only take effect\n";
  797.     print "  in combination with the --list option\n";
  798.     print "[ -d | --device < device number >\n";
  799.     print "  for profiles only:\n";
  800.     print "  set the device number the profile should\n";
  801.     print "  take effect on. Default is device nr: 0\n";
  802.     print "[ -h | --help ]\n";
  803.     print "  show this message\n";
  804.     exit(0);
  805. }
  806.  
  807. #---[ HashMerge ]--------#
  808. sub HashMerge {
  809. #----------------------------------------------------------
  810. # merge data of dest hash into the source
  811. # hash and return the modified source hash
  812. #
  813.     my (%source) = %{$_[0]};
  814.     my (%dest)   = %{$_[1]};
  815.  
  816.     my $k;       # key
  817.     my $v;       # value 
  818.     my $ref;     # reference
  819.     my $a;       # joined keys
  820.  
  821.     while(($k,$v) = each(%dest)) {
  822.     @key = ();
  823.     push(@key,$k);
  824.     if (ref($v) eq "HASH") {
  825.         $ref = $dest{$k};
  826.         TreeBranch($ref);
  827.     } else {
  828.         $a   = join("}{",@key);
  829.         $a   =~ s/}/'}/g;
  830.         $a   =~ s/{/{'/g;
  831.         my $command = "\$source{'$a'}='$v'";
  832.         eval($command);
  833.     }
  834.     }
  835.     return(%source);
  836.      # /.../ 
  837.     # Inline sub routine for recursive call
  838.     # --------------------------------------
  839.     sub TreeBranch {
  840.         my $ref  = $_[0];
  841.         my $k;
  842.         my $v;
  843.         my $a;
  844.  
  845.         while(($k,$v) = each(%{$ref})) {
  846.         push(@key,$k);
  847.         if (ref($v) eq "HASH") {
  848.             TreeBranch($v);
  849.         } else {
  850.             $a   = join("}{",@key);
  851.             $a   =~ s/}/'}/g;
  852.             $a   =~ s/{/{'/g;
  853.             my $command = "\$source{'$a'}='$v'";
  854.             eval($command);
  855.         }
  856.         pop(@key);
  857.         }
  858.         return;
  859.     }
  860. }
  861.  
  862. #---[ ImportProfile ]-------#
  863. sub ImportProfile {
  864. #----------------------------------------------------------
  865. # import profile information and return the
  866. # changes imported into the given hash
  867. #
  868.     my $profile = $_[0];      # profile file name
  869.     my $device  = $_[1];      # base device number 
  870.     my %source  = %{$_[2]};   # source hash
  871.  
  872.     my $l;         # line
  873.     my $new;       # new device number
  874.     my @result;    # result as list
  875.     my @add;       # new sections through the profile
  876.     my $newsec;    # loop counter for new sections
  877.     my $data;      # raw profile key
  878.     my $line;      # raw profile data
  879.     my @v;         # list of keys (->)
  880.     my $search;    # formatted search string
  881.     my $size;      # size of @v
  882.     my $ViewValue; # Tree view
  883.     my $ViewRef;   # Tree view reference
  884.     my $key;       # equals $data
  885.     my $value;     # equals $ViewValue
  886.     my $str;       # join "->" @v
  887.  
  888.     # check device...
  889.     # ----------------
  890.     if (! defined $device) {
  891.         $device = 0;
  892.     }
  893.     # check file...
  894.     # --------------
  895.     if (! -f $profile) {
  896.         return (%source);
  897.     }
  898.     # read profile data...
  899.     # ---------------------
  900.     open(DATA,"$profile");
  901.     while($l = <DATA>) {
  902.     chomp($l);
  903.     SWITCH: for ($l) {
  904.     /^.*\[X\].*/         && do {
  905.         $l =~ s/\[X\]/$device/g;
  906.     };
  907.  
  908.     /^.*\[X\+([1-9]).*/  && do {
  909.         $new = $device + $1;
  910.         $l =~ s/\[X\+[1-9]\]/$new/g;
  911.         push(@add,$new);
  912.     };
  913.     }
  914.     push(@result,$l);
  915.     }
  916.     close(DATA);
  917.  
  918.     # include the data to the hash.
  919.     # /.../
  920.     # if a profile includes new sections we had to create 
  921.     # space for this sections. Therefore the branch on the
  922.     # old section is moved to the next section ( old +1 )
  923.     # ------------------------------------------------------
  924.     @add = unique (@add);
  925.     foreach $newsec (@add) {
  926.         %source = HMoveBranch(\%source,$newsec);
  927.     }
  928.     foreach (@result) {
  929.     if ($_ =~ /(.*)=.*{(.*)}.*/) {
  930.         $data      = $1;
  931.         $line      = $2;
  932.         $line      =~ s/ +//g;
  933.         @v         = split(/->/,$line);
  934.         $search    = join("->",@v);
  935.         $size      = @v;
  936.         $ViewValue = "";
  937.         $ViewRef   = "";
  938.         $ViewValue = HGetValue(\%source,$search);
  939.         $ViewValue =~ s/^ +//g;
  940.         $ViewValue =~ s/ +$//g;
  941.         $_ = "$data = $ViewValue\n";
  942.     }
  943.     if ($_ =~ /^(.*)=(.*)/) {
  944.         $key       = $1;
  945.         $value     = $2;
  946.         $key       =~ s/ +//g;
  947.         $value     =~ s/^ +//g;
  948.         @v         = split(/->/,$key);
  949.         $str       = join("->",@v);
  950.         %source    = HSetValue(\%source,$str,$value);
  951.     }
  952.     }
  953.     %source = HUpdateServerLayout(\%source); 
  954.     return (%source);
  955. }
  956.  
  957. #---[ CheckFramebufferModes ]----#
  958. sub CheckFramebufferModes {
  959. #----------------------------------------------------------
  960. # Check if the fbdev driver is used... if yes get the
  961. # currently used framebuffer resolution and color depth
  962. # and build the Modes:<X> = <Y> line
  963.     my %import  = %{$_[0]};
  964.     foreach (keys %{$import{Card}}) {
  965.     my @keylist = split(/ +/,$_);
  966.     if (($keylist[1] eq "Driver") && ($import{Card}{$_} eq "fbdev")) {
  967.         my $resolution = GetFbResolution();
  968.         my $colordepth = GetFbColor();
  969.         $import{Desktop}{"$keylist[0] Modes:$colordepth"} = $resolution;
  970.         $import{Desktop}{"$keylist[0] ColorDepth"} = $colordepth;
  971.     }
  972.     }
  973.     return (%import);
  974. }
  975.  
  976. #---[ unique ]----#
  977. sub unique {
  978. #----------------------------------------------------------
  979. # create unique list of members
  980. #
  981.     my @list = @_;
  982.     my @result;
  983.     my %map;
  984.  
  985.     sub num { $a <=> $b; };
  986.     foreach (@list) {
  987.     if ($_ =~ /[0-9]+/) {
  988.         $map{$_} = $_;
  989.     }
  990.     }
  991.     @result = sort num keys(%map);
  992.     return(@result);
  993. }
  994.  
  995. #---[ CreateSecureDir ]-------#
  996. sub CreateSecureDir {
  997. #----------------------------------------------------------
  998. # create secure directory using mktemp
  999. #
  1000.     my $dir;
  1001.     $dir = qx(mktemp -qd /tmp/isax.XXXXXX);
  1002.     $dir =~ s/\n+//g;
  1003.     if (! -d $dir) {
  1004.         die "ISaX: could not create tmp dir: $dir";
  1005.     }
  1006.     return($dir);
  1007. }
  1008.  
  1009. #---[ RemoveSecureDir ]-------#
  1010. sub RemoveSecureDir {
  1011. #----------------------------------------------------------
  1012. # remove secure directory
  1013. #
  1014.     my $dir = $_[0];
  1015.     qx(rm -rf $dir);
  1016. }
  1017.  
  1018. #---[ GetFbColor ]-----#
  1019. sub GetFbColor {
  1020. #----------------------------------------------------------
  1021. # this function test for the framebuffer
  1022. # color depth
  1023. #
  1024.     my $data = FBSet::FbGetData();
  1025.     my $cols = $data->swig_depth_get();
  1026.     if ($cols < 8) {
  1027.         return 8;
  1028.     }
  1029.     return $cols;
  1030. }
  1031.  
  1032. #---[ GetFbResolution ]-----#
  1033. sub GetFbResolution {
  1034. #----------------------------------------------------------
  1035. # this function test for the framebuffer
  1036. # resolution
  1037. #
  1038.     my $data = FBSet::FbGetData();
  1039.     my $xres = $data->swig_x_get();
  1040.     my $yres = $data->swig_y_get();
  1041.     return $xres."x".$yres;
  1042. }
  1043.  
  1044. #---[ ConstructInputOptions ]-----#
  1045. sub ConstructInputOptions {
  1046. #----------------------------------------------------------
  1047. # refering to the MergeParseResult function we will create
  1048. # the RawOption index according to the InputOptions keys
  1049. #
  1050.     my %input = %{$_[0]};
  1051.     my %InputOptions;
  1052.     $InputOptions{Protocol}           = 1;
  1053.     $InputOptions{Device}             = 1;
  1054.     $InputOptions{SampleRate}         = 1;
  1055.     $InputOptions{BaudRate}           = 1;
  1056.     $InputOptions{Emulate3Buttons}    = 1;
  1057.     $InputOptions{Emulate3Timeout}    = 1;
  1058.     $InputOptions{ChordMiddle}        = 1;
  1059.     $InputOptions{ClearDTR}           = 1;
  1060.     $InputOptions{ClearRTS}           = 1;
  1061.     $InputOptions{ZAxisMapping}       = 1;
  1062.     $InputOptions{MinX}               = 1;
  1063.     $InputOptions{MaxX}               = 1;
  1064.     $InputOptions{MinY}               = 1;
  1065.     $InputOptions{MaxY}               = 1;
  1066.     $InputOptions{MaximumYPosition}   = 1;
  1067.     $InputOptions{MinimumYPosition}   = 1;
  1068.     $InputOptions{MaximumXPosition}   = 1;
  1069.     $InputOptions{MinimumXPosition}   = 1;
  1070.     $InputOptions{ScreenNumber}       = 1;
  1071.     $InputOptions{ScreenNo}           = 1;
  1072.     $InputOptions{ReportingMode}      = 1;
  1073.     $InputOptions{Rotation}           = 1;
  1074.     $InputOptions{ButtonThreshold}    = 1;
  1075.     $InputOptions{ButtonNumber}       = 1;
  1076.     $InputOptions{Buttons}            = 1;
  1077.     $InputOptions{SendCoreEvents}     = 1;
  1078.     $InputOptions{Vendor}             = 1;
  1079.     $InputOptions{Name}               = 1;
  1080.     $InputOptions{Type}               = 1;
  1081.     $InputOptions{Mode}               = 1;
  1082.     $InputOptions{Load}               = 1;
  1083.     $InputOptions{InputFashion}       = 1;
  1084.     $InputOptions{Option}             = 1;
  1085.     $InputOptions{TopX}               = 1;
  1086.     $InputOptions{TopY}               = 1;
  1087.     $InputOptions{BottomX}            = 1;
  1088.     $InputOptions{BottomY}            = 1;
  1089.     $InputOptions{Suppress}           = 1;
  1090.     $InputOptions{Serial}             = 1;
  1091.     $InputOptions{EmulateWheel}       = 1;
  1092.     $InputOptions{EmulateWheelButton} = 1;
  1093.  
  1094.     foreach my $id (keys %{$input{InputDevice}}) {
  1095.         my $option = "";
  1096.         if ($input{InputDevice}{$id}{Identifier} =~ /Mouse\[(.*)\]/) {
  1097.             foreach my $opt (keys %{$input{InputDevice}{$id}{Option}}) {
  1098.             if (! defined $InputOptions{$opt}) {
  1099.                 my $optval = $input{InputDevice}{$id}{Option}{$opt};
  1100.                 if ($optval ne "") {
  1101.                     $option = "$option,\"$opt\" \"$optval\"";
  1102.                     $option =~ s/^,//;
  1103.                     $input{InputDevice}{$id}{Option}{RawOption} = $option;
  1104.                     delete $input{InputDevice}{$id}{Option}{$opt};
  1105.                 }
  1106.             }
  1107.             }
  1108.         }
  1109.     }
  1110.     return %input;
  1111. }
  1112.  
  1113. # start with main...
  1114. # -------------------
  1115. main();
  1116.