]> git.ipfire.org Git - thirdparty/util-linux.git/blob - libfdisk/src/utils.c
115409065b35026982b0e1bcea8b6713b857221e
[thirdparty/util-linux.git] / libfdisk / src / utils.c
1
2 #include "fdiskP.h"
3 #include "pathnames.h"
4 #include "canonicalize.h"
5
6 #include <ctype.h>
7
8 /**
9 * SECTION: utils
10 * @title: Utils
11 * @short_description: misc fdisk functions
12 */
13
14 static int read_from_device(struct fdisk_context *cxt,
15 unsigned char *buf,
16 uintmax_t start, size_t size)
17 {
18 ssize_t r;
19
20 assert(cxt);
21
22 DBG(CXT, ul_debugobj(cxt, "reading: offset=%ju, size=%zu",
23 start, size));
24
25 r = lseek(cxt->dev_fd, start, SEEK_SET);
26 if (r == -1)
27 {
28 DBG(CXT, ul_debugobj(cxt, "failed to seek to offset %ju: %m", start));
29 return -errno;
30 }
31
32 r = read(cxt->dev_fd, buf, size);
33 if (r < 0 || (size_t)r != size) {
34 if (!errno)
35 errno = EINVAL; /* probably too small file/device */
36 DBG(CXT, ul_debugobj(cxt, "failed to read %zu from offset %ju: %m",
37 size, start));
38 return -errno;
39 }
40
41 return 0;
42 }
43
44
45 /*
46 * Zeros in-memory first sector buffer
47 */
48 int fdisk_init_firstsector_buffer(struct fdisk_context *cxt,
49 unsigned int protect_off,
50 unsigned int protect_size)
51 {
52 if (!cxt)
53 return -EINVAL;
54
55 assert(protect_off + protect_size <= cxt->sector_size);
56
57 if (!cxt->firstsector || cxt->firstsector_bufsz != cxt->sector_size) {
58 /* Let's allocate a new buffer if no allocated yet, or the
59 * current buffer has incorrect size */
60 if (!cxt->parent || cxt->parent->firstsector != cxt->firstsector)
61 free(cxt->firstsector);
62
63 DBG(CXT, ul_debugobj(cxt, "initialize in-memory first sector "
64 "buffer [sector_size=%lu]", cxt->sector_size));
65 cxt->firstsector = calloc(1, cxt->sector_size);
66 if (!cxt->firstsector)
67 return -ENOMEM;
68
69 cxt->firstsector_bufsz = cxt->sector_size;
70 return 0;
71 }
72
73 DBG(CXT, ul_debugobj(cxt, "zeroize in-memory first sector buffer"));
74 memset(cxt->firstsector, 0, cxt->firstsector_bufsz);
75
76 if (protect_size) {
77 /*
78 * It would be possible to reuse data from cxt->firstsector
79 * (call memset() for non-protected area only) and avoid one
80 * read() from the device, but it seems like a too fragile
81 * solution as we have no clue about stuff in the buffer --
82 * maybe it was already modified. Let's re-read from the device
83 * to be sure. -- kzak 13-Apr-2015
84 */
85 DBG(CXT, ul_debugobj(cxt, "first sector protection enabled -- re-reading"));
86 read_from_device(cxt, cxt->firstsector, protect_off, protect_size);
87 }
88 return 0;
89 }
90
91 int fdisk_read_firstsector(struct fdisk_context *cxt)
92 {
93 int rc;
94
95 assert(cxt);
96 assert(cxt->sector_size);
97
98 rc = fdisk_init_firstsector_buffer(cxt, 0, 0);
99 if (rc)
100 return rc;
101
102 assert(cxt->sector_size == cxt->firstsector_bufsz);
103
104
105 return read_from_device(cxt, cxt->firstsector, 0, cxt->sector_size);
106 }
107
108 /**
109 * fdisk_partname:
110 * @dev: device name
111 * @partno: partition name
112 *
113 * Return: allocated buffer with partition name, use free() to deallocate.
114 */
115 char *fdisk_partname(const char *dev, size_t partno)
116 {
117 char *res = NULL;
118 const char *p = "";
119 char *dev_mapped = NULL;
120 int w = 0;
121
122 if (!dev || !*dev) {
123 if (asprintf(&res, "%zd", partno) > 0)
124 return res;
125 return NULL;
126 }
127
128 /* It is impossible to predict /dev/dm-N partition names. */
129 if (strncmp(dev, "/dev/dm-", sizeof("/dev/dm-") - 1) == 0) {
130 dev_mapped = canonicalize_dm_name (dev + 5);
131 if (dev_mapped)
132 dev = dev_mapped;
133 }
134
135 w = strlen(dev);
136 if (isdigit(dev[w - 1]))
137 #ifdef __GNU__
138 p = "s";
139 #else
140 p = "p";
141 #endif
142
143 /* devfs kludge - note: fdisk partition names are not supposed
144 to equal kernel names, so there is no reason to do this */
145 if (strcmp(dev + w - 4, "disc") == 0) {
146 w -= 4;
147 p = "part";
148 }
149
150 /* udev names partitions by appending -partN
151 e.g. ata-SAMSUNG_SV8004H_0357J1FT712448-part1
152 multipath-tools kpartx.rules also append -partN */
153 if ((strncmp(dev, _PATH_DEV_BYID, sizeof(_PATH_DEV_BYID) - 1) == 0) ||
154 strncmp(dev, _PATH_DEV_BYPATH, sizeof(_PATH_DEV_BYPATH) - 1) == 0 ||
155 strncmp(dev, "/dev/mapper", sizeof("/dev/mapper") - 1) == 0) {
156
157 /* check for <name><partno>, e.g. mpatha1 */
158 if (asprintf(&res, "%.*s%zu", w, dev, partno) <= 0)
159 res = NULL;
160 if (res && access(res, F_OK) == 0)
161 goto done;
162
163 free(res);
164
165 /* check for partition seperator "p" */
166 if (asprintf(&res, "%.*sp%zu", w, dev, partno) <= 0)
167 res = NULL;
168 if (res && access(res, F_OK) == 0)
169 goto done;
170
171 free(res);
172
173 /* otherwise, default to "-path" */
174 p = "-part";
175 }
176
177 if (asprintf(&res, "%.*s%s%zu", w, dev, p, partno) <= 0)
178 res = NULL;
179 done:
180 free(dev_mapped);
181 return res;
182 }
183
184 #ifdef TEST_PROGRAM
185 struct fdisk_label *fdisk_new_dos_label(struct fdisk_context *cxt) { return NULL; }
186 struct fdisk_label *fdisk_new_bsd_label(struct fdisk_context *cxt) { return NULL; }
187
188 static int test_partnames(struct fdisk_test *ts, int argc, char *argv[])
189 {
190 size_t i;
191 const char *disk = argv[1];
192
193 for (i = 0; i < 5; i++) {
194 char *p = fdisk_partname(disk, i + 1);
195 if (p)
196 printf("%zu: '%s'\n", i + 1, p);
197 free(p);
198 }
199
200 return 0;
201 }
202
203 int main(int argc, char *argv[])
204 {
205 struct fdisk_test tss[] = {
206 { "--partnames", test_partnames, "<diskname>" },
207 { NULL }
208 };
209
210 return fdisk_run_test(tss, argc, argv);
211 }
212
213 #endif