4 # This code is issued under the GNU General Public License.
5 # See the file COPYING in this distribution
7 # Copyright (C) 1998, Stelias Computing
9 # Modified for InterMezzo from Gordian's HSM bcache device/jcm module
10 # Copyright (C) 1999, Carnegie Mellon University
12 # Derived from InterMezzo's incontrol, modified for OBD's
13 # Copyright (C) 1999, Stelias Computing
18 BEGIN { require "asm/errno.ph" };
19 BEGIN { require "asm/ioctl.ph" };
21 # p2ph generated invalid macros for ioctl stuff, so I override some of it here
22 eval 'sub OBD_IOC_CREATE () { &_IOC(2, ord(\'f\'), 3, 4);}' unless
23 defined(&OBD_IOC_CREATE);
24 eval 'sub OBD_IOC_SETUP () { &_IOC(1, ord(\'f\'), 4, 4);}' unless
25 defined(&OBD_IOC_SETUP);
26 eval 'sub OBD_IOC_CLEANUP () { &_IOC(0, ord(\'f\'), 5, 0);}' unless
27 defined(&OBD_IOC_CLEANUP);
28 eval 'sub OBD_IOC_DESTROY () { &_IOC(1, ord(\'f\'), 6, 4);}' unless
29 defined(&OBD_IOC_DESTROY);
30 eval 'sub OBD_IOC_PREALLOCATE () { &_IOC(3, ord(\'f\'), 7, 4);}' unless
31 defined(&OBD_IOC_PREALLOCATE);
32 eval 'sub OBD_IOC_DEC_USE_COUNT () { &_IOC(0, ord(\'f\'), 8, 0);}' unless
33 defined(&OBD_IOC_DEC_USE_COUNT);
34 eval 'sub OBD_IOC_SETATTR () { &_IOC(1, ord(\'f\'), 9, 4);}' unless
35 defined(&OBD_IOC_SETATTR);
36 eval 'sub OBD_IOC_GETATTR () { &_IOC(2, ord(\'f\'), 10, 4);}' unless
37 defined(&OBD_IOC_GETATTR);
38 eval 'sub OBD_IOC_READ () { &_IOC(3, ord(\'f\'), 11, 4);}' unless
39 defined(&OBD_IOC_READ);
40 eval 'sub OBD_IOC_WRITE () { &_IOC(3, ord(\'f\'), 12, 4);}' unless
41 defined(&OBD_IOC_WRITE);
42 eval 'sub OBD_IOC_CONNECT () { &_IOC(2, ord(\'f\'), 13, 4);}' unless
43 defined(&OBD_IOC_CONNECT);
44 eval 'sub OBD_IOC_DISCONNECT () { &_IOC(1, ord(\'f\'), 14, 4);}' unless
45 defined(&OBD_IOC_DISCONNECT);
46 eval 'sub OBD_IOC_STATFS () { &_IOC(3, ord(\'f\'), 15, 4);}' unless
47 defined(&OBD_IOC_STATFS);
48 eval 'sub OBD_IOC_SYNC () { &_IOC(2, ord(\'f\'), 16, 4);}' unless
49 defined(&OBD_IOC_SYNC);
50 eval 'sub OBD_IOC_READ2 () { &_IOC(3, ord(\'f\'), 17, 4);}' unless
51 defined(&OBD_IOC_READ2);
52 eval 'sub OBD_IOC_FORMATOBD () { &_IOC(3, ord(\'f\'), 18, 4);}' unless
53 defined(&OBD_IOC_FORMATOBD);
54 eval 'sub OBD_IOC_PARTITION () { &_IOC(3, ord(\'f\'), 19, 4);}' unless
55 defined(&OBD_IOC_PARTITION);
56 eval 'sub OBD_IOC_ATTACH () { &_IOC(3, ord(\'f\'), 20, 4);}' unless
57 defined(&OBD_IOC_ATTACH);
58 eval 'sub OBD_IOC_DETACH () { &_IOC(3, ord(\'f\'), 21, 4);}' unless
59 defined(&OBD_IOC_DETACH);
60 eval 'sub OBD_IOC_COPY () { &_IOC(3, ord(\'f\'), 22, 4);}' unless
61 defined(&OBD_IOC_COPY);
62 eval 'sub OBD_IOC_MIGR () { &_IOC(3, ord(\'f\'), 23, 4);}' unless
63 defined(&OBD_IOC_MIGR);
64 eval 'sub OBD_SNAP_SETTABLE () { &_IOC(3, ord(\'f\'), 40, 4);}' unless
65 defined(&OBD_SNAP_SETTABLE);
66 eval 'sub OBD_SNAP_PRINTTABLE () { &_IOC(3, ord(\'f\'), 41, 4);}' unless
67 defined(&OBD_SNAP_PRINTTABLE);
68 eval 'sub OBD_SNAP_DELETE() { &_IOC(3, ord(\'f\'), 42, 4);}' unless
69 defined(&OBD_SNAP_DELETE);
70 eval 'sub OBD_SNAP_RESTORE() { &_IOC(3, ord(\'f\'), 43, 4);}' unless
71 defined(&OBD_SNAP_RESTORE);
73 eval 'sub OBD_EXT2_RUNIT () { &_IOC(3, ord(\'f\'), 61, 4);}' unless
74 defined(&OBD_EXT2_RUNIT);
76 eval 'sub ATTR_MODE () {1;}' unless defined(&ATTR_MODE);
77 eval 'sub ATTR_UID () {2;}' unless defined(&ATTR_UID);
78 eval 'sub ATTR_GID () {4;}' unless defined(&ATTR_GID);
79 eval 'sub ATTR_SIZE () {8;}' unless defined(&ATTR_SIZE);
80 eval 'sub ATTR_ATIME () {16;}' unless defined(&ATTR_ATIME);
81 eval 'sub ATTR_MTIME () {32;}' unless defined(&ATTR_MTIME);
82 eval 'sub ATTR_CTIME () {64;}' unless defined(&ATTR_CTIME);
92 # NOTE long long are layed out in ia32 memory as follows:
93 # u = 0xaaaabbbbccccdddd has ccccdddd at &u and aaaabbbb 4 bytes on
94 # this may be different on other architectures
96 # we use 32-bit integers for all 64-bit quantities in this program
97 # #define OBD_INLINESZ 64
98 # #define OBD_OBDMDSZ 64
99 # /* Note: 64-bit types are 64-bit aligned in structure */
107 # obd_blocks o_blocks;
108 # obd_blksize o_blksize;
113 # obd_flag o_obdflags;
115 # obd_flag o_valid; /* hot fields in this obdo */
116 # char o_inline[OBD_INLINESZ];
117 # char o_obdmd[OBD_OBDMDSZ];
118 # struct list_head o_list;
119 # struct obd_ops *o_op;
124 pack "LL LL LL LL LL LL LL L L L L L L L L a60 a64 L L L",
142 0, 0, # struct list_head
166 $obdo->{obdmd}) = unpack "x${offset}Lx4 Lx4 Lx4 Lx4 Lx4 Lx4 Lx4 L L L L L L L L a60 a64", $buf;
174 printf "id: %d\ngrp: %d\natime: %s\nmtime: %s\nctime: %s\nsize: %d\nblocks: %d\nblksize: %d\nmode: %x\nuid: %d\ngid: %d\nflags: %x\nobdflags: %x\nnlink: %d\nvalid: %x\ninline: %s\nobdmd: %s\n",
197 GetOptions("f!" => \$file, "device=s" => \$::device, ) || die "Getoptions";
200 # get a console for the app
207 ('device' => {func => "Device", doc => "device <dev>: open another OBD device"},
208 'create' => {func => "Create", doc => "create: creates a new inode"},
209 'attach' => {func => "Attach", doc => "attach { ext2_obd | snap_obd snapdev snapidx tableno | scsi_obd adapter bus tid lun }" },
210 'detach' => {func => "Detach", doc => "detach this device"},
211 'testext2iterator' => {func => "TestExt2Iterator", doc => "test ext2 iterator function"},
212 'snapset' => {func => "SnapSetTable", doc => "snapset <tableno> <file>: set the table (created with snaptable) as table #tableno" },
213 'snapprint' => {func => "SnapPrint", doc => "snapprint <tableno>: output the contents of table #tableno to the syslog"},
214 'snapdelete' => {func => "SnapDelete", doc => "snapdelete: delete connected snap obd objects from disk"},
215 'snaprestore' => {func => "SnapRestore", doc => "snaprestore : restore connected old snap objects to be current"},
216 'snaptable' => {func => "SnapShotTable", doc => "snaptable: build a snapshot table (interactive)"},
217 'copy' => {func => "Copy", doc => "copy <srcid> <tgtid>: copy objects"},
218 'migrate' => {func => "Migrate", doc => "migrate <srcid> <tgtid>: migrate data from one object to another"},
219 'format' => {func => "Format", doc => "format type adapter bus tid lun size"},
220 'partition' => {func => "Partition", doc => "partition type adapter bus tid lun partition size"},
221 'setup' => {func => "Setup", doc => "setup [type]: link this OBD device to the underlying device (default type ext2_obd)"},
222 'connect' => {func => "Connect", doc => "connect: allocates client ID for this session"},
223 'disconnect' => {func => "Disconnect", doc => "disconnect [id]: frees client resources"},
224 'sync' => {func => "Sync", doc => "sync: flushes buffers to disk"},
225 'destroy' => {func => "Destroy", doc => "destroy <inode>: destroys an inode"},
226 'cleanup' => {func => "Cleanup", doc => "cleanup the minor obd device"},
227 'dec_use_count' => {func => "Decusecount", doc => "decreases the module use count so that the module can be removed following an oops"},
228 'read' => {func => "Read", doc => "read <inode> <count> [offset]"},
229 'fsread' => {func => "Read2", doc => "read <inode> <count> [offset]"},
230 'write' => {func => "Write", doc => "write <inode> <offset> <text>"},
231 'setattr' => {func => "Setattr", doc => "setattr <inode> [mode [uid [gid [size [atime [mtime [ctime]]]]]]]"},
232 'getattr' => {func => "Getattr", doc => "getattr <inode>: displays inode object attributes"},
233 'preallocate' => {func => "Preallocate", doc => "preallocate [num]: requests preallocation of num inodes."},
234 'statfs' => {func => "Statfs", doc => "statfs: filesystem status information"},
235 'help' => {func => \&Help, doc => "help: this message"},
236 'quit' => {func => \&Quit, doc => "see \"exit\""},
237 'exit' => {func => \&Quit, doc => "see \"quit\""}
241 # setup completion function
243 my @jcm_cmd_list = keys %commands;
258 return $term->readline(@_);
271 $term = new Term::ReadLine 'obdcontrol ';
272 $attribs = $term->Attribs;
273 $attribs->{attempted_completion_function} = \&completeme;
274 $term->ornaments('md,me,,'); # bold face prompt
276 # make sure stdout is not buffered
277 STDOUT->autoflush(1);
280 # Get on with the show
284 #------------------------------------------------------------------------------
286 my ($text, $line, $start, $end) = @_;
287 if (substr($line, 0, $start) =~ /^\s*$/) {
288 $attribs->{completion_word} = \@jcm_cmd_list;
289 return $term->completion_matches($text,
290 $attribs->{'list_completion_function'});
297 my @completions = completeme($given, $given, 0, length($given));
298 if ($#completions == 0) {
299 $name = shift @completions;
305 # start making requests
308 $line = $term->readline("obdcontrol > ");
316 my @arg = split(' ', $line);
317 my $word = shift @arg;
323 $cmd = find_command($word);
326 printf STDERR "$word: No such command, or not unique.\n";
330 if ($cmd eq "help" || $cmd eq "exit" || $cmd eq "quit") {
331 return (&{$commands{$cmd}->{func}}(@arg));
335 return (&{$commands{$cmd}->{func}}(@arg));
339 # select the OBD device we talk to
344 print "Disconnecting active session ($::client_id)...";
345 Disconnect($::client_id);
348 $device = "/dev/obd0";
351 # Open the device, as we need an FD for the ioctl
352 sysopen(DEV_OBD, $device, 0) || die "Cannot open $device";
353 print "Device now $device\n";
365 print "error: missing type\n";
367 print "usage: attach {ext2_obd | snap_obd | scsi_obd}\n";
371 if ($type eq "scsi_obd" ) {
377 $data = pack("iiii", $adapter, $bus, $tid, $lun);
379 } elsif ($type eq "snap_obd" ) {
384 $data = pack("iii", $snapdev, $snapidx, $tableno);
386 } elsif ($type eq "ext2_obd") {
389 print "error: unknown attach type $type\n";
393 my $len = length($type);
394 my $cl = length($data);
396 print "type $type (len $len), datalen $datalen ($cl)\n";
397 my $packed = pack("Lipip", $::client_id, length($type), $type, $datalen, $data);
399 my $rc = ioctl(DEV_OBD, &OBD_IOC_ATTACH, $packed);
402 print STDERR "ioctl failed: $!\n";
403 } elsif ($rc eq "0 but true") {
404 print "Finished (success)\n";
406 print "ioctl returned error code $rc.\n";
413 my $rc = ioctl(DEV_OBD, &OBD_IOC_DETACH, $data);
416 print STDERR "ioctl failed: $!\n";
417 } elsif ($rc eq "0 but true") {
418 print "Finished (success)\n";
420 print "ioctl returned error code $rc.\n";
425 sub TestExt2Iterator {
426 if (!defined($::client_id)) {
427 print "You must first ``connect''.\n";
432 my $type = "ext2_obd";
434 $data = pack("i", 4711); # bogus data
437 my $len = length($type);
438 my $cl = length($data);
439 my $add = pack("p", $data);
440 print "type $type (len $len), datalen $datalen ($cl)\n";
441 my $packed = pack("Lipip", $::client_id, length($type), $type, $datalen, $data);
443 my $rc = ioctl(DEV_OBD, &OBD_EXT2_RUNIT, $packed);
446 print STDERR "ioctl failed: $!\n";
447 } elsif ($rc eq "0 but true") {
448 print "Finished (success)\n";
450 print "ioctl returned error code $rc.\n";
456 if (!defined($::client_id)) {
457 print "You must first ``connect''.\n";
462 my $type = "snap_obd";
464 $data = pack("i", 4711); # bogus data
467 my $len = length($type);
468 my $cl = length($data);
469 my $add = pack("p", $data);
470 print "type $type (len $len), datalen $datalen ($cl)\n";
471 my $packed = pack("Lipip", $::client_id, length($type), $type, $datalen, $data);
473 # XXX We need to fix this up so that after the objects in this snapshot
474 # are deleted, the snapshot itself is also removed from the table.
475 my $rc = ioctl(DEV_OBD, &OBD_SNAP_DELETE, $packed);
478 print STDERR "ioctl failed: $!\n";
479 } elsif ($rc eq "0 but true") {
480 print "Finished (success)\n";
482 print "ioctl returned error code $rc.\n";
487 # this routine does the whole job
489 my $restoreto = shift;
490 my $snaptable = shift;
494 # don't do anything until connected
495 if (!defined($::client_id)) {
496 print "You must first ``connect''.\n";
500 if ( ! $snaptable || ! defined $restoreto ) {
501 print "Usage: snaprestore \"restore to slot\" \"snaptable\" \"tableno\"\n";
505 if ( ! -f $snaptable ) {
506 print "Table $snaptable doesn't exist\n";
510 my $table = ReadSnapShotTable($snaptable);
511 $restoretime = FindSnapInTable($table, $restoreto);
512 if ( ! defined $table->{0} || ! defined $restoretime ) {
513 PrintSnapShotTable($table);
514 print "No current or $restoreto slot in this table\n";
518 my $currentindex = $table->{0};
519 if ( $table->{$restoretime} == $currentindex ) {
520 print "You should not restore to the current snapshot\n";
524 # swap the entries for 0 and $restoreto
525 my $tmp = $table->{$restoretime};
526 $table->{$restoretime} = $table->{0};
528 # PrintSnapShotTable($table);
531 WriteSnapShotTable($snaptable, $table);
533 # set it in the kernel
534 SnapSetTable($tableno, $snaptable);
536 # ready for the ioctl
538 my $type = "snap_obd";
539 $data = pack("i", $currentindex); # slot of previous current snapshot
542 my $len = length($type);
543 my $cl = length($data);
544 my $packed = pack("Lipip", $::client_id, length($type), $type, $datalen, $data);
546 my $rc = ioctl(DEV_OBD, &OBD_SNAP_RESTORE, $packed);
549 print STDERR "ioctl failed: $!\n";
550 } elsif ($rc eq "0 but true") {
551 print "Snaprestore finished (success)\n";
552 delete $table->{$restoretime} if defined $restoretime;
554 WriteSnapShotTable($snaptable, $table);
556 # set it in the kernel
557 SnapSetTable($tableno, $snaptable);
558 # PrintSnapShotTable($table);
561 print "ioctl returned error code $rc.\n";
565 sub FindSnapInTable {
569 foreach my $restoretime ( keys %{$table} ) {
570 if ( $table->{$restoretime} == $snapno) {
571 print "Found key $restoretime for snapno $snapno\n";
581 my $type = "snap_obd";
582 my $snaptableno = shift;
584 $data = pack("i", $snaptableno);
587 my $len = length($type);
588 my $cl = length($data);
589 my $add = pack("p", $data);
590 print "type $type (len $len), datalen $datalen ($cl)\n";
591 my $packed = pack("Lipip", $::client_id, length($type), $type, $datalen, $data);
593 my $rc = ioctl(DEV_OBD, &OBD_SNAP_PRINTTABLE, $packed);
596 print STDERR "ioctl failed: $!\n";
597 } elsif ($rc eq "0 but true") {
598 print "Finished (success)\n";
600 print "ioctl returned error code $rc.\n";
606 my $type = "snap_obd";
607 my $snaptableno = shift;
615 print "No such file $file\n";
618 $table = ReadSnapShotTable($file);
620 $snapcount = keys %{$table};
621 print "Snapcount $snapcount\n";
623 if ( ! defined $table->{0} ) {
624 print "No current snapshot in table! First make one\n";
627 $data = pack("ii", $snaptableno, $snapcount);
629 foreach my $time (sort keys %{$table}) {
630 $data .= pack("Ii", $time, $table->{$time});
634 my $len = length($type);
635 my $cl = length($data);
636 my $add = pack("p", $data);
637 print "type $type (len $len), datalen $datalen ($cl)\n";
638 my $packed = pack("Lipip", $::client_id, length($type), $type, $datalen, $data);
640 my $rc = ioctl(DEV_OBD, &OBD_SNAP_SETTABLE, $packed);
643 print STDERR "ioctl failed: $!\n";
644 } elsif ($rc eq "0 but true") {
645 print "Finished (success)\n";
647 print "ioctl returned error code $rc.\n";
654 my $file = &readl("enter file name: ");
658 my $table = ReadSnapShotTable($file);
661 PrintSnapShotTable($table);
662 my $action = &readl("Add, Delete or Quit [adq]: ");
663 goto done if ($action =~ "^q.*" );
664 goto add if ($action =~ "^a.*");
665 goto del if ($action =~ "^d.*");
669 my $idx = &readl("enter index where you want this snapshot: ");
670 my $time = &readl("enter time or 'now' or 'current': ");
671 my $oldtime = SnapFindTimeFromIdx($idx, $table);
672 if (defined $oldtime) {
673 print "This already exists, first clean up\n";
677 if ( $time eq 'now' ) {
679 } elsif ( $time eq 'current' ) {
682 $table->{$time} = $idx;
686 $didx = &readl("Enter index to delete: ");
687 my $deltime = SnapFindTimeFromIdx($didx, $table);
688 delete $table->{$deltime} if defined $deltime;
692 my $ok = &readl("OK with new table? [Yn]: ");
693 unless ( $ok eq "n" ) {
694 WriteSnapShotTable($file, $table);
698 sub SnapFindTimeFromIdx {
702 foreach my $time ( keys %{$table} ) {
703 if ( $table->{$time} == $idx ) {
710 sub PrintSnapShotTable {
714 foreach $time ( sort keys %{$table} ) {
715 my $stime = localtime($time);
719 printf "Time: %s -- Index %d\n", $stime, $table->{$time};
723 sub ReadSnapShotTable {
730 my ($time, $index) = split ;
731 $table->{$time} = $index;
735 PrintSnapShotTable($table);
740 sub WriteSnapShotTable {
745 foreach my $time ( sort keys %{$table} ) {
746 print FH "$time $table->{$time}\n";
756 # Note: _copy IOCTL takes parameters as dst, src.
757 # Copy function takes parameters as src, dst.
758 my $data = pack("III", $::client_id, $dstid, $srcid);
761 my $packed = pack("ip", $datalen, $data);
762 my $rc = ioctl(DEV_OBD, &OBD_IOC_COPY, $packed);
765 print STDERR "ioctl failed: $!\n";
766 } elsif ($rc eq "0 but true") {
767 print "Finished (success)\n";
769 print "ioctl returned error code $rc.\n";
778 # Note: _migr IOCTL takes parameters as dst, src.
779 # Migrate function takes parameters as src, dst.
780 my $data = pack("III", $::client_id, $dstid, $srcid);
783 my $packed = pack("ip", $datalen, $data);
784 my $rc = ioctl(DEV_OBD, &OBD_IOC_MIGR, $packed);
787 print STDERR "ioctl failed: $!\n";
788 } elsif ($rc eq "0 but true") {
789 print "Finished (success)\n";
791 print "ioctl returned error code $rc.\n";
799 my $data = pack("i", $size);
802 my $packed = pack("ip", $datalen, $data);
803 my $rc = ioctl(DEV_OBD, &OBD_IOC_FORMATOBD, $packed);
806 print STDERR "ioctl failed: $!\n";
807 } elsif ($rc eq "0 but true") {
808 print "Finished (success)\n";
810 print "ioctl returned error code $rc.\n";
818 my $data = pack("ii", $partno, $size);
821 my $packed = pack("ip", $datalen, $data);
822 my $rc = ioctl(DEV_OBD, &OBD_IOC_PARTITION, $packed);
825 print STDERR "ioctl failed: $!\n";
826 } elsif ($rc eq "0 but true") {
827 print "Finished (success)\n";
829 print "ioctl returned error code $rc.\n";
839 # XXX we need a getinfo ioctl to validate parameters
842 if ($arg && !defined($::st = stat($arg))) {
843 print "$arg is not a valid device\n";
848 $dev = $::st->rdev() unless $dev;
849 $data = pack("i", $dev);
853 my $packed = pack("ip", $datalen, $data);
854 my $rc = ioctl(DEV_OBD, &OBD_IOC_SETUP, $packed);
857 print STDERR "ioctl failed: $!\n";
858 } elsif ($rc eq "0 but true") {
859 print "Finished (success)\n";
861 print "ioctl returned error code $rc.\n";
867 my $rc = ioctl(DEV_OBD, &OBD_IOC_CLEANUP, $err);
870 print STDERR "ioctl failed: $!\n";
871 } elsif ($rc eq "0 but true") {
872 print "Finished (success)\n";
875 print "ioctl returned error code $rc.\n";
884 $rc = ioctl(DEV_OBD, &OBD_IOC_CONNECT, $packed);
885 $id = unpack("I", $packed);
888 print STDERR "ioctl failed: $!\n";
889 } elsif ($rc eq "0 but true") {
891 print "Client ID : $id\n";
892 print "Finished (success)\n";
894 print "ioctl returned error code $rc.\n";
906 print "syntax: disconnect [client ID]\n";
907 print "When client ID is not given, the last valid client ID to be returned by a\n";
908 print "connect command this session is used; there is no such ID.\n";
912 my $packed = pack("L", $id);
913 my $rc = ioctl(DEV_OBD, &OBD_IOC_DISCONNECT, $packed);
916 print STDERR "ioctl failed: $!\n";
917 } elsif ($rc eq "0 but true") {
918 $::client_id = undef;
919 print "Finished (success)\n";
921 print "ioctl returned error code $rc.\n";
931 if (defined($quiet) && $quiet ne "quiet") {
932 print "syntax: create [number of objects [quiet]]\n";
936 my $packed = pack("IL", $::client_id, $prealloc);
937 if (!defined($arg) || scalar($arg) < 2) {
938 print "Creating 1 object...\n";
939 $rc = ioctl(DEV_OBD, &OBD_IOC_CREATE, $packed);
940 if (!defined($quiet)) {
941 my $ino = unpack("L", $packed);
942 print "Created object #$ino.\n";
947 print "Creating " . scalar($arg) . " objects...\n";
948 for ($i = 0; $i < scalar($arg); $i++) {
949 $rc = ioctl(DEV_OBD, &OBD_IOC_CREATE, $packed);
950 my $ino = unpack("L", $packed);
951 if ($rc ne "0 but true") {
953 $packed = pack("IL", $::client_id, $prealloc);
954 } elsif (!defined($quiet)) {
955 $packed = pack("IL", $::client_id, $prealloc);
956 print "Created object #$ino.\n";
962 print STDERR "ioctl failed: $!\n";
963 } elsif ($rc eq "0 but true") {
964 print "Finished (success)\n";
966 print "ioctl returned error code $rc.\n";
972 my $rc = ioctl(DEV_OBD, &OBD_IOC_SYNC, $err);
975 print STDERR "ioctl failed: $!\n";
976 } elsif ($rc eq "0 but true") {
977 print "Finished (success)\n";
979 print "ioctl returned error code $rc.\n";
984 if (!defined($::client_id)) {
985 print "You must first ``connect''.\n";
991 if (!defined($arg) || scalar($arg) < 1) {
992 print "destroy requires the object number to destroy.\n";
996 print "Destroying object $arg...\n";
997 my $packed = pack("IL", $::client_id, $arg);
998 my $rc = ioctl(DEV_OBD, &OBD_IOC_DESTROY, $packed);
1001 print STDERR "ioctl failed: $!\n";
1002 } elsif ($rc eq "0 but true") {
1003 print "Finished (success)\n";
1005 print "ioctl returned error code $rc.\n";
1010 if (!defined($::client_id)) {
1011 print "You must first ``connect''.\n";
1017 if (!defined($inode) || scalar($inode) < 1) {
1018 print "invalid arguments; type \"help getattr\" for a synopsis\n";
1024 $obdo->{id} = $inode;
1025 my $packed = pack("L", $::client_id) . obdo_pack($obdo);
1026 my $rc = ioctl(DEV_OBD, &OBD_IOC_GETATTR, $packed);
1030 print STDERR "ioctl failed: $!\n";
1031 } elsif ($rc eq "0 but true") {
1032 $obdo = obdo_unpack($packed, 4);
1035 print "ioctl returned error code $rc.\n";
1040 if (!defined($::client_id)) {
1041 print "You must first ``connect''.\n";
1047 my $mode = oct(shift);
1055 if (defined($uid)) {
1056 $valid |= &ATTR_UID;
1058 if (defined($gid)) {
1059 $valid |= &ATTR_GID;
1061 if (defined($size)) {
1062 $valid |= &ATTR_SIZE;
1064 if (defined($atime)) {
1065 $valid |= &ATTR_ATIME;
1067 if (defined($mtime)) {
1068 $valid |= &ATTR_MTIME;
1070 if (defined($ctime)) {
1071 $valid |= &ATTR_CTIME;
1073 if (defined($mode)) {
1074 $valid |= &ATTR_MODE;
1077 if (!defined($inode) || scalar($inode) < 1) {
1078 print "invalid arguments; type \"help setattr\" for a synopsis\n";
1083 # unsigned int ia_valid; (32)
1084 # umode_t ia_mode; (16)
1085 # uid_t ia_uid; (16)
1086 # gid_t ia_gid; (16)
1087 # -- 16 bit alignment here! --
1088 # off_t ia_size; (32)
1089 # time_t ia_atime; (32)
1090 # time_t ia_mtime; (32)
1091 # time_t ia_ctime; (32)
1092 # unsigned int ia_attr_flags; (32)
1095 printf "valid is %x, mode is %o\n", $valid, $mode;
1096 my $packed = pack("ILLSssx2ILLLL", $::client_id, $inode, $valid, $mode,
1097 $uid, $gid, $size, $atime, $mtime, $ctime, 0);
1098 my $rc = ioctl(DEV_OBD, &OBD_IOC_SETATTR, $packed);
1101 print STDERR "ioctl failed: $!\n";
1102 } elsif ($rc eq "0 but true") {
1103 print "Finished (success)\n";
1105 print "ioctl returned error code $rc.\n";
1110 if (!defined($::client_id)) {
1111 print "You must first ``connect''.\n";
1119 if (!defined($inode) || scalar($inode) < 1 || !defined($count) ||
1120 $count < 1 || (defined($offset) && $offset < 0)) {
1121 print "invalid arguments; type \"help read\" for a synopsis\n";
1125 if (!defined($offset)) {
1129 print("Reading $count bytes starting at byte $offset from object " .
1132 # "allocate" a large enough buffer
1133 my $buf = sprintf("%${count}s", " ");
1134 die "suck" if (length($buf) != $count);
1136 # the perl we're using doesn't support pack type Q, and offset is 64 bits
1137 my $packed = pack("ILpLLL", $::client_id, $inode, $buf, $count, $offset, 0);
1139 my $rc = ioctl(DEV_OBD, &OBD_IOC_READ, $packed);
1141 $retval = unpack("l", $packed);
1144 print STDERR "ioctl failed: $!\n";
1145 } elsif ($rc eq "0 but true") {
1147 print substr($buf, 0, $retval);
1148 print "\nRead $retval of an attempted $count bytes.\n";
1149 print "Finished (success)\n";
1151 print "Finished (error $retval)\n";
1154 print "ioctl returned error code $rc.\n";
1159 if (!defined($::client_id)) {
1160 print "You must first ``connect''.\n";
1168 if (!defined($inode) || scalar($inode) < 1 || !defined($count) ||
1169 $count < 1 || (defined($offset) && $offset < 0)) {
1170 print "invalid arguments; type \"help read\" for a synopsis\n";
1174 if (!defined($offset)) {
1178 print("Reading $count bytes starting at byte $offset from object " .
1181 # "allocate" a large enough buffer
1182 my $buf = sprintf("%${count}s", " ");
1183 die "suck" if (length($buf) != $count);
1185 # the perl we're using doesn't support pack type Q, and offset is 64 bits
1186 my $packed = pack("ILpLLL", $::client_id, $inode, $buf, $count, $offset, 0);
1188 my $rc = ioctl(DEV_OBD, &OBD_IOC_READ2, $packed);
1190 $retval = unpack("l", $packed);
1193 print STDERR "ioctl failed: $!\n";
1194 } elsif ($rc eq "0 but true") {
1196 print substr($buf, 0, $retval);
1197 print "\nRead $retval of an attempted $count bytes.\n";
1198 print "Finished (success)\n";
1200 print "Finished (error $retval)\n";
1203 print "ioctl returned error code $rc.\n";
1208 if (!defined($::client_id)) {
1209 print "You must first ``connect''.\n";
1215 my $text = join(' ', @_);
1216 my $count = length($text);
1218 if (!defined($inode) || scalar($inode) < 1 || !defined($offset) ||
1219 scalar($offset) < 0) {
1220 print "invalid arguments; type \"help write\" for a synopsis\n";
1224 if (!defined($text)) {
1229 print("Writing $count bytes starting at byte $offset to object " .
1232 # the perl we're using doesn't support pack type Q
1233 my $packed = pack("ILpLLL", $::client_id, $inode, $text, $count, $offset, 0);
1234 my $rc = ioctl(DEV_OBD, &OBD_IOC_WRITE, $packed);
1236 $retval = unpack("l", $packed);
1239 print STDERR "ioctl failed: $!\n";
1240 } elsif ($rc eq "0 but true") {
1242 print "\nWrote $retval of an attempted $count bytes.\n";
1243 print "Finished (success)\n";
1245 print "Finished (error $retval)\n";
1248 print "ioctl returned error code $rc.\n";
1255 if (!defined($::client_id)) {
1256 print "You must first ``connect''.\n";
1260 if (!defined($arg) || scalar($arg) < 1 || scalar($arg) > 32) {
1264 print "Preallocating $arg inodes...\n";
1265 my $packed = pack("LLx128", $::client_id, $arg);
1266 # client id, alloc, inodes[32]
1268 my $rc = ioctl(DEV_OBD, &OBD_IOC_PREALLOCATE, $packed);
1271 print STDERR "ioctl failed: $!\n";
1272 } elsif ($rc eq "0 but true") {
1273 my $alloc = unpack("x4L", $packed);
1274 my @inodes = unpack("x8L32", $packed);
1277 print "Got $alloc inodes: ";
1278 foreach $i (@inodes) {
1281 print "\nFinished (success)\n";
1283 print "ioctl returned error code $rc.\n";
1288 my $rc = ioctl(DEV_OBD, &OBD_IOC_DEC_USE_COUNT, 0);
1291 print STDERR "ioctl failed: $!\n";
1292 } elsif ($rc eq "0 but true") {
1293 print "Finished (success)\n";
1295 print "ioctl returned error code $rc.\n";
1300 if (!defined($::client_id)) {
1301 print "You must first ``connect''.\n";
1313 # __kernel_fsid_t f_fsid; (64 bits)
1318 my $packed = pack("LLLLLLLIILL6", $::client_id, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1321 my $rc = ioctl(DEV_OBD, &OBD_IOC_STATFS, $packed);
1324 print STDERR "ioctl failed: $!\n";
1325 } elsif ($rc eq "0 but true") {
1326 # skip both the conn_id and the fs_type in the buffer
1327 my ($bsize, $blocks, $bfree, $bavail, $files, $ffree) =
1328 unpack("x4x4LLLLLL", $packed);
1329 print("$bsize byte blocks: $blocks, " . ($blocks - $bfree) . " used, " .
1330 "$bfree free ($bavail available).\n");
1331 print "$files files, " . ($files - $ffree) . " used, $ffree free.\n";
1332 print "Finished (success)\n";
1334 print "ioctl returned error code $rc.\n";
1341 if ( !$arg || !$commands{$arg} ) {
1342 print "Comands: ", join( ' ', @jcm_cmd_list), "\n";
1344 print "Usage: " . $commands{$arg}->{doc} . "\n";
1350 print "Disconnecting active session ($::client_id)...";
1351 Disconnect($::client_id);