]> git.ipfire.org Git - thirdparty/mdadm.git/blame - sysfs.c
Centralise code for copying uuid
[thirdparty/mdadm.git] / sysfs.c
CommitLineData
e86c9dd6
NB
1/*
2 * sysfs - extract md related information from sysfs. Part of:
3 * mdadm - manage Linux "md" devices aka RAID arrays.
4 *
5 * Copyright (C) 2006 Neil Brown <neilb@suse.de>
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@suse.de>
24 */
25
26#include "mdadm.h"
27#include <dirent.h>
28
29int load_sys(char *path, char *buf)
30{
31 int fd = open(path, O_RDONLY);
32 int n;
33 if (fd < 0)
34 return -1;
35 n = read(fd, buf, 1024);
36 close(fd);
37 if (n <=0 || n >= 1024)
38 return -1;
39 buf[n] = 0;
40 if (buf[n-1] == '\n')
41 buf[n-1] = 0;
42 return 0;
43}
44
45struct sysarray *sysfs_read(int fd, int devnum, unsigned long options)
46{
47 /* Longest possible name in sysfs, mounted at /sys, is
48 * /sys/block/md_dXXX/md/dev-XXXXX/block/dev
49 * /sys/block/md_dXXX/md/metadata_version
50 * which is about 41 characters. 50 should do for now
51 */
52 char fname[50];
53 char buf[1024];
54 char *base;
55 char *dbase;
56 struct sysarray *sra;
57 struct sysdev *dev;
58 DIR *dir;
59 struct dirent *de;
60
61 sra = malloc(sizeof(*sra));
62 if (sra == NULL)
63 return sra;
64
65 if (fd >= 0) {
66 struct stat stb;
67 if (fstat(fd, &stb)) return NULL;
68 if (major(stb.st_rdev)==9)
69 sprintf(sra->name, "md%d", minor(stb.st_rdev));
70 else
71 sprintf(sra->name, "md_d%d",
7fa42a0b 72 minor(stb.st_rdev)>>MdpMinorShift);
e86c9dd6
NB
73 } else {
74 if (devnum >= 0)
75 sprintf(sra->name, "md%d", devnum);
76 else
77 sprintf(sra->name, "md_d%d",
78 -1-devnum);
79 }
80 sprintf(fname, "/sys/block/%s/md/", sra->name);
81 base = fname + strlen(fname);
82
83 sra->devs = NULL;
84 if (options & GET_LEVEL) {
85 strcpy(base, "level");
86 if (load_sys(fname, buf))
87 goto abort;
88 sra->level = map_name(pers, buf);
89 }
90 if (options & GET_LAYOUT) {
91 strcpy(base, "layout");
92 if (load_sys(fname, buf))
93 goto abort;
94 sra->layout = strtoul(buf, NULL, 0);
95 }
96 if (options & GET_COMPONENT) {
97 strcpy(base, "component_size");
98 if (load_sys(fname, buf))
99 goto abort;
100 sra->component_size = strtoull(buf, NULL, 0);
353632d9
NB
101 /* sysfs reports "K", but we want sectors */
102 sra->component_size *= 2;
e86c9dd6
NB
103 }
104 if (options & GET_CHUNK) {
105 strcpy(base, "chunk_size");
106 if (load_sys(fname, buf))
107 goto abort;
108 sra->chunk = strtoul(buf, NULL, 0);
109 }
758d3a8e
NB
110 if (options & GET_CACHE) {
111 strcpy(base, "stripe_cache_size");
112 if (load_sys(fname, buf))
113 goto abort;
114 sra->cache_size = strtoul(buf, NULL, 0);
115 }
37dfc3d6
NB
116 if (options & GET_MISMATCH) {
117 strcpy(base, "mismatch_cnt");
118 if (load_sys(fname, buf))
119 goto abort;
120 sra->mismatch_cnt = strtoul(buf, NULL, 0);
121 }
e86c9dd6
NB
122
123 if (! (options & GET_DEVS))
124 return sra;
125
126 /* Get all the devices as well */
127 *base = 0;
128 dir = opendir(fname);
129 if (!dir)
130 goto abort;
131 sra->spares = 0;
132
133 while ((de = readdir(dir)) != NULL) {
134 char *ep;
135 if (de->d_ino == 0 ||
136 strncmp(de->d_name, "dev-", 4) != 0)
137 continue;
138 strcpy(base, de->d_name);
139 dbase = base + strlen(base);
140 *dbase++ = '/';
141
142 dev = malloc(sizeof(*dev));
143 if (!dev)
144 goto abort;
145 dev->next = sra->devs;
146 sra->devs = dev;
147
148 /* Always get slot, major, minor */
149 strcpy(dbase, "slot");
150 if (load_sys(fname, buf))
151 goto abort;
152 dev->role = strtoul(buf, &ep, 10);
153 if (*ep) dev->role = -1;
154
155 strcpy(dbase, "block/dev");
156 if (load_sys(fname, buf))
157 goto abort;
158 sscanf(buf, "%d:%d", &dev->major, &dev->minor);
159
160 if (options & GET_OFFSET) {
161 strcpy(dbase, "offset");
162 if (load_sys(fname, buf))
163 goto abort;
164 dev->offset = strtoull(buf, NULL, 0);
165 }
166 if (options & GET_SIZE) {
167 strcpy(dbase, "size");
168 if (load_sys(fname, buf))
169 goto abort;
170 dev->size = strtoull(buf, NULL, 0);
171 }
172 if (options & GET_STATE) {
173 dev->state = 0;
174 strcpy(dbase, "state");
175 if (load_sys(fname, buf))
176 goto abort;
177 if (strstr(buf, "in_sync"))
178 dev->state |= (1<<MD_DISK_SYNC);
179 if (strstr(buf, "faulty"))
180 dev->state |= (1<<MD_DISK_FAULTY);
181 if (dev->state == 0)
182 sra->spares++;
183 }
184 if (options & GET_ERROR) {
185 strcpy(buf, "errors");
186 if (load_sys(fname, buf))
187 goto abort;
188 dev->errors = strtoul(buf, NULL, 0);
189 }
190 }
191 return sra;
192
193 abort:
194 while (sra && sra->devs) {
195 dev = sra->devs;
196 sra->devs = dev->next;
197 free(dev);
198 }
199 if(sra) free(sra);
200 return NULL;
201}
202
203unsigned long long get_component_size(int fd)
204{
205 /* Find out the component size of the array.
206 * We cannot trust GET_ARRAY_INFO ioctl as it's
207 * size field is only 32bits.
208 * So look in /sys/block/mdXXX/md/component_size
353632d9 209 *
8686f3ed 210 * This returns in units of sectors.
e86c9dd6
NB
211 */
212 struct stat stb;
213 char fname[50];
214 int n;
215 if (fstat(fd, &stb)) return 0;
216 if (major(stb.st_rdev) == 9)
217 sprintf(fname, "/sys/block/md%d/md/component_size",
218 minor(stb.st_rdev));
219 else
220 sprintf(fname, "/sys/block/md_d%d/md/component_size",
7fa42a0b 221 minor(stb.st_rdev)>>MdpMinorShift);
e86c9dd6
NB
222 fd = open(fname, O_RDONLY);
223 if (fd < 0)
224 return 0;
225 n = read(fd, fname, sizeof(fname));
226 close(fd);
227 if (n == sizeof(fname))
228 return 0;
229 fname[n] = 0;
8686f3ed 230 return strtoull(fname, NULL, 10) * 2;
e86c9dd6
NB
231}
232
233int sysfs_set_str(struct sysarray *sra, struct sysdev *dev,
234 char *name, char *val)
235{
236 char fname[50];
237 int n;
238 int fd;
239 sprintf(fname, "/sys/block/%s/md/%s/%s",
240 sra->name, dev?dev->name:"", name);
241 fd = open(fname, O_WRONLY);
242 if (fd < 0)
243 return -1;
244 n = write(fd, val, strlen(val));
245 close(fd);
246 if (n != strlen(val))
247 return -1;
248 return 0;
249}
250
251int sysfs_set_num(struct sysarray *sra, struct sysdev *dev,
252 char *name, unsigned long long val)
253{
254 char valstr[50];
255 sprintf(valstr, "%llu", val);
256 return sysfs_set_str(sra, dev, name, valstr);
257}
258
259int sysfs_get_ll(struct sysarray *sra, struct sysdev *dev,
260 char *name, unsigned long long *val)
261{
262 char fname[50];
263 char buf[50];
264 int n;
265 int fd;
266 char *ep;
267 sprintf(fname, "/sys/block/%s/md/%s/%s",
268 sra->name, dev?dev->name:"", name);
269 fd = open(fname, O_RDONLY);
270 if (fd < 0)
271 return -1;
272 n = read(fd, buf, sizeof(buf));
273 close(fd);
274 if (n <= 0)
275 return -1;
276 buf[n] = 0;
277 *val = strtoull(buf, &ep, 0);
278 if (ep == buf || (*ep != 0 && *ep != '\n' && *ep != ' '))
279 return -1;
280 return 0;
281}