blob: 4424d9cbba1bedf59891d59b0f5752f90a9e2895
1 | /* vi: set sw=4 ts=4: */ |
2 | /* |
3 | * Mini losetup implementation for busybox |
4 | * |
5 | * Copyright (C) 2002 Matt Kraai. |
6 | * |
7 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. |
8 | */ |
9 | //config:config LOSETUP |
10 | //config: bool "losetup" |
11 | //config: default y |
12 | //config: select PLATFORM_LINUX |
13 | //config: help |
14 | //config: losetup is used to associate or detach a loop device with a regular |
15 | //config: file or block device, and to query the status of a loop device. This |
16 | //config: version does not currently support enabling data encryption. |
17 | |
18 | //kbuild:lib-$(CONFIG_LOSETUP) += losetup.o |
19 | |
20 | //applet:IF_LOSETUP(APPLET(losetup, BB_DIR_SBIN, BB_SUID_DROP)) |
21 | |
22 | //usage:#define losetup_trivial_usage |
23 | //usage: "[-r] [-o OFS] {-f|LOOPDEV} FILE - associate loop devices\n" |
24 | //usage: " losetup -d LOOPDEV - disassociate\n" |
25 | //usage: " losetup -a - show status\n" |
26 | //usage: " losetup -f - show next free loop device" |
27 | //usage:#define losetup_full_usage "\n\n" |
28 | //usage: " -o OFS Start OFS bytes into FILE" |
29 | //usage: "\n -r Read-only" |
30 | //usage: "\n -f Show/use next free loop device" |
31 | //usage: |
32 | //usage:#define losetup_notes_usage |
33 | //usage: "One argument (losetup /dev/loop1) will display the current association\n" |
34 | //usage: "(if any), or disassociate it (with -d). The display shows the offset\n" |
35 | //usage: "and filename of the file the loop device is currently bound to.\n\n" |
36 | //usage: "Two arguments (losetup /dev/loop1 file.img) create a new association,\n" |
37 | //usage: "with an optional offset (-o 12345). Encryption is not yet supported.\n" |
38 | //usage: "losetup -f will show the first loop free loop device\n\n" |
39 | |
40 | #include "libbb.h" |
41 | |
42 | /* 1048575 is a max possible minor number in Linux circa 2010 */ |
43 | /* for now use something less extreme */ |
44 | #define MAX_LOOP_NUM 1023 |
45 | |
46 | int losetup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
47 | int losetup_main(int argc UNUSED_PARAM, char **argv) |
48 | { |
49 | unsigned opt; |
50 | char *opt_o; |
51 | char dev[LOOP_NAMESIZE]; |
52 | enum { |
53 | OPT_d = (1 << 0), |
54 | OPT_o = (1 << 1), |
55 | OPT_f = (1 << 2), |
56 | OPT_a = (1 << 3), |
57 | OPT_r = (1 << 4), /* must be last */ |
58 | }; |
59 | |
60 | opt_complementary = "?2:d--ofar:a--ofr"; |
61 | opt = getopt32(argv, "do:far", &opt_o); |
62 | argv += optind; |
63 | |
64 | /* LOOPDEV */ |
65 | if (!opt && argv[0] && !argv[1]) { |
66 | char *s; |
67 | |
68 | s = query_loop(argv[0]); |
69 | if (!s) |
70 | bb_simple_perror_msg_and_die(argv[0]); |
71 | printf("%s: %s\n", argv[0], s); |
72 | if (ENABLE_FEATURE_CLEAN_UP) |
73 | free(s); |
74 | return EXIT_SUCCESS; |
75 | } |
76 | |
77 | /* -d LOOPDEV */ |
78 | if (opt == OPT_d && argv[0]) { |
79 | if (del_loop(argv[0])) |
80 | bb_simple_perror_msg_and_die(argv[0]); |
81 | return EXIT_SUCCESS; |
82 | } |
83 | |
84 | /* -a */ |
85 | if (opt == OPT_a) { |
86 | int n; |
87 | for (n = 0; n < MAX_LOOP_NUM; n++) { |
88 | char *s; |
89 | |
90 | sprintf(dev, LOOP_FORMAT, n); |
91 | s = query_loop(dev); |
92 | if (s) { |
93 | printf("%s: %s\n", dev, s); |
94 | free(s); |
95 | } |
96 | } |
97 | return EXIT_SUCCESS; |
98 | } |
99 | |
100 | /* contains -f */ |
101 | if (opt & OPT_f) { |
102 | char *s; |
103 | int n = 0; |
104 | |
105 | do { |
106 | if (n > MAX_LOOP_NUM) |
107 | bb_error_msg_and_die("no free loop devices"); |
108 | sprintf(dev, LOOP_FORMAT, n++); |
109 | s = query_loop(dev); |
110 | free(s); |
111 | } while (s); |
112 | /* now: dev is next free "/dev/loopN" */ |
113 | if ((opt == OPT_f) && !argv[0]) { |
114 | puts(dev); |
115 | return EXIT_SUCCESS; |
116 | } |
117 | } |
118 | |
119 | /* [-r] [-o OFS] {-f|LOOPDEV} FILE */ |
120 | if (argv[0] && ((opt & OPT_f) || argv[1])) { |
121 | unsigned long long offset = 0; |
122 | char *d = dev; |
123 | |
124 | if (opt & OPT_o) |
125 | offset = xatoull(opt_o); |
126 | if (!(opt & OPT_f)) |
127 | d = *argv++; |
128 | |
129 | if (argv[0]) { |
130 | if (set_loop(&d, argv[0], offset, (opt & OPT_r)) < 0) |
131 | bb_simple_perror_msg_and_die(argv[0]); |
132 | return EXIT_SUCCESS; |
133 | } |
134 | } |
135 | |
136 | bb_show_usage(); /* does not return */ |
137 | /*return EXIT_FAILURE;*/ |
138 | } |
139 |