/* This file is in the public domain. */ /* * These are lifted from rf_netbsdkintf.c. They should not be here; * either they should come from a .h file or there should be a * raidframe interface to read component labels directly. But until * either the interface or the .h file appears, we have to get them * somehow. */ #define CLABEL_OFFSET 16384 /* bytes, ie, suitable for lseek */ #define CLABEL_SIZE 1024 /* bytes */ /* * Getting these from the include file that provides them would mean * (a) using an include file not exported to /usr/include and (b) * hauling in most of the raidframe include files. Apparently * separation of the manifest constants (which are really an interface, * between raidframe the disks) from the implementation (all the * internals) was...not considered worth doing. Grrr. * * To compound the confusion, raidctl ignores the version field (!), * printing it but ignoring the value, and silently treats 0 as DIRTY * and all non-zero values as CLEAN (!!) when looking at the clean * fields - I don't know of any document that defines the interface * precisely enough to tell whether this is raidctl incorrectly * assuming things about the values of RF_RAID_DIRTY and * RF_RAID_CLEAN, or the kernel code incorrectly implying (by making * them manifest constants) that their actual values are irrelevant * when clean is really an int-used-as-boolean, but it must be at * least one of those. * * RAIDframe badly needs real interface specs. */ #define RF_COMPONENT_LABEL_VERSION_1 1 #define RF_COMPONENT_LABEL_VERSION 2 #define RF_RAID_DIRTY 0 #define RF_RAID_CLEAN 1 /* * Another bit of ugliness: the status field of RF_ComponentLabel_t is * typed as an int, but the values are enum values. Unwarranted * chumminess with the language at its finest - and more reason to * want good interfaces with real specs. This doesn't lead to * #defines here, just ugly casts when printing below. */ /* * And another grossness: parityConfig is a *text character* giving the * RAID level (eg, '0', ie, 48 on ASCII machines, for RAID0). As a * result of this misdesign, the code uses weird stuff like 'T' for * parity declustering, exposing these clear through to userland * config files, rather than having strings in the config file which * get mapped to proper opaque constants for the userland/kernel * interface. * * We could simply use characters in the switch. But it seems better * to me to confine the ugliness to this block of #defines. (The * information behind these comes from mapsw[] in rf_layout.c in the * kernel source - this is another case where a well-defined interface * is badly needed.) */ #define PARITY_CONFIG_PARITY_DECLUSTERING 'T' #define PARITY_CONFIG_DISTRIBUTED_SPARING_PARITY_DECLUSTERING 'D' #define PARITY_CONFIG_DECLUSTERD_P_Q 'P' #define PARITY_CONFIG_RAID5_ROTATED_SPARING 'R' #define PARITY_CONFIG_CHAINED_DECLUSTERING 'C' #define PARITY_CONFIG_INTERLEAVED_DECLUSTERING 'I' #define PARITY_CONFIG_RAID0 '0' #define PARITY_CONFIG_RAID1 '1' #define PARITY_CONFIG_RAID4 '4' #define PARITY_CONFIG_RAID5 '5' #define PARITY_CONFIG_EVENODD 'E' #define PARITY_CONFIG_DECLUSTERED_EVENODD 'e' #define PARITY_CONFIG_PARITY_LOGGING 'L' #include #include #include #include #include #include #include #include #include extern const char *__progname; /* Fucking namespace pollution - hijacks "devname". */ static const char *devname_; static char devpath[MAXPATHLEN]; static unsigned char clabel[CLABEL_SIZE]; static int devfd; static RF_ComponentLabel_t label; int main(int, char **); int main(int ac, char **av) { int n; if (sizeof(label) > CLABEL_SIZE) { fprintf(stderr,"%s: label size (%d) > CLABEL_SIZE (%d); fix and rebuild\n",__progname,(int)sizeof(label),CLABEL_SIZE); exit(1); } if (ac != 2) { fprintf(stderr,"Usage: %s partition\n",__progname); exit(1); } devname_ = av[1]; devfd = opendisk(devname_,O_RDONLY,&devpath[0],MAXPATHLEN,0); if (devfd < 0) { fprintf(stderr,"%s: %s: %s\n",__progname,devname_,strerror(errno)); exit(1); } n = pread(devfd,&clabel[0],CLABEL_SIZE,CLABEL_OFFSET); if (n < 0) { fprintf(stderr,"%s: %s: reading label: %s\n",__progname,devname_,strerror(errno)); exit(1); } if (n == 0) { fprintf(stderr,"%s: %s: EOF reading label\n",__progname,devname_); exit(1); } if (n < sizeof(label)) { fprintf(stderr,"%s: %s: label too short (%d < %d)\n",__progname,devname_,n,(int)sizeof(label)); exit(1); } bcopy(&clabel[0],&label,sizeof(label)); printf("Version: %d\n",label.version); switch (label.version) { case RF_COMPONENT_LABEL_VERSION_1: printf("Serial: %d\n",label.serial_number); printf("Modcounter: %d\n",label.mod_counter); printf("Row: %d of %d\n",label.row,label.num_rows); printf("Column: %d of %d\n",label.column,label.num_columns); switch (label.clean) { case RF_RAID_DIRTY: printf("Clean: DIRTY\n"); break; case RF_RAID_CLEAN: printf("Clean: CLEAN\n"); break; default: printf("Clean: %d\n",label.clean); break; } switch (label.status) { case (int)rf_ds_optimal: printf("Status: optimal\n"); break; case (int)rf_ds_failed: printf("Status: failed\n"); break; case (int)rf_ds_reconstructing: printf("Status: reconstructing\n"); break; case (int)rf_ds_dist_spared: printf("Status: dist_spared\n"); break; case (int)rf_ds_spared: printf("Status: spared\n"); break; case (int)rf_ds_spare: printf("Status: spare\n"); break; case (int)rf_ds_used_spare: printf("Status: used_spare\n"); break; default: printf("Status: %d\n",label.status); break; } break; case RF_COMPONENT_LABEL_VERSION: printf("Serial: %d\n",label.serial_number); printf("Modcounter: %d\n",label.mod_counter); printf("Row: %d of %d\n",label.row,label.num_rows); printf("Column: %d of %d\n",label.column,label.num_columns); switch (label.clean) { case RF_RAID_DIRTY: printf("Clean: DIRTY\n"); break; case RF_RAID_CLEAN: printf("Clean: CLEAN\n"); break; default: printf("Clean: %d\n",label.clean); break; } switch (label.status) { case (int)rf_ds_optimal: printf("Status: optimal\n"); break; case (int)rf_ds_failed: printf("Status: failed\n"); break; case (int)rf_ds_reconstructing: printf("Status: reconstructing\n"); break; case (int)rf_ds_dist_spared: printf("Status: dist_spared\n"); break; case (int)rf_ds_spared: printf("Status: spared\n"); break; case (int)rf_ds_spare: printf("Status: spare\n"); break; case (int)rf_ds_used_spare: printf("Status: used_spare\n"); break; default: printf("Status: %d\n",label.status); break; } printf("Sectors per stripe unit: %d\n",label.sectPerSU); printf("Stripe units per parity unit: %d\n",label.SUsPerPU); printf("Stripe units per reconstruction unit: %d\n",label.SUsPerRU); switch (label.parityConfig) { case PARITY_CONFIG_PARITY_DECLUSTERING: printf("RAID level: Parity declustering\n"); break; case PARITY_CONFIG_DISTRIBUTED_SPARING_PARITY_DECLUSTERING: printf("RAID level: Distributed sparing parity declustering\n"); break; case PARITY_CONFIG_DECLUSTERD_P_Q: printf("RAID level: Declustered P+Q\n"); break; case PARITY_CONFIG_RAID5_ROTATED_SPARING: printf("RAID level: RAID5 with rotated sparing\n"); break; case PARITY_CONFIG_CHAINED_DECLUSTERING: printf("RAID level: Chained declustering\n"); break; case PARITY_CONFIG_INTERLEAVED_DECLUSTERING: printf("RAID level: Interleaved declustering\n"); break; case PARITY_CONFIG_RAID0: printf("RAID level: RAID0\n"); break; case PARITY_CONFIG_RAID1: printf("RAID level: RAID1\n"); break; case PARITY_CONFIG_RAID4: printf("RAID level: RAID4\n"); break; case PARITY_CONFIG_RAID5: printf("RAID level: RAID5\n"); break; case PARITY_CONFIG_EVENODD: printf("RAID level: EvenOdd\n"); break; case PARITY_CONFIG_DECLUSTERED_EVENODD: printf("RAID level: Declustered EvenOdd\n"); break; case PARITY_CONFIG_PARITY_LOGGING: printf("RAID level: Parity logging\n"); break; default: printf("RAID level: %d\n",label.parityConfig); break; } printf("Max outstanding requests: %d\n",label.maxOutstanding); printf("Component sector size: %d\n",label.blockSize); printf("Component blocks used: %d\n",label.numBlocks); printf("Partition size: %d\n",label.partitionSize); switch (label.autoconfigure) { case 0: switch (label.root_partition) { case 0: printf("Autoconfiguration: No\n"); break; default: printf("Autoconfiguration: autoconfigure=%d root_partition=%d\n",label.autoconfigure,label.root_partition); break; } break; case 1: switch (label.root_partition) { case 0: printf("Autoconfiguration: Yes\n"); break; case 1: printf("Autoconfiguration: Root\n"); break; default: printf("Autoconfiguration: autoconfigure=%d root_partition=%d\n",label.autoconfigure,label.root_partition); break; } break; default: printf("Autoconfiguration: autoconfigure=%d root_partition=%d\n",label.autoconfigure,label.root_partition); break; } printf("Last configured as unit: %d\n",label.last_unit); printf("Config order: %d\n",label.config_order); break; } return(0); }