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