Add 'no_partitions' feature
[multipath-tools/.git] / kpartx / devmapper.c
1 /*
2  * Copyright (c) 2004, 2005 Christophe Varoqui
3  */
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <stdint.h>
8 #include <libdevmapper.h>
9 #include <ctype.h>
10 #include <errno.h>
11 #include "devmapper.h"
12
13 #define UUID_PREFIX "part%d-"
14 #define MAX_PREFIX_LEN 8
15 #define PARAMS_SIZE 1024
16
17 #ifndef LIBDM_API_COOKIE
18 static inline int dm_task_set_cookie(struct dm_task *dmt, uint32_t *c, int a)
19 {
20        return 1;
21 }
22 #endif
23
24 extern int
25 dm_prereq (char * str, int x, int y, int z)
26 {
27         int r = 1;
28         struct dm_task *dmt;
29         struct dm_versions *target;
30         struct dm_versions *last_target;
31
32         if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
33                 return 1;
34
35         dm_task_no_open_count(dmt);
36
37         if (!dm_task_run(dmt))
38                 goto out;
39
40         target = dm_task_get_versions(dmt);
41
42         /* Fetch targets and print 'em */
43         do {
44                 last_target = target;
45
46                 if (!strncmp(str, target->name, strlen(str)) &&
47                     /* dummy prereq on multipath version */
48                     target->version[0] >= x &&
49                     target->version[1] >= y &&
50                     target->version[2] >= z
51                    )
52                         r = 0;
53
54                 target = (void *) target + target->next;
55         } while (last_target != target);
56
57         out:
58         dm_task_destroy(dmt);
59         return r;
60 }
61
62 extern int
63 dm_simplecmd (int task, const char *name, int no_flush, uint32_t *cookie) {
64         int r = 0;
65         int udev_wait_flag = (task == DM_DEVICE_RESUME ||
66                               task == DM_DEVICE_REMOVE);
67         struct dm_task *dmt;
68
69         if (!(dmt = dm_task_create(task)))
70                 return 0;
71
72         if (!dm_task_set_name(dmt, name))
73                 goto out;
74
75         dm_task_no_open_count(dmt);
76         dm_task_skip_lockfs(dmt);
77
78         if (no_flush)
79                 dm_task_no_flush(dmt);
80
81         if (udev_wait_flag && !dm_task_set_cookie(dmt, cookie, 0))
82                 goto out;
83         r = dm_task_run(dmt);
84
85         out:
86         dm_task_destroy(dmt);
87         return r;
88 }
89
90 extern int
91 dm_addmap (int task, const char *name, const char *target,
92            const char *params, uint64_t size, int ro, const char *uuid, int part,
93            mode_t mode, uid_t uid, gid_t gid, uint32_t *cookie) {
94         int r = 0;
95         struct dm_task *dmt;
96         char *prefixed_uuid = NULL;
97
98         if (!(dmt = dm_task_create (task)))
99                 return 0;
100
101         if (!dm_task_set_name (dmt, name))
102                 goto addout;
103
104         if (!dm_task_add_target (dmt, 0, size, target, params))
105                 goto addout;
106
107         if (ro && !dm_task_set_ro (dmt))
108                         goto addout;
109
110         if (task == DM_DEVICE_CREATE && uuid) {
111                 prefixed_uuid = malloc(MAX_PREFIX_LEN + strlen(uuid) + 1);
112                 if (!prefixed_uuid) {
113                         fprintf(stderr, "cannot create prefixed uuid : %s\n",
114                                 strerror(errno));
115                         goto addout;
116                 }
117                 sprintf(prefixed_uuid, UUID_PREFIX "%s", part, uuid);
118                 if (!dm_task_set_uuid(dmt, prefixed_uuid))
119                         goto addout;
120         }
121
122         if (!dm_task_set_mode(dmt, mode))
123                 goto addout;
124         if (!dm_task_set_uid(dmt, uid))
125                 goto addout;
126         if (!dm_task_set_gid(dmt, gid))
127                 goto addout;
128
129         dm_task_no_open_count(dmt);
130
131         if (task == DM_DEVICE_CREATE && !dm_task_set_cookie(dmt, cookie, 0))
132                 goto addout;
133         r = dm_task_run (dmt);
134
135         addout:
136         dm_task_destroy (dmt);
137
138         return r;
139 }
140
141 extern int
142 dm_map_present (char * str)
143 {
144         int r = 0;
145         struct dm_task *dmt;
146         struct dm_info info;
147
148         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
149                 return 0;
150
151         if (!dm_task_set_name(dmt, str))
152                 goto out;
153
154         dm_task_no_open_count(dmt);
155
156         if (!dm_task_run(dmt))
157                 goto out;
158
159         if (!dm_task_get_info(dmt, &info))
160                 goto out;
161
162         if (info.exists)
163                 r = 1;
164 out:
165         dm_task_destroy(dmt);
166         return r;
167 }
168
169
170 char *
171 dm_mapname(int major, int minor)
172 {
173         struct dm_task *dmt;
174         char *mapname = NULL;
175         const char *map;
176
177         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
178                 return NULL;
179
180         dm_task_no_open_count(dmt);
181         dm_task_set_major(dmt, major);
182         dm_task_set_minor(dmt, minor);
183
184         if (!dm_task_run(dmt))
185                 goto out;
186
187         map = dm_task_get_name(dmt);
188         if (map && strlen(map))
189                 mapname = strdup(map);
190
191 out:
192         dm_task_destroy(dmt);
193         return mapname;
194 }
195
196 /*
197  * dm_get_first_dep
198  *
199  * Return the device number of the first dependend device
200  * for a given target.
201  */
202 dev_t dm_get_first_dep(char *devname)
203 {
204         struct dm_task *dmt;
205         struct dm_deps *dm_deps;
206         dev_t ret = 0;
207
208         if ((dmt = dm_task_create(DM_DEVICE_DEPS)) == NULL) {
209                 return ret;
210         }
211         if (!dm_task_set_name(dmt, devname)) {
212                 goto out;
213         }
214         if (!dm_task_run(dmt)) {
215                 goto out;
216         }
217         if ((dm_deps = dm_task_get_deps(dmt)) == NULL) {
218                 goto out;
219         }
220         if (dm_deps->count > 0) {
221                 ret = dm_deps->device[0];
222         }
223 out:
224         dm_task_destroy(dmt);
225
226         return ret;
227 }
228
229 char *
230 dm_mapuuid(int major, int minor)
231 {
232         struct dm_task *dmt;
233         const char *tmp;
234         char *uuid = NULL;
235
236         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
237                 return NULL;
238
239         dm_task_no_open_count(dmt);
240         dm_task_set_major(dmt, major);
241         dm_task_set_minor(dmt, minor);
242
243         if (!dm_task_run(dmt))
244                 goto out;
245
246         tmp = dm_task_get_uuid(dmt);
247         if (tmp[0] != '\0')
248                 uuid = strdup(tmp);
249 out:
250         dm_task_destroy(dmt);
251         return uuid;
252 }
253
254 int
255 dm_devn (char * mapname, int *major, int *minor)
256 {
257         int r = 1;
258         struct dm_task *dmt;
259         struct dm_info info;
260
261         if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
262                 return 0;
263
264         if (!dm_task_set_name(dmt, mapname))
265                 goto out;
266
267         if (!dm_task_run(dmt))
268                 goto out;
269
270         if (!dm_task_get_info(dmt, &info))
271                 goto out;
272
273         *major = info.major;
274         *minor = info.minor;
275
276         r = 0;
277 out:
278         dm_task_destroy(dmt);
279         return r;
280 }
281
282 int
283 dm_get_map(int major, int minor, char * outparams)
284 {
285         int r = 1;
286         struct dm_task *dmt;
287         void *next = NULL;
288         uint64_t start, length;
289         char *target_type = NULL;
290         char *params = NULL;
291
292         if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
293                 return 1;
294
295         dm_task_set_major(dmt, major);
296         dm_task_set_minor(dmt, minor);
297         dm_task_no_open_count(dmt);
298
299         if (!dm_task_run(dmt))
300                 goto out;
301
302         /* Fetch 1st target */
303         next = dm_get_next_target(dmt, next, &start, &length,
304                                   &target_type, &params);
305
306         if (snprintf(outparams, PARAMS_SIZE, "%s", params) <= PARAMS_SIZE)
307                 r = 0;
308 out:
309         dm_task_destroy(dmt);
310         return r;
311 }
312
313 #define FEATURE_NO_PART "no_partitions"
314
315 int
316 dm_no_partitions(int major, int minor)
317 {
318         char params[PARAMS_SIZE], *ptr;
319         int i, num_features;
320
321         if (dm_get_map(major, minor, params))
322                 return 0;
323
324         ptr = params;
325         num_features = strtoul(params, &ptr, 10);
326         if ((ptr == params) || num_features == 0) {
327                 /* No features found, return success */
328                 return 0;
329         }
330         for (i = 0; (i < num_features); i++) {
331                 if (!ptr || ptr > params + strlen(params))
332                         break;
333                 /* Skip whitespaces */
334                 while(ptr && *ptr == ' ') ptr++;
335                 if (!strncmp(ptr, FEATURE_NO_PART, strlen(FEATURE_NO_PART)))
336                         return 1;
337                 ptr = strchr(ptr, ' ');
338         }
339         return 0;
340 }