Whamcloud - gitweb
Cleanup : no more "sim" now "ext2"
[fs/lustre-release.git] / lustre / obdclass / obdcontrol
1 #!/usr/bin/perl
2
3 #
4 # This code is issued under the GNU General Public License.
5 # See the file COPYING in this distribution
6 #
7 # Copyright (C) 1998, Stelias Computing
8
9 # Modified for InterMezzo from Gordian's HSM bcache device/jcm module
10 # Copyright (C) 1999, Carnegie Mellon University
11 #
12 # Derived from InterMezzo's incontrol, modified for OBD's
13 # Copyright (C) 1999, Stelias Computing
14 #
15 #
16
17 #use strict;
18 BEGIN { require "asm/errno.ph" };
19 BEGIN { require "asm/ioctl.ph" };
20
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_OBDDEV () { &_IOC(1, ord(\'f\'), 4, 4);}' unless
25   defined(&OBD_IOC_SETUP_OBDDEV);
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
59 eval 'sub ATTR_MODE () {1;}' unless defined(&ATTR_MODE);
60 eval 'sub ATTR_UID () {2;}' unless defined(&ATTR_UID);
61 eval 'sub ATTR_GID () {4;}' unless defined(&ATTR_GID);
62 eval 'sub ATTR_SIZE () {8;}' unless defined(&ATTR_SIZE);
63 eval 'sub ATTR_ATIME () {16;}' unless defined(&ATTR_ATIME);
64 eval 'sub ATTR_MTIME () {32;}' unless defined(&ATTR_MTIME);
65 eval 'sub ATTR_CTIME () {64;}' unless defined(&ATTR_CTIME);
66
67 use Getopt::Long;
68 use File::stat;
69 use Storable;
70 use Carp;
71 use Term::ReadLine;
72 use IO::Handle;
73
74
75 my ($file);
76
77 GetOptions("f!" => \$file, "device=s" => \$::device, "fs=s" => $::filesystem) || die "Getoptions";
78
79
80 # get a console for the app
81
82 my $line;
83 my $command;
84 my $arg;
85
86 my %commands =
87     ('device' => {func => "Device", doc => "device <dev>: open another OBD device"},
88      'filesystem' => {func => "Filesystem", doc => "filesystem <dev>: partition for direct OBD device"},
89      'create' => {func => "Create", doc => "create: creates a new inode"},
90      'attach' => {func => "Attach", doc => "format type [adapter bus tid lun]"},
91      'format' => {func => "Format", doc => "format type adapter bus tid lun size"},
92      'partition' => {func => "Partition", doc => "partition type adapter bus tid lun partition size"},
93      'setup' => {func => "Setup", doc => "setup: link the ext2 partition (default /dev/loop0) to this obddev"},
94      'connect' => {func => "Connect", doc => "connect: allocates client ID for this session"},
95      'disconnect' => {func => "Disconnect", doc => "disconnect [id]: frees client resources"},
96      'sync' => {func => "Sync", doc => "sync: flushes buffers to disk"},
97      'destroy' => {func => "Destroy", doc => "setup: destroys an inode"},
98      'cleanup' => {func => "Cleanup", doc => "cleanup the minor obd device"},
99      'dec_use_count' => {func => "Decusecount", doc => "decreases the module use count so that the module can be removed following an oops"},
100      'read' => {func => "Read", doc => "read <inode> <count> [offset]"},
101      'fsread' => {func => "Read2", doc => "read <inode> <count> [offset]"},
102      'write' => {func => "Write", doc => "write <inode> <offset> <text>"},
103      'setattr' => {func => "Setattr", doc => "setattr <inode> [mode [uid [gid [size [atime [mtime [ctime]]]]]]]"},
104      'getattr' => {func => "Getattr", doc => "getattr <inode>: displays inode object attributes"},
105      'preallocate' => {func => "Preallocate", doc => "preallocate [num]: requests preallocation of num inodes."},
106      'statfs' => {func => "Statfs", doc => "statfs: filesystem status information"},
107      'help' => {func => \&Help,  doc => "help: this message"},
108      'quit' => {func => \&Quit,  doc => "see \"exit\""},
109      'exit' => {func => \&Quit,  doc => "see \"quit\""}
110     );
111
112 #
113 #       setup completion function
114 #
115 my @jcm_cmd_list = keys %commands;
116
117 my $term, $attribs;
118
119
120 # Get going....
121
122 Device($::device);
123 Filesystem($::filesystem);
124 if ( $file ) {
125         while ( <STDIN> ) {
126             print $_;
127             execute_line($_);
128         }
129         exit 0;
130 } else {
131     $term = new Term::ReadLine 'obdcontrol ';
132     $attribs = $term->Attribs;
133     $attribs->{attempted_completion_function} = \&completeme;
134     $term->ornaments('md,me,,');        # bold face prompt
135     
136     # make sure stdout is not buffered
137     STDOUT->autoflush(1);
138
139
140     # Get on with the show
141     process_line();
142 }
143
144 #------------------------------------------------------------------------------
145 sub completeme {
146     my ($text, $line, $start, $end) = @_;
147     if (substr($line, 0, $start) =~ /^\s*$/) {
148         $attribs->{completion_word} = \@jcm_cmd_list;
149         return $term->completion_matches($text,
150                                          $attribs->{'list_completion_function'});
151     }
152 }
153
154 sub find_command {
155     my $given = shift;
156     my $name;
157     my @completions = completeme($given, $given, 0, length($given));
158     if ($#completions == 0) {
159         $name = shift @completions;
160     }
161
162     return $name;
163 }
164
165 # start making requests
166 sub process_line {
167   foo:
168     $line = $term->readline("obdcontrol > ");
169     execute_line($line);
170     goto foo;
171 }
172
173 sub execute_line {
174     my $line = shift;
175
176     my @arg = split(' ', $line);
177     my $word = shift @arg;
178
179     my $cmd;
180     if ( $file ) {
181         $cmd = $word;
182     } else {
183         $cmd = find_command($word);
184     }
185     unless ($cmd) {
186         printf STDERR "$word: No such command, or not unique.\n";
187         return (-1);
188     }
189
190     if ($cmd eq "help" || $cmd eq "exit" || $cmd eq "quit") {
191         return (&{$commands{$cmd}->{func}}(@arg));
192     }
193
194     # Call the function.
195     return (&{$commands{$cmd}->{func}}(@arg));
196 }
197
198 # set the object store in the ext2 formatted block device
199 sub Filesystem {
200     my $filesystem = shift;
201     $filesystem = "/dev/loop0" unless $filesystem;
202     
203     $::filesystem = $filesystem;
204     if (!defined($::st = stat($filesystem))) {
205         die "Unable to stat $filesystem.\n";
206     }
207 }
208
209 # select the OBD device we talk to
210 sub Device {
211     my $device = shift;
212
213     if (! $device ) {
214         $device = "/dev/obd0";
215     }
216     $::device = $device;
217     # Open the device, as we need an FD for the ioctl
218     sysopen(DEV_OBD, $device, 0) || die "Cannot open $device";
219
220 }
221
222
223
224 sub Attach {
225     my $err = 0;
226     my $type = shift;
227     my $data;
228     my $datalen = 0;
229
230     if ($type eq "obdscsi" ) {
231         my $adapter = shift;
232         my $bus = shift;
233         my $tid = shift;
234         my $lun = shift;
235         $data = pack("iiiii", $adapter, $bus, $tid, $lun, $size);
236         $datalen = 4 * 4;
237     }
238
239     my $packed = pack("ipip", length($type), $type, $datalen, $data);
240
241     my $rc = ioctl(DEV_OBD, &OBD_IOC_ATTACH, $packed);
242
243     if (!defined $rc) {
244         print STDERR "ioctl failed: $!\n";
245     } elsif ($rc eq "0 but true") {
246         print "Finished (success)\n";
247     } else {
248         print "ioctl returned error code $rc.\n";
249     }
250 }
251
252 sub Format {
253     my $err = 0;
254     my $size = shift;
255     my $data = pack("i", $size);
256     my $datalen = 4;
257
258     my $packed = pack("ip", $datalen, $data);
259     my $rc = ioctl(DEV_OBD, &OBD_IOC_FORMATOBD, $packed);
260
261     if (!defined $rc) {
262         print STDERR "ioctl failed: $!\n";
263     } elsif ($rc eq "0 but true") {
264         print "Finished (success)\n";
265     } else {
266         print "ioctl returned error code $rc.\n";
267     }
268 }
269
270 sub Partition {
271     my $err = 0;
272     my $partno = shift;
273     my $size = shift;
274     my $data = pack("ii", $partno, $size);
275     my $datalen = 2 * 4;
276
277     my $packed = pack("ip", $datalen, $data);
278     my $rc = ioctl(DEV_OBD, &OBD_IOC_PARTITION, $packed);
279
280     if (!defined $rc) {
281         print STDERR "ioctl failed: $!\n";
282     } elsif ($rc eq "0 but true") {
283         print "Finished (success)\n";
284     } else {
285         print "ioctl returned error code $rc.\n";
286     }
287 }
288
289 sub Setup {
290     my $err = 0;
291     my $type = shift;
292     my $data;
293     my $datalen = 0;
294     
295     $type = "ext2_obd" unless $type;
296
297     if ( $type eq "ext2_obd" ) {
298         my $dev = shift;
299         $dev = $::st->rdev() unless $dev;
300         $data = pack("i", $dev);
301         $datalen = 4;
302     }
303
304     my $packed = pack("ip", $datalen, $data);
305     my $rc = ioctl(DEV_OBD, &OBD_IOC_SETUP_OBDDEV, $packed);
306
307     if (!defined $rc) {
308         print STDERR "ioctl failed: $!\n";
309     } elsif ($rc eq "0 but true") {
310         print "Finished (success)\n";
311     } else {
312         print "ioctl returned error code $rc.\n";
313     }
314 }
315
316 sub Cleanup {
317     my $err = "0";
318     my $rc = ioctl(DEV_OBD, &OBD_IOC_CLEANUP, $err);
319
320     if (!defined $rc) {
321         print STDERR "ioctl failed: $!\n";
322     } elsif ($rc eq "0 but true") {
323         print "Finished (success)\n";
324         $::client_id = 0;
325     } else {
326         print "ioctl returned error code $rc.\n";
327     }
328 }
329
330
331 sub Connect {
332     my $rc;
333
334     my $packed = "";
335     $rc = ioctl(DEV_OBD, &OBD_IOC_CONNECT, $packed);
336     $id = unpack("I", $packed);
337
338     if (!defined $rc) {
339         print STDERR "ioctl failed: $!\n";
340     } elsif ($rc eq "0 but true") {
341         $::client_id = $id;
342         print "Client ID     : $id\n";
343         print "Finished (success)\n";
344     } else {
345         print "ioctl returned error code $rc.\n";
346     }
347 }
348
349 sub Disconnect {
350     my $id = shift;
351
352     if (!defined($id)) {
353         $id = $::client_id;
354     }
355
356     if (!defined($id)) {
357         print "syntax: disconnect [client ID]\n";
358         print "When client ID is not given, the last valid client ID to be returned by a\n";
359         print "connect command this session is used; there is no such ID.\n";
360         return;
361     }
362
363     my $packed = pack("L", $id);
364     my $rc = ioctl(DEV_OBD, &OBD_IOC_DISCONNECT, $packed);
365
366     if (!defined $rc) {
367         print STDERR "ioctl failed: $!\n";
368     } elsif ($rc eq "0 but true") {
369         $::client_id = undef;
370         print "Finished (success)\n";
371     } else {
372         print "ioctl returned error code $rc.\n";
373     }
374 }
375
376 sub Create {
377     my $arg = shift;
378     my $quiet = shift;
379     my $rc;
380     my $prealloc = 0;
381
382     if (defined($quiet) && !($quiet eq "quiet")) {
383         print "syntax: create [number of objects [quiet]]\n";
384         return;
385     }
386
387     my $packed = pack("IL", $::client_id, $prealloc);
388     if (!defined($arg) || scalar($arg) < 2) {
389         print "Creating 1 object...\n";
390         $rc = ioctl(DEV_OBD, &OBD_IOC_CREATE, $packed);
391         if (!defined($quiet)) {
392             my $ino = unpack("L", $packed);
393             print "Created object #$ino.\n";
394         }
395     } else {
396         my $i;
397
398         print "Creating " . scalar($arg) . " objects...\n";
399         for ($i = 0; $i < scalar($arg); $i++) {
400             $rc = ioctl(DEV_OBD, &OBD_IOC_CREATE, $packed);
401             my $ino = unpack("L", $packed);
402             if (!($rc eq "0 but true")) {
403                 last;
404                 $packed = pack("IL", $::client_id, $prealloc);
405             } elsif (!defined($quiet)) {
406                 $packed = pack("IL", $::client_id, $prealloc);
407                 print "Created object #$ino.\n";
408             }
409         }
410     }
411
412     if (!defined $rc) {
413         print STDERR "ioctl failed: $!\n";
414     } elsif ($rc eq "0 but true") {
415         print "Finished (success)\n";
416     } else {
417         print "ioctl returned error code $rc.\n";
418     }
419 }
420
421 sub Sync {
422     my $err = "0";
423     my $rc = ioctl(DEV_OBD, &OBD_IOC_SYNC, $err);
424
425     if (!defined $rc) {
426         print STDERR "ioctl failed: $!\n";
427     } elsif ($rc eq "0 but true") {
428         print "Finished (success)\n";
429     } else {
430         print "ioctl returned error code $rc.\n";
431     }
432 }
433
434 sub Destroy {
435     if (!defined($::client_id)) {
436         print "You must first ``connect''.\n";
437         return;
438     }
439
440     my $arg = shift;
441
442     if (!defined($arg) || scalar($arg) < 1) {
443         print "destroy requires the object number to destroy.\n";
444         return;
445     }
446
447     print "Destroying object $arg...\n";
448     my $packed = pack("IL", $::client_id, $arg);
449     my $rc = ioctl(DEV_OBD, &OBD_IOC_DESTROY, $packed);
450
451     if (!defined $rc) {
452         print STDERR "ioctl failed: $!\n";
453     } elsif ($rc eq "0 but true") {
454         print "Finished (success)\n";
455     } else {
456         print "ioctl returned error code $rc.\n";
457     }
458 }
459
460 sub Getattr {
461     if (!defined($::client_id)) {
462         print "You must first ``connect''.\n";
463         return;
464     }
465
466     my $inode = shift;
467
468     if (!defined($inode) || scalar($inode) < 1) {
469         print "invalid arguments; type \"help getattr\" for a synopsis\n";
470         return;
471     }
472
473     # see Setattr
474     my $packed = pack("ILsx2lLLLI", $::client_id, $inode, 0, 0, 0, 0, 0, 0, 0,
475                       0);
476     my $rc = ioctl(DEV_OBD, &OBD_IOC_GETATTR, $packed);
477
478     if (!defined $rc) {
479         print STDERR "ioctl failed: $!\n";
480     } elsif ($rc eq "0 but true") {
481         my ($valid, $mode, $uid, $gid, $size, $atime, $mtime, $ctime, $flags);
482         ($valid, $mode, $uid, $gid, $size, $atime, $mtime, $ctime, $flags) =
483           unpack("ISssx2lLLLI", $packed);
484
485         printf("Inode: %d  Mode:  %o\n", $inode, $mode);
486         printf("User: %6d   Group: %6d   Size: %d\n", $uid, $gid, $size);
487         printf("ctime: %08lx -- %s\n", $ctime, scalar(gmtime($ctime)));
488         printf("atime: %08lx -- %s\n", $atime, scalar(gmtime($atime)));
489         printf("mtime: %08lx -- %s\n", $mtime, scalar(gmtime($mtime)));
490         printf("flags: %08x\n", $flags);
491         print "Finished (success)\n";
492     } else {
493         print "ioctl returned error code $rc.\n";
494     }
495 }
496
497 sub Setattr {
498     if (!defined($::client_id)) {
499         print "You must first ``connect''.\n";
500         return;
501     }
502
503     my $inode = shift;
504     my $valid = 0;
505     my $mode = oct(shift);
506     my $uid = shift;
507     my $gid = shift;
508     my $size = shift;
509     my $atime = shift;
510     my $mtime = shift;
511     my $ctime = shift;
512
513     if (defined($uid)) {
514         $valid |= &ATTR_UID;
515     }
516     if (defined($gid)) {
517         $valid |= &ATTR_GID;
518     }
519     if (defined($size)) {
520         $valid |= &ATTR_SIZE;
521     }
522     if (defined($atime)) {
523         $valid |= &ATTR_ATIME;
524     }
525     if (defined($mtime)) {
526         $valid |= &ATTR_MTIME;
527     }
528     if (defined($ctime)) {
529         $valid |= &ATTR_CTIME;
530     }
531     if (defined($mode)) {
532         $valid |= &ATTR_MODE;
533     }
534
535     if (!defined($inode) || scalar($inode) < 1) {
536         print "invalid arguments; type \"help setattr\" for a synopsis\n";
537         return;
538     }
539
540     #struct iattr {
541     #        unsigned int    ia_valid; (32)
542     #        umode_t         ia_mode; (16)
543     #        uid_t           ia_uid; (16)
544     #        gid_t           ia_gid; (16)
545     # -- 16 bit alignment here! --
546     #        off_t           ia_size; (32)
547     #        time_t          ia_atime; (32)
548     #        time_t          ia_mtime; (32)
549     #        time_t          ia_ctime; (32)
550     #        unsigned int    ia_attr_flags; (32)
551     #};
552
553     printf "valid is %x, mode is %o\n", $valid, $mode;
554     my $packed = pack("ILLSssx2ILLLL", $::client_id, $inode, $valid, $mode,
555                       $uid, $gid, $size, $atime, $mtime, $ctime, 0);
556     my $rc = ioctl(DEV_OBD, &OBD_IOC_SETATTR, $packed);
557
558     if (!defined $rc) {
559         print STDERR "ioctl failed: $!\n";
560     } elsif ($rc eq "0 but true") {
561         print "Finished (success)\n";
562     } else {
563         print "ioctl returned error code $rc.\n";
564     }
565 }
566
567 sub Read {
568     if (!defined($::client_id)) {
569         print "You must first ``connect''.\n";
570         return;
571     }
572
573     my $inode = shift;
574     my $count = shift;
575     my $offset = shift;
576   
577     if (!defined($inode) || scalar($inode) < 1 || !defined($count) ||
578         $count < 1 || (defined($offset) && $offset < 0)) {
579         print "invalid arguments; type \"help read\" for a synopsis\n";
580         return;
581     }
582
583     if (!defined($offset)) {
584         $offset = 0;
585     }
586
587     print("Reading $count bytes starting at byte $offset from object " .
588           "$inode...\n");
589
590     # "allocate" a large enough buffer
591     my $buf = sprintf("%${count}s", " ");
592     die "suck" if (length($buf) != $count);
593
594     # the perl we're using doesn't support pack type Q, and offset is 64 bits
595     my $packed = pack("ILpLLL", $::client_id, $inode, $buf, $count, $offset, 0);
596
597     my $rc = ioctl(DEV_OBD, &OBD_IOC_READ, $packed);
598
599     $retval = unpack("l", $packed);
600
601     if (!defined $rc) {
602         print STDERR "ioctl failed: $!\n";
603     } elsif ($rc eq "0 but true") {
604         if ($retval >= 0) {
605                 print substr($buf, 0, $retval);
606                 print "\nRead $retval of an attempted $count bytes.\n";
607                 print "Finished (success)\n";
608         } else {
609                 print "Finished (error $retval)\n";
610         }
611     } else {
612         print "ioctl returned error code $rc.\n";
613     }
614 }
615
616 sub Read2 {
617     if (!defined($::client_id)) {
618         print "You must first ``connect''.\n";
619         return;
620     }
621
622     my $inode = shift;
623     my $count = shift;
624     my $offset = shift;
625   
626     if (!defined($inode) || scalar($inode) < 1 || !defined($count) ||
627         $count < 1 || (defined($offset) && $offset < 0)) {
628         print "invalid arguments; type \"help read\" for a synopsis\n";
629         return;
630     }
631
632     if (!defined($offset)) {
633         $offset = 0;
634     }
635
636     print("Reading $count bytes starting at byte $offset from object " .
637           "$inode...\n");
638
639     # "allocate" a large enough buffer
640     my $buf = sprintf("%${count}s", " ");
641     die "suck" if (length($buf) != $count);
642
643     # the perl we're using doesn't support pack type Q, and offset is 64 bits
644     my $packed = pack("ILpLLL", $::client_id, $inode, $buf, $count, $offset, 0);
645
646     my $rc = ioctl(DEV_OBD, &OBD_IOC_READ2, $packed);
647
648     $retval = unpack("l", $packed);
649
650     if (!defined $rc) {
651         print STDERR "ioctl failed: $!\n";
652     } elsif ($rc eq "0 but true") {
653         if ($retval >= 0) {
654                 print substr($buf, 0, $retval);
655                 print "\nRead $retval of an attempted $count bytes.\n";
656                 print "Finished (success)\n";
657         } else {
658                 print "Finished (error $retval)\n";
659         }
660     } else {
661         print "ioctl returned error code $rc.\n";
662     }
663 }
664
665 sub Write {
666     if (!defined($::client_id)) {
667         print "You must first ``connect''.\n";
668         return;
669     }
670
671     my $inode = shift;
672     my $offset = shift;
673     my $text = join(' ', @_);
674     my $count = length($text);
675
676     if (!defined($inode) || scalar($inode) < 1 || !defined($offset) ||
677         scalar($offset) < 0) {
678         print "invalid arguments; type \"help write\" for a synopsis\n";
679         return;
680     }
681
682     if (!defined($text)) {
683         $text = "";
684         $count = 0;
685     }
686
687     print("Writing $count bytes starting at byte $offset to object " .
688           "$inode...\n");
689
690     # the perl we're using doesn't support pack type Q
691     my $packed = pack("ILpLLL", $::client_id, $inode, $text, $count, $offset, 0);
692     my $rc = ioctl(DEV_OBD, &OBD_IOC_WRITE, $packed);
693
694     $retval = unpack("l", $packed);
695
696     if (!defined $rc) {
697         print STDERR "ioctl failed: $!\n";
698     } elsif ($rc eq "0 but true") {
699         if ($retval >= 0) {
700                 print "\nWrote $retval of an attempted $count bytes.\n";
701                 print "Finished (success)\n";
702         } else {
703                 print "Finished (error $retval)\n";
704         }
705     } else {
706         print "ioctl returned error code $rc.\n";
707     }
708 }
709
710 sub Preallocate {
711     my $arg = shift;
712
713     if (!defined($::client_id)) {
714         print "You must first ``connect''.\n";
715         return;
716     }
717
718     if (!defined($arg) || scalar($arg) < 1 || scalar($arg) > 32) {
719         $arg = 32;
720     }
721
722     print "Preallocating $arg inodes...\n";
723     my $packed = pack("LLx128", $::client_id, $arg);
724     # client id, alloc, inodes[32]
725
726     my $rc = ioctl(DEV_OBD, &OBD_IOC_PREALLOCATE, $packed);
727
728     if (!defined $rc) {
729         print STDERR "ioctl failed: $!\n";
730     } elsif ($rc eq "0 but true") {
731         my $alloc = unpack("x4L", $packed);
732         my @inodes = unpack("x8L32", $packed);
733         my $i;
734
735         print "Got $alloc inodes: ";
736         foreach $i (@inodes) {
737             print $i . " ";
738         }
739         print "\nFinished (success)\n";
740     } else {
741         print "ioctl returned error code $rc.\n";
742     }
743 }
744
745 sub Decusecount {
746     my $rc = ioctl(DEV_OBD, &OBD_IOC_DEC_USE_COUNT, 0);
747
748     if (!defined $rc) {
749         print STDERR "ioctl failed: $!\n";
750     } elsif ($rc eq "0 but true") {
751         print "Finished (success)\n";
752     } else {
753         print "ioctl returned error code $rc.\n";
754     }
755 }
756
757 sub Statfs {
758     if (!defined($::client_id)) {
759         print "You must first ``connect''.\n";
760         return;
761     }
762
763     # struct statfs {
764     #         long f_type;
765     #         long f_bsize;
766     #         long f_blocks;
767     #         long f_bfree;
768     #         long f_bavail;
769     #         long f_files;
770     #         long f_ffree;
771     #         __kernel_fsid_t f_fsid; (64 bits)
772     #         long f_namelen;
773     #         long f_spare[6];
774     # };
775
776     my $packed = pack("LLLLLLLIILL6", $::client_id, 0, 0, 0, 0, 0, 0, 0, 0, 0,
777                       0, 0, 0, 0, 0, 0);
778
779     my $rc = ioctl(DEV_OBD, &OBD_IOC_STATFS, $packed);
780
781     if (!defined $rc) {
782         print STDERR "ioctl failed: $!\n";
783     } elsif ($rc eq "0 but true") {
784         # skip both the conn_id and the fs_type in the buffer
785         my ($bsize, $blocks, $bfree, $bavail, $files, $ffree) =
786             unpack("x4x4LLLLLL", $packed);
787         print("$bsize byte blocks: $blocks, " . ($blocks - $bfree) . " used, " .
788               "$bfree free ($bavail available).\n");
789         print "$files files, " . ($files - $ffree) . " used, $ffree free.\n";
790         print "Finished (success)\n";
791     } else {
792         print "ioctl returned error code $rc.\n";
793     }
794 }
795
796 sub Help {
797     my $arg = shift;
798
799     if ( !$arg || !$commands{$arg} ) {
800         print "Comands: ", join( ' ', @jcm_cmd_list), "\n";
801     } else {
802         print "Usage: " .  $commands{$arg}->{doc} . "\n";
803     }
804 }
805
806 sub Quit {
807     if ($::client_id) {
808         print "Disconnecting active session ($::client_id)...";
809         Disconnect($::client_id);
810     }
811     exit;
812 }