cant remember?
[php-bacula-disk-changer.git] / bin / pbdc.php
index b7b8d07..6649e0a 100644 (file)
@@ -1,10 +1,11 @@
 <?php
 
-$BASE_LIB="../lib";
-$BASE_DATA="../db";
-$BACULA_USER="paulr";
+$BASE_LIB=$_SERVER["BASE_LIB"];
+$BASE_DIR=$_SERVER["BASE_DIR"];
+$BASE_DATA=$_SERVER["BASE_DATA"];
+$BACULA_USER=$_SERVER["BACULA_USER"];
 
-global $BASE_DATA, $BASE_LIB, $BACULA_USER;
+global $BASE_DATA, $BASE_LIB, $BACULA_USER, $BASE_DIR;
 
 require_once "$BASE_LIB/lib.php";
 
@@ -25,26 +26,190 @@ switch($command) {
                init();
                break;
        case "bacula-config":
+               bacula_config();
                break;
        case "add-disk":
                add_disk();
                break;
        case "disks":
+               list_disks();
                break;
        case "status":
+               pbdc_status();
                break;
        default:
                echo "invalid command\n";
 }
 
+function bacula_config()
+{
+       global $BASE_DATA, $BASE_LIB, $BACULA_USER, $argv, $BASE_DIR;
+       
+       check_init_and_fail($argv[1]);
+       $changer = $argv[1];
+
+       $db = db_getDB($argv[1]);
+       
+       $ntapes = conf_getVal($changer, "ndrives");
+       $tapeloc = conf_getVal($changer, "drivelocation");
+       $tapesz = conf_getVal($changer, "tapesize");
+       
+       // TODO: do this bit
+       // bacula-sd.conf
+       ?>
+-------------------------------- bacula-sd.conf -----------------------------
+Autochanger {
+  Name = <?php echo "$changer\n"?>
+<?php
+  for($i=0; $i<$ntapes; $i++) {
+       echo "  Device = \"$changer-drive$i\"\n";
+  } 
+?>
+  Changer Command = "<?php echo $BASE_DIR."/bin/pbdc-bacula"?> %c %o %S %a %d"
+  Changer Device = "<?php echo $changer ?>"
+}
+
+<?php 
+       for($i=0; $i < $ntapes; $i++) {
+?>
+Device {
+  Name = <?php echo "\"$changer-drive$i\"\n" ?>
+  DriveIndex = <?php echo "$i\n" ?>
+  Autochanger = yes;
+  DeviceType = File
+  MediaType = File
+  ArchiveDevice = <?php echo "\"$tapeloc/$changer-drive$i\"\n" ?>
+  RemovableMedia = no;
+  RandomAccess = yes;
+}
+
+
+<?php
+       } 
+?>
+
+
+-------------------------------- bacula-dir.conf -----------------------------
+Storage {
+  Name = <INSERT STORAGE NAME>
+  Address = <ADDRESS OF WHERE SD IS RUNNING>
+  SDPort = 9103
+  Password = "<SD PASSWORD>"
+  Device = <?php echo "\"$changer-drive$i\"\n" ?>
+  Media Type = File
+  Autochanger = yes;
+}
+
+# a pool for our storage
+Pool {
+  Name = <POOL NAME GOES HERE>
+  Pool Type = Backup
+  Recycle = yes                        # Bacula can automatically recycle Volumes
+  AutoPrune = yes                      # Prune expired volumes
+  Volume Retention = 50 days           # I set this to 50 days, dont ask me why
+  Maximum Volume Bytes = <?php echo "$tapesz"."G"?>           # Limit Volume size to something reasonable
+  Maximum Volumes = 1000               # Limit number of Volumes in Pool SET THIS
+}
+
+# add a default job job defs for our pool - modify where necessary
+# i.e. look at the normal jobdefs, or modify that with your backup defs.
+JobDefs {
+  Name = "PBDCJobDefs"
+  Type = Backup
+  Level = Incremental
+  Storage = <INSERT STORAGE NAME>
+  Messages = Standard
+  Pool = <POOL NAME GOES HERE>
+  Priority = 10
+  Write Bootstrap = "/var/lib/bacula/%c.bsr"
+}
+
+
+<?php
+
+}
+
+function pbdc_status()
+{
+       global $BASE_DATA, $BASE_LIB, $BACULA_USER, $argv;
+       
+       check_init_and_fail($argv[1]);
+       $changer = $argv[1];
+
+       $db = db_getDB($argv[1]);
+       
+       $res = $db->query("select * from disk_list");
+       
+       $tapeloc = conf_getVal($changer, "drivelocation");
+       $amloc = conf_getVal($changer, "automountdir");
+       
+       $ret = false;
+       foreach($res as $row) {
+               echo "Listing tapes for disk ".$row["disk_id"].", ".$row["disk_name"]."\n";
+               //echo "dir: $amloc/".$row["disk_name"]."/pbdc/".$argv[1]."/tapes/\n";
+               //exit(0);
+               $dh = opendir("$amloc/".$row["disk_name"]."/pbdc/".$argv[1]."/tapes/");
+               while(($file = readdir($dh)) !== false) {
+                       if(ereg("d[0-9]+_vol[0-9]+", $file)!=false) {
+                               $sql = "select slot_no from slots where tape_name=='$file'";
+                               $res2 = $db->query($sql);
+                               if($res2) {
+                                       foreach($res2 as $row2)
+                                       $slot = $row2["slot_no"];
+                               } else $slot = "none";
+                               echo "Tape: $file (slot $slot)\n";
+                       } else {
+                               //echo "didnt match: $file\n";
+                       }
+                       //exit(0);
+               }
+               closedir($dh);
+       }
+       
+       $nt = (int)(conf_getVal($changer, "ndrives"));
+       for($i = 0; $i < $nt; $i++) {
+               if(file_exists("$tapeloc/$changer-drive$i")) {
+                       $rl = basename(readlink("$tapeloc/$changer-drive$i"));
+                       echo "drive $i points has tape $rl loaded\n";
+               } else {
+                       echo "drive $i is unloaded\n";
+               }
+       }
+}
+
+function list_disks()
+{
+       global $BASE_DATA, $BASE_LIB, $BACULA_USER, $argv;
+       
+       check_init_and_fail($argv[1]);
+       
+       $db = db_getDB($argv[1]);
+       
+       $res = $db->query("select * from disk_list");
+       
+       $ret = false;
+       foreach($res as $row) {
+               echo "Disk ".$row["disk_id"].": ".$row["disk_name"]."\n";
+               $ret = true;    
+       }
+       
+       if(!$ret) {
+               echo "No disks defined yet for this changer\n";
+       }
+       
+       
+       return;
+}
+
 function init()
 {
        global $BASE_DATA, $BASE_LIB, $BACULA_USER, $argv;
        
        // check if we are the bacula user
-       $user = posix_getlogin();
+       //$user = posix_getlogin();
+       $user = $_SERVER["USER"];
        if($user != $BACULA_USER) {
-               echo "This command must be run as the bacula user\n";
+               echo "This command must be run as the bacula user ($BACULA_USER not $user)\n";
                exit(0);
        }
        
@@ -52,12 +217,13 @@ function init()
        
        echo "This command will init the data for $changer_name\n";
        
-       if(file_exists("$BASE_DATA/$changer_name.db")) {
+       if(file_exists("$BASE_DATA/$changer_name.db")&&check_init($changer_name)) {
                //echo "Daemon is already init'd, are you sure you wish to do this, it will loose all config [y/n]:";
                $r = readline("Daemon is already init'd, are you sure you wish to do this, it will loose all config [y/n]:");
                if($r == "y") {
                        echo "Ok, but its your disaster, waiting 5 seconds prior to init'ing the database (hit ctrl-c to exit)\n";
                        sleep(5);
+                       unlink("$BASE_DATA/$changer_name.db");
                } else {
                        echo "Ok, not doing it, so long chum\n";
                        exit(0);
@@ -66,14 +232,82 @@ function init()
        
        echo "Creating database\n";
        $ra = readline("Directory where automount occurs [/changer/]:");
-       $rb = readline("Number of drives [1]:");
+       $rb = readline("Number of drives [2]:");
        $rc = readline("Size of tapes [20] (in gb):");
+       $rd = readline("Where to store drive pointers [/var/run/bacula/]:");
        
        if($ra == "") $ra = "/changer/";
-       if($rb == "") $rb = 1;
+       if($rb == "") $rb = 2;
        if($rc == "") $rc = 20;
+       if($rd == "") $rd = "/var/run/bacula/";
        
-       db_getDB($changer_name);
+       conf_setVal($changer_name, "automountdir", "$ra");
+       conf_setVal($changer_name, "ndrives", "$rb");
+       conf_setVal($changer_name, "tapesize", "$rc");
+       conf_setVal($changer_name, "drivelocation", "$rd");
+       
+       // check if they were set
+       // echo "got: ".conf_getVal($changer_name, "automountdir").", and ".conf_getVal($changer_name, "tapesize").", and ".conf_getVal($changer_name, "ndrives")."\n";
+}
+
+function check_init_and_fail($changer)
+{
+       $lk = conf_getVal($changer, "automountdir");
+       if(!$lk) {
+               echo "DB not init'd yet, please run init first\n";
+               exit(0);
+       } 
+}
+
+function check_init($changer)
+{
+       $lk = conf_getVal($changer, "automountdir");
+       if(!$lk) {
+               return false;
+       } 
+       
+       return true;
+}
+
+function disk_get_size($file, $realname="")
+{
+       global $BASE_DATA, $BASE_LIB, $BACULA_USER, $argv;
+       
+       check_init_and_fail($argv[1]);
+
+       $changer = $argv[1];
+       
+       error_reporting(E_ALL);
+       
+       $dh = opendir("/dev/disk/by-uuid");
+       $amdir = conf_getVal($changer, "automountdir");
+       
+       $ts = 0;
+
+       $parsed = false;
+       if(file_exists("/$amdir/$file/.")) {
+               $cmd = "/bin/df -k /$amdir/$file/. |/usr/bin/tail -1  |/usr/bin/awk '{ print $4 }'";
+               $pl = popen($cmd, "r");
+               if($pl) {
+                       $f = fread($pl, 1024);
+                       //echo "cmd: $cmd\nf: $f\n";
+                       $ts = (int)($f);
+                       if($ts > 1) $parsed = true;
+                       pclose($pl);
+               }
+       }
+       
+       if(!$parsed && $realname != "") {
+               $fh = fopen("/sys/class/block/$realname/size", "r");
+               $lk = ((int)(fgets($fh)));
+               $ts = ($lk/1024)*512;
+               fclose($fh);
+               
+       }
+       
+       $realsize = (int)(($ts/1024)/1024);
+
+       return $realsize;
 }
 
 function add_disk()
@@ -82,7 +316,12 @@ function add_disk()
        // creating pbdc/changer_name/stuff.
        global $BASE_DATA, $BASE_LIB, $BACULA_USER, $argv;
        
+       check_init_and_fail($argv[1]);
+       
+       $changer = $argv[1];
+       
        $dh = opendir("/dev/disk/by-uuid");
+       $amdir = conf_getVal($changer, "automountdir");
        
        $disk = "";
        $i = 0;
@@ -91,18 +330,15 @@ function add_disk()
                if($file != "." && $file != "..") {
                        $st = stat("/dev/disk/by-uuid/".$file);
                        $realname = basename(readlink("/dev/disk/by-uuid/".$file));
+                       $realsize = disk_get_size($file, $realname);
                        
-                       // now get the size
-                       $fh = fopen("/sys/class/block/$realname/size", "r");
-                       $rl = fgets($fh);
-                       fclose($fh);
-                       $realsize = (int)(((($rl/1024)*512)/1024)/1024);
-                       
+                       // now get the size, first lets try and parse df output
                        echo "disk $i: /dev/$realname or /dev/disk/by-uuid/$file of size ".$realsize."gb\n";
                        $disk[$i]["real"] = "/dev/$realname";
                        $disk[$i]["syml"] = "/dev/disk/by-uuid/".$file;
                        $disk[$i]["size"] = $realsize;
                        $i++;
+                       
                }
        }
        
@@ -123,6 +359,102 @@ function add_disk()
 
        // now we try and init the disk
        // we have to get automount directory config
-       //$k = mkdir();
+       $dir = conf_getVal($argv[1], "automountdir");
+       if(!is_dir($dir)) {
+               echo "cant find automount directory, $dir\n";
+       }
+       $mkd = "$dir/".basename($disk[$i]["syml"])."/pbdc/".$argv[1]."/tapes/";
+       $k = mkdir($mkd, 0700, true);
+       
+       if(!is_dir($mkd)) {
+               echo "Error, couldn't create directory, check permissions on $mkd?\n";
+       }
+       
+       $ts = conf_getVal($argv[1], "tapesize");
+       $max = (int)($disk[$i]["size"]/$ts);
+       
+       $kt = (int)(readline("No of tapes to create [max:$max] @ ".$ts."gb each:"));
+       if($kt == "") $kt = $max;
+       if($kt < 0) $kt = $max;
+       if($kt > $max) {
+               echo "Sorry, max number of tapes is $max, creating $max instead\n";
+               $kt = $max;
+       }
+       
+       $did = add_diskToDB($argv[1], basename($disk[$i]["syml"]));
+       
+       if(!$did) {
+               echo "Disk already exists, doing nothing\n";
+               exit(0);
+       }
+       
+       // disk names are d.$did_vol0000x
+       //echo "did: $did\n";
+       for($ii=0; $ii < $kt; $ii++) {
+               $tid = sprintf("d%d_vol%04d", $did, $ii);
+               //echo "would create $tid\n";
+               $tp = "$dir/".basename($disk[$i]["syml"])."/pbdc/".$argv[1]."/tapes/$tid";
+               if(!file_exists($tp)) {
+                       fopen($tp, "w");
+                       echo "created tape $tid\n";
+               } else {
+                       echo "tape $tid already existed\n";
+               }
+               add_to_slot($argv[1], $tid, $did);
+       }
+}
+
+function add_to_slot($changer, $tapename, $disk_id)
+{
+       global $BASE_DATA, $BASE_LIB, $BACULA_USER, $argv;
+       
+       $db = db_getDB($changer);
+       
+       $slot = "";
+       $slots = 0;
+       $max_slot = 0;
+       
+       $res = $db->query("select * from slots");
+       foreach($res as $row) {
+               $slot[$row["slot_no"]]["diskid"] = $row["disk_id"];
+               $slot[$row["slot_no"]]["tapename"] = $row["tape_name"];
+               $slots++;
+               if($row["slot_no"] > $max_slot) $max_slot = $row["slot_no"];
+       }
+       
+       // first tape, straight in with you
+       if($slots == 0) {
+               $db->query("insert into slots values (NULL, 1, $disk_id, '$tapename')");
+               return;
+       }
+       
+       // next hunt thru the slots and see if its filled yet.
+       foreach($slot as $lk) {
+               if($lk["tapename"] == $tapename) {
+                       // tape was already there, move along
+                       return;
+               }
+       }
+       
+       // now we go from 0 to the end looking for a free slot
+       for($i=1; $i < $max_slot; $i++) {
+               if(!isset($slot[$i])) {
+                       // we have a free slot, but it shouldnt appear that way like that.. oh well.
+                       $db->query("insert into slots values (NULL, $i, $disk_id, '$tapename')");
+                       return;
+               }
+               if($slot[$i]["tapename"] == "") {
+                       // slot is free
+                       $db->query("delete from slots where slot_no='$i'");
+                       $db->query("insert into slots values (NULL, $i, $disk_id, '$tapename')");
+                       return;
+               }
+       }
+       
+       // So much error checking to do.
+       // if we made it here, we need more slots.
+       $ns = $max_slot + 1;
+       $db->query("insert into slots values (NULL, $ns, $disk_id, '$tapename')");
+       return;
 }
 ?>
\ No newline at end of file