~ubuntu-branches/ubuntu/karmic/cryptsetup/karmic-proposed

« back to all changes in this revision

Viewing changes to lib/libdevmapper.c

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2009-05-10 17:29:32 UTC
  • mfrom: (0.1.4 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090510172932-1e485f99qk3psrg0
Tags: 2:1.0.6+20090405.svn49-1ubuntu1
* Merge from debian unstable, remaining changes:
  - Ubuntu specific:
    + debian/rules: link dynamically for better security supportability and
      smaller packages.
    + debian/control: Depend on initramfs-tools so system is not potentially
      rendered unbootable.
  - debian/initramfs/cryptroot-script wait for encrypted device to appear,
    report with log_*_msg (debian bug 488271).
  - debian/initramfs/cryptroot-hook: fix support for UUID and LABEL
    correlation between fstab and crypttab (debian bug 522041).
  - debian/askpass.c, debian/initramfs/cryptroot-script: using newline
    escape in passphrase prompt to avoid line-wrapping (debian bug 528133).
* Drop 04_fix_udevsettle_call.patch: fixed upstream differently.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
#define DEVICE_DIR      "/dev"
18
18
 
19
19
#define CRYPT_TARGET    "crypt"
20
 
 
21
 
#define UDEVSETTLE      "/sbin/udevsettle"
22
 
 
23
 
static void run_udevsettle(void)
24
 
{
25
 
        system(UDEVSETTLE);
26
 
}
 
20
#define RETRY_COUNT     5
27
21
 
28
22
static void set_dm_error(int level, const char *file, int line,
29
23
                         const char *f, ...)
38
32
        va_end(va);
39
33
}
40
34
 
 
35
static int _dm_simple(int task, const char *name);
 
36
 
41
37
static int dm_init(void)
42
38
{
43
39
        dm_log_init(set_dm_error);
 
40
        if (!_dm_simple(DM_DEVICE_LIST_VERSIONS, "test")) {
 
41
                set_error("Cannot communicate with device-mapper. Is the dm_mod module loaded?");
 
42
                return -1;
 
43
        }
 
44
 
44
45
        return 1;       /* unsafe memory */
45
46
}
46
47
 
50
51
        dm_lib_release();
51
52
}
52
53
 
53
 
static void flush_dm_workqueue(void)
54
 
{
55
 
        /* 
56
 
         * Unfortunately this is the only way to trigger libdevmapper's
57
 
         * update_nodes function 
58
 
         */ 
59
 
        dm_exit(); 
60
 
        dm_init();
61
 
}
62
 
 
63
54
static char *__lookup_dev(char *path, dev_t dev)
64
55
{
65
56
        struct dirent *entry;
152
143
        return params;
153
144
}
154
145
 
 
146
/* DM helpers */
 
147
static int _dm_simple(int task, const char *name)
 
148
{
 
149
        int r = 0;
 
150
        struct dm_task *dmt;
 
151
 
 
152
        if (!(dmt = dm_task_create(task)))
 
153
                return 0;
 
154
 
 
155
        if (!dm_task_set_name(dmt, name))
 
156
                goto out;
 
157
 
 
158
        r = dm_task_run(dmt);
 
159
 
 
160
      out:
 
161
        dm_task_destroy(dmt);
 
162
        return r;
 
163
}
 
164
 
 
165
static int _error_device(struct crypt_options *options)
 
166
{
 
167
        struct dm_task *dmt;
 
168
        int r = 0;
 
169
 
 
170
        if (!(dmt = dm_task_create(DM_DEVICE_RELOAD)))
 
171
                return 0;
 
172
 
 
173
        if (!dm_task_set_name(dmt, options->name))
 
174
                goto error;
 
175
 
 
176
        if (!dm_task_add_target(dmt, UINT64_C(0), options->size, "error", ""))
 
177
                goto error;
 
178
 
 
179
        if (!dm_task_set_ro(dmt))
 
180
                goto error;
 
181
 
 
182
        if (!dm_task_no_open_count(dmt))
 
183
                goto error;
 
184
 
 
185
        if (!dm_task_run(dmt))
 
186
                goto error;
 
187
 
 
188
        if (!_dm_simple(DM_DEVICE_RESUME, options->name)) {
 
189
                _dm_simple(DM_DEVICE_CLEAR, options->name);
 
190
                goto error;
 
191
        }
 
192
 
 
193
        r = 1;
 
194
 
 
195
error:
 
196
        dm_task_destroy(dmt);
 
197
        return r;
 
198
}
 
199
 
 
200
static int _dm_remove(struct crypt_options *options, int force)
 
201
{
 
202
        int r = -EINVAL;
 
203
        int retries = force ? RETRY_COUNT : 1;
 
204
 
 
205
        /* If force flag is set, replace device with error, read-only target.
 
206
         * it should stop processes from reading it and also removed underlying
 
207
         * device from mapping, so it is usable again.
 
208
         * Force flag should be used only for temporary devices, which are
 
209
         * intended to work inside cryptsetup only!
 
210
         * Anyway, if some process try to read temporary cryptsetup device,
 
211
         * it is bug - no other process should try touch it (e.g. udev).
 
212
         */
 
213
        if (force) {
 
214
                 _error_device(options);
 
215
                retries = RETRY_COUNT;
 
216
        }
 
217
 
 
218
        do {
 
219
                r = _dm_simple(DM_DEVICE_REMOVE, options->name) ? 0 : -EINVAL;
 
220
                if (--retries)
 
221
                        sleep(1);
 
222
        } while (r == -EINVAL && retries);
 
223
 
 
224
        dm_task_update_nodes();
 
225
 
 
226
        return r;
 
227
}
 
228
 
155
229
static int dm_create_device(int reload, struct crypt_options *options,
156
230
                            const char *key)
157
231
{
191
265
        if (dmi.read_only)
192
266
                options->flags |= CRYPT_FLAG_READONLY;
193
267
 
194
 
        /* run udevsettle to avoid a race in libdevmapper causing busy dm devices */
195
 
        run_udevsettle();
196
 
 
197
268
        r = 0;
198
 
        
199
269
out:
200
270
        if (r < 0 && !reload) {
201
271
                char *error = (char *)get_error();
202
272
                if (error)
203
273
                        error = strdup(error);
204
 
                if (dmt)
205
 
                        dm_task_destroy(dmt);
206
274
 
207
 
                if (!(dmt = dm_task_create(DM_DEVICE_REMOVE)))
208
 
                        goto out_restore_error;
209
 
                if (!dm_task_set_name(dmt, options->name))
210
 
                        goto out_restore_error;
211
 
                if (!dm_task_run(dmt))
 
275
                if (!_dm_remove(options, 0))
212
276
                        goto out_restore_error;
213
277
 
214
278
out_restore_error:
224
288
                dm_task_destroy(dmt);
225
289
        if(dmt_query)
226
290
                dm_task_destroy(dmt_query);
227
 
        flush_dm_workqueue();
 
291
        dm_task_update_nodes();
228
292
        return r;
229
293
}
230
294
 
352
416
        return r;
353
417
}
354
418
 
355
 
static int dm_remove_device(struct crypt_options *options)
 
419
static int dm_remove_device(int force, struct crypt_options *options)
356
420
{
357
 
        struct dm_task *dmt;
358
 
        int r = -EINVAL;
359
 
 
360
 
        if (!(dmt = dm_task_create(DM_DEVICE_REMOVE)))
361
 
                goto out;
362
 
        if (!dm_task_set_name(dmt, options->name))
363
 
                goto out;
364
 
        if (!dm_task_run(dmt))
365
 
                goto out;
366
 
 
367
 
        r = 0;
368
 
 
369
 
out:    
370
 
        if (dmt)
371
 
                dm_task_destroy(dmt);
372
 
        flush_dm_workqueue();
373
 
        return r;
 
421
        if (!options || !options->name)
 
422
                return -EINVAL;
 
423
 
 
424
        return _dm_remove(options, force);;
374
425
}
375
426
 
376
427