Changeset 2982 in MondoRescue for branches/3.0/mondo/src/common/libmondo-raid.c
- Timestamp:
- Mar 30, 2012, 2:43:01 AM (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/3.0/mondo/src/common/libmondo-raid.c
r2971 r2982 974 974 975 975 976 int parse_mdstat(struct raidlist_itself *raidlist, char *device_prefix) { 977 978 const char delims[] = " "; 979 980 FILE *fin; 981 int res = 0, row, i, index_min; 982 int v = 0; 983 int lastpos = 0; 984 size_t len = 0; 985 char *token; 986 char *string = NULL; 987 char *cmd = NULL; 988 char *pos; 989 char type; 990 char *strtmp; 991 992 // open file 993 if (!(fin = fopen(MDSTAT_FILE, "r"))) { 994 log_msg(1, "Could not open %s.\n", MDSTAT_FILE); 995 return 1; 996 } 997 // initialise record, build progress and row counters 998 raidlist->entries = 0; 999 raidlist->el[raidlist->entries].progress = 999; 1000 row = 1; 1001 // skip first output row - contains registered RAID levels 1002 res = getline(&string, &len, fin); 1003 // parse the rest 1004 while ( !feof_unlocked(fin) ) { 1005 res = getline(&string, &len, fin); 1006 if (res <= 0) break; 1007 // trim leading spaces 1008 pos = string; 1009 while (*pos == ' ') pos += 1; 1010 mr_asprintf(&strtmp, "%s", pos); 976 int parse_mdstat(char *mdstat_fname, struct raidlist_itself *raidlist, char *device_prefix) { 977 978 const char delims[] = " "; 979 980 FILE *fin = NULL; 981 int res = 0, row, i, index_min; 982 int v = 0; 983 int lastpos = 0; 984 size_t len = 0; 985 char *token = NULL; 986 char *string = NULL; 987 char *cmd = NULL; 988 char *pos = NULL; 989 char type; 990 char *strtmp = NULL; 991 char *strtmp2 = NULL; 992 993 // open file 994 if (!(fin = fopen(mdstat_fname, "r"))) { 995 log_msg(1, "Could not open %s.\n", mdstat_fname); 996 return 1; 997 } 998 // initialise record, build progress and row counters 999 raidlist->entries = 0; 1000 raidlist->el[raidlist->entries].progress = 999; 1001 row = 1; 1002 // skip first output row - contains registered RAID levels 1003 res = getline(&strtmp2, &len, fin); 1004 mr_free(strtmp2); 1005 // parse the rest 1006 while ( !feof_unlocked(fin) ) { 1007 res = getline(&string, &len, fin); 1008 log_msg(8, "mdstat line '%s' read.\n", string); 1009 if (res <= 0) break; 1010 // trim spaces 1011 strip_spaces(string); 1012 log_msg(8, "mdstat line 2 '%s' read.\n", string); 1013 // if we have newline after only spaces, this is a blank line, update 1014 // counters, otherwise do normal parsing 1015 if (!strcmp(string,"")) { 1016 row = 1; 1017 raidlist->entries++; 1018 raidlist->el[raidlist->entries].progress = 999; 1019 } else { 1020 switch (row) { 1021 case 1: // device information 1022 // check whether last line of record and if so skip 1023 log_msg(8, "This is the device line\n"); 1024 pos = strcasestr(string, "unused devices: "); 1025 if (pos != NULL) { 1026 break; 1027 } 1028 // tokenise string 1029 token = mr_strtok(string, delims, &lastpos); 1030 if (token == NULL) { 1031 // should not happen ! 1032 break; 1033 } 1034 // get RAID device name 1035 mr_asprintf(&strtmp,"%s%s", device_prefix, token); 1036 strncpy(raidlist->el[raidlist->entries].raid_device, strtmp, 63); 1037 raidlist->el[raidlist->entries].raid_device[64] = '\0'; 1038 mr_free(strtmp); 1039 mr_free(token); 1040 // store the UUID value in the additional_vars structure 1041 v = raidlist->el[raidlist->entries].additional_vars.entries; 1042 strcpy(raidlist->el[raidlist->entries].additional_vars.el[v].label, "UUID"); 1043 mr_asprintf(&cmd,"mdadm --detail %s | grep UUID | cut -d: -f2- | sed 's/^ *//'", raidlist->el[raidlist->entries].raid_device); 1044 mr_asprintf(&strtmp, "%s", call_program_and_get_last_line_of_output(cmd)); 1045 strcpy(raidlist->el[raidlist->entries].additional_vars.el[v].value, strtmp); 1046 mr_free(strtmp); 1047 v++; 1048 raidlist->el[raidlist->entries].additional_vars.entries = v; 1049 // skip ':' and status 1050 token = mr_strtok (string, delims, &lastpos); 1051 if (token == NULL) { 1052 // should not happen ! 1053 break; 1054 } 1055 mr_free(token); 1056 token = mr_strtok (string, delims, &lastpos); 1057 if (token == NULL) { 1058 // should not happen ! 1059 break; 1060 } 1061 if (!strcmp(token, "inactive")) { 1062 log_msg(1, "RAID device '%s' inactive.\n", 1063 raidlist->el[raidlist->entries].raid_device); 1064 mr_free(string); 1065 mr_free(token); 1066 return 1; 1067 } 1068 mr_free(token); 1069 1070 // get RAID level 1071 token = mr_strtok (string, delims, &lastpos); 1072 if (token == NULL) { 1073 // should not happen ! 1074 break; 1075 } 1076 // skip potential auto-read-only entry 1077 if (!strcmp(token, "(auto-read-only)")) { 1078 mr_free(token); 1079 token = mr_strtok (string, delims, &lastpos); 1080 if (token == NULL) { 1081 // should not happen ! 1082 break; 1083 } 1084 } 1085 if (!strcmp(token, "multipath")) { 1086 raidlist->el[raidlist->entries].raid_level = -2; 1087 } else if (!strcmp(token, "linear")) { 1088 raidlist->el[raidlist->entries].raid_level = -1; 1089 } else if (!strcmp(token, "raid0")) { 1090 raidlist->el[raidlist->entries].raid_level = 0; 1091 } else if (!strcmp(token, "raid1")) { 1092 raidlist->el[raidlist->entries].raid_level = 1; 1093 } else if (!strcmp(token, "raid4")) { 1094 raidlist->el[raidlist->entries].raid_level = 4; 1095 } else if (!strcmp(token, "raid5")) { 1096 raidlist->el[raidlist->entries].raid_level = 5; 1097 } else if (!strcmp(token, "raid6")) { 1098 raidlist->el[raidlist->entries].raid_level = 6; 1099 } else if (!strcmp(token, "raid10")) { 1100 raidlist->el[raidlist->entries].raid_level = 10; 1101 } else { 1102 log_msg(1, "Unknown RAID level '%s'.\n", token); 1103 mr_free(string); 1104 mr_free(token); 1105 return 1; 1106 } 1107 mr_free(token); 1108 1109 // get RAID devices (type, index, device) 1110 // Note: parity disk for RAID4 is last normal disk, there is no '(P)' 1111 raidlist->el[raidlist->entries].data_disks.entries = 0; 1112 raidlist->el[raidlist->entries].spare_disks.entries = 0; 1113 raidlist->el[raidlist->entries].failed_disks.entries = 0; 1114 while((token = mr_strtok (string, delims, &lastpos))) { 1115 if ((pos = strstr(token, "("))) { 1116 type = *(pos+1); 1117 } else { 1118 type = ' '; 1119 } 1120 pos = strstr(token, "["); 1121 *pos = '\0'; 1122 switch(type) { 1123 case ' ': // normal data disks 1124 raidlist->el[raidlist->entries].data_disks.el[raidlist->el[raidlist->entries].data_disks.entries].index = atoi(pos + 1); 1125 mr_asprintf(&strtmp,"%s%s", device_prefix, token); 1126 strcpy(raidlist->el[raidlist->entries].data_disks.el[raidlist->el[raidlist->entries].data_disks.entries].device, strtmp); 1127 mr_free(strtmp); 1128 raidlist->el[raidlist->entries].data_disks.entries++; 1129 break; 1130 case 'S': // spare disks 1131 raidlist->el[raidlist->entries].spare_disks.el[raidlist->el[raidlist->entries].spare_disks.entries].index = atoi(pos + 1); 1132 mr_asprintf(&strtmp,"%s%s", device_prefix, token); 1133 strcpy(raidlist->el[raidlist->entries].spare_disks.el[raidlist->el[raidlist->entries].spare_disks.entries].device, strtmp); 1134 mr_free(strtmp); 1135 raidlist->el[raidlist->entries].spare_disks.entries++; 1136 break; 1137 case 'F': // failed disks 1138 raidlist->el[raidlist->entries].failed_disks.el[raidlist->el[raidlist->entries].failed_disks.entries].index = atoi(pos + 1); 1139 mr_asprintf(&strtmp,"%s%s", device_prefix, token); 1140 strcpy(raidlist->el[raidlist->entries].failed_disks.el[raidlist->el[raidlist->entries].failed_disks.entries].device, strtmp); 1141 mr_free(strtmp); 1142 raidlist->el[raidlist->entries].failed_disks.entries++; 1143 log_it("At least one failed disk found in RAID array.\n"); 1144 break; 1145 default: // error 1146 log_msg(1, "Unknown device type '%c'\n", type); 1147 mr_free(string); 1148 mr_free(token); 1149 return 1; 1150 break; 1151 } 1152 mr_free(token); 1153 } 1154 1155 // adjust index for each device so that it starts with 0 for every type 1156 index_min = 99; 1157 for (i=0; i<raidlist->el[raidlist->entries].data_disks.entries;i++) { 1158 if (raidlist->el[raidlist->entries].data_disks.el[i].index < index_min) { 1159 index_min = raidlist->el[raidlist->entries].data_disks.el[i].index; 1160 } 1161 } 1162 if (index_min > 0) { 1163 for (i=0; i<raidlist->el[raidlist->entries].data_disks.entries;i++) { 1164 raidlist->el[raidlist->entries].data_disks.el[i].index = raidlist->el[raidlist->entries].data_disks.el[i].index - index_min; 1165 } 1166 } 1167 index_min = 99; 1168 for (i=0; i<raidlist->el[raidlist->entries].spare_disks.entries;i++) { 1169 if (raidlist->el[raidlist->entries].spare_disks.el[i].index < index_min) { 1170 index_min = raidlist->el[raidlist->entries].spare_disks.el[i].index; 1171 } 1172 } 1173 if (index_min > 0) { 1174 for (i=0; i<raidlist->el[raidlist->entries].spare_disks.entries;i++) { 1175 raidlist->el[raidlist->entries].spare_disks.el[i].index = raidlist->el[raidlist->entries].spare_disks.el[i].index - index_min; 1176 } 1177 } 1178 index_min = 99; 1179 for (i=0; i<raidlist->el[raidlist->entries].failed_disks.entries;i++) { 1180 if (raidlist->el[raidlist->entries].failed_disks.el[i].index < index_min) { 1181 index_min = raidlist->el[raidlist->entries].failed_disks.el[i].index; 1182 } 1183 } 1184 if (index_min > 0) { 1185 for (i=0; i<raidlist->el[raidlist->entries].failed_disks.entries;i++) { 1186 raidlist->el[raidlist->entries].failed_disks.el[i].index = raidlist->el[raidlist->entries].failed_disks.el[i].index - index_min; 1187 } 1188 } 1189 break; 1190 case 2: // config information 1191 // check for persistent super block 1192 if (strcasestr(string, "super non-persistent")) { 1193 raidlist->el[raidlist->entries].persistent_superblock = 0; 1194 } else { 1195 raidlist->el[raidlist->entries].persistent_superblock = 1; 1196 } 1197 // extract chunk size 1198 if (!(pos = strcasestr(string, "k chunk"))) { 1199 raidlist->el[raidlist->entries].chunk_size = -1; 1200 } else { 1201 while (*pos != ' ') { 1202 pos -= 1; 1203 if (pos < string) { 1204 log_it("String underflow!\n"); 1205 mr_free(string); 1206 return 1; 1207 } 1208 } 1209 raidlist->el[raidlist->entries].chunk_size = atoi(pos + 1); 1210 } 1211 // extract parity if present 1212 if ((pos = strcasestr(string, "algorithm"))) { 1213 raidlist->el[raidlist->entries].parity = atoi(pos + 9); 1214 } else { 1215 raidlist->el[raidlist->entries].parity = -1; 1216 } 1217 break; 1218 case 3: // optional build status information 1219 if (!(pos = strchr(string, '\%'))) { 1220 if (strcasestr(string, "delayed")) { 1221 raidlist->el[raidlist->entries].progress = -1; // delayed (therefore, stuck at 0%) 1222 } else { 1223 raidlist->el[raidlist->entries].progress = 999; // not found 1224 } 1225 } else { 1226 while (*pos != ' ') { 1227 pos -= 1; 1228 if (pos < string) { 1229 printf("ERROR: String underflow!\n"); 1230 mr_free(string); 1231 return 1; 1232 } 1233 } 1234 raidlist->el[raidlist->entries].progress = atoi(pos); 1235 } 1236 break; 1237 default: // error or IN PROGRESS 1238 if (raidlist->el[raidlist->entries].progress != -1 && 1239 raidlist->el[raidlist->entries].progress != 999) { 1240 log_msg(1, "Row %d should not occur in record!\n", row); 1241 } 1242 break; 1243 } 1244 row++; 1245 } 1246 // free string 1011 1247 mr_free(string); 1012 string = strtmp; 1013 // if we have newline after only spaces, this is a blank line, update 1014 // counters, otherwise do normal parsing 1015 if (*string == '\n') { 1016 row = 1; 1017 raidlist->entries++; 1018 raidlist->el[raidlist->entries].progress = 999; 1019 } else { 1020 switch (row) { 1021 case 1: // device information 1022 // check whether last line of record and if so skip 1023 pos = strcasestr(string, "unused devices: "); 1024 if (pos == string) { 1025 //raidlist->entries--; 1026 break; 1027 } 1028 // tokenise string 1029 token = mr_strtok (string, delims, &lastpos); 1030 // get RAID device name 1031 mr_asprintf(&strtmp,"%s%s", device_prefix, token); 1032 strcpy(raidlist->el[raidlist->entries].raid_device, strtmp); 1033 mr_free(strtmp); 1034 mr_free(token); 1035 // store the UUID value in the additional_vars structure 1036 v = raidlist->el[raidlist->entries].additional_vars.entries; 1037 strcpy(raidlist->el[raidlist->entries].additional_vars.el[v].label, "UUID"); 1038 mr_asprintf(&cmd,"mdadm --detail %s | grep UUID | cut -d: -f2- | sed 's/^ *//'", raidlist->el[raidlist->entries].raid_device); 1039 mr_asprintf(&strtmp, "%s", call_program_and_get_last_line_of_output(cmd)); 1040 strcpy(raidlist->el[raidlist->entries].additional_vars.el[v].value, strtmp); 1041 v++; 1042 raidlist->el[raidlist->entries].additional_vars.entries = v; 1043 // skip ':' and status 1044 token = mr_strtok (string, delims, &lastpos); 1045 mr_free(token); 1046 token = mr_strtok (string, delims, &lastpos); 1047 if (!strcmp(token, "inactive")) { 1048 log_msg(1, "RAID device '%s' inactive.\n", 1049 raidlist->el[raidlist->entries].raid_device); 1050 mr_free(string); 1051 mr_free(token); 1052 return 1; 1053 } 1054 mr_free(token); 1055 1056 // get RAID level 1057 token = mr_strtok (string, delims, &lastpos); 1058 // skip potential auto-read-only entry 1059 if (!strcmp(token, "(auto-read-only)")) { 1060 mr_free(token); 1061 token = mr_strtok (string, delims, &lastpos); 1062 } 1063 if (!strcmp(token, "multipath")) { 1064 raidlist->el[raidlist->entries].raid_level = -2; 1065 } else if (!strcmp(token, "linear")) { 1066 raidlist->el[raidlist->entries].raid_level = -1; 1067 } else if (!strcmp(token, "raid0")) { 1068 raidlist->el[raidlist->entries].raid_level = 0; 1069 } else if (!strcmp(token, "raid1")) { 1070 raidlist->el[raidlist->entries].raid_level = 1; 1071 } else if (!strcmp(token, "raid4")) { 1072 raidlist->el[raidlist->entries].raid_level = 4; 1073 } else if (!strcmp(token, "raid5")) { 1074 raidlist->el[raidlist->entries].raid_level = 5; 1075 } else if (!strcmp(token, "raid6")) { 1076 raidlist->el[raidlist->entries].raid_level = 6; 1077 } else if (!strcmp(token, "raid10")) { 1078 raidlist->el[raidlist->entries].raid_level = 10; 1079 } else { 1080 log_msg(1, "Unknown RAID level '%s'.\n", token); 1081 mr_free(string); 1082 mr_free(token); 1083 return 1; 1084 } 1085 mr_free(token); 1086 1087 // get RAID devices (type, index, device) 1088 // Note: parity disk for RAID4 is last normal disk, there is no '(P)' 1089 raidlist->el[raidlist->entries].data_disks.entries = 0; 1090 raidlist->el[raidlist->entries].spare_disks.entries = 0; 1091 raidlist->el[raidlist->entries].failed_disks.entries = 0; 1092 while((token = mr_strtok (string, delims, &lastpos))) { 1093 if ((pos = strstr(token, "("))) { 1094 type = *(pos+1); 1095 } else { 1096 type = ' '; 1097 } 1098 pos = strstr(token, "["); 1099 *pos = '\0'; 1100 switch(type) { 1101 case ' ': // normal data disks 1102 raidlist->el[raidlist->entries].data_disks.el[raidlist->el[raidlist->entries].data_disks.entries].index = atoi(pos + 1); 1103 mr_asprintf(&strtmp,"%s%s", device_prefix, token); 1104 strcpy(raidlist->el[raidlist->entries].data_disks.el[raidlist->el[raidlist->entries].data_disks.entries].device, strtmp); 1105 mr_free(strtmp); 1106 raidlist->el[raidlist->entries].data_disks.entries++; 1107 break; 1108 case 'S': // spare disks 1109 raidlist->el[raidlist->entries].spare_disks.el[raidlist->el[raidlist->entries].spare_disks.entries].index = atoi(pos + 1); 1110 mr_asprintf(&strtmp,"%s%s", device_prefix, token); 1111 strcpy(raidlist->el[raidlist->entries].spare_disks.el[raidlist->el[raidlist->entries].spare_disks.entries].device, strtmp); 1112 mr_free(strtmp); 1113 raidlist->el[raidlist->entries].spare_disks.entries++; 1114 break; 1115 case 'F': // failed disks 1116 raidlist->el[raidlist->entries].failed_disks.el[raidlist->el[raidlist->entries].failed_disks.entries].index = atoi(pos + 1); 1117 mr_asprintf(&strtmp,"%s%s", device_prefix, token); 1118 strcpy(raidlist->el[raidlist->entries].failed_disks.el[raidlist->el[raidlist->entries].failed_disks.entries].device, strtmp); 1119 mr_free(strtmp); 1120 raidlist->el[raidlist->entries].failed_disks.entries++; 1121 log_it("At least one failed disk found in RAID array.\n"); 1122 break; 1123 default: // error 1124 log_msg(1, "Unknown device type '%c'\n", type); 1125 mr_free(string); 1126 mr_free(token); 1127 return 1; 1128 break; 1129 } 1130 mr_free(token); 1131 } 1132 1133 // adjust index for each device so that it starts with 0 for every type 1134 index_min = 99; 1135 for (i=0; i<raidlist->el[raidlist->entries].data_disks.entries;i++) { 1136 if (raidlist->el[raidlist->entries].data_disks.el[i].index < index_min) { 1137 index_min = raidlist->el[raidlist->entries].data_disks.el[i].index; 1138 } 1139 } 1140 if (index_min > 0) { 1141 for (i=0; i<raidlist->el[raidlist->entries].data_disks.entries;i++) { 1142 raidlist->el[raidlist->entries].data_disks.el[i].index = raidlist->el[raidlist->entries].data_disks.el[i].index - index_min; 1143 } 1144 } 1145 index_min = 99; 1146 for (i=0; i<raidlist->el[raidlist->entries].spare_disks.entries;i++) { 1147 if (raidlist->el[raidlist->entries].spare_disks.el[i].index < index_min) { 1148 index_min = raidlist->el[raidlist->entries].spare_disks.el[i].index; 1149 } 1150 } 1151 if (index_min > 0) { 1152 for (i=0; i<raidlist->el[raidlist->entries].spare_disks.entries;i++) { 1153 raidlist->el[raidlist->entries].spare_disks.el[i].index = raidlist->el[raidlist->entries].spare_disks.el[i].index - index_min; 1154 } 1155 } 1156 index_min = 99; 1157 for (i=0; i<raidlist->el[raidlist->entries].failed_disks.entries;i++) { 1158 if (raidlist->el[raidlist->entries].failed_disks.el[i].index < index_min) { 1159 index_min = raidlist->el[raidlist->entries].failed_disks.el[i].index; 1160 } 1161 } 1162 if (index_min > 0) { 1163 for (i=0; i<raidlist->el[raidlist->entries].failed_disks.entries;i++) { 1164 raidlist->el[raidlist->entries].failed_disks.el[i].index = raidlist->el[raidlist->entries].failed_disks.el[i].index - index_min; 1165 } 1166 } 1167 break; 1168 case 2: // config information 1169 // check for persistent super block 1170 if (strcasestr(string, "super non-persistent")) { 1171 raidlist->el[raidlist->entries].persistent_superblock = 0; 1172 } else { 1173 raidlist->el[raidlist->entries].persistent_superblock = 1; 1174 } 1175 // extract chunk size 1176 if (!(pos = strcasestr(string, "k chunk"))) { 1177 raidlist->el[raidlist->entries].chunk_size = -1; 1178 } else { 1179 while (*pos != ' ') { 1180 pos -= 1; 1181 if (pos < string) { 1182 log_it("String underflow!\n"); 1183 mr_free(string); 1184 return 1; 1185 } 1186 } 1187 raidlist->el[raidlist->entries].chunk_size = atoi(pos + 1); 1188 } 1189 // extract parity if present 1190 if ((pos = strcasestr(string, "algorithm"))) { 1191 raidlist->el[raidlist->entries].parity = atoi(pos + 9); 1192 } else { 1193 raidlist->el[raidlist->entries].parity = -1; 1194 } 1195 break; 1196 case 3: // optional build status information 1197 if (!(pos = strchr(string, '\%'))) { 1198 if (strcasestr(string, "delayed")) { 1199 raidlist->el[raidlist->entries].progress = -1; // delayed (therefore, stuck at 0%) 1200 } else { 1201 raidlist->el[raidlist->entries].progress = 999; // not found 1202 } 1203 } else { 1204 while (*pos != ' ') { 1205 pos -= 1; 1206 if (pos < string) { 1207 printf("ERROR: String underflow!\n"); 1208 mr_free(string); 1209 return 1; 1210 } 1211 } 1212 raidlist->el[raidlist->entries].progress = atoi(pos); 1213 } 1214 break; 1215 default: // error or IN PROGRESS 1216 if (raidlist->el[raidlist->entries].progress != -1 && 1217 raidlist->el[raidlist->entries].progress != 999) { 1218 log_msg(1, "Row %d should not occur in record!\n", row); 1219 } 1220 break; 1221 } 1222 row++; 1223 } 1224 } 1225 // close file 1226 fclose(fin); 1227 // free string 1228 mr_free(string); 1229 // return success 1230 return 0; 1231 1232 } 1233 1234 1235 1236 1237 int create_raidtab_from_mdstat(char *raidtab_fname) 1248 } 1249 // close file 1250 fclose(fin); 1251 // return success 1252 return 0; 1253 1254 } 1255 1256 1257 1258 1259 int create_raidtab_from_mdstat(char *mdstat_fname,char *raidtab_fname) 1238 1260 { 1239 1261 struct raidlist_itself *raidlist; … … 1243 1265 1244 1266 // FIXME: Prefix '/dev/' should really be dynamic! 1245 if (parse_mdstat( raidlist, "/dev/")) {1246 log_to_screen("Sorry, cannot read %s", MDSTAT_FILE);1267 if (parse_mdstat(mdstat_fname,raidlist, "/dev/")) { 1268 log_to_screen("Sorry, cannot read %s", mdstat_fname); 1247 1269 return (1); 1248 1270 }
Note:
See TracChangeset
for help on using the changeset viewer.