Line data Source code
1 : /*
2 : * Copyright (C) 2014 Red Hat, Inc.
3 : *
4 : * This library is free software; you can redistribute it and/or
5 : * modify it under the terms of the GNU Lesser General Public
6 : * License as published by the Free Software Foundation; either
7 : * version 2.1 of the License, or (at your option) any later version.
8 : *
9 : * This library is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : * Lesser General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public
15 : * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16 : *
17 : * Author: Vratislav Podzimek <vpodzime@redhat.com>
18 : */
19 :
20 : #include <glib.h>
21 : #include <unistd.h>
22 : #include <glob.h>
23 : #include <string.h>
24 : #include <fcntl.h>
25 : #include <sys/ioctl.h>
26 : #include <linux/loop.h>
27 : #include <errno.h>
28 : #include <blockdev/utils.h>
29 : #include "loop.h"
30 :
31 : #ifndef LOOP_SET_BLOCK_SIZE
32 : #define LOOP_SET_BLOCK_SIZE 0x4C09
33 : #endif
34 :
35 : /**
36 : * SECTION: loop
37 : * @short_description: plugin for operations with loop devices
38 : * @title: Loop
39 : * @include: loop.h
40 : *
41 : * A plugin for operations with loop devices. All sizes passed
42 : * in/out to/from the functions are in bytes.
43 : */
44 :
45 : static GMutex loop_control_lock;
46 :
47 : /**
48 : * bd_loop_error_quark: (skip)
49 : */
50 0 : GQuark bd_loop_error_quark (void)
51 : {
52 0 : return g_quark_from_static_string ("g-bd-loop-error-quark");
53 : }
54 :
55 : /**
56 : * bd_loop_init:
57 : *
58 : * Initializes the plugin. **This function is called automatically by the
59 : * library's initialization functions.**
60 : *
61 : */
62 157 : gboolean bd_loop_init (void) {
63 : /* nothing to do here */
64 157 : return TRUE;
65 : };
66 :
67 : /**
68 : * bd_loop_close:
69 : *
70 : * Cleans up after the plugin. **This function is called automatically by the
71 : * library's functions that unload it.**
72 : *
73 : */
74 157 : void bd_loop_close (void) {
75 : /* nothing to do here */
76 157 : }
77 :
78 :
79 : /**
80 : * bd_loop_is_tech_avail:
81 : * @tech: the queried tech
82 : * @mode: a bit mask of queried modes of operation (#BDLoopTechMode) for @tech
83 : * @error: (out) (optional): place to store error (details about why the @tech-@mode combination is not available)
84 : *
85 : * Returns: whether the @tech-@mode combination is available -- supported by the
86 : * plugin implementation and having all the runtime dependencies available
87 : */
88 1 : gboolean bd_loop_is_tech_avail (BDLoopTech tech G_GNUC_UNUSED, guint64 mode G_GNUC_UNUSED, GError **error G_GNUC_UNUSED) {
89 : /* all combinations are supported by this implementation of the plugin */
90 1 : return TRUE;
91 : }
92 :
93 0 : void bd_loop_info_free (BDLoopInfo *info) {
94 0 : if (info == NULL)
95 0 : return;
96 :
97 0 : g_free (info->backing_file);
98 0 : g_free (info);
99 : }
100 :
101 0 : BDLoopInfo* bd_loop_info_copy (BDLoopInfo *info) {
102 0 : if (info == NULL)
103 0 : return NULL;
104 :
105 0 : BDLoopInfo *new_info = g_new0 (BDLoopInfo, 1);
106 :
107 0 : new_info->backing_file = g_strdup (info->backing_file);
108 0 : new_info->offset = info->offset;
109 0 : new_info->autoclear = info->autoclear;
110 0 : new_info->direct_io = info->direct_io;
111 0 : new_info->part_scan = info->part_scan;
112 0 : new_info->read_only = info->read_only;
113 :
114 0 : return new_info;
115 : }
116 :
117 10 : static gchar* _loop_get_backing_file (const gchar *dev_name, GError **error) {
118 10 : gchar *sys_path = g_strdup_printf ("/sys/class/block/%s/loop/backing_file", dev_name);
119 10 : gchar *ret = NULL;
120 10 : gboolean success = FALSE;
121 :
122 10 : if (access (sys_path, R_OK) != 0) {
123 0 : g_free (sys_path);
124 0 : return NULL;
125 : }
126 :
127 10 : success = g_file_get_contents (sys_path, &ret, NULL, error);
128 10 : if (!success) {
129 : /* error is already populated */
130 0 : g_free (sys_path);
131 0 : return NULL;
132 : }
133 :
134 10 : g_free (sys_path);
135 10 : return g_strstrip (ret);
136 : }
137 :
138 : /**
139 : * bd_loop_info:
140 : * @loop: name of the loop device to get information about (e.g. "loop0")
141 : * @error: (out) (optional): place to store error (if any)
142 : *
143 : * Returns: (transfer full): information about the @loop device or %NULL in case of error
144 : *
145 : * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_QUERY
146 : */
147 10 : BDLoopInfo* bd_loop_info (const gchar *loop, GError **error) {
148 10 : BDLoopInfo *info = NULL;
149 10 : g_autofree gchar *dev_loop = NULL;
150 10 : gint fd = -1;
151 : struct loop_info64 li64;
152 10 : GError *l_error = NULL;
153 :
154 10 : if (!g_str_has_prefix (loop, "/dev/"))
155 10 : dev_loop = g_strdup_printf ("/dev/%s", loop);
156 :
157 10 : fd = open (dev_loop ? dev_loop : loop, O_RDONLY);
158 10 : if (fd < 0) {
159 0 : g_set_error (error, BD_LOOP_ERROR, BD_LOOP_ERROR_DEVICE,
160 : "Failed to open device %s: %m", loop);
161 0 : return NULL;
162 : }
163 :
164 10 : memset (&li64, 0, sizeof (li64));
165 10 : if (ioctl (fd, LOOP_GET_STATUS64, &li64) < 0) {
166 0 : g_set_error (error, BD_LOOP_ERROR,
167 0 : errno == ENXIO ? BD_LOOP_ERROR_DEVICE : BD_LOOP_ERROR_FAIL,
168 : "Failed to get status of the device %s: %m", loop);
169 0 : close (fd);
170 0 : return NULL;
171 : }
172 :
173 10 : close (fd);
174 :
175 10 : info = g_new0 (BDLoopInfo, 1);
176 10 : info->offset = li64.lo_offset;
177 10 : if ((li64.lo_flags & LO_FLAGS_AUTOCLEAR) != 0)
178 2 : info->autoclear = TRUE;
179 10 : if ((li64.lo_flags & LO_FLAGS_DIRECT_IO) != 0)
180 0 : info->direct_io = TRUE;
181 10 : if ((li64.lo_flags & LO_FLAGS_PARTSCAN) != 0)
182 9 : info->part_scan = TRUE;
183 10 : if ((li64.lo_flags & LO_FLAGS_READ_ONLY) != 0)
184 1 : info->read_only = TRUE;
185 :
186 10 : info->backing_file = _loop_get_backing_file (loop, &l_error);
187 10 : if (l_error) {
188 0 : bd_loop_info_free (info);
189 0 : g_set_error (error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
190 0 : "Failed to get backing file of the device %s: %s", loop, l_error->message);
191 0 : g_clear_error (&l_error);
192 0 : return NULL;
193 : }
194 :
195 10 : return info;
196 : }
197 :
198 : /**
199 : * bd_loop_get_loop_name:
200 : * @file: path of the backing file to get loop name for
201 : * @error: (out) (optional): place to store error (if any)
202 : *
203 : * Returns: (transfer full): name of the loop device associated with the given
204 : * @file or %NULL if failed to determine
205 : *
206 : * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_QUERY
207 : */
208 2 : gchar* bd_loop_get_loop_name (const gchar *file, GError **error G_GNUC_UNUSED) {
209 : glob_t globbuf;
210 : gchar **path_p;
211 2 : gboolean success = FALSE;
212 2 : gchar *content = NULL;
213 2 : gboolean found = FALSE;
214 : gchar **parts;
215 : gchar *ret;
216 :
217 2 : if (glob ("/sys/block/loop*/loop/backing_file", GLOB_NOSORT, NULL, &globbuf) != 0) {
218 1 : return NULL;
219 : }
220 :
221 2 : for (path_p = globbuf.gl_pathv; *path_p && !found; path_p++) {
222 1 : success = g_file_get_contents (*path_p, &content, NULL, NULL);
223 1 : if (!success)
224 0 : continue;
225 :
226 1 : g_strstrip (content);
227 1 : found = (g_strcmp0 (content, file) == 0);
228 1 : g_free (content);
229 : }
230 :
231 1 : if (!found) {
232 0 : globfree (&globbuf);
233 0 : return NULL;
234 : }
235 :
236 1 : parts = g_strsplit (*(path_p - 1), "/", 5);
237 1 : ret = g_strdup (parts[3]);
238 1 : g_strfreev (parts);
239 :
240 1 : globfree (&globbuf);
241 1 : return ret;
242 : }
243 :
244 : /**
245 : * bd_loop_setup:
246 : * @file: file to setup as a loop device
247 : * @offset: offset of the start of the device (in @file)
248 : * @size: maximum size of the device (or 0 to leave unspecified)
249 : * @read_only: whether to setup as read-only (%TRUE) or read-write (%FALSE)
250 : * @part_scan: whether to enforce partition scan on the newly created device or not
251 : * @sector_size: logical sector size for the loop device in bytes (or 0 for default)
252 : * @loop_name: (optional) (out): if not %NULL, it is used to store the name of the loop device
253 : * @error: (out) (optional): place to store error (if any)
254 : *
255 : * Returns: whether the @file was successfully setup as a loop device or not
256 : *
257 : * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_CREATE
258 : */
259 31 : gboolean bd_loop_setup (const gchar *file, guint64 offset, guint64 size, gboolean read_only, gboolean part_scan, guint64 sector_size, const gchar **loop_name, GError **error) {
260 31 : gint fd = -1;
261 31 : gboolean ret = FALSE;
262 :
263 : /* open as RDWR so that @read_only determines whether the device is
264 : read-only or not */
265 31 : fd = open (file, O_RDWR);
266 31 : if (fd < 0) {
267 1 : g_set_error (error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
268 : "Failed to open the backing file '%s': %m", file);
269 1 : return FALSE;
270 : }
271 :
272 30 : ret = bd_loop_setup_from_fd (fd, offset, size, read_only, part_scan, sector_size, loop_name, error);
273 30 : close (fd);
274 30 : return ret;
275 : }
276 :
277 : /**
278 : * bd_loop_setup_from_fd:
279 : * @fd: file descriptor for a file to setup as a new loop device
280 : * @offset: offset of the start of the device (in file given by @fd)
281 : * @size: maximum size of the device (or 0 to leave unspecified)
282 : * @read_only: whether to setup as read-only (%TRUE) or read-write (%FALSE)
283 : * @part_scan: whether to enforce partition scan on the newly created device or not
284 : * @sector_size: logical sector size for the loop device in bytes (or 0 for default)
285 : * @loop_name: (optional) (out): if not %NULL, it is used to store the name of the loop device
286 : * @error: (out) (optional): place to store error (if any)
287 : *
288 : * Returns: whether a new loop device was successfully setup for @fd or not
289 : *
290 : * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_CREATE
291 : */
292 30 : gboolean bd_loop_setup_from_fd (gint fd, guint64 offset, guint64 size, gboolean read_only, gboolean part_scan, guint64 sector_size, const gchar **loop_name, GError **error) {
293 30 : gint loop_control_fd = -1;
294 30 : gint loop_number = -1;
295 30 : gchar *loop_device = NULL;
296 30 : gint loop_fd = -1;
297 : struct loop_info64 li64;
298 30 : guint64 progress_id = 0;
299 30 : gint status = 0;
300 30 : guint n_try = 0;
301 30 : GError *l_error = NULL;
302 :
303 30 : progress_id = bd_utils_report_started ("Started setting up loop device");
304 :
305 30 : loop_control_fd = open ("/dev/loop-control", O_RDWR);
306 30 : if (loop_control_fd == -1) {
307 0 : g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
308 : "Failed to open the loop-control device: %m");
309 0 : bd_utils_report_finished (progress_id, l_error->message);
310 0 : g_propagate_error (error, l_error);
311 0 : return FALSE;
312 : }
313 :
314 : /* XXX: serialize access to loop-control (seems to be required, but it's not
315 : documented anywhere) */
316 30 : g_mutex_lock (&loop_control_lock);
317 30 : loop_number = ioctl (loop_control_fd, LOOP_CTL_GET_FREE);
318 30 : g_mutex_unlock (&loop_control_lock);
319 30 : close (loop_control_fd);
320 30 : if (loop_number < 0) {
321 0 : g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
322 : "Failed to open the loop-control device: %m");
323 0 : bd_utils_report_finished (progress_id, l_error->message);
324 0 : g_propagate_error (error, l_error);
325 0 : return FALSE;
326 : }
327 :
328 30 : bd_utils_report_progress (progress_id, 33, "Got free loop device");
329 :
330 30 : loop_device = g_strdup_printf ("/dev/loop%d", loop_number);
331 30 : loop_fd = open (loop_device, read_only ? O_RDONLY : O_RDWR);
332 30 : if (loop_fd == -1) {
333 0 : g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
334 : "Failed to open the %s device: %m", loop_device);
335 0 : g_free (loop_device);
336 0 : bd_utils_report_finished (progress_id, l_error->message);
337 0 : g_propagate_error (error, l_error);
338 0 : return FALSE;
339 : }
340 :
341 30 : memset (&li64, '\0', sizeof (li64));
342 30 : if (read_only)
343 2 : li64.lo_flags |= LO_FLAGS_READ_ONLY;
344 30 : if (part_scan)
345 28 : li64.lo_flags |= LO_FLAGS_PARTSCAN;
346 30 : if (offset > 0)
347 2 : li64.lo_offset = offset;
348 30 : if (size > 0)
349 1 : li64.lo_sizelimit = size;
350 30 : if (ioctl (loop_fd, LOOP_SET_FD, fd) < 0) {
351 0 : g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_DEVICE,
352 : "Failed to associate the %s device with the file descriptor: %m", loop_device);
353 0 : g_free (loop_device);
354 0 : close (loop_fd);
355 0 : bd_utils_report_finished (progress_id, l_error->message);
356 0 : g_propagate_error (error, l_error);
357 0 : return FALSE;
358 : }
359 :
360 30 : bd_utils_report_progress (progress_id, 66, "Associated the loop device");
361 :
362 : /* we may need to try multiple times with some delays in case the device is
363 : busy at the very moment */
364 30 : for (n_try=10, status=-1; (status != 0) && (n_try > 0); n_try--) {
365 30 : status = ioctl (loop_fd, LOOP_SET_STATUS64, &li64);
366 30 : if (status < 0 && errno == EAGAIN)
367 0 : g_usleep (100 * 1000); /* microseconds */
368 : else
369 : break;
370 : }
371 :
372 30 : if (status != 0) {
373 0 : g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
374 : "Failed to set status for the %s device: %m", loop_device);
375 0 : g_free (loop_device);
376 0 : close (loop_fd);
377 0 : bd_utils_report_finished (progress_id, l_error->message);
378 0 : g_propagate_error (error, l_error);
379 0 : return FALSE;
380 : }
381 :
382 30 : if (sector_size > 0) {
383 2 : for (n_try=10, status=-1; (status != 0) && (n_try > 0); n_try--) {
384 2 : status = ioctl (loop_fd, LOOP_SET_BLOCK_SIZE, (unsigned long) sector_size);
385 2 : if (status < 0 && errno == EAGAIN)
386 0 : g_usleep (100 * 1000); /* microseconds */
387 : else
388 : break;
389 : }
390 :
391 2 : if (status != 0) {
392 0 : g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
393 : "Failed to set sector size for the %s device: %m", loop_device);
394 0 : g_free (loop_device);
395 0 : close (loop_fd);
396 0 : bd_utils_report_finished (progress_id, l_error->message);
397 0 : g_propagate_error (error, l_error);
398 0 : return FALSE;
399 : }
400 : }
401 :
402 30 : if (loop_name)
403 30 : *loop_name = g_strdup_printf ("loop%d", loop_number);
404 :
405 30 : g_free (loop_device);
406 30 : close (loop_fd);
407 30 : bd_utils_report_finished (progress_id, "Completed");
408 30 : return TRUE;
409 : }
410 :
411 : /**
412 : * bd_loop_teardown:
413 : * @loop: path or name of the loop device to tear down
414 : * @error: (out) (optional): place to store error (if any)
415 : *
416 : * Returns: whether the @loop device was successfully torn down or not
417 : *
418 : * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_DESTROY
419 : */
420 34 : gboolean bd_loop_teardown (const gchar *loop, GError **error) {
421 34 : gchar *dev_loop = NULL;
422 34 : gint loop_fd = -1;
423 34 : guint64 progress_id = 0;
424 34 : GError *l_error = NULL;
425 :
426 34 : progress_id = bd_utils_report_started ("Started tearing down loop device");
427 :
428 34 : if (!g_str_has_prefix (loop, "/dev/"))
429 15 : dev_loop = g_strdup_printf ("/dev/%s", loop);
430 :
431 34 : loop_fd = open (dev_loop ? dev_loop : loop, O_RDONLY);
432 34 : g_free (dev_loop);
433 34 : if (loop_fd == -1) {
434 0 : g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
435 : "Failed to open the %s device: %m", loop);
436 0 : bd_utils_report_finished (progress_id, l_error->message);
437 0 : g_propagate_error (error, l_error);
438 0 : return FALSE;
439 : }
440 :
441 34 : if (ioctl (loop_fd, LOOP_CLR_FD) < 0) {
442 0 : g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
443 : "Failed to detach the backing file from the %s device: %m", loop);
444 0 : close (loop_fd);
445 0 : bd_utils_report_finished (progress_id, l_error->message);
446 0 : g_propagate_error (error, l_error);
447 0 : return FALSE;
448 : }
449 :
450 34 : close (loop_fd);
451 34 : bd_utils_report_finished (progress_id, "Completed");
452 :
453 34 : return TRUE;
454 : }
455 :
456 : /**
457 : * bd_loop_set_autoclear:
458 : * @loop: path or name of the loop device
459 : * @autoclear: whether to set or unset the autoclear flag
460 : * @error: (out) (optional): place to store error (if any)
461 : *
462 : * Returns: whether the autoclear flag was successfully set on the @loop device or not
463 : *
464 : * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_MODIFY
465 : */
466 5 : gboolean bd_loop_set_autoclear (const gchar *loop, gboolean autoclear, GError **error) {
467 5 : gchar *dev_loop = NULL;
468 5 : gint fd = -1;
469 : struct loop_info64 li64;
470 5 : guint64 progress_id = 0;
471 5 : gchar *msg = NULL;
472 5 : GError *l_error = NULL;
473 :
474 5 : if (!g_str_has_prefix (loop, "/dev/"))
475 3 : dev_loop = g_strdup_printf ("/dev/%s", loop);
476 :
477 5 : msg = g_strdup_printf ("Started setting up the autoclear flag on the /dev/%s device",
478 : dev_loop ? dev_loop : loop);
479 5 : progress_id = bd_utils_report_started (msg);
480 5 : g_free (msg);
481 :
482 5 : fd = open (dev_loop ? dev_loop : loop, O_RDWR);
483 5 : g_free (dev_loop);
484 5 : if (fd < 0) {
485 1 : g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_DEVICE,
486 : "Failed to open device %s: %m", loop);
487 1 : bd_utils_report_finished (progress_id, l_error->message);
488 1 : g_propagate_error (error, l_error);
489 1 : return FALSE;
490 : }
491 :
492 4 : memset (&li64, 0, sizeof (li64));
493 4 : if (ioctl (fd, LOOP_GET_STATUS64, &li64) < 0) {
494 0 : g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
495 : "Failed to get status of the device %s: %m", loop);
496 0 : close (fd);
497 0 : bd_utils_report_finished (progress_id, l_error->message);
498 0 : g_propagate_error (error, l_error);
499 0 : return FALSE;
500 : }
501 :
502 4 : if (autoclear)
503 2 : li64.lo_flags |= LO_FLAGS_AUTOCLEAR;
504 : else
505 2 : li64.lo_flags &= (~LO_FLAGS_AUTOCLEAR);
506 :
507 4 : if (ioctl (fd, LOOP_SET_STATUS64, &li64) < 0) {
508 0 : g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
509 : "Failed to set status of the device %s: %m", loop);
510 0 : close (fd);
511 0 : bd_utils_report_finished (progress_id, l_error->message);
512 0 : g_propagate_error (error, l_error);
513 0 : return FALSE;
514 : }
515 :
516 4 : close (fd);
517 4 : bd_utils_report_finished (progress_id, "Completed");
518 4 : return TRUE;
519 : }
520 :
521 : /**
522 : * bd_loop_set_capacity:
523 : * @loop: path or name of the loop device
524 : * @error: (out) (optional): place to store error (if any)
525 : *
526 : * Force the loop driver to reread the size of the file associated with the
527 : * specified @loop device.
528 : *
529 : * Returns: whether the LOOP_SET_CAPACITY ioctl was successfully issued or not.
530 : *
531 : * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_MODIFY
532 : */
533 2 : gboolean bd_loop_set_capacity (const gchar *loop, GError **error) {
534 2 : gchar *dev_loop = NULL;
535 2 : gint fd = -1;
536 2 : guint64 progress_id = 0;
537 2 : gchar *msg = NULL;
538 2 : guint n_try = 0;
539 2 : gint status = 0;
540 2 : GError *l_error = NULL;
541 :
542 2 : if (!g_str_has_prefix (loop, "/dev/"))
543 2 : dev_loop = g_strdup_printf ("/dev/%s", loop);
544 :
545 2 : msg = g_strdup_printf ("Started setting up capacity on the %s device",
546 : dev_loop ? dev_loop : loop);
547 2 : progress_id = bd_utils_report_started (msg);
548 2 : g_free (msg);
549 :
550 2 : fd = open (dev_loop ? dev_loop : loop, O_RDWR);
551 2 : g_free (dev_loop);
552 2 : if (fd < 0) {
553 1 : g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_DEVICE,
554 : "Failed to open device %s: %m", loop);
555 1 : bd_utils_report_finished (progress_id, l_error->message);
556 1 : g_propagate_error (error, l_error);
557 1 : return FALSE;
558 : }
559 :
560 1 : for (n_try=10, status=-1; (status != 0) && (n_try > 0); n_try--) {
561 1 : status = ioctl (fd, LOOP_SET_CAPACITY, 0);
562 1 : if (status < 0 && errno == EAGAIN)
563 0 : g_usleep (100 * 1000); /* microseconds */
564 : else
565 : break;
566 : }
567 :
568 1 : if (status != 0) {
569 0 : g_set_error (&l_error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
570 : "Failed to set capacity of the device %s: %m", loop);
571 0 : close (fd);
572 0 : bd_utils_report_finished (progress_id, l_error->message);
573 0 : g_propagate_error (error, l_error);
574 0 : return FALSE;
575 : }
576 :
577 1 : close (fd);
578 1 : bd_utils_report_finished (progress_id, "Completed");
579 1 : return TRUE;
580 : }
|