source: rtems/cpukit/libfs/src/rfs/rtems-rfs-shell.c @ 9b48dc6

4.115
Last change on this file since 9b48dc6 was 9b48dc6, checked in by Alan Cudmore <alan.cudmore@…>, on 12/18/13 at 17:37:47

For PR 2162 - RFS File System - statvfs reports 1 block free

This is for the RFS file system. The statvfs call reports 1 block free
when the file system is full because it does not account for the superblock
in its calculation of free blocks.
This is a simple fix that adjusts the number of blocks reported to account
for the superblock. We may want to wait for a more complete solution such
as locating the superblock in each group.

  • Property mode set to 100644
File size: 18.8 KB
Line 
1/**
2 * @file
3 *
4 * @brief RTEMS File Systems Shell Commands Support
5 * @ingroup rtems_rfs
6 */
7
8/*
9 *  COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
10 *
11 *  The license and distribution terms for this file may be
12 *  found in the file LICENSE in this distribution or at
13 *  http://www.rtems.com/license/LICENSE.
14 */
15
16#if HAVE_CONFIG_H
17#include "config.h"
18#endif
19
20#include <inttypes.h>
21#include <string.h>
22
23#include <rtems/rfs/rtems-rfs-block.h>
24#include <rtems/rfs/rtems-rfs-buffer.h>
25#include <rtems/rfs/rtems-rfs-group.h>
26#include <rtems/rfs/rtems-rfs-inode.h>
27#include <rtems/rfs/rtems-rfs-dir.h>
28#include <rtems/rtems-rfs-format.h>
29
30#include <sys/statvfs.h>
31
32#if __rtems__
33#include "rtems-rfs-rtems.h"
34#include "rtems-rfs-shell.h"
35#endif
36
37/**
38 * The type of the shell handlers we have.
39 */
40typedef int (*rtems_rfs_shell_handler) (rtems_rfs_file_system* fs, int argc, char *argv[]);
41
42/**
43 * Table of handlers we parse to invoke the command.
44 */
45typedef struct
46{
47  const char*             name;
48  rtems_rfs_shell_handler handler;
49  const char*             help;
50} rtems_rfs_shell_cmd;
51
52/**
53 * Lock the file system.
54 */
55static void
56rtems_rfs_shell_lock_rfs (rtems_rfs_file_system* fs)
57{
58#if __rtems__
59  rtems_rfs_rtems_lock (fs);
60#endif
61}
62
63/**
64 * Unlock the file system.
65 */
66static void
67rtems_rfs_shell_unlock_rfs (rtems_rfs_file_system* fs)
68{
69#if __rtems__
70  rtems_rfs_rtems_unlock (fs);
71#endif
72}
73
74/**
75 * Get the file system data from the specific path. Checks to make sure the path is
76 * pointing to a valid RFS file system.
77 */
78static int
79rtems_rfs_get_fs (const char* path, rtems_rfs_file_system** fs)
80{
81  struct statvfs sb;
82  int            rc;
83
84  rc = statvfs (path, &sb);
85  if (rc < 0)
86  {
87    printf ("error: cannot statvfs path: %s: (%d) %s\n",
88            path, errno, strerror (errno));
89    return -1;
90  }
91
92  if (sb.f_fsid != RTEMS_RFS_SB_MAGIC)
93  {
94    printf ("error: path '%s' is not on an RFS file system\n", path);
95    return -1;
96  }
97
98#if __rtems__
99  /*
100   * Now find the path location on the file system. This will give the file
101   * system data.
102   */
103  {
104    rtems_filesystem_eval_path_context_t ctx;
105    int eval_flags = RTEMS_FS_FOLLOW_LINK;
106    const rtems_filesystem_location_info_t *currentloc =
107      rtems_filesystem_eval_path_start (&ctx, path, eval_flags);
108    *fs = rtems_rfs_rtems_pathloc_dev (currentloc);
109    rtems_filesystem_eval_path_cleanup (&ctx);
110  }
111#endif
112
113  return rc;
114}
115
116static int
117rtems_rfs_shell_data (rtems_rfs_file_system* fs, int argc, char *argv[])
118{
119  size_t blocks;
120  size_t inodes;
121  int    bpcent;
122  int    ipcent;
123
124  printf ("RFS Filesystem Data\n");
125  printf ("             flags: %08" PRIx32 "\n", fs->flags);
126#if 0
127  printf ("            device: %08lx\n",         rtems_rfs_fs_device (fs));
128#endif
129  printf ("            blocks: %zu\n",           rtems_rfs_fs_blocks (fs));
130  printf ("        block size: %zu\n",           rtems_rfs_fs_block_size (fs));
131  printf ("              size: %" PRIu64 "\n",   rtems_rfs_fs_size (fs));
132  printf ("  media block size: %" PRIu32 "\n",   rtems_rfs_fs_media_block_size (fs));
133  printf ("        media size: %" PRIu64 "\n",   rtems_rfs_fs_media_size (fs));
134  printf ("            inodes: %" PRIu32 "\n",   rtems_rfs_fs_inodes (fs));
135  printf ("        bad blocks: %" PRIu32 "\n",   fs->bad_blocks);
136  printf ("  max. name length: %" PRIu32 "\n",   rtems_rfs_fs_max_name (fs));
137  printf ("            groups: %d\n",            fs->group_count);
138  printf ("      group blocks: %zd\n",           fs->group_blocks);
139  printf ("      group inodes: %zd\n",           fs->group_inodes);
140  printf ("  inodes per block: %zd\n",           fs->inodes_per_block);
141  printf ("  blocks per block: %zd\n",           fs->blocks_per_block);
142  printf ("     singly blocks: %zd\n",           fs->block_map_singly_blocks);
143  printf ("    doublly blocks: %zd\n",           fs->block_map_doubly_blocks);
144  printf (" max. held buffers: %" PRId32 "\n",   fs->max_held_buffers);
145
146  rtems_rfs_shell_lock_rfs (fs);
147
148  rtems_rfs_group_usage (fs, &blocks, &inodes);
149
150  rtems_rfs_shell_unlock_rfs (fs);
151
152  bpcent = (blocks * 1000) / (rtems_rfs_fs_blocks (fs) - 1);
153  ipcent = (inodes * 1000) / rtems_rfs_fs_inodes (fs);
154
155  printf ("       blocks used: %zd (%d.%d%%)\n",
156          blocks, bpcent / 10, bpcent % 10);
157  printf ("       inodes used: %zd (%d.%d%%)\n",
158          inodes, ipcent / 10, ipcent % 10);
159
160  return 0;
161}
162
163static int
164rtems_rfs_shell_block (rtems_rfs_file_system* fs, int argc, char *argv[])
165{
166  rtems_rfs_buffer_handle buffer;
167  rtems_rfs_block_no      block;
168  uint8_t*                data;
169  bool                    state;
170  int                     b;
171  int                     rc;
172
173  if (argc <= 1)
174  {
175    printf ("error: no block number provided\n");
176    return 1;
177  }
178
179  block = strtoul (argv[1], 0, 0);
180
181  rtems_rfs_shell_lock_rfs (fs);
182
183  rc = rtems_rfs_group_bitmap_test (fs, false, block, &state);
184  if (rc > 0)
185  {
186    rtems_rfs_shell_unlock_rfs (fs);
187    printf ("error: testing block state: block=%" PRIu32 ": (%d) %s\n",
188            block, rc, strerror (rc));
189    return 1;
190  }
191
192  printf (" %5" PRIu32 ": block %s\n", block, state ? "allocated" : "free");
193
194  rc = rtems_rfs_buffer_handle_open (fs, &buffer);
195  if (rc > 0)
196  {
197    rtems_rfs_shell_unlock_rfs (fs);
198    printf ("error: opening buffer handle: block=%" PRIu32 ": (%d) %s\n",
199            block, rc, strerror (rc));
200    return 1;
201  }
202
203  rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true);
204  if (rc > 0)
205  {
206    rtems_rfs_buffer_handle_close (fs, &buffer);
207    rtems_rfs_shell_unlock_rfs (fs);
208    printf ("error: requesting buffer handle: block=%" PRIu32 ": (%d) %s\n",
209            block, rc, strerror (rc));
210    return 1;
211  }
212
213  for (b = 0, data = rtems_rfs_buffer_data (&buffer);
214       b < rtems_rfs_fs_block_size (fs);
215       b++, data++)
216  {
217    int mod = b % 16;
218    if (mod == 0)
219    {
220      if (b)
221        printf ("\n");
222      printf ("%04x ", b);
223    }
224    if (mod == 8)
225      printf (" ");
226    printf ("%02x ", *data);
227  }
228
229  printf ("\n");
230
231  rc = rtems_rfs_buffer_handle_close (fs, &buffer);
232  if (rc > 0)
233  {
234    rtems_rfs_shell_unlock_rfs (fs);
235    printf ("error: closing buffer handle: block=%" PRIu32 ": (%d) %s\n",
236            block, rc, strerror (rc));
237    return 1;
238  }
239
240  rtems_rfs_shell_unlock_rfs (fs);
241
242  return 0;
243}
244
245static int
246rtems_rfs_shell_inode (rtems_rfs_file_system* fs, int argc, char *argv[])
247{
248  rtems_rfs_ino start;
249  rtems_rfs_ino end;
250  rtems_rfs_ino total;
251  rtems_rfs_ino ino;
252  bool          show_all;
253  bool          error_check_only;
254  bool          forced;
255  bool          have_start;
256  bool          have_end;
257  int           arg;
258  int           b;
259  int           rc;
260
261  total = fs->group_inodes * fs->group_count;
262  start = RTEMS_RFS_ROOT_INO;
263  end = total - 1;
264  show_all = false;
265  error_check_only = false;
266  forced = false;
267  have_start = have_end = false;
268
269  for (arg = 1; arg < argc; arg++)
270  {
271    if (argv[arg][0] == '-')
272    {
273      switch (argv[arg][1])
274      {
275        case 'a':
276          show_all = true;
277          break;
278        case 'e':
279          error_check_only = true;
280          break;
281        case 'f':
282          forced = true;
283          break;
284        default:
285          printf ("warning: option ignored: %s\n", argv[arg]);
286          break;
287      }
288    }
289    else
290    {
291      if (have_end && have_start)
292        printf ("warning: option ignored: %s\n", argv[arg]);
293      else if (!have_start)
294      {
295        start = end = strtoul (argv[arg], 0, 0);
296        have_start = true;
297      }
298      else
299      {
300        end = strtoul (argv[arg], 0, 0);
301        have_end = true;
302      }
303    }
304  }
305
306  if ((start >= total) || (end >= total))
307  {
308    printf ("error: inode out of range (0->%" PRId32 ").\n", total - 1);
309    return 1;
310  }
311
312  rtems_rfs_shell_lock_rfs (fs);
313
314  for (ino = start; ino <= end; ino++)
315  {
316    rtems_rfs_inode_handle inode;
317    bool                   allocated;
318
319    rc = rtems_rfs_group_bitmap_test (fs, true, ino, &allocated);
320    if (rc > 0)
321    {
322      rtems_rfs_shell_unlock_rfs (fs);
323      printf ("error: testing inode state: ino=%" PRIu32 ": (%d) %s\n",
324              ino, rc, strerror (rc));
325      return 1;
326    }
327
328    if (show_all || allocated)
329    {
330      uint16_t mode;
331      bool     error;
332
333      rc = rtems_rfs_inode_open (fs, ino, &inode, true);
334      if (rc > 0)
335      {
336        rtems_rfs_shell_unlock_rfs (fs);
337        printf ("error: opening inode handle: ino=%" PRIu32 ": (%d) %s\n",
338                ino, rc, strerror (rc));
339        return 1;
340      }
341
342      error = false;
343
344      mode = rtems_rfs_inode_get_mode (&inode);
345
346      if (error_check_only)
347      {
348        if (!RTEMS_RFS_S_ISDIR (mode) &&
349            !RTEMS_RFS_S_ISCHR (mode) &&
350            !RTEMS_RFS_S_ISBLK (mode) &&
351            !RTEMS_RFS_S_ISREG (mode) &&
352            !RTEMS_RFS_S_ISLNK (mode))
353          error = true;
354        else
355        {
356#if NEED_TO_HANDLE_DIFFERENT_TYPES
357          int b;
358          for (b = 0; b < RTEMS_RFS_INODE_BLOCKS; b++)
359          {
360            uint32_t block;
361            block = rtems_rfs_inode_get_block (&inode, b);
362            if ((block <= RTEMS_RFS_SUPERBLOCK_SIZE) ||
363                (block >= rtems_rfs_fs_blocks (fs)))
364              error = true;
365          }
366#endif
367        }
368      }
369
370      if (!error_check_only || error)
371      {
372        printf (" %5" PRIu32 ": pos=%06" PRIu32 ":%04zx %c ",
373                ino, rtems_rfs_buffer_bnum (&inode.buffer),
374                inode.offset * RTEMS_RFS_INODE_SIZE,
375                allocated ? 'A' : 'F');
376
377        if (!allocated && !forced)
378          printf (" --\n");
379        else
380        {
381          const char* type;
382          type = "UKN";
383          if (RTEMS_RFS_S_ISDIR (mode))
384            type = "DIR";
385          else if (RTEMS_RFS_S_ISCHR (mode))
386            type = "CHR";
387          else if (RTEMS_RFS_S_ISBLK (mode))
388            type = "BLK";
389          else if (RTEMS_RFS_S_ISREG (mode))
390            type = "REG";
391          else if (RTEMS_RFS_S_ISLNK (mode))
392            type = "LNK";
393          printf ("links=%03i mode=%04x (%s/%03o) bo=%04u bc=%04" PRIu32 " b=[",
394                  rtems_rfs_inode_get_links (&inode),
395                  mode, type, mode & ((1 << 10) - 1),
396                  rtems_rfs_inode_get_block_offset (&inode),
397                  rtems_rfs_inode_get_block_count (&inode));
398          for (b = 0; b < (RTEMS_RFS_INODE_BLOCKS - 1); b++)
399            printf ("%" PRIu32 " ", rtems_rfs_inode_get_block (&inode, b));
400          printf ("%" PRIu32 "]\n", rtems_rfs_inode_get_block (&inode, b));
401        }
402      }
403
404      rc = rtems_rfs_inode_close (fs, &inode);
405      if (rc > 0)
406      {
407        rtems_rfs_shell_unlock_rfs (fs);
408        printf ("error: closing inode handle: ino=%" PRIu32 ": (%d) %s\n",
409                ino, rc, strerror (rc));
410        return 1;
411      }
412    }
413  }
414
415  rtems_rfs_shell_unlock_rfs (fs);
416
417  return 0;
418}
419
420static int
421rtems_rfs_shell_dir (rtems_rfs_file_system* fs, int argc, char *argv[])
422{
423  rtems_rfs_buffer_handle buffer;
424  rtems_rfs_block_no      block;
425  uint8_t*                data;
426  bool                    state;
427  int                     entry;
428  int                     b;
429  int                     rc;
430
431  if (argc <= 1)
432  {
433    printf ("error: no block number provided\n");
434    return 1;
435  }
436
437  block = strtoul (argv[1], 0, 0);
438
439  rtems_rfs_shell_lock_rfs (fs);
440
441  rc = rtems_rfs_group_bitmap_test (fs, false, block, &state);
442  if (rc > 0)
443  {
444    rtems_rfs_shell_unlock_rfs (fs);
445    printf ("error: testing block state: block=%" PRIu32 ": (%d) %s\n",
446            block, rc, strerror (rc));
447    return 1;
448  }
449
450  printf (" %5" PRIu32 ": block %s\n", block, state ? "allocated" : "free");
451
452  rc = rtems_rfs_buffer_handle_open (fs, &buffer);
453  if (rc > 0)
454  {
455    rtems_rfs_shell_unlock_rfs (fs);
456    printf ("error: opening buffer handle: block=%" PRIu32 ": (%d) %s\n",
457            block, rc, strerror (rc));
458    return 1;
459  }
460
461  rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true);
462  if (rc > 0)
463  {
464    rtems_rfs_buffer_handle_close (fs, &buffer);
465    rtems_rfs_shell_unlock_rfs (fs);
466    printf ("error: requesting buffer handle: block=%" PRIu32 ": (%d) %s\n",
467            block, rc, strerror (rc));
468    return 1;
469  }
470
471  b = 0;
472  entry = 1;
473  data = rtems_rfs_buffer_data (&buffer);
474
475  while (b < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE - 1))
476  {
477    rtems_rfs_ino eino;
478    int           elength;
479    int           length;
480    int           c;
481
482    eino    = rtems_rfs_dir_entry_ino (data);
483    elength = rtems_rfs_dir_entry_length (data);
484
485    if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY)
486      break;
487
488    if ((elength < RTEMS_RFS_DIR_ENTRY_SIZE) ||
489        (elength >= rtems_rfs_fs_max_name (fs)))
490    {
491      printf (" %5d: entry length appears corrupt: %d\n", entry, elength);
492      break;
493    }
494
495    if ((eino < RTEMS_RFS_ROOT_INO) || (eino >= rtems_rfs_fs_inodes (fs)))
496    {
497      printf (" %5d: entry ino appears corrupt: ino=%" PRId32 "\n", entry, eino);
498      break;
499    }
500
501    length = elength - RTEMS_RFS_DIR_ENTRY_SIZE;
502
503    printf (" %5d: %04x inode=%-6" PRIu32 " hash=%08" PRIx32 " name[%03u]=",
504            entry, b,
505            rtems_rfs_dir_entry_ino (data),
506            rtems_rfs_dir_entry_hash (data),
507            length);
508
509    if (length > 50)
510      length = 50;
511
512    for (c = 0; c < length; c++)
513      printf ("%c", data[RTEMS_RFS_DIR_ENTRY_SIZE + c]);
514    if (length < elength - RTEMS_RFS_DIR_ENTRY_SIZE)
515      printf ("...");
516    printf ("\n");
517
518    b += elength;
519    data += elength;
520    entry++;
521  }
522
523  rc = rtems_rfs_buffer_handle_close (fs, &buffer);
524  if (rc > 0)
525  {
526    rtems_rfs_shell_unlock_rfs (fs);
527    printf ("error: closing buffer handle: block=%" PRIu32 ": (%d) %s\n",
528            block, rc, strerror (rc));
529    return 1;
530  }
531
532  rtems_rfs_shell_unlock_rfs (fs);
533
534  return 0;
535}
536
537static int
538rtems_rfs_shell_group (rtems_rfs_file_system* fs, int argc, char *argv[])
539{
540  int start;
541  int end;
542  int g;
543
544  start = 0;
545  end = fs->group_count - 1;
546
547  switch (argc)
548  {
549    case 1:
550      break;
551    case 2:
552      start = end = strtoul (argv[1], 0, 0);
553      break;
554    case 3:
555      start = strtoul (argv[1], 0, 0);
556      end = strtoul (argv[2], 0, 0);
557      break;
558    default:
559      printf ("error: too many arguments.\n");
560      return 1;
561  }
562
563  if ((start < 0) || (end < 0) ||
564      (start >= fs->group_count) || (end >= fs->group_count))
565  {
566    printf ("error: group out of range (0->%d).\n", fs->group_count);
567    return 1;
568  }
569
570  rtems_rfs_shell_lock_rfs (fs);
571
572  for (g = start; g <= end; g++)
573  {
574    rtems_rfs_group* group = &fs->groups[g];
575    size_t           blocks;
576    size_t           inodes;
577    blocks = group->size - rtems_rfs_bitmap_map_free (&group->block_bitmap);
578    inodes = fs->group_inodes - rtems_rfs_bitmap_map_free (&group->inode_bitmap);
579    printf (" %4d: base=%-7" PRIu32 " size=%-6zu blocks=%-5zu (%3zu%%) inode=%-5zu (%3zu%%)\n",
580            g, group->base, group->size,
581            blocks, (blocks * 100)  / group->size,
582            inodes, (inodes * 100) / fs->group_inodes);
583  }
584
585  rtems_rfs_shell_unlock_rfs (fs);
586
587  return 0;
588}
589
590
591static void
592rtems_rfs_shell_usage (const char* arg)
593{
594  printf ("%s: RFS debugger\n", arg);
595  printf ("  %s [-hl] <path> <command>\n", arg);
596  printf ("   where:\n");
597  printf ("     path:    Path to the mounted RFS file system\n");
598  printf ("     command: A debugger command. See -l for a list plus help.\n");
599  printf ("     -h:      This help\n");
600  printf ("     -l:      The debugger command list.\n");
601}
602
603int
604rtems_shell_debugrfs (int argc, char *argv[])
605{
606  const rtems_rfs_shell_cmd table[] =
607  {
608    { "block", rtems_rfs_shell_block,
609      "Display the contents of a block, block <bno>, block <bno>..<bno>" },
610    { "data", rtems_rfs_shell_data,
611      "Display file system data, data" },
612    { "dir", rtems_rfs_shell_dir,
613      "Display a block as a table for directory entrie, dir <bno>" },
614    { "group", rtems_rfs_shell_group,
615      "Display the group data of a file system, group, group <group>, group <start> <end>" },
616    { "inode", rtems_rfs_shell_inode,
617      "Display an inode, inode <ino>, inode> <ino>..<ino>" }
618  };
619
620  int arg;
621  int t;
622
623  for (arg = 1; arg < argc; arg++)
624  {
625    if (argv[arg][0] != '-')
626      break;
627
628    switch (argv[arg][1])
629    {
630      case 'h':
631        rtems_rfs_shell_usage (argv[0]);
632        return 0;
633      case 'l':
634        printf ("%s: commands are:\n", argv[0]);
635        for (t = 0; t < (sizeof (table) / sizeof (const rtems_rfs_shell_cmd)); t++)
636          printf ("  %s\t\t%s\n", table[t].name, table[t].help);
637        return 0;
638      default:
639        printf ("error: unknown option: %s\n", argv[arg]);
640        return 1;
641    }
642  }
643
644  if ((argc - arg) < 2)
645    printf ("error: you need at least a path and command, try %s -h\n", argv[0]);
646  else
647  {
648    rtems_rfs_file_system* fs;
649    if (rtems_rfs_get_fs (argv[arg], &fs) == 0)
650    {
651      for (t = 0; t < (sizeof (table) / sizeof (const rtems_rfs_shell_cmd)); t++)
652        if (strcmp (argv[arg + 1], table[t].name) == 0)
653          return table[t].handler (fs, argc - 2, argv + 2);
654      printf ("error: command not found: %s\n", argv[arg + 1]);
655    }
656  }
657
658  return 1;
659}
660
661int
662rtems_shell_rfs_format (int argc, char* argv[])
663{
664  rtems_rfs_format_config config;
665  const char*             driver = NULL;
666  int                     arg;
667
668  memset (&config, 0, sizeof (rtems_rfs_format_config));
669
670  for (arg = 1; arg < argc; arg++)
671  {
672    if (argv[arg][0] == '-')
673    {
674      switch (argv[arg][1])
675      {
676        case 'v':
677          config.verbose = true;
678          break;
679
680        case 's':
681          arg++;
682          if (arg >= argc)
683          {
684            printf ("error: block size needs an argument\n");
685            return 1;
686          }
687          config.block_size = strtoul (argv[arg], 0, 0);
688          break;
689
690        case 'b':
691          arg++;
692          if (arg >= argc)
693          {
694            printf ("error: group block count needs an argument\n");
695            return 1;
696          }
697          config.group_blocks = strtoul (argv[arg], 0, 0);
698          break;
699
700        case 'i':
701          arg++;
702          if (arg >= argc)
703          {
704            printf ("error: group inode count needs an argument\n");
705            return 1;
706          }
707          config.group_inodes = strtoul (argv[arg], 0, 0);
708          break;
709
710        case 'I':
711          config.initialise_inodes = true;
712          break;
713
714        case 'o':
715          arg++;
716          if (arg >= argc)
717          {
718            printf ("error: inode percentage overhead needs an argument\n");
719            return 1;
720          }
721          config.inode_overhead = strtoul (argv[arg], 0, 0);
722          break;
723
724        default:
725          printf ("error: invalid option: %s\n", argv[arg]);
726          return 1;
727      }
728    }
729    else
730    {
731      if (!driver)
732        driver = argv[arg];
733      else
734      {
735        printf ("error: only one driver name allowed: %s\n", argv[arg]);
736        return 1;
737      }
738    }
739  }
740
741  if (!driver) {
742    printf ("error: no driver name provided\n");
743    return 1;
744  }
745
746  if (rtems_rfs_format (driver, &config) < 0)
747  {
748    printf ("error: format of %s failed: %s\n",
749            driver, strerror (errno));
750    return 1;
751  }
752
753  return 0;
754}
Note: See TracBrowser for help on using the repository browser.