Patch title: Release 94 bulk changes
Abstract:
File: /pliant/fullpliant/recover.pli
Key:
    Removed line
    Added line
abstract
  [This is Pliant CDROM installation/recovery script.]

submodule "/pliant/fullpliant/computer.pli"
module "/pliant/language/compiler.pli"
module "/pliant/language/stream.pli"
module "/pliant/language/stream/filesystembase.pli"
module "/pliant/language/stream/multi.pli"
module "install.pli"
module "/pliant/admin/file.pli"
module "/pliant/admin/execute.pli"
module "/pliant/linux/storage/partition.pli"
module "/pliant/linux/storage/filesystem.pli"
module "/pliant/language/ui/ansi_terminal.pli"
module "/pliant/linux/kernel/shutdown.pli"
module "/pliant/linux/network/net.pli"
module "/pliant/linux/network/boot.pli"
module "/pliant/language/stream/tcp.pli"
module "/pliant/appli/database/light.pli"
module "/pliant/storage/database/light.pli"
module "/pliant/util/crypto/rsa.pli"
module "/pliant/util/network/ping.pli"
module "/pliant/protocol/dns/name.pli"
module "/pliant/protocol/http/site.pli"
module "/pliant/language/context.pli"

constant mdadm (file_query "file:/bin/mdadm" standard)=success

function display_hardware
  (var Stream s) open "file:/proc/pci" in+safe
  while not s:atend
    if (s:readline parse any word:"device" any:(var Str vendor) ":" any:(var Str device) "(" word:"rev" any:(var Str rev) ")" any)
      var Str v_name := "" ; var Str d_name := "" ; var CBool v_ok := false ; var CBool d_ok := false
      (var Stream lst) open "data:/pliant/fullpliant/pci_device_listing1.txt" in+safe
      while not lst:atend
        var Str l := lst readline
        if (l 4 1)="[tab]"
          v_ok := upper:(l 0 4)=upper:vendor
          if v_ok
            v_name := l 5 l:len
        eif (l 0 1)="[tab]" and upper:(l 1 4)=upper:device and v_ok
          d_name := l 6 l:len
      v_ok := false ; d_ok := false
      (var Stream lst) open "data:/pliant/fullpliant/pci_device_listing2.txt" in+safe
      while not lst:atend
        var Str l := lst readline
        if (l parse any:(var Str code) _ any:(var Str id) _ any:(var Str name))
          if code="V"
            v_ok := upper:id=upper:vendor ; d_ok := false
            if v_ok
              v_name := name
          eif code="D"
            d_ok := v_ok and upper:id=upper:device
            if d_ok
              d_name := l 7 l:len
          eif code="R"
            if d_ok and upper:(right id 4 "0")=upper:(right rev 4 "0")
              d_name := name
      console upper:vendor " " v_name "  " upper:device " " upper:rev " " d_name eol

function recover c action options
  arg_rw Data:Computer c ; arg Str action options

  enumerate_partitions c (var Dictionary partitions) (var Dictionary disks)
  if action="partition"
    if (file_query "file:/proc/mdstat" standard)=success
      for (var Int i) 0 15
        execute "raidstop /dev/md"+string:i quiet
      if mdadm
          execute "mdadm --stop --scan" quiet
      else
        for (var Int i) 0 15
          execute "raidstop /dev/md"+string:i quiet
    each d disks type Str
      console "Partitioning " d " disk" eol
      install_partition c d
    each p partitions type DiskPartition
      if p:name<>"" and p:filesystem<>"raid"
      var Str disk_image := p:options option "disk_image" Str
      if disk_image<>""
        console "Extracting " disk_image " disk image to partition " p:device
        console ": " (shunt (file_copy "gzip:file:/fullpliant/archive/partition/"+disk_image+".gz" p:device reduced)=success "ok" "failed") eol
      eif p:name<>"" and p:filesystem<>"raid"
        console "Formating " p:device " partition"
        console ": " (shunt (install_format c p:name)=success "ok" "failed") eol

  if action="format"
    console "Formating root partition"
    console ": " (shunt (install_format c "root")=success "ok" "failed") eol
  
  if action="setup"
    console "Setup the system identity, IP and routing" eol
  eif action="recover"
    console "Recovering the system" eol
  else
    console "Installing the system" eol
  if (filesystem_mount c:env:"partition":"root":"device" "file:/mnt/target/" "")=failure
    console "Failed to mount " c:env:"partition":"root":"device" " partition" eol
    return
  pliant_multi_file_system mount "target:/" "file:/mnt/target/" pliant_default_file_system

  var Array:FileInfo files := file_list "target:/pliant/binary/" standard
  for (var Int i) 0 files:size-1
    if files:i:extension=".dump"
      file_delete files:i:name
  if action<>"setup"
    if action="recover"
      file_move "target:/pliant_security/" "target:/pliant_security.backup/"
    var Str embedded := c:env:"pliant":"system":"embedded"
    if embedded<>""
      file_extract "file:/fullpliant/archive/embedded/"+embedded+".tgz" "target:/"+embedded+"/"
    file_extract "file:/fullpliant/archive/"+keyof:c+".tgz" "target:/"
    if action="recover"
      file_tree_delete "target:/pliant_security/"
      file_move "target:/pliant_security.backup/" "target:/pliant_security/"
    console "Making system bootable" eol
    var Str root := c:env:"partition":"root":"device"
    var Str raid := c:env:"partition":"root":"raid_devices"
    var Str lbd := "device:/hda"
    if (root parse "device:/sd" any) or (root parse "device:/md" any) and ((raid parse "device:/sd" any) or (raid parse "sd" any))
      lbd := "device:/sda"
    var Str boot := c:env:"hardware":"disk":"boot"
    if boot<>""
      lbd := boot
    var Str lilo_options := c:env:"kernel":"constant":"options"
    lilo_install c "target:/" lbd root lilo_options ""

  var Str fullname := options option "fullname" Str
  if (fullname parse any:(var Str name) "." any:(var Str domain))
    if (data_read "target:/pliant_security/this_computer.pdb" "/env/pliant/http/site_key_bits" (var Int bits))=failure
      bits := 1024
    bits := options option "bits" Int bits
    console "Generating a "+string:bits+" bits key (be patient)" eol
    rsa_generate "target:"+fullname bits ""
    (var Stream s) open "target:/pliant_security/this_computer.pdb" append+safe
    s writeline "<pdata path=[dq]/env/pliant/identity/name[dq]>"+name+"</pdata>"
    s writeline "<pdata path=[dq]/env/pliant/identity/domain[dq]>"+domain+"</pdata>"
    s close
  var List:Str extra_lines
  (var Stream s) open "target:/pliant_security/user.pdb" in+safe
  while not s:atend
    if (s:readline eparse "<pdata path=[dq]/user/" any:(var Str user) "/right/" any:(var Str right) "/server[dq]>" (pattern keyof:c) "</pdata>")
      extra_lines += "<pdata path=[dq]/user/"+user+"/right/"+right+"/server[dq]>"+fullname+"</pdata>"
  (var Stream s) open "target:/pliant_security/user.pdb" append+safe
  each line extra_lines
    s writeline line
  s close
  var Str ip := options option "ip" Str
  var Str mask := options option "mask" Str
  if ip<>""
    (var Stream s) open "target:/pliant_security/name.pdb" append+safe
    s writeline "<pdelete path=[dq]/name/"+fullname+"[dq] />"
    s writeline "<pdata path=[dq]/host/"+fullname+"/ip[dq]>"+ip+"</pdata>"
    s writeline "<pdata path=[dq]/mask/"+ip+"[dq]>"+mask+"</pdata>"
    s close
  var Str route := options option "route" Str
  if route<>""
    (var Stream s) open "target:/pliant_security/this_computer.pdb" append+safe
    s writeline "<pdata path=[dq]/env/net_route/default/path[dq]>"+route+"</pdata>"
    s close

  pliant_multi_file_system dismount "target:/"
  filesystem_dismount "file:/mnt/target/"
  console "Done: DON'T FORGET TO REMOVE THE CD" eol
  sleep 30
  console "Now shutting down." eol
  kernel_shutdown false

function is_partition device -> c
  arg Str device ; arg CBool c
  (var Stream s) open device in+safe+nocache
  var Address buffer := memory_allocate 4096 null
  s raw_read buffer 4096
  memory_free buffer
  c := shunt s=success true false

function recover_menu
  console eol
  console "PCI hardware content is:" eol
  display_hardware
  console eol
  console "FULLPLIANT INSTALL/RECOVERY UTILITY" eol
  console eol
  if this_computer:env:"pliant":"system":"medium"<>"cdrom"
    console "This utility must be executed from a CD" eol
    return
  var Str fullname ip mask route
  console "Current identity:" eol
  for (var Int i) 0 2
    var Str root := shunt i=0 "md0" i=1 "hda1" i=2 "sda1" ""
    if fullname=""
      if (is_partition "device:/"+root) and (filesystem_mount "device:/"+root "file:/mnt/target/" "readonly nocheck")=success
        pliant_multi_file_system mount "target:/" "file:/mnt/target/" pliant_default_file_system
        if (data_read "target:/pliant_security/this_computer.pdb" "/env/pliant/identity/name" (var Str name))=success and (data_read "target:/pliant_security/this_computer.pdb" "/env/pliant/identity/domain" (var Str domain))=success
          fullname := name+"."+domain
          console "  computer name is " fullname eol
          computer_fullname := fullname
          if (data_read "target:/pliant_security/name.pdb" "/host/"+fullname+"/ip" ip)=success
            console "  IP is " ip eol
            net_shutdown "eth0"
            if (net_configure "eth0" ip+"/255.255.255.0")=failure
              console "Failed to reconfigure network card." eol
          if (data_read "target:/pliant_security/this_computer.pdb" "/env/net_route/default/path" route)=success or (data_read "target:/pliant_security/this_computer.pdb" "/env/net_route/internet/path" route)=success
            console "  default route is " route eol
            if (net_route "0.0.0.0/0.0.0.0" route)=failure
              console "Failed to set default route." eol
            console "  " (shunt (net_ping "212.180.52.85")=success "Internet connection is ok." "INTERNET CONNECTION IS BROKEN !") eol
          var CBool matched := false
          if (data_read "target:/pliant_security/name.pdb" "/host/"+fullname+"/public_key" (var Str public_key))=success
            if (data_read "target:/pliant_security/name_secret.pdb" "/host/"+fullname+"/private_key" (var Str private_key))=success
              console "  found " rsa_nbbits:public_key " bits key" eol
              site_database:data:site delete fullname
              site_secret_database:data:site delete fullname
              name_database:data:host create fullname
              name_database:data:host:fullname public_key := public_key
              name_secret_database:data:host create fullname
              name_secret_database:data:host:fullname private_key := private_key
              matched := (public_key parse word:"rsa" any:(var Str n1) _ any) and (private_key parse word:"rsa" any:(var Str n2) _ any) and n1=n2
          if not matched
            console "Could not find existing keys pair: generating a new one" eol
            rsa_generate "host:"+fullname 128 ""
        pliant_multi_file_system dismount "target:/"
        filesystem_dismount "file:/mnt/target/"
  console eol
  var Data:Computer c ; var Int count := 0
  console "Available computer models are: " eol
  each cc computer
    if (file_query "file:/fullpliant/archive/"+keyof:cc+".tgz" standard)=success
      console "  " keyof:cc eol
      c :> cc ; count += 1   
  console eol
  if count<>1
    var Str cname := keyboard_input "Computer model: "
    c :> computer cname
    if not exists:c or (file_query "file:/fullpliant/archive/"+cname+".tgz" standard)=failure
      console "There is no such a computer." eol
      return
    console eol
  var CBool canonical := false
  if { var Str new_fullname := keyboard_input "Computer name: " ; new_fullname<>"" }
    fullname := new_fullname
    if (fullname search "." -1)=(-1)
      console "The name must be something like "+fullname+".openpack.org" eol
      return
    computer_fullname := fullname
  eif fullname=""
    canonical := true
    fullname := keyof c
    computer_fullname := keyof c
  if canonical
    each t computer:fullname:env
      if (keyof:t parse "net_" any)
        this_computer:env create keyof:t
        data_copy t (this_computer:env keyof:t)
    net_boot
    console (shunt (net_ping "212.180.52.85")=success "Internet connection is ok." "INTERNET CONNECTION IS BROKEN !") eol
  eif { var Str new_ip := keyboard_input "IP: " ; new_ip<>"" }
    ip := new_ip
    var Str mask := keyboard_input "mask: "
    net_shutdown "eth0"
    if (net_configure "eth0" ip+"/"+mask)=success
      console "Network card is configured." eol
    else
      console "Failed to reconfigure network card." eol
    route := keyboard_input "Default route: "
    if route<>""
      if (net_route "0.0.0.0/0.0.0.0" route)=success
        console "Default route is ok." eol
      else
        console "Failed to set default route." eol
      console (shunt (net_ping "212.180.52.85")=success "Internet connection is ok." "INTERNET CONNECTION IS BROKEN !") eol
  part menu
    console eol
    console "Possible actions are: command check parted partition format install recover setup" eol
    console "If you select 'partition', all datas on all disks will be lost." eol
    console "If you select 'format', all datas on the "+c:env:"partition":"root":"device"+" partition will be lost." eol
    console "If you select 'install', your programs and configuration files will be reset." eol
    console "If you select 'recover', only programs should be reset." eol
    console "If you select 'setup', only computer name, IP and default route will be changed." eol
    console "Anyway, nothing is granted." eol
    console eol
    var Str action := keyboard_input "action: "
    console eol
    if action="command"
      var Link:List program :> new List
      while { var Str l := keyboard_input "> " ; l<>"" }
        program append addressof:(new Str l)
      pliant_compiler_semaphore request
      var Link:Module module :> new Module
      module name := "recover"
      module include the_module:"/pliant/language/basic/safe.pli"
      module include the_module:"/pliant/language/compiler.pli"
      module include the_module:"/pliant/admin/file.pli"
      module include the_module:"/pliant/admin/execute.pli"
      error_push_record (var ErrorRecord e) error_filter_all
      compile_text program module
      var Str err := shunt e:id<>error_id_noerror e:message ""
      e id := error_id_noerror
      error_pull_record e
      pliant_compiler_semaphore release
      if err<>""
        console err eol
      restart menu
    eif action="check"
      filesystem_mount c:env:"partition":"root":"device" "file:/mnt/target/" "check readonly"
      filesystem_dismount "file:/mnt/target/"
      restart menu
    eif (action parse word:"check" any:(var Str device))
      filesystem_mount device "file:/mnt/target/" "check readonly"
      filesystem_dismount "file:/mnt/target/"
      restart menu
    eif action="parted"
      execute "parted"
      restart menu
    eif action="partition" or action="format" or action="install" or action="recover" or action="setup"
      recover c action "fullname "+string:fullname+" ip "+string:ip+" mask "+string:mask+" route "+string:route
    else
      console "Unsupported action specifyed." eol
      restart menu

function downgrade timeout
  arg Float timeout
  if (execute "tar -zc -f /boot/downgrade.tmp /pliant/")<>0
    console "Failed to create recovery tarball" eol
    return
  file_move "file:/boot/downgrade.tmp" "file:/boot/downgrade.tgz"  
  var Float remain := timeout
  while remain>0
    sleep 1
    if (file_query "file:/boot/downgrade.tgz" standard)=undefined
      return
    remain -= 1
  file_move "file:/boot/downgrade.tgz" "file:/boot/do_downgrade.tgz"  
  if (file_query "file:/boot/do_downgrade.tgz" standard)=defined
    (var Stream log) open "file:/boot/downgrade.log" append+safe
    log writeline "Pliant tree was downgraded on "+string:datetime
    log close
    console "*** DOWNGRADING THE PLIANT TREE ***" eol
    file_tree_delete "file:/pliant/"
    file_extract "file:/boot/do_downgrade.tgz" "file:/"
    file_delete "file:/boot/do_downgrade.tgz"  
    var Array:FileInfo files := file_list "file:/pliant/binary/" standard
    for (var Int i) 0 files:size-1
      if files:i:extension=".dump"
        file_delete files:i:name

  
export display_hardware recover_menu downgrade