blob: fd4ec6232d97cc51f2e74ac22b73cbac020ba7d6 [file] [log] [blame]
bigbiff bigbiffe60683a2013-02-22 20:55:50 -05001/*
2 * No copyright is claimed. This code is in the public domain; do with
3 * it what you wish.
4 *
5 * Written by Karel Zak <kzak@redhat.com>
6 */
7#include <ctype.h>
8#include <fcntl.h>
9#include <unistd.h>
10#include "c.h"
11#include "at.h"
12#include "pathnames.h"
13#include "sysfs.h"
14
15char *sysfs_devno_attribute_path(dev_t devno, char *buf,
16 size_t bufsiz, const char *attr)
17{
18 int len;
19
20 if (attr)
21 len = snprintf(buf, bufsiz, _PATH_SYS_DEVBLOCK "/%d:%d/%s",
22 major(devno), minor(devno), attr);
23 else
24 len = snprintf(buf, bufsiz, _PATH_SYS_DEVBLOCK "/%d:%d",
25 major(devno), minor(devno));
26
27 return (len < 0 || (size_t) len + 1 > bufsiz) ? NULL : buf;
28}
29
30int sysfs_devno_has_attribute(dev_t devno, const char *attr)
31{
32 char path[PATH_MAX];
33 struct stat info;
34
35 if (!sysfs_devno_attribute_path(devno, path, sizeof(path), attr))
36 return 0;
37 if (stat(path, &info) == 0)
38 return 1;
39 return 0;
40}
41
42char *sysfs_devno_path(dev_t devno, char *buf, size_t bufsiz)
43{
44 return sysfs_devno_attribute_path(devno, buf, bufsiz, NULL);
45}
46
47dev_t sysfs_devname_to_devno(const char *name, const char *parent)
48{
49 char buf[PATH_MAX], *path = NULL;
50 dev_t dev = 0;
51
52 if (strncmp("/dev/", name, 5) == 0) {
53 /*
54 * Read from /dev
55 */
56 struct stat st;
57
58 if (stat(name, &st) == 0)
59 dev = st.st_rdev;
60 else
61 name += 5; /* unaccesible, or not node in /dev */
62 }
63
64 if (!dev && parent && strncmp("dm-", name, 3)) {
65 /*
66 * Create path to /sys/block/<parent>/<name>/dev
67 */
68 int len = snprintf(buf, sizeof(buf),
69 _PATH_SYS_BLOCK "/%s/%s/dev", parent, name);
70 if (len < 0 || (size_t) len + 1 > sizeof(buf))
71 return 0;
72 path = buf;
73
74 } else if (!dev) {
75 /*
76 * Create path to /sys/block/<name>/dev
77 */
78 int len = snprintf(buf, sizeof(buf),
79 _PATH_SYS_BLOCK "/%s/dev", name);
80 if (len < 0 || (size_t) len + 1 > sizeof(buf))
81 return 0;
82 path = buf;
83 }
84
85 if (path) {
86 /*
87 * read devno from sysfs
88 */
89 FILE *f;
90 int maj = 0, min = 0;
91
92 f = fopen(path, "r");
93 if (!f)
94 return 0;
95
96 if (fscanf(f, "%d:%d", &maj, &min) == 2)
97 dev = makedev(maj, min);
98 fclose(f);
99 }
100 return dev;
101}
102
103/*
104 * Returns devname (e.g. "/dev/sda1") for the given devno.
105 *
106 * Note that the @buf has to be large enough to store /sys/dev/block/<maj:min>
107 * symlinks.
108 *
109 * Please, use more robust blkid_devno_to_devname() in your applications.
110 */
111char *sysfs_devno_to_devpath(dev_t devno, char *buf, size_t bufsiz)
112{
113 struct sysfs_cxt cxt;
114 char *name;
115 size_t sz;
116 struct stat st;
117
118 if (sysfs_init(&cxt, devno, NULL))
119 return NULL;
120
121 name = sysfs_get_devname(&cxt, buf, bufsiz);
122 sysfs_deinit(&cxt);
123
124 if (!name)
125 return NULL;
126
127 sz = strlen(name);
128
129 if (sz + sizeof("/dev/") > bufsiz)
130 return NULL;
131
132 /* create the final "/dev/<name>" string */
133 memmove(buf + 5, name, sz + 1);
134 memcpy(buf, "/dev/", 5);
135
136 if (!stat(buf, &st) && S_ISBLK(st.st_mode) && st.st_rdev == devno)
137 return buf;
138
139 return NULL;
140}
141
142int sysfs_init(struct sysfs_cxt *cxt, dev_t devno, struct sysfs_cxt *parent)
143{
144 char path[PATH_MAX];
145 int fd, rc;
146
147 memset(cxt, 0, sizeof(*cxt));
148 cxt->dir_fd = -1;
149
150 if (!sysfs_devno_path(devno, path, sizeof(path)))
151 goto err;
152
153 fd = open(path, O_RDONLY);
154 if (fd < 0)
155 goto err;
156 cxt->dir_fd = fd;
157
158 cxt->dir_path = strdup(path);
159 if (!cxt->dir_path)
160 goto err;
161 cxt->devno = devno;
162 cxt->parent = parent;
163 return 0;
164err:
165 rc = errno > 0 ? -errno : -1;
166 sysfs_deinit(cxt);
167 return rc;
168}
169
170void sysfs_deinit(struct sysfs_cxt *cxt)
171{
172 if (!cxt)
173 return;
174
175 if (cxt->dir_fd >= 0)
176 close(cxt->dir_fd);
177 free(cxt->dir_path);
178
179 memset(cxt, 0, sizeof(*cxt));
180
181 cxt->dir_fd = -1;
182}
183
184int sysfs_stat(struct sysfs_cxt *cxt, const char *attr, struct stat *st)
185{
186 int rc = fstat_at(cxt->dir_fd, cxt->dir_path, attr, st, 0);
187
188 if (rc != 0 && errno == ENOENT &&
189 strncmp(attr, "queue/", 6) == 0 && cxt->parent) {
190
191 /* Exception for "queue/<attr>". These attributes are available
192 * for parental devices only
193 */
194 return fstat_at(cxt->parent->dir_fd,
195 cxt->parent->dir_path, attr, st, 0);
196 }
197 return rc;
198}
199
200int sysfs_has_attribute(struct sysfs_cxt *cxt, const char *attr)
201{
202 struct stat st;
203
204 return sysfs_stat(cxt, attr, &st) == 0;
205}
206
207static int sysfs_open(struct sysfs_cxt *cxt, const char *attr)
208{
209 int fd = open_at(cxt->dir_fd, cxt->dir_path, attr, O_RDONLY);
210
211 if (fd == -1 && errno == ENOENT &&
212 strncmp(attr, "queue/", 6) == 0 && cxt->parent) {
213
214 /* Exception for "queue/<attr>". These attributes are available
215 * for parental devices only
216 */
217 fd = open_at(cxt->parent->dir_fd, cxt->dir_path, attr, O_RDONLY);
218 }
219 return fd;
220}
221
222ssize_t sysfs_readlink(struct sysfs_cxt *cxt, const char *attr,
223 char *buf, size_t bufsiz)
224{
225 if (!cxt->dir_path)
226 return -1;
227
228 if (attr)
229 return readlink_at(cxt->dir_fd, cxt->dir_path, attr, buf, bufsiz);
230
231 /* read /sys/dev/block/<maj:min> link */
232 return readlink(cxt->dir_path, buf, bufsiz);
233}
234
235DIR *sysfs_opendir(struct sysfs_cxt *cxt, const char *attr)
236{
237 DIR *dir;
238 int fd = -1;
239
240 if (attr)
241 fd = sysfs_open(cxt, attr);
242
243 else if (cxt->dir_fd >= 0)
244 /* request to open root of device in sysfs (/sys/block/<dev>)
245 * -- we cannot use cxt->sysfs_fd directly, because closedir()
246 * will close this our persistent file descriptor.
247 */
248 fd = dup(cxt->dir_fd);
249
250 if (fd < 0)
251 return NULL;
252
253 dir = fdopendir(fd);
254 if (!dir) {
255 close(fd);
256 return NULL;
257 }
258 if (!attr)
259 rewinddir(dir);
260 return dir;
261}
262
263
264static FILE *sysfs_fopen(struct sysfs_cxt *cxt, const char *attr)
265{
266 int fd = sysfs_open(cxt, attr);
267
268 return fd < 0 ? NULL : fdopen(fd, "r");
269}
270
271
272static struct dirent *xreaddir(DIR *dp)
273{
274 struct dirent *d;
275
276 while ((d = readdir(dp))) {
277 if (!strcmp(d->d_name, ".") ||
278 !strcmp(d->d_name, ".."))
279 continue;
280
281 /* blacklist here? */
282 break;
283 }
284 return d;
285}
286
287int sysfs_is_partition_dirent(DIR *dir, struct dirent *d, const char *parent_name)
288{
289 char path[256];
290
291#ifdef _DIRENT_HAVE_D_TYPE
292 if (d->d_type != DT_DIR &&
293 d->d_type != DT_LNK)
294 return 0;
295#endif
296 if (parent_name) {
297 const char *p = parent_name;
298 size_t len;
299
300 /* /dev/sda --> "sda" */
301 if (*parent_name == '/') {
302 p = strrchr(parent_name, '/');
303 if (!p)
304 return 0;
305 p++;
306 }
307
308 len = strlen(p);
309 if (strlen(d->d_name) <= len)
310 return 0;
311
312 /* partitions subdir name is
313 * "<parent>[:digit:]" or "<parent>p[:digit:]"
314 */
315 return strncmp(p, d->d_name, len) == 0 &&
316 ((*(d->d_name + len) == 'p' && isdigit(*(d->d_name + len + 1)))
317 || isdigit(*(d->d_name + len)));
318 }
319
320 /* Cannot use /partition file, not supported on old sysfs */
321 snprintf(path, sizeof(path), "%s/start", d->d_name);
322
323 return access(path, R_OK) == 0;
324}
325
326/*
327 * Converts @partno (partition number) to devno of the partition.
328 * The @cxt handles wholedisk device.
329 *
330 * Note that this code does not expect any special format of the
331 * partitions devnames.
332 */
333dev_t sysfs_partno_to_devno(struct sysfs_cxt *cxt, int partno)
334{
335 DIR *dir;
336 struct dirent *d;
337 char path[256];
338 dev_t devno = 0;
339
340 dir = sysfs_opendir(cxt, NULL);
341 if (!dir)
342 return 0;
343
344 while ((d = xreaddir(dir))) {
345 int n, maj, min;
346
347 if (!sysfs_is_partition_dirent(dir, d, NULL))
348 continue;
349
350 snprintf(path, sizeof(path), "%s/partition", d->d_name);
351 if (sysfs_read_int(cxt, path, &n))
352 continue;
353
354 if (n == partno) {
355 snprintf(path, sizeof(path), "%s/dev", d->d_name);
356 if (sysfs_scanf(cxt, path, "%d:%d", &maj, &min) == 2)
357 devno = makedev(maj, min);
358 break;
359 }
360 }
361
362 closedir(dir);
363 return devno;
364}
365
366
367int sysfs_scanf(struct sysfs_cxt *cxt, const char *attr, const char *fmt, ...)
368{
369 FILE *f = sysfs_fopen(cxt, attr);
370 va_list ap;
371 int rc;
372
373 if (!f)
374 return -EINVAL;
375 va_start(ap, fmt);
376 rc = vfscanf(f, fmt, ap);
377 va_end(ap);
378
379 fclose(f);
380 return rc;
381}
382
383
384int sysfs_read_s64(struct sysfs_cxt *cxt, const char *attr, int64_t *res)
385{
386 int64_t x = 0;
387
388 if (sysfs_scanf(cxt, attr, "%"SCNd64, &x) == 1) {
389 if (res)
390 *res = x;
391 return 0;
392 }
393 return -1;
394}
395
396int sysfs_read_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t *res)
397{
398 uint64_t x = 0;
399
400 if (sysfs_scanf(cxt, attr, "%"SCNu64, &x) == 1) {
401 if (res)
402 *res = x;
403 return 0;
404 }
405 return -1;
406}
407
408int sysfs_read_int(struct sysfs_cxt *cxt, const char *attr, int *res)
409{
410 int x = 0;
411
412 if (sysfs_scanf(cxt, attr, "%d", &x) == 1) {
413 if (res)
414 *res = x;
415 return 0;
416 }
417 return -1;
418}
419
420char *sysfs_strdup(struct sysfs_cxt *cxt, const char *attr)
421{
422 char buf[1024];
423 return sysfs_scanf(cxt, attr, "%1023[^\n]", buf) == 1 ?
424 strdup(buf) : NULL;
425}
426
427int sysfs_count_dirents(struct sysfs_cxt *cxt, const char *attr)
428{
429 DIR *dir;
430 int r = 0;
431
432 if (!(dir = sysfs_opendir(cxt, attr)))
433 return 0;
434
435 while (xreaddir(dir)) r++;
436
437 closedir(dir);
438 return r;
439}
440
441int sysfs_count_partitions(struct sysfs_cxt *cxt, const char *devname)
442{
443 DIR *dir;
444 struct dirent *d;
445 int r = 0;
446
447 if (!(dir = sysfs_opendir(cxt, NULL)))
448 return 0;
449
450 while ((d = xreaddir(dir))) {
451 if (sysfs_is_partition_dirent(dir, d, devname))
452 r++;
453 }
454
455 closedir(dir);
456 return r;
457}
458
459/*
460 * Returns slave name if there is only one slave, otherwise returns NULL.
461 * The result should be deallocated by free().
462 */
463char *sysfs_get_slave(struct sysfs_cxt *cxt)
464{
465 DIR *dir;
466 struct dirent *d;
467 char *name = NULL;
468
469 if (!(dir = sysfs_opendir(cxt, "slaves")))
470 return NULL;
471
472 while ((d = xreaddir(dir))) {
473 if (name)
474 goto err; /* more slaves */
475
476 name = strdup(d->d_name);
477 }
478
479 closedir(dir);
480 return name;
481err:
482 free(name);
483 closedir(dir);
484 return NULL;
485}
486
487/*
488 * Note that the @buf has to be large enough to store /sys/dev/block/<maj:min>
489 * symlinks.
490 */
491char *sysfs_get_devname(struct sysfs_cxt *cxt, char *buf, size_t bufsiz)
492{
493 char *name = NULL;
494 ssize_t sz;
495
496 sz = sysfs_readlink(cxt, NULL, buf, bufsiz - 1);
497 if (sz < 0)
498 return NULL;
499
500 buf[sz] = '\0';
501 name = strrchr(buf, '/');
502 if (!name)
503 return NULL;
504
505 name++;
506 sz = strlen(name);
507
508 memmove(buf, name, sz + 1);
509 return buf;
510}
511
512/* returns basename and keeps dirname in the @path */
513static char *stripoff_last_component(char *path)
514{
515 char *p = strrchr(path, '/');
516
517 if (!p)
518 return NULL;
519 *p = '\0';
520 return ++p;
521}
522
523static int get_dm_wholedisk(struct sysfs_cxt *cxt, char *diskname,
524 size_t len, dev_t *diskdevno)
525{
526 int rc = 0;
527 char *name;
528
529 /* Note, sysfs_get_slave() returns the first slave only,
530 * if there is more slaves, then return NULL
531 */
532 name = sysfs_get_slave(cxt);
533 if (!name)
534 return -1;
535
536 if (diskname && len) {
537 strncpy(diskname, name, len);
538 diskname[len - 1] = '\0';
539 }
540
541 if (diskdevno) {
542 *diskdevno = sysfs_devname_to_devno(name, NULL);
543 if (!*diskdevno)
544 rc = -1;
545 }
546
547 free(name);
548 return rc;
549}
550
551int sysfs_devno_to_wholedisk(dev_t dev, char *diskname,
552 size_t len, dev_t *diskdevno)
553{
554 struct sysfs_cxt cxt;
555 int is_part = 0;
556
557 if (!dev || sysfs_init(&cxt, dev, NULL) != 0)
558 return -1;
559
560 is_part = sysfs_has_attribute(&cxt, "partition");
561 if (!is_part) {
562 /*
563 * Extra case for partitions mapped by device-mapper.
564 *
565 * All regualar partitions (added by BLKPG ioctl or kernel PT
566 * parser) have the /sys/.../partition file. The partitions
567 * mapped by DM don't have such file, but they have "part"
568 * prefix in DM UUID.
569 */
570 char *uuid = sysfs_strdup(&cxt, "dm/uuid");
571 char *tmp = uuid;
572 char *prefix = uuid ? strsep(&tmp, "-") : NULL;
573
574 if (prefix && strncasecmp(prefix, "part", 4) == 0)
575 is_part = 1;
576 free(uuid);
577
578 if (is_part &&
579 get_dm_wholedisk(&cxt, diskname, len, diskdevno) == 0)
580 /*
581 * partitioned device, mapped by DM
582 */
583 goto done;
584
585 is_part = 0;
586 }
587
588 if (!is_part) {
589 /*
590 * unpartitioned device
591 */
592 if (diskname && len) {
593 if (!sysfs_get_devname(&cxt, diskname, len))
594 goto err;
595 }
596 if (diskdevno)
597 *diskdevno = dev;
598
599 } else {
600 /*
601 * partitioned device
602 * - readlink /sys/dev/block/8:1 = ../../block/sda/sda1
603 * - dirname ../../block/sda/sda1 = ../../block/sda
604 * - basename ../../block/sda = sda
605 */
606 char linkpath[PATH_MAX];
607 char *name;
608 int linklen;
609
610 linklen = sysfs_readlink(&cxt, NULL,
611 linkpath, sizeof(linkpath) - 1);
612 if (linklen < 0)
613 goto err;
614 linkpath[linklen] = '\0';
615
616 stripoff_last_component(linkpath); /* dirname */
617 name = stripoff_last_component(linkpath); /* basename */
618 if (!name)
619 goto err;
620
621 if (diskname && len) {
622 strncpy(diskname, name, len);
623 diskname[len - 1] = '\0';
624 }
625
626 if (diskdevno) {
627 *diskdevno = sysfs_devname_to_devno(name, NULL);
628 if (!*diskdevno)
629 goto err;
630 }
631 }
632
633done:
634 sysfs_deinit(&cxt);
635 return 0;
636err:
637 sysfs_deinit(&cxt);
638 return -1;
639}
640
641
642int sysfs_scsi_get_hctl(struct sysfs_cxt *cxt, int *h, int *c, int *t, int *l)
643{
644 char buf[PATH_MAX], *hctl;
645 ssize_t len;
646
647 if (!cxt)
648 return -EINVAL;
649 if (cxt->has_hctl)
650 goto done;
651
652 len = sysfs_readlink(cxt, "device", buf, sizeof(buf) - 1);
653 if (len < 0)
654 return len;
655
656 buf[len] = '\0';
657 hctl = strrchr(buf, '/') + 1;
658 if (!hctl)
659 return -1;
660
661 if (sscanf(hctl, "%d:%d:%d:%d", &cxt->scsi_host, &cxt->scsi_channel,
662 &cxt->scsi_target, &cxt->scsi_lun) != 4)
663 return -1;
664
665 cxt->has_hctl = 1;
666done:
667 if (h)
668 *h = cxt->scsi_host;
669 if (c)
670 *c = cxt->scsi_channel;
671 if (t)
672 *t = cxt->scsi_target;
673 if (l)
674 *l = cxt->scsi_lun;
675 return 0;
676}
677
678
679static char *sysfs_scsi_host_attribute_path(struct sysfs_cxt *cxt,
680 const char *type, char *buf, size_t bufsz, const char *attr)
681{
682 int len;
683 int host;
684
685 if (sysfs_scsi_get_hctl(cxt, &host, NULL, NULL, NULL))
686 return NULL;
687
688 if (attr)
689 len = snprintf(buf, bufsz, _PATH_SYS_CLASS "/%s_host/host%d/%s",
690 type, host, attr);
691 else
692 len = snprintf(buf, bufsz, _PATH_SYS_CLASS "/%s_host/host%d",
693 type, host);
694
695 return (len < 0 || (size_t) len + 1 > bufsz) ? NULL : buf;
696}
697
698char *sysfs_scsi_host_strdup_attribute(struct sysfs_cxt *cxt,
699 const char *type, const char *attr)
700{
701 char buf[1024];
702 int rc;
703 FILE *f;
704
705 if (!attr || !type ||
706 !sysfs_scsi_host_attribute_path(cxt, type, buf, sizeof(buf), attr))
707 return NULL;
708
709 if (!(f = fopen(buf, "r")))
710 return NULL;
711
712 rc = fscanf(f, "%1023[^\n]", buf);
713 fclose(f);
714
715 return rc == 1 ? strdup(buf) : NULL;
716}
717
718int sysfs_scsi_host_is(struct sysfs_cxt *cxt, const char *type)
719{
720 char buf[PATH_MAX];
721 struct stat st;
722
723 if (!type || !sysfs_scsi_host_attribute_path(cxt, type,
724 buf, sizeof(buf), NULL))
725 return 0;
726
727 return stat(buf, &st) == 0 && S_ISDIR(st.st_mode);
728}
729
730static char *sysfs_scsi_attribute_path(struct sysfs_cxt *cxt,
731 char *buf, size_t bufsz, const char *attr)
732{
733 int len, h, c, t, l;
734
735 if (sysfs_scsi_get_hctl(cxt, &h, &c, &t, &l) != 0)
736 return NULL;
737
738 if (attr)
739 len = snprintf(buf, bufsz, _PATH_SYS_SCSI "/devices/%d:%d:%d:%d/%s",
740 h,c,t,l, attr);
741 else
742 len = snprintf(buf, bufsz, _PATH_SYS_SCSI "/devices/%d:%d:%d:%d",
743 h,c,t,l);
744 return (len < 0 || (size_t) len + 1 > bufsz) ? NULL : buf;
745}
746
747int sysfs_scsi_has_attribute(struct sysfs_cxt *cxt, const char *attr)
748{
749 char path[PATH_MAX];
750 struct stat st;
751
752 if (!sysfs_scsi_attribute_path(cxt, path, sizeof(path), attr))
753 return 0;
754
755 return stat(path, &st) == 0;
756}
757
758int sysfs_scsi_path_contains(struct sysfs_cxt *cxt, const char *pattern)
759{
760 char path[PATH_MAX], linkc[PATH_MAX];
761 struct stat st;
762 ssize_t len;
763
764 if (!sysfs_scsi_attribute_path(cxt, path, sizeof(path), NULL))
765 return 0;
766
767 if (stat(path, &st) != 0)
768 return 0;
769
770 len = readlink(path, linkc, sizeof(linkc) - 1);
771 if (len < 0)
772 return 0;
773
774 linkc[len] = '\0';
775 return strstr(linkc, pattern) != NULL;
776}
777
778#ifdef TEST_PROGRAM_SYSFS
779#include <errno.h>
780#include <err.h>
781#include <stdlib.h>
782
783int main(int argc, char *argv[])
784{
785 struct sysfs_cxt cxt = UL_SYSFSCXT_EMPTY;
786 char *devname;
787 dev_t devno;
788 char path[PATH_MAX];
789 int i, is_part;
790 uint64_t u64;
791 ssize_t len;
792
793 if (argc != 2)
794 errx(EXIT_FAILURE, "usage: %s <devname>", argv[0]);
795
796 devname = argv[1];
797 devno = sysfs_devname_to_devno(devname, NULL);
798
799 if (!devno)
800 err(EXIT_FAILURE, "failed to read devno");
801
802 is_part = sysfs_devno_has_attribute(devno, "partition");
803
804 printf("NAME: %s\n", devname);
805 printf("DEVNO: %u (%d:%d)\n", (unsigned int) devno, major(devno), minor(devno));
806 printf("DEVNOPATH: %s\n", sysfs_devno_path(devno, path, sizeof(path)));
807 printf("DEVPATH: %s\n", sysfs_devno_to_devpath(devno, path, sizeof(path)));
808 printf("PARTITION: %s\n", is_part ? "YES" : "NOT");
809
810 if (sysfs_init(&cxt, devno, NULL))
811 return EXIT_FAILURE;
812
813 len = sysfs_readlink(&cxt, NULL, path, sizeof(path) - 1);
814 if (len > 0) {
815 path[len] = '\0';
816 printf("DEVNOLINK: %s\n", path);
817 }
818
819 if (!is_part) {
820 printf("First 5 partitions:\n");
821 for (i = 1; i <= 5; i++) {
822 dev_t dev = sysfs_partno_to_devno(&cxt, i);
823 if (dev)
824 printf("\t#%d %d:%d\n", i, major(dev), minor(dev));
825 }
826 }
827
828 printf("SLAVES: %d\n", sysfs_count_dirents(&cxt, "slaves"));
829
830 if (sysfs_read_u64(&cxt, "size", &u64))
831 printf("read SIZE failed\n");
832 else
833 printf("SIZE: %jd\n", u64);
834
835 if (sysfs_read_int(&cxt, "queue/hw_sector_size", &i))
836 printf("read SECTOR failed\n");
837 else
838 printf("SECTOR: %d\n", i);
839
840 printf("DEVNAME: %s\n", sysfs_get_devname(&cxt, path, sizeof(path)));
841
842 sysfs_deinit(&cxt);
843 return EXIT_SUCCESS;
844}
845#endif