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 if (strcmp(token
, "ID") == 0)
63 return 0; /* non-content tag */
65 pr
= blkid_new_probe();
69 blkid_probe_enable_superblocks(pr
, TRUE
);
70 blkid_probe_set_superblocks_flags(pr
,
71 BLKID_SUBLKS_LABEL
| BLKID_SUBLKS_UUID
);
73 blkid_probe_enable_partitions(pr
, TRUE
);
74 blkid_probe_set_partitions_flags(pr
, BLKID_PARTS_ENTRY_DETAILS
);
76 fd
= open(devname
, O_RDONLY
|O_CLOEXEC
|O_NONBLOCK
);
81 if (blkid_probe_set_device(pr
, fd
, 0, 0))
83 rc
= blkid_do_safeprobe(pr
);
86 rc
= blkid_probe_lookup_value(pr
, name
, &data
, &len
);
88 rc
= memcmp(value
, data
, len
);
90 DBG(EVALUATE
, ul_debug("%s: %s verification %s",
91 devname
, name
, rc
== 0 ? "PASS" : "FAILED"));
96 /* for non-root users we use unverified udev links */
97 return errsv
== EACCES
? 0 : rc
;
99 #endif /* CONFIG_BLKID_VERIFY_UDEV*/
103 * @devname: absolute path to the device
104 * @action: event string
106 * Returns: -1 in case of failure, or 0 on success.
108 int blkid_send_uevent(const char *devname
, const char *action
)
110 char uevent
[PATH_MAX
];
115 DBG(EVALUATE
, ul_debug("%s: uevent '%s' requested", devname
, action
));
117 if (!devname
|| !action
)
119 if (stat(devname
, &st
) || !S_ISBLK(st
.st_mode
))
122 snprintf(uevent
, sizeof(uevent
), "/sys/dev/block/%d:%d/uevent",
123 major(st
.st_rdev
), minor(st
.st_rdev
));
125 f
= fopen(uevent
, "w" UL_CLOEXECSTR
);
128 if (fputs(action
, f
) >= 0)
130 if (close_stream(f
) != 0)
131 DBG(EVALUATE
, ul_debug("write failed: %s", uevent
));
133 DBG(EVALUATE
, ul_debug("%s: send uevent %s",
134 uevent
, rc
== 0 ? "SUCCESS" : "FAILED"));
138 static char *evaluate_by_udev(const char *token
, const char *value
, int uevent
)
145 DBG(EVALUATE
, ul_debug("evaluating by udev %s=%s", token
, value
));
147 if (!strcmp(token
, "UUID"))
148 strcpy(dev
, _PATH_DEV_BYUUID
"/");
149 else if (!strcmp(token
, "LABEL"))
150 strcpy(dev
, _PATH_DEV_BYLABEL
"/");
151 else if (!strcmp(token
, "PARTLABEL"))
152 strcpy(dev
, _PATH_DEV_BYPARTLABEL
"/");
153 else if (!strcmp(token
, "PARTUUID"))
154 strcpy(dev
, _PATH_DEV_BYPARTUUID
"/");
155 else if (!strcmp(token
, "ID"))
156 strcpy(dev
, _PATH_DEV_BYID
"/");
158 DBG(EVALUATE
, ul_debug("unsupported token %s", token
));
159 return NULL
; /* unsupported tag */
163 if (blkid_encode_string(value
, &dev
[len
], sizeof(dev
) - len
) != 0)
166 DBG(EVALUATE
, ul_debug("expected udev link: %s", dev
));
169 goto failed
; /* link or device does not exist */
171 if (!S_ISBLK(st
.st_mode
))
174 path
= canonicalize_path(dev
);
178 #ifdef CONFIG_BLKID_VERIFY_UDEV
179 if (verify_tag(path
, token
, value
))
185 DBG(EVALUATE
, ul_debug("failed to evaluate by udev"));
188 blkid_send_uevent(path
, "change");
193 static char *evaluate_by_scan(const char *token
, const char *value
,
194 blkid_cache
*cache
, struct blkid_config
*conf
)
196 blkid_cache c
= cache
? *cache
: NULL
;
199 DBG(EVALUATE
, ul_debug("evaluating by blkid scan %s=%s", token
, value
));
202 char *cachefile
= blkid_get_cache_filename(conf
);
203 blkid_get_cache(&c
, cachefile
);
209 res
= blkid_get_devname(c
, token
, value
);
220 * blkid_evaluate_tag:
221 * @token: token name (e.g "LABEL" or "UUID") or unparsed tag (e.g. "LABEL=foo")
222 * @value: token data (e.g. "foo")
223 * @cache: pointer to cache (or NULL when you don't want to re-use the cache)
225 * Returns: allocated string with a device name.
227 char *blkid_evaluate_tag(const char *token
, const char *value
, blkid_cache
*cache
)
229 struct blkid_config
*conf
= NULL
;
230 char *t
= NULL
, *v
= NULL
;
237 if (!cache
|| !*cache
)
240 DBG(EVALUATE
, ul_debug("evaluating %s%s%s", token
, value
? "=" : "",
241 value
? value
: ""));
244 if (!strchr(token
, '=')) {
248 if (blkid_parse_tag_string(token
, &t
, &v
) != 0 || !t
|| !v
)
254 conf
= blkid_read_config(NULL
);
258 for (i
= 0; i
< conf
->nevals
; i
++) {
259 if (conf
->eval
[i
] == BLKID_EVAL_UDEV
)
260 ret
= evaluate_by_udev(token
, value
, conf
->uevent
);
261 else if (conf
->eval
[i
] == BLKID_EVAL_SCAN
)
262 ret
= evaluate_by_scan(token
, value
, cache
, conf
);
267 DBG(EVALUATE
, ul_debug("%s=%s evaluated as %s", token
, value
, ret
));
269 blkid_free_config(conf
);
276 * blkid_evaluate_spec:
277 * @spec: unparsed tag (e.g. "LABEL=foo") or path (e.g. /dev/dm-0)
278 * @cache: pointer to cache (or NULL when you don't want to re-use the cache)
280 * All returned paths are canonicalized, device-mapper paths are converted
281 * to the /dev/mapper/name format.
283 * Returns: allocated string with a device name.
285 char *blkid_evaluate_spec(const char *spec
, blkid_cache
*cache
)
287 char *t
= NULL
, *v
= NULL
, *res
;
292 if (strchr(spec
, '=') &&
293 blkid_parse_tag_string(spec
, &t
, &v
) != 0) /* parse error */
297 res
= blkid_evaluate_tag(t
, v
, cache
);
299 res
= canonicalize_path(spec
);
308 int main(int argc
, char *argv
[])
310 blkid_cache cache
= NULL
;
314 fprintf(stderr
, "usage: %s <tag> | <spec>\n", argv
[0]);
320 res
= blkid_evaluate_spec(argv
[1], &cache
);
324 blkid_put_cache(cache
);
326 return res
? EXIT_SUCCESS
: EXIT_FAILURE
;