• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/busybox/util-linux/volume_id/
1/* vi: set sw=4 ts=4: */
2/*
3 * Support functions for mounting devices by label/uuid
4 *
5 * Copyright (C) 2006 by Jason Schoon <floydpink@gmail.com>
6 * Some portions cribbed from e2fsprogs, util-linux, dosfstools
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 */
10#include <sys/mount.h> /* BLKGETSIZE64 */
11#if !defined(BLKGETSIZE64)
12# define BLKGETSIZE64 _IOR(0x12,114,size_t)
13#endif
14#include "volume_id_internal.h"
15
16static struct uuidCache_s {
17	struct uuidCache_s *next;
18	dev_t devno;
19	char *device;
20	char *label;
21	char *uc_uuid; /* prefix makes it easier to grep for */
22} *uuidCache;
23
24/* Returns !0 on error.
25 * Otherwise, returns malloc'ed strings for label and uuid
26 * (and they can't be NULL, although they can be "").
27 * NB: closes fd. */
28static int
29get_label_uuid(int fd, char **label, char **uuid)
30{
31	int rv = 1;
32	uint64_t size;
33	struct volume_id *vid;
34
35	/* fd is owned by vid now */
36	vid = volume_id_open_node(fd);
37
38	if (ioctl(/*vid->*/fd, BLKGETSIZE64, &size) != 0)
39		size = 0;
40
41	if (volume_id_probe_all(vid, /*0,*/ size) != 0)
42		goto ret;
43
44	if (vid->label[0] != '\0' || vid->uuid[0] != '\0') {
45		*label = xstrndup(vid->label, sizeof(vid->label));
46		*uuid  = xstrndup(vid->uuid, sizeof(vid->uuid));
47		dbg("found label '%s', uuid '%s'", *label, *uuid);
48		rv = 0;
49	}
50 ret:
51	free_volume_id(vid); /* also closes fd */
52	return rv;
53}
54
55/* NB: we take ownership of (malloc'ed) label and uuid */
56static void
57uuidcache_addentry(char *device, dev_t devno, char *label, char *uuid)
58{
59	struct uuidCache_s *last;
60
61	if (!uuidCache) {
62		last = uuidCache = xzalloc(sizeof(*uuidCache));
63	} else {
64		for (last = uuidCache; last->next; last = last->next)
65			continue;
66		last->next = xzalloc(sizeof(*uuidCache));
67		last = last->next;
68	}
69	/*last->next = NULL; - xzalloc did it*/
70	last->devno = devno;
71	last->device = device;
72	last->label = label;
73	last->uc_uuid = uuid;
74}
75
76/* If get_label_uuid() on device_name returns success,
77 * add a cache entry for this device.
78 * If device node does not exist, it will be temporarily created. */
79static int FAST_FUNC
80uuidcache_check_device(const char *device,
81		struct stat *statbuf,
82		void *userData UNUSED_PARAM,
83		int depth UNUSED_PARAM)
84{
85	char *uuid = uuid; /* for compiler */
86	char *label = label;
87	int fd;
88
89	/* note: this check rejects links to devices, among other nodes */
90	if (!S_ISBLK(statbuf->st_mode))
91		return TRUE;
92
93	/* Users report that mucking with floppies (especially non-present
94	 * ones) is significant PITA. This is a horribly dirty hack,
95	 * but it is very useful in real world.
96	 * If this will ever need to be enabled, consider using O_NONBLOCK.
97	 */
98	if (major(statbuf->st_rdev) == 2)
99		return TRUE;
100
101	fd = open(device, O_RDONLY);
102	if (fd < 0)
103		return TRUE;
104
105	/* get_label_uuid() closes fd in all cases (success & failure) */
106	if (get_label_uuid(fd, &label, &uuid) == 0) {
107		/* uuidcache_addentry() takes ownership of all three params */
108		uuidcache_addentry(xstrdup(device), statbuf->st_rdev, label, uuid);
109	}
110	return TRUE;
111}
112
113static void
114uuidcache_init(void)
115{
116	if (uuidCache)
117		return;
118
119	/* We were scanning /proc/partitions
120	 * and /proc/sys/dev/cdrom/info here.
121	 * Missed volume managers. I see that "standard" blkid uses these:
122	 * /dev/mapper/control
123	 * /proc/devices
124	 * /proc/evms/volumes
125	 * /proc/lvm/VGs
126	 * This is unacceptably complex. Let's just scan /dev.
127	 * (Maybe add scanning of /sys/block/XXX/dev for devices
128	 * somehow not having their /dev/XXX entries created?) */
129
130	recursive_action("/dev", ACTION_RECURSE,
131		uuidcache_check_device, /* file_action */
132		NULL, /* dir_action */
133		NULL, /* userData */
134		0 /* depth */);
135}
136
137#define UUID   1
138#define VOL    2
139#define DEVNO  3
140
141static char *
142get_spec_by_x(int n, const char *t, dev_t *devnoPtr)
143{
144	struct uuidCache_s *uc;
145
146	uuidcache_init();
147	uc = uuidCache;
148
149	while (uc) {
150		switch (n) {
151		case UUID:
152			/* case of hex numbers doesn't matter */
153			if (strcasecmp(t, uc->uc_uuid) == 0)
154				goto found;
155			break;
156		case VOL:
157			if (uc->label[0] && strcmp(t, uc->label) == 0)
158				goto found;
159			break;
160		case DEVNO:
161			if (uc->devno == (*devnoPtr))
162				goto found;
163			break;
164		}
165		uc = uc->next;
166	}
167	return NULL;
168
169found:
170	if (devnoPtr)
171		*devnoPtr = uc->devno;
172	return xstrdup(uc->device);
173}
174
175/* Used by blkid */
176void display_uuid_cache(void)
177{
178	struct uuidCache_s *u;
179
180	uuidcache_init();
181	u = uuidCache;
182	while (u) {
183		printf("%s:", u->device);
184		if (u->label[0])
185			printf(" LABEL=\"%s\"", u->label);
186		if (u->uc_uuid[0])
187			printf(" UUID=\"%s\"", u->uc_uuid);
188		bb_putchar('\n');
189		u = u->next;
190	}
191}
192
193/* Used by mount and findfs & old_e2fsprogs */
194
195char *get_devname_from_label(const char *spec)
196{
197	return get_spec_by_x(VOL, spec, NULL);
198}
199
200char *get_devname_from_uuid(const char *spec)
201{
202	return get_spec_by_x(UUID, spec, NULL);
203}
204
205char *get_devname_from_device(dev_t dev)
206{
207	return get_spec_by_x(DEVNO, NULL, &dev);
208}
209
210int resolve_mount_spec(char **fsname)
211{
212	char *tmp = *fsname;
213
214	if (strncmp(*fsname, "UUID=", 5) == 0)
215		tmp = get_devname_from_uuid(*fsname + 5);
216	else if (strncmp(*fsname, "LABEL=", 6) == 0)
217		tmp = get_devname_from_label(*fsname + 6);
218	else
219		return 0; /* no UUID= or LABEL= prefix found */
220
221	if (!tmp)
222		return -2; /* device defined by UUID= or LABEL= wasn't found */
223
224	*fsname = tmp;
225	return 1;
226}
227