Create missing /dev files where needed.
[thirdparty/mdadm.git] / Detail.c
1 /*
2  * mdadm - manage Linux "md" devices aka RAID arrays.
3  *
4  * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
5  *
6  *
7  *    This program is free software; you can redistribute it and/or modify
8  *    it under the terms of the GNU General Public License as published by
9  *    the Free Software Foundation; either version 2 of the License, or
10  *    (at your option) any later version.
11  *
12  *    This program is distributed in the hope that it will be useful,
13  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *    GNU General Public License for more details.
16  *
17  *    You should have received a copy of the GNU General Public License
18  *    along with this program; if not, write to the Free Software
19  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  *    Author: Neil Brown
22  *    Email: <neilb@cse.unsw.edu.au>
23  *    Paper: Neil Brown
24  *           School of Computer Science and Engineering
25  *           The University of New South Wales
26  *           Sydney, 2052
27  *           Australia
28  */
29
30 #include        "mdadm.h"
31 #include        "md_p.h"
32 #include        "md_u.h"
33
34 int Detail(char *dev, int brief, int test)
35 {
36         /*
37          * Print out details for an md array by using
38          * GET_ARRAY_INFO and GET_DISK_INFO ioctl calls
39          */
40
41         int fd = open(dev, O_RDONLY, 0);
42         int vers;
43         mdu_array_info_t array;
44         mdu_disk_info_t *disks;
45         int next;
46         int d;
47         time_t atime;
48         char *c;
49         char *devices = NULL;
50         int spares = 0;
51         struct stat stb;
52         int is_26 = get_linux_version() >= 2006000;
53         int is_rebuilding = 0;
54         int failed = 0;
55         struct supertype *st = NULL;
56         int max_disks = MD_SB_DISKS;
57
58         void *super = NULL;
59         int rv = test ? 4 : 1;
60
61         if (fd < 0) {
62                 fprintf(stderr, Name ": cannot open %s: %s\n",
63                         dev, strerror(errno));
64                 return rv;
65         }
66         vers = md_get_version(fd);
67         if (vers < 0) {
68                 fprintf(stderr, Name ": %s does not appear to be an md device\n",
69                         dev);
70                 close(fd);
71                 return rv;
72         }
73         if (vers < 9000) {
74                 fprintf(stderr, Name ": cannot get detail for md device %s: driver version too old.\n",
75                         dev);
76                 close(fd);
77                 return rv;
78         }
79         if (ioctl(fd, GET_ARRAY_INFO, &array)<0) {
80                 if (errno == ENODEV)
81                         fprintf(stderr, Name ": md device %s does not appear to be active.\n",
82                                 dev);
83                 else
84                         fprintf(stderr, Name ": cannot get array detail for %s: %s\n",
85                                 dev, strerror(errno));
86                 close(fd);
87                 return rv;
88         }
89         st = super_by_version(array.major_version, array.minor_version);
90
91         if (fstat(fd, &stb) != 0 && !S_ISBLK(stb.st_mode))
92                 stb.st_rdev = 0;
93         rv = 0;
94
95         if (st) max_disks = st->max_devs;
96
97         /* try to load a superblock */
98         for (d= 0; d<max_disks; d++) {
99                 mdu_disk_info_t disk;
100                 char *dv;
101                 disk.number = d;
102                 if (ioctl(fd, GET_DISK_INFO, &disk) < 0)
103                         continue;
104                 if (d >= array.raid_disks &&
105                     disk.major == 0 &&
106                     disk.minor == 0)
107                         continue;
108                 if ((dv=map_dev(disk.major, disk.minor, 1))) {
109                         if (!super && (disk.state & (1<<MD_DISK_ACTIVE))) {
110                                 /* try to read the superblock from this device
111                                  * to get more info
112                                  */
113                                 int fd2 = dev_open(dv, O_RDONLY);
114                                 if (fd2 >=0 && st &&
115                                     st->ss->load_super(st, fd2, &super, NULL) == 0) {
116                                         struct mdinfo info;
117                                         st->ss->getinfo_super(&info, super);
118                                         if (info.array.ctime != array.ctime ||
119                                             info.array.level != array.level) {
120                                                 free(super);
121                                                 super = NULL;
122                                         }
123                                 }
124                                 if (fd2 >= 0) close(fd2);
125                         }
126                 }
127         }
128
129         /* Ok, we have some info to print... */
130         c = map_num(pers, array.level);
131         if (brief) 
132                 printf("ARRAY %s level=%s num-devices=%d", dev, c?c:"-unknown-",array.raid_disks );
133         else {
134                 mdu_bitmap_file_t bmf;
135                 unsigned long array_size;
136                 unsigned long long larray_size;
137                 struct mdstat_ent *ms = mdstat_read(0, 0);
138                 struct mdstat_ent *e;
139                 int devnum = array.md_minor;
140                 if (major(stb.st_rdev) != MD_MAJOR)
141                         devnum = -1 - devnum;
142
143                 for (e=ms; e; e=e->next)
144                         if (e->devnum == devnum)
145                                 break;
146 #ifdef BLKGETSIZE64
147                 if (ioctl(fd, BLKGETSIZE64, &larray_size)==0)
148                         ;
149                 else
150 #endif
151                         if (ioctl(fd, BLKGETSIZE, &array_size)==0) {
152                                 larray_size = array_size;
153                                 larray_size <<= 9;
154                         }
155                 
156                 else larray_size = 0;
157
158                 printf("%s:\n", dev);
159                 printf("        Version : %02d.%02d.%02d\n",
160                        array.major_version, array.minor_version, array.patch_version);
161                 atime = array.ctime;
162                 printf("  Creation Time : %.24s\n", ctime(&atime));
163                 printf("     Raid Level : %s\n", c?c:"-unknown-");
164                 if (larray_size)
165                         printf("     Array Size : %llu%s\n", (larray_size>>10), human_size(larray_size));
166                 if (array.level >= 1) {
167                         if (array.major_version != 0 &&
168                             (larray_size >= 0xFFFFFFFFULL|| array.size == 0)) {
169                                 unsigned long long dsize = get_component_size(fd);
170                                 if (dsize > 0)
171                                         printf("    Device Size : %llu%s\n", dsize, human_size((long long)array.size<<10));
172                                 else
173                                         printf("    Device Size : unknown\n");
174                         } else
175                                 printf("    Device Size : %d%s\n", array.size, human_size((long long)array.size<<10));
176                 }
177                 printf("   Raid Devices : %d\n", array.raid_disks);
178                 printf("  Total Devices : %d\n", array.nr_disks);
179                 printf("Preferred Minor : %d\n", array.md_minor);
180                 printf("    Persistence : Superblock is %spersistent\n",
181                        array.not_persistent?"not ":"");
182                 printf("\n");
183                 if (ioctl(fd, GET_BITMAP_FILE, &bmf) == 0 &&
184                         bmf.pathname[0]) {
185                         printf("  Intent Bitmap : %s\n", bmf.pathname);
186                         printf("\n");
187                 } else if (array.state & (1<<MD_SB_BITMAP_PRESENT))
188                         printf("  Intent Bitmap : Internal\n\n");
189                 atime = array.utime;
190                 printf("    Update Time : %.24s\n", ctime(&atime));
191                 printf("          State : %s%s%s\n",
192                        (array.state&(1<<MD_SB_CLEAN))?"clean":"active",
193                        array.active_disks < array.raid_disks? ", degraded":"",
194                        (!e || e->percent < 0) ? "" :
195                         (e->resync) ? ", resyncing": ", recovering");
196                 printf(" Active Devices : %d\n", array.active_disks);
197                 printf("Working Devices : %d\n", array.working_disks);
198                 printf(" Failed Devices : %d\n", array.failed_disks);
199                 printf("  Spare Devices : %d\n", array.spare_disks);
200                 printf("\n");
201                 if (array.level == 5) {
202                         c = map_num(r5layout, array.layout);
203                         printf("         Layout : %s\n", c?c:"-unknown-");
204                 }
205                 if (array.level == 10) {
206                         printf("         Layout : near=%d, far=%d\n", 
207                                array.layout&255, (array.layout>>8)&255);
208                 }
209                 switch (array.level) {
210                 case 0:
211                 case 4:
212                 case 5:
213                 case 10:
214                 case 6:
215                         printf("     Chunk Size : %dK\n\n", array.chunk_size/1024);
216                         break;
217                 case -1:
218                         printf("       Rounding : %dK\n\n", array.chunk_size/1024);
219                         break;
220                 default: break;
221                 }
222         
223                 if (e && e->percent >= 0) {
224                         printf(" Rebuild Status : %d%% complete\n\n", e->percent);
225                         is_rebuilding = 1;
226                 }
227                 free_mdstat(ms);
228
229                 if (super && st)
230                         st->ss->detail_super(super);
231
232                 printf("    Number   Major   Minor   RaidDevice State\n");
233         }
234         disks = malloc(max_disks * sizeof(mdu_disk_info_t));
235         for (d=0; d<max_disks; d++) {
236                 disks[d].state = (1<<MD_DISK_REMOVED);
237                 disks[d].major = disks[d].minor = 0;
238                 disks[d].number = disks[d].raid_disk = d;
239         }
240
241         next = array.raid_disks;
242         for (d=0; d < max_disks; d++) {
243                 mdu_disk_info_t disk;
244                 disk.number = d;
245                 if (ioctl(fd, GET_DISK_INFO, &disk) < 0) {
246                         if (d < array.raid_disks)
247                                 fprintf(stderr, Name ": cannot get device detail for device %d: %s\n",
248                                         d, strerror(errno));
249                         continue;
250                 }
251                 if (disk.major == 0 && disk.minor == 0)
252                         continue;
253                 if (disk.raid_disk >= 0 && disk.raid_disk < array.raid_disks) 
254                         disks[disk.raid_disk] = disk;
255                 else if (next < max_disks)
256                         disks[next++] = disk;
257         }
258
259         for (d= 0; d < max_disks; d++) {
260                 char *dv;
261                 mdu_disk_info_t disk = disks[d];
262
263                 if (d >= array.raid_disks &&
264                     disk.major == 0 &&
265                     disk.minor == 0)
266                         continue;
267                 if (!brief) {
268                         if (d == array.raid_disks) printf("\n");
269                         if (disk.raid_disk < 0)
270                                 printf("   %5d   %5d    %5d        -     ", 
271                                        disk.number, disk.major, disk.minor);
272                         else
273                                 printf("   %5d   %5d    %5d    %5d     ", 
274                                        disk.number, disk.major, disk.minor, disk.raid_disk);
275                         if (disk.state & (1<<MD_DISK_FAULTY)) { 
276                                 printf(" faulty"); 
277                                 if (disk.raid_disk < array.raid_disks &&
278                                     disk.raid_disk >= 0)
279                                         failed++;
280                         }
281                         if (disk.state & (1<<MD_DISK_ACTIVE)) printf(" active");
282                         if (disk.state & (1<<MD_DISK_SYNC)) printf(" sync");
283                         if (disk.state & (1<<MD_DISK_REMOVED)) printf(" removed");
284                         if (disk.state & (1<<MD_DISK_WRITEMOSTLY)) printf(" writemostly");
285                         if ((disk.state &
286                              ((1<<MD_DISK_ACTIVE)|(1<<MD_DISK_SYNC)|(1<<MD_DISK_REMOVED)))
287                             == 0) {
288                                 printf(" spare");
289                                 if (is_26) {
290                                         if (disk.raid_disk < array.raid_disks && disk.raid_disk >= 0)
291                                                 printf(" rebuilding");
292                                 } else if (is_rebuilding && failed) {
293                                         /* Taking a bit of a risk here, we remove the
294                                          * device from the array, and then put it back.
295                                          * If this fails, we are rebuilding
296                                          */
297                                         int err = ioctl(fd, HOT_REMOVE_DISK, makedev(disk.major, disk.minor));
298                                         if (err == 0) ioctl(fd, HOT_ADD_DISK, makedev(disk.major, disk.minor));
299                                         if (err && errno ==  EBUSY)
300                                                 printf(" rebuilding");
301                                 }
302                         }
303                 }
304                 if (disk.state == 0) spares++;
305                 if (test && d < array.raid_disks && disk.state & (1<<MD_DISK_FAULTY)) {
306                         if ((rv & 1) && (array.level ==4 || array.level == 5))
307                                 rv |= 2;
308                         rv |= 1;
309                 }
310                 if ((dv=map_dev(disk.major, disk.minor, 0))) {
311                         if (brief) {
312                                 if (devices) {
313                                         devices = realloc(devices,
314                                                           strlen(devices)+1+strlen(dv)+1);
315                                         strcat(strcat(devices,","),dv);
316                                 } else
317                                         devices = strdup(dv);
318                         } else
319                                 printf("   %s", dv);
320                 }
321                 if (!brief) printf("\n");
322         }
323         if (spares && brief) printf(" spares=%d", spares);
324         if (super && brief && st)
325                 st->ss->brief_detail_super(super);
326
327         if (brief > 1 && devices) printf("\n   devices=%s", devices);
328         if (brief) printf("\n");
329         if (test && (rv&2)) rv &= ~1;
330         close(fd);
331         return rv;
332 }