]> git.ipfire.org Git - thirdparty/mdadm.git/blob - mdstat.c
9711e54afe46d93703b7b26ed2b63abaabb8ee7f
[thirdparty/mdadm.git] / mdstat.c
1 /*
2 * mdstat - parse /proc/mdstat file. Part of:
3 * mdadm - manage Linux "md" devices aka RAID arrays.
4 *
5 * Copyright (C) 2002 Neil Brown <neilb@cse.unsw.edu.au>
6 *
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * Author: Neil Brown
23 * Email: <neilb@cse.unsw.edu.au>
24 * Paper: Neil Brown
25 * School of Computer Science and Engineering
26 * The University of New South Wales
27 * Sydney, 2052
28 * Australia
29 */
30
31 /*
32 * The /proc/mdstat file comes in at least 3 flavours:
33 * In an unpatched 2.2 kernel (md 0.36.6):
34 * Personalities : [n raidx] ...
35 * read_ahead {not set|%d sectors}
36 * md0 : {in}active{ raidX /dev/hda... %d blocks{ maxfault=%d}}
37 * md1 : .....
38 *
39 * Normally only 4 md lines, but all are listed.
40 *
41 * In a patched 2.2 kernel (md 0.90.0)
42 * Personalities : [raidx] ...
43 * read_ahead {not set|%d sectors}
44 * mdN : {in}active {(readonly)} raidX dev[%d]{(F)} ... %d blocks STATUS RESYNC
45 * ... Only initialised arrays listed
46 * unused: dev dev dev | <none>
47 *
48 * STATUS is personality dependant:
49 * linear: %dk rounding
50 * raid0: %dk chunks
51 * raid1: [%d/%d] [U_U] ( raid/working. operational or not)
52 * raid5: level 4/5, %dk chunk, algorithm %d [%d/%d] [U_U]
53 *
54 * RESYNC is empty or:
55 * {resync|recovery}=%u%% finish=%u.%umin
56 * or
57 * resync=DELAYED
58 *
59 * In a 2.4 kernel (md 0.90.0/2.4)
60 * Personalities : [raidX] ...
61 * read_ahead {not set|%d sectors}
62 * mdN : {in}active {(read-only)} raidX dev[%d]{(F)} ...
63 * %d blocks STATUS
64 * RESYNC
65 * unused: dev dev .. | <none>
66 *
67 * STATUS matches 0.90.0/2.2
68 * RESYNC includes [===>....],
69 * adds a space after {resync|recovery} and before and after '='
70 * adds a decimal to the recovery percent.
71 * adds (%d/%d) resync amount and max_blocks, before finish.
72 * adds speed=%dK/sec after finish
73 *
74 *
75 *
76 * Out of this we want to extract:
77 * list of devices, active or not
78 * pattern of failed drives (so need number of drives)
79 * percent resync complete
80 *
81 * As continuation is indicated by leading space, we use
82 * conf_line from config.c to read logical lines
83 *
84 */
85
86 #include "mdadm.h"
87 #include "dlink.h"
88
89 void free_mdstat(struct mdstat_ent *ms)
90 {
91 while (ms) {
92 struct mdstat_ent *t;
93 if (ms->dev) free(ms->dev);
94 if (ms->level) free(ms->level);
95 if (ms->pattern) free(ms->pattern);
96 t = ms;
97 ms = ms->next;
98 free(t);
99 }
100 }
101
102 struct mdstat_ent *mdstat_read()
103 {
104 FILE *f;
105 struct mdstat_ent *all, **end;
106 char *line;
107
108 f = fopen("/proc/mdstat", "r");
109 if (f == NULL)
110 return NULL;
111
112 all = NULL;
113 end = &all;
114 for (; (line = conf_line(f)) ; free_line(line)) {
115 struct mdstat_ent *ent;
116 char *w;
117 int devnum;
118 char *ep;
119
120 if (strcmp(line, "Personalities")==0)
121 continue;
122 if (strcmp(line, "read_ahead")==0)
123 continue;
124 if (strcmp(line, "unused")==0)
125 continue;
126 /* Better be an md line.. */
127 if (strncmp(line, "md", 2)!= 0)
128 continue;
129 if (strncmp(line, "md_d", 4) == 0)
130 devnum = -1-strtoul(line+4, &ep, 10);
131 else if (strncmp(line, "md", 2) == 0)
132 devnum = strtoul(line+2, &ep, 10);
133 else
134 continue;
135 if (ep == NULL || *ep ) {
136 /* fprintf(stderr, Name ": bad /proc/mdstat line starts: %s\n", line); */
137 continue;
138 }
139
140 ent = malloc(sizeof(*ent));
141 if (!ent) {
142 fprintf(stderr, Name ": malloc failed reading /proc/mdstat.\n");
143 free_line(line);
144 fclose(f);
145 return all;
146 }
147 ent->dev = ent->level = ent->pattern= NULL;
148 ent->next = NULL;
149 ent->percent = -1;
150 ent->active = -1;
151
152 ent->dev = strdup(line);
153 ent->devnum = devnum;
154
155 for (w=dl_next(line); w!= line ; w=dl_next(w)) {
156 int l = strlen(w);
157 char *eq;
158 if (strcmp(w, "active")==0)
159 ent->active = 1;
160 else if (strcmp(w, "inactive")==0)
161 ent->active = 0;
162 else if (ent->active >=0 &&
163 ent->level == NULL &&
164 w[0] != '(' /*readonly*/)
165 ent->level = strdup(w);
166 else if (!ent->pattern &&
167 w[0] == '[' &&
168 (w[1] == 'U' || w[1] == '_')) {
169 ent->pattern = strdup(w+1);
170 if (ent->pattern[l-2]==']')
171 ent->pattern[l-2] = '\0';
172 } else if (ent->percent == -1 &&
173 strncmp(w, "re", 2)== 0 &&
174 w[l-1] == '%' &&
175 (eq=strchr(w, '=')) != NULL ) {
176 ent->percent = atoi(eq+1);
177 } else if (ent->percent == -1 &&
178 w[0] >= '0' &&
179 w[0] <= '9' &&
180 w[l-1] == '%') {
181 ent->percent = atoi(w);
182 }
183 }
184 *end = ent;
185 end = &ent->next;
186 }
187 fclose(f);
188 return all;
189 }