PageRenderTime 29ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/release/src/router/mdadm/mdopen.c

https://gitlab.com/envieidoc/advancedtomato2
C | 342 lines | 246 code | 18 blank | 78 comment | 108 complexity | c2f8d6df2a9aacd973b3423822505925 MD5 | raw file
  1. /*
  2. * mdadm - manage Linux "md" devices aka RAID arrays.
  3. *
  4. * Copyright (C) 2001-2006 Neil Brown <neilb@suse.de>
  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. #include "mdadm.h"
  30. #include "md_p.h"
  31. #include <ctype.h>
  32. void make_dev_symlink(char *dev)
  33. {
  34. char *new = strdup(dev);
  35. if (!new) return;
  36. /* /dev/md/0 -> /dev/md0
  37. * /dev/md/d0 -> /dev/md_d0
  38. */
  39. if (isdigit(new[8]))
  40. strcpy(new+7, new+8);
  41. else
  42. new[7] = '_';
  43. if (symlink(dev+5, new))
  44. perror(new);
  45. }
  46. void make_parts(char *dev, int cnt, int symlinks)
  47. {
  48. /* make 'cnt' partition devices for 'dev'
  49. * We use the major/minor from dev and add 1..cnt
  50. * If dev ends with a digit, we add "p%d" else "%d"
  51. * If the name exists, we use it's owner/mode,
  52. * else that of dev
  53. */
  54. struct stat stb;
  55. int major, minor;
  56. int i;
  57. int nlen = strlen(dev) + 20;
  58. char *name = malloc(nlen);
  59. int dig = isdigit(dev[strlen(dev)-1]);
  60. if (cnt==0) cnt=4;
  61. if (stat(dev, &stb)!= 0)
  62. return;
  63. if (!S_ISBLK(stb.st_mode))
  64. return;
  65. major = major(stb.st_rdev);
  66. minor = minor(stb.st_rdev);
  67. for (i=1; i <= cnt ; i++) {
  68. struct stat stb2;
  69. snprintf(name, nlen, "%s%s%d", dev, dig?"p":"", i);
  70. if (stat(name, &stb2)==0) {
  71. if (!S_ISBLK(stb2.st_mode))
  72. continue;
  73. if (stb2.st_rdev == makedev(major, minor+i))
  74. continue;
  75. unlink(name);
  76. } else {
  77. stb2 = stb;
  78. }
  79. if (mknod(name, S_IFBLK | 0600, makedev(major, minor+i)))
  80. perror("mknod");
  81. if (chown(name, stb2.st_uid, stb2.st_gid))
  82. perror("chown");
  83. if (chmod(name, stb2.st_mode & 07777))
  84. perror("chmod");
  85. if (symlinks && strncmp(name, "/dev/md/", 8) == 0)
  86. make_dev_symlink(name);
  87. stat(name, &stb2);
  88. add_dev(name, &stb2, 0, NULL);
  89. }
  90. }
  91. /*
  92. * Open a given md device, and check that it really is one.
  93. * If 'autof' is given, then we need to create, or recreate, the md device.
  94. * If the name already exists, and is not a block device, we fail.
  95. * If it exists and is not an md device, is not the right type (partitioned or not),
  96. * or is currently in-use, we remove the device, but remember the owner and mode.
  97. * If it now doesn't exist, we find a new md array and create the device.
  98. * Default ownership/mode comes from config file.
  99. */
  100. int open_mddev(char *dev, int autof)
  101. {
  102. int mdfd;
  103. struct stat stb;
  104. int major = MD_MAJOR;
  105. int minor = 0;
  106. int must_remove = 0;
  107. struct mdstat_ent *mdlist;
  108. int num;
  109. struct createinfo *ci = conf_get_create_info();
  110. int parts;
  111. if (autof == 0)
  112. autof = ci->autof;
  113. parts = autof >> 3;
  114. autof &= 7;
  115. if (autof && autof != 1) {
  116. /* autof is set, so we need to check that the name is ok,
  117. * and possibly create one if not
  118. */
  119. int std;
  120. stb.st_mode = 0;
  121. if (stat(dev, &stb)==0 && ! S_ISBLK(stb.st_mode)) {
  122. fprintf(stderr, Name ": %s is not a block device.\n",
  123. dev);
  124. return -1;
  125. }
  126. /* check major number is correct */
  127. num = -1;
  128. std = is_standard(dev, &num);
  129. if (std>0) major = get_mdp_major();
  130. switch(autof) {
  131. case 2: /* only create is_standard names */
  132. if (!std && !stb.st_mode) {
  133. fprintf(stderr, Name
  134. ": %s does not exist and is not a 'standard' name "
  135. "so it cannot be created\n", dev);
  136. return -1;
  137. }
  138. break;
  139. case 3: /* create md, reject std>0 */
  140. if (std > 0) {
  141. fprintf(stderr, Name ": that --auto option "
  142. "not compatable with device named %s\n", dev);
  143. return -1;
  144. }
  145. break;
  146. case 4: /* create mdp, reject std<0 */
  147. if (std < 0) {
  148. fprintf(stderr, Name ": that --auto option "
  149. "not compatable with device named %s\n", dev);
  150. return -1;
  151. }
  152. break;
  153. case 5: /* default to md if not standard */
  154. break;
  155. case 6: /* default to mdp if not standard */
  156. if (std == 0) major = get_mdp_major();
  157. break;
  158. }
  159. /* major is final. num is -1 if not standard */
  160. if (stb.st_mode && major(stb.st_rdev) != major)
  161. must_remove = 1;
  162. if (stb.st_mode && !must_remove) {
  163. /* looks ok, see if it is available */
  164. mdfd = open(dev, O_RDWR, 0);
  165. if (mdfd < 0) {
  166. fprintf(stderr, Name ": error opening %s: %s\n",
  167. dev, strerror(errno));
  168. return -1;
  169. } else if (md_get_version(mdfd) <= 0) {
  170. fprintf(stderr, Name ": %s does not appear to be an md device\n",
  171. dev);
  172. close(mdfd);
  173. return -1;
  174. }
  175. if (major != MD_MAJOR && parts > 0)
  176. make_parts(dev, parts, ci->symlinks);
  177. return mdfd;
  178. }
  179. /* Ok, need to find a minor that is not in use.
  180. * If the device name is in a 'standard' format,
  181. * intuit the minor from that, else
  182. * easiest to read /proc/mdstat, and hunt through for
  183. * an unused number
  184. */
  185. if (num < 0) {
  186. /* need to pick an unused number */
  187. mdlist = mdstat_read(0, 0);
  188. /* Choose a large number. Start from 127 and search down,
  189. * but if nothing is found, start really big
  190. */
  191. for (num = 127 ; num != 128 ; num = num ? num-1 : (1<<22)-1) {
  192. struct mdstat_ent *me;
  193. int devnum = num;
  194. if (major != MD_MAJOR)
  195. devnum = -1-num;
  196. for (me=mdlist; me; me=me->next)
  197. if (me->devnum == devnum)
  198. break;
  199. if (!me) {
  200. /* doesn't exist in mdstat.
  201. * make sure it is new to /dev too
  202. */
  203. char *dn;
  204. if (major != MD_MAJOR)
  205. minor = num << MdpMinorShift;
  206. else
  207. minor = num;
  208. dn = map_dev(major,minor, 0);
  209. if (dn==NULL || is_standard(dn, NULL)) {
  210. /* this number only used by a 'standard' name,
  211. * so it is safe to use
  212. */
  213. break;
  214. }
  215. }
  216. }
  217. } else if (major == MD_MAJOR)
  218. minor = num;
  219. else
  220. minor = num << MdpMinorShift;
  221. /* major and minor have been chosen */
  222. /* If it was a 'standard' name and it is in-use, then
  223. * the device could already be correct
  224. */
  225. if (stb.st_mode && major(stb.st_rdev) == major &&
  226. minor(stb.st_rdev) == minor)
  227. ;
  228. else {
  229. if (major(makedev(major,minor)) != major ||
  230. minor(makedev(major,minor)) != minor) {
  231. fprintf(stderr, Name ": Need newer C library to use more than 4 partitionable md devices, sorry\n");
  232. return -1;
  233. }
  234. if (must_remove)
  235. unlink(dev);
  236. if (strncmp(dev, "/dev/md/", 8) == 0) {
  237. if (mkdir("/dev/md",0700)==0) {
  238. if (chown("/dev/md", ci->uid, ci->gid))
  239. perror("chown /dev/md");
  240. if (chmod("/dev/md", ci->mode| ((ci->mode>>2) & 0111)))
  241. perror("chmod /dev/md");
  242. }
  243. }
  244. if (mknod(dev, S_IFBLK|0600, makedev(major, minor))!= 0) {
  245. fprintf(stderr, Name ": failed to create %s\n", dev);
  246. return -1;
  247. }
  248. if (must_remove) {
  249. if (chown(dev, stb.st_uid, stb.st_gid))
  250. perror("chown");
  251. if (chmod(dev, stb.st_mode & 07777))
  252. perror("chmod");
  253. } else {
  254. if (chown(dev, ci->uid, ci->gid))
  255. perror("chown");
  256. if (chmod(dev, ci->mode))
  257. perror("chmod");
  258. }
  259. stat(dev, &stb);
  260. add_dev(dev, &stb, 0, NULL);
  261. if (ci->symlinks && strncmp(dev, "/dev/md/", 8) == 0)
  262. make_dev_symlink(dev);
  263. if (major != MD_MAJOR)
  264. make_parts(dev,parts, ci->symlinks);
  265. }
  266. }
  267. mdfd = open(dev, O_RDWR, 0);
  268. if (mdfd < 0)
  269. fprintf(stderr, Name ": error opening %s: %s\n",
  270. dev, strerror(errno));
  271. else if (md_get_version(mdfd) <= 0) {
  272. fprintf(stderr, Name ": %s does not appear to be an md device\n",
  273. dev);
  274. close(mdfd);
  275. mdfd = -1;
  276. }
  277. return mdfd;
  278. }
  279. int open_mddev_devnum(char *devname, int devnum, char *name, char *chosen_name)
  280. {
  281. /* Open the md device with number 'devnum', possibly using 'devname',
  282. * possibly constructing a name with 'name', but in any case, copying
  283. * the name into 'chosen_name'
  284. */
  285. int major, minor;
  286. struct stat stb;
  287. if (devname)
  288. strcpy(chosen_name, devname);
  289. else if (name && strchr(name,'/') == NULL) {
  290. char *n = strchr(name, ':');
  291. if (n) n++; else n = name;
  292. if (isdigit(*n) && devnum < 0)
  293. sprintf(chosen_name, "/dev/md/d%s", n);
  294. else
  295. sprintf(chosen_name, "/dev/md/%s", n);
  296. } else {
  297. if (devnum >= 0)
  298. sprintf(chosen_name, "/dev/md%d", devnum);
  299. else
  300. sprintf(chosen_name, "/dev/md/d%d", -1-devnum);
  301. }
  302. if (devnum >= 0) {
  303. major = MD_MAJOR;
  304. minor = devnum;
  305. } else {
  306. major = get_mdp_major();
  307. minor = (-1-devnum) << 6;
  308. }
  309. if (stat(chosen_name, &stb) == 0) {
  310. /* It already exists. Check it is right. */
  311. if ( ! S_ISBLK(stb.st_mode) ||
  312. stb.st_rdev != makedev(major, minor)) {
  313. errno = EEXIST;
  314. return -1;
  315. }
  316. } else {
  317. if (mknod(chosen_name, S_IFBLK | 0600,
  318. makedev(major, minor)) != 0) {
  319. return -1;
  320. }
  321. /* FIXME chown/chmod ?? */
  322. }
  323. return open(chosen_name, O_RDWR);
  324. }