~ubuntu-branches/ubuntu/hardy/mdadm/hardy-updates

« back to all changes in this revision

Viewing changes to {arch}/++pristine-trees/unlocked/mdadm/mdadm--integration/mdadm--integration--1.12.0/pkg-mdadm-devel@lists.alioth.debian.org--2005/mdadm--integration--1.12.0--patch-4/mdopen.c

  • Committer: Package Import Robot
  • Author(s): Scott James Remnant
  • Date: 2006-07-11 17:23:21 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20060711172321-070tz7lox9adujtw
Tags: 2.4.1-6ubuntu1
* Merge from debian unstable, remaining changes:
  - integration with initramfs-tools,
  - autocreate devices when udev is in use,
  - use lstat in mdopen.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 <ctype.h>
33
 
 
34
 
void make_parts(char *dev, int cnt)
35
 
{
36
 
        /* make 'cnt' partition devices for 'dev'
37
 
         * We use the major/minor from dev and add 1..cnt
38
 
         * If dev ends with a digit, we add "p%d" else "%d"
39
 
         * If the name exists, we use it's owner/mode,
40
 
         * else that of dev
41
 
         */
42
 
        struct stat stb;
43
 
        int major, minor;
44
 
        int i;
45
 
        int nlen = strlen(dev) + 20;
46
 
        char *name = malloc(nlen);
47
 
        int dig = isdigit(dev[strlen(dev)-1]);
48
 
 
49
 
        if (stat(dev, &stb)!= 0)
50
 
                return;
51
 
        if (!S_ISBLK(stb.st_mode))
52
 
                return;
53
 
        major = major(stb.st_rdev);
54
 
        minor = minor(stb.st_rdev);
55
 
        for (i=1; i <= cnt ; i++) {
56
 
                struct stat stb2;
57
 
                snprintf(name, nlen, "%s%s%d", dev, dig?"p":"", i);
58
 
                if (stat(name, &stb2)==0) {
59
 
                        if (!S_ISBLK(stb2.st_mode))
60
 
                                continue;
61
 
                        if (stb2.st_rdev == makedev(major, minor+i))
62
 
                                continue;
63
 
                        unlink(name);
64
 
                } else {
65
 
                        stb2 = stb;
66
 
                }
67
 
                mknod(name, S_IFBLK | 0600, makedev(major, minor+i));
68
 
                chown(name, stb2.st_uid, stb2.st_gid);
69
 
                chmod(name, stb2.st_mode & 07777);
70
 
                stat(name, &stb2);
71
 
                add_dev(name, &stb2, 0, NULL);
72
 
        }
73
 
}
74
 
 
75
 
/*
76
 
 * Open a given md device, and check that it really is one.
77
 
 * If 'autof' is given, then we need to create, or recreate, the md device.
78
 
 * If the name already exists, and is not a block device, we fail.
79
 
 * If it exists and is not an md device, is not the right type (partitioned or not),
80
 
 * or is currently in-use, we remove the device, but remember the owner and mode.
81
 
 * If it now doesn't exist, we find a new md array and create the device.
82
 
 * Default ownership is user=0, group=0 perm=0600
83
 
 */
84
 
int open_mddev(char *dev, int autof)
85
 
{
86
 
        int mdfd;
87
 
        struct stat stb;
88
 
        int major = MD_MAJOR;
89
 
        int minor = 0;
90
 
        int must_remove = 0;
91
 
        struct mdstat_ent *mdlist;
92
 
        int num;
93
 
 
94
 
        if (autof) {
95
 
                /* autof is set, so we need to check that the name is ok,
96
 
                 * and possibly create one if not
97
 
                 */
98
 
                if (autof == -2 && !is_standard(dev, NULL)) {
99
 
                        fprintf(stderr, Name ": --auto=yes requires a 'standard' md device name, not %s\n", dev);
100
 
                        return -1;
101
 
                }
102
 
                stb.st_mode = 0;
103
 
                if (stat(dev, &stb)==0 && ! S_ISBLK(stb.st_mode)) {
104
 
                        fprintf(stderr, Name ": %s is not a block device.\n",
105
 
                                dev);
106
 
                        return -1;
107
 
                }
108
 
                /* check major number is correct */
109
 
                if (autof>0)
110
 
                        major = get_mdp_major();
111
 
                if (stb.st_mode && major(stb.st_rdev) != major)
112
 
                        must_remove = 1;
113
 
                if (stb.st_mode && !must_remove) {
114
 
                        mdu_array_info_t array;
115
 
                        /* looks ok, see if it is available */
116
 
                        mdfd = open(dev, O_RDWR, 0);
117
 
                        if (mdfd < 0) {
118
 
                                fprintf(stderr, Name ": error opening %s: %s\n",
119
 
                                        dev, strerror(errno));
120
 
                                return -1;
121
 
                        } else if (md_get_version(mdfd) <= 0) {
122
 
                                fprintf(stderr, Name ": %s does not appear to be an md device\n",
123
 
                                        dev);
124
 
                                close(mdfd);
125
 
                                return -1;
126
 
                        }
127
 
                        if (ioctl(mdfd, GET_ARRAY_INFO, &array)==0) {
128
 
                                /* already active */
129
 
                                must_remove = 1;
130
 
                                close(mdfd);
131
 
                        } else {
132
 
                                if (autof > 0)
133
 
                                        make_parts(dev, autof);
134
 
                                return mdfd;
135
 
                        }
136
 
                }
137
 
                /* Ok, need to find a minor that is not in use.
138
 
                 * If the device name is in a 'standard' format,
139
 
                 * intuit the minor from that, else
140
 
                 * easiest to read /proc/mdstat, and hunt through for
141
 
                 * an unused number 
142
 
                 */
143
 
                switch(is_standard(dev, &num)) {
144
 
                case -1: /* non partitioned */
145
 
                        if (autof > 0) {
146
 
                                fprintf(stderr, Name ": that --auto option not compatable with device named %s\n", dev);
147
 
                                return -1;
148
 
                        }
149
 
                        minor = num;
150
 
                        num = -1-num;
151
 
                        break;
152
 
                case 1: /* partitioned */
153
 
                        if (autof == -1) {
154
 
                                fprintf(stderr, Name ": that --auto option not compatable with device named %s\n", dev);
155
 
                                return -1;
156
 
                        }
157
 
                        minor = num <<  MdpMinorShift;
158
 
                        major = get_mdp_major();
159
 
                        break;
160
 
                case 0: /* not standard, pick an unused number */
161
 
                        mdlist = mdstat_read(0);
162
 
                        for (num= (autof>0)?-1:0 ; ; num+= (autof>2)?-1:1) {
163
 
                                struct mdstat_ent *me;
164
 
                                for (me=mdlist; me; me=me->next)
165
 
                                        if (me->devnum == num)
166
 
                                                break;
167
 
                                if (!me) {
168
 
                                        /* doesn't exist if mdstat.
169
 
                                         * make sure it is new to /dev too
170
 
                                         */
171
 
                                        char *dn;
172
 
                                        if (autof > 0) 
173
 
                                                minor = (-1-num) << MdpMinorShift;
174
 
                                        else
175
 
                                                minor = num;
176
 
                                        dn = map_dev(major,minor);
177
 
                                        if (dn==NULL || is_standard(dn, NULL)) {
178
 
                                                /* this number only used by a 'standard' name,
179
 
                                                 * so it is safe to use
180
 
                                                 */
181
 
                                                break;
182
 
                                        }
183
 
                                }
184
 
                        }
185
 
                }
186
 
                /* major and minor have been chosen */
187
 
                
188
 
                /* If it was a 'standard' name and it is in-use, then
189
 
                 * the device could already be correct
190
 
                 */
191
 
                if (stb.st_mode && major(stb.st_rdev) == major &&
192
 
                    minor(stb.st_rdev) == minor)
193
 
                        ;
194
 
                else {
195
 
                        if (major(makedev(major,minor)) != major ||
196
 
                            minor(makedev(major,minor)) != minor) {
197
 
                                fprintf(stderr, Name ": Need newer C library to use more than 4 partitionable md devices, sorry\n");
198
 
                                return -1;
199
 
                        }
200
 
                        if (must_remove)
201
 
                                unlink(dev);
202
 
 
203
 
                        if (mknod(dev, S_IFBLK|0600, makedev(major, minor))!= 0) {
204
 
                                fprintf(stderr, Name ": failed to create %s\n", dev);
205
 
                                return -1;
206
 
                        }
207
 
                        if (must_remove) {
208
 
                                chown(dev, stb.st_uid, stb.st_gid);
209
 
                                chmod(dev, stb.st_mode & 07777);
210
 
                        }
211
 
                        stat(dev, &stb);
212
 
                        add_dev(dev, &stb, 0, NULL);
213
 
                        make_parts(dev,autof);
214
 
                }
215
 
        }
216
 
        mdfd = open(dev, O_RDWR, 0);
217
 
        if (mdfd < 0)
218
 
                fprintf(stderr, Name ": error opening %s: %s\n",
219
 
                        dev, strerror(errno));
220
 
        else if (md_get_version(mdfd) <= 0) {
221
 
                fprintf(stderr, Name ": %s does not appear to be an md device\n",
222
 
                        dev);
223
 
                close(mdfd);
224
 
                mdfd = -1;
225
 
        }
226
 
        return mdfd;
227
 
}
228