2 * evaluate.c - very high-level API to evaluate LABELs or UUIDs
4 * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
6 * This file may be redistributed under the terms of the
7 * GNU Lesser General Public License.
15 #include <sys/types.h>
16 #ifdef HAVE_SYS_STAT_H
25 #include "pathnames.h"
26 #include "canonicalize.h"
27 #include "closestream.h"
33 * @title: Tags and Spec evaluation
34 * @short_description: top-level API for LABEL and UUID evaluation.
36 * This API provides very simple and portable way how evaluate LABEL and UUID
37 * tags. The blkid_evaluate_tag() and blkid_evaluate_spec() work on 2.4 and
38 * 2.6 systems and on systems with or without udev. Currently, the libblkid
39 * library supports "udev" and "scan" methods. The "udev" method uses udev
40 * /dev/disk/by-* symlinks and the "scan" method scans all block devices from
41 * the /proc/partitions file. The evaluation could be controlled by the
42 * /etc/blkid.conf config file. The default is to try "udev" and then "scan"
45 * The blkid_evaluate_tag() also automatically informs udevd when an obsolete
46 * /dev/disk/by-* symlink is detected.
48 * If you are not sure how translate LABEL or UUID to the device name use this
52 #ifdef CONFIG_BLKID_VERIFY_UDEV
53 /* returns zero when the device has NAME=value (LABEL/UUID) */
54 static int verify_tag(const char *devname
, const char *name
, const char *value
)
62 pr
= blkid_new_probe();
66 blkid_probe_enable_superblocks(pr
, TRUE
);
67 blkid_probe_set_superblocks_flags(pr
,
68 BLKID_SUBLKS_LABEL
| BLKID_SUBLKS_UUID
);
70 blkid_probe_enable_partitions(pr
, TRUE
);
71 blkid_probe_set_partitions_flags(pr
, BLKID_PARTS_ENTRY_DETAILS
);
73 fd
= open(devname
, O_RDONLY
|O_CLOEXEC
);
78 if (blkid_probe_set_device(pr
, fd
, 0, 0))
80 rc
= blkid_do_safeprobe(pr
);
83 rc
= blkid_probe_lookup_value(pr
, name
, &data
, &len
);
85 rc
= memcmp(value
, data
, len
);
87 DBG(EVALUATE
, ul_debug("%s: %s verification %s",
88 devname
, name
, rc
== 0 ? "PASS" : "FAILED"));
93 /* for non-root users we use unverified udev links */
94 return errsv
== EACCES
? 0 : rc
;
96 #endif /* CONFIG_BLKID_VERIFY_UDEV*/
100 * @devname: absolute path to the device
101 * @action: event string
103 * Returns: -1 in case of failure, or 0 on success.
105 int blkid_send_uevent(const char *devname
, const char *action
)
107 char uevent
[PATH_MAX
];
112 DBG(EVALUATE
, ul_debug("%s: uevent '%s' requested", devname
, action
));
114 if (!devname
|| !action
)
116 if (stat(devname
, &st
) || !S_ISBLK(st
.st_mode
))
119 snprintf(uevent
, sizeof(uevent
), "/sys/dev/block/%d:%d/uevent",
120 major(st
.st_rdev
), minor(st
.st_rdev
));
122 f
= fopen(uevent
, "w" UL_CLOEXECSTR
);
125 if (fputs(action
, f
) >= 0)
127 if (close_stream(f
) != 0)
128 DBG(EVALUATE
, ul_debug("write failed: %s", uevent
));
130 DBG(EVALUATE
, ul_debug("%s: send uevent %s",
131 uevent
, rc
== 0 ? "SUCCES" : "FAILED"));
135 static char *evaluate_by_udev(const char *token
, const char *value
, int uevent
)
142 DBG(EVALUATE
, ul_debug("evaluating by udev %s=%s", token
, value
));
144 if (!strcmp(token
, "UUID"))
145 strcpy(dev
, _PATH_DEV_BYUUID
"/");
146 else if (!strcmp(token
, "LABEL"))
147 strcpy(dev
, _PATH_DEV_BYLABEL
"/");
148 else if (!strcmp(token
, "PARTLABEL"))
149 strcpy(dev
, _PATH_DEV_BYPARTLABEL
"/");
150 else if (!strcmp(token
, "PARTUUID"))
151 strcpy(dev
, _PATH_DEV_BYPARTUUID
"/");
153 DBG(EVALUATE
, ul_debug("unsupported token %s", token
));
154 return NULL
; /* unsupported tag */
158 if (blkid_encode_string(value
, &dev
[len
], sizeof(dev
) - len
) != 0)
161 DBG(EVALUATE
, ul_debug("expected udev link: %s", dev
));
164 goto failed
; /* link or device does not exist */
166 if (!S_ISBLK(st
.st_mode
))
169 path
= canonicalize_path(dev
);
173 #ifdef CONFIG_BLKID_VERIFY_UDEV
174 if (verify_tag(path
, token
, value
))
180 DBG(EVALUATE
, ul_debug("failed to evaluate by udev"));
183 blkid_send_uevent(path
, "change");
188 static char *evaluate_by_scan(const char *token
, const char *value
,
189 blkid_cache
*cache
, struct blkid_config
*conf
)
191 blkid_cache c
= cache
? *cache
: NULL
;
194 DBG(EVALUATE
, ul_debug("evaluating by blkid scan %s=%s", token
, value
));
197 char *cachefile
= blkid_get_cache_filename(conf
);
198 blkid_get_cache(&c
, cachefile
);
204 res
= blkid_get_devname(c
, token
, value
);
215 * blkid_evaluate_tag:
216 * @token: token name (e.g "LABEL" or "UUID") or unparsed tag (e.g. "LABEL=foo")
217 * @value: token data (e.g. "foo")
218 * @cache: pointer to cache (or NULL when you don't want to re-use the cache)
220 * Returns: allocated string with a device name.
222 char *blkid_evaluate_tag(const char *token
, const char *value
, blkid_cache
*cache
)
224 struct blkid_config
*conf
= NULL
;
225 char *t
= NULL
, *v
= NULL
;
232 if (!cache
|| !*cache
)
235 DBG(EVALUATE
, ul_debug("evaluating %s%s%s", token
, value
? "=" : "",
236 value
? value
: ""));
239 if (!strchr(token
, '=')) {
243 blkid_parse_tag_string(token
, &t
, &v
);
250 conf
= blkid_read_config(NULL
);
254 for (i
= 0; i
< conf
->nevals
; i
++) {
255 if (conf
->eval
[i
] == BLKID_EVAL_UDEV
)
256 ret
= evaluate_by_udev(token
, value
, conf
->uevent
);
257 else if (conf
->eval
[i
] == BLKID_EVAL_SCAN
)
258 ret
= evaluate_by_scan(token
, value
, cache
, conf
);
263 DBG(EVALUATE
, ul_debug("%s=%s evaluated as %s", token
, value
, ret
));
265 blkid_free_config(conf
);
272 * blkid_evaluate_spec:
273 * @spec: unparsed tag (e.g. "LABEL=foo") or path (e.g. /dev/dm-0)
274 * @cache: pointer to cache (or NULL when you don't want to re-use the cache)
276 * All returned paths are canonicalized, device-mapper paths are converted
277 * to the /dev/mapper/name format.
279 * Returns: allocated string with a device name.
281 char *blkid_evaluate_spec(const char *spec
, blkid_cache
*cache
)
283 char *t
= NULL
, *v
= NULL
, *res
;
288 if (strchr(spec
, '=') &&
289 blkid_parse_tag_string(spec
, &t
, &v
) != 0) /* parse error */
293 res
= blkid_evaluate_tag(t
, v
, cache
);
295 res
= canonicalize_path(spec
);
304 int main(int argc
, char *argv
[])
306 blkid_cache cache
= NULL
;
310 fprintf(stderr
, "usage: %s <tag> | <spec>\n", argv
[0]);
316 res
= blkid_evaluate_spec(argv
[1], &cache
);
320 blkid_put_cache(cache
);
322 return res
? EXIT_SUCCESS
: EXIT_FAILURE
;