]>
git.ipfire.org Git - thirdparty/mdadm.git/blob - lib.c
2 * mdadm - manage Linux "md" devices aka RAID arrays.
4 * Copyright (C) 2011 Neil Brown <neilb@suse.de>
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.
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.
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
22 * Email: <neilb@suse.de>
28 /* This fill contains various 'library' style function. They
29 * have no dependency on anything outside this file.
32 int get_mdp_major(void)
34 static int mdp_major
= -1;
43 fl
= fopen("/proc/devices", "r");
46 while ((w
= conf_word(fl
, 1))) {
47 if (have_block
&& strcmp(w
, "devices:")==0)
49 have_block
= (strcmp(w
, "Block")==0);
52 if (have_devices
&& strcmp(w
, "mdp")==0)
61 void fmt_devname(char *name
, int num
)
64 sprintf(name
, "md%d", num
);
66 sprintf(name
, "md_d%d", -1-num
);
69 char *devnum2devname(int num
)
72 fmt_devname(name
,num
);
76 int devname2devnum(char *name
)
80 if (strncmp(name
, "md_d", 4)==0)
81 num
= -1-strtoul(name
+4, &ep
, 10);
83 num
= strtoul(name
+2, &ep
, 10);
87 int stat2devnum(struct stat
*st
)
94 if ((S_IFMT
& st
->st_mode
) == S_IFBLK
) {
95 if (major(st
->st_rdev
) == MD_MAJOR
)
96 return minor(st
->st_rdev
);
97 else if (major(st
->st_rdev
) == (unsigned)get_mdp_major())
98 return -1- (minor(st
->st_rdev
)>>MdpMinorShift
);
100 /* must be an extended-minor partition. Look at the
101 * /sys/dev/block/%d:%d link which must look like
102 * ../../block/mdXXX/mdXXXpYY
104 sprintf(path
, "/sys/dev/block/%d:%d", major(st
->st_rdev
),
106 n
= readlink(path
, link
, sizeof(link
)-1);
110 cp
= strrchr(link
, '/');
112 cp
= strrchr(link
, '/');
113 if (cp
&& strncmp(cp
, "/md", 3) == 0)
114 return devname2devnum(cp
+1);
120 int fd2devnum(int fd
)
123 if (fstat(fd
, &stb
) == 0)
124 return stat2devnum(&stb
);
131 * convert a major/minor pair for a block device into a name in /dev, if possible.
132 * On the first call, walk /dev collecting name.
133 * Put them in a simple linked listfor now.
140 int devlist_ready
= 0;
142 int add_dev(const char *name
, const struct stat
*stb
, int flag
, struct FTW
*s
)
146 if (S_ISLNK(stb
->st_mode
)) {
147 if (stat(name
, &st
) != 0)
152 if ((stb
->st_mode
&S_IFMT
)== S_IFBLK
) {
153 char *n
= strdup(name
);
154 struct devmap
*dm
= malloc(sizeof(*dm
));
155 if (strncmp(n
, "/dev/./", 7)==0)
158 dm
->major
= major(stb
->st_rdev
);
159 dm
->minor
= minor(stb
->st_rdev
);
170 int add_dev_1(const char *name
, const struct stat
*stb
, int flag
)
172 return add_dev(name
, stb
, flag
, NULL
);
174 int nftw(const char *path
, int (*han
)(const char *name
, const struct stat
*stb
, int flag
, struct FTW
*s
), int nopenfd
, int flags
)
176 return ftw(path
, add_dev_1
, nopenfd
);
179 int nftw(const char *path
, int (*han
)(const char *name
, const struct stat
*stb
, int flag
, struct FTW
*s
), int nopenfd
, int flags
)
183 #endif /* HAVE_FTW */
184 #endif /* HAVE_NFTW */
187 * Find a block device with the right major/minor number.
188 * If we find multiple names, choose the shortest.
189 * If we find a name in /dev/md/, we prefer that.
190 * This applies only to names for MD devices.
191 * If 'prefer' is set (normally to e.g. /by-path/)
192 * then we prefer a name which contains that string.
194 char *map_dev_preferred(int major
, int minor
, int create
,
198 char *regular
= NULL
, *preferred
=NULL
;
201 if (major
== 0 && minor
== 0)
205 if (!devlist_ready
) {
209 struct devmap
*d
= devlist
;
214 if (lstat(dev
, &stb
)==0 &&
215 S_ISLNK(stb
.st_mode
))
217 nftw(dev
, add_dev
, 10, FTW_PHYS
);
222 for (p
=devlist
; p
; p
=p
->next
)
223 if (p
->major
== major
&&
225 if (strncmp(p
->name
, "/dev/md/",8) == 0
226 || (prefer
&& strstr(p
->name
, prefer
))) {
227 if (preferred
== NULL
||
228 strlen(p
->name
) < strlen(preferred
))
231 if (regular
== NULL
||
232 strlen(p
->name
) < strlen(regular
))
236 if (!regular
&& !preferred
&& !did_check
) {
240 if (create
&& !regular
&& !preferred
) {
242 snprintf(buf
, sizeof(buf
), "%d:%d", major
, minor
);
246 return preferred
? preferred
: regular
;
251 /* conf_word gets one word from the conf file.
252 * if "allow_key", then accept words at the start of a line,
253 * otherwise stop when such a word is found.
254 * We assume that the file pointer is at the end of a word, so the
255 * next character is a space, or a newline. If not, it is the start of a line.
258 char *conf_word(FILE *file
, int allow_key
)
265 char *word
= malloc(wsize
);
269 while (wordfound
==0) {
270 /* at the end of a word.. */
273 while (c
!= EOF
&& c
!= '\n')
276 if (c
== '\n') continue;
278 if (c
!= ' ' && c
!= '\t' && ! allow_key
) {
282 /* looks like it is safe to get a word here, if there is one */
284 /* first, skip any spaces */
285 while (c
== ' ' || c
== '\t')
287 if (c
!= EOF
&& c
!= '\n' && c
!= '#') {
288 /* we really have a character of a word, so start saving it */
289 while (c
!= EOF
&& c
!= '\n' && (quote
|| (c
!=' ' && c
!= '\t'))) {
291 if (quote
&& c
== quote
) quote
= 0;
292 else if (quote
== 0 && (c
== '\'' || c
== '"'))
295 if (len
== wsize
-1) {
297 word
= realloc(word
, wsize
);
303 /* Hack for broken kernels (2.6.14-.24) that put
304 * "active(auto-read-only)"
305 * in /proc/mdstat instead of
306 * "active (auto-read-only)"
308 if (c
== '(' && len
>= 6
309 && strncmp(word
+len
-6, "active", 6) == 0)
313 if (c
!= EOF
) ungetc(c
, file
);
317 /* Further HACK for broken kernels.. 2.6.14-2.6.24 */
318 if (strcmp(word
, "auto-read-only)") == 0)
319 strcpy(word
, "(auto-read-only)");
321 /* printf("word is <%s>\n", word); */