2 * No copyright is claimed. This code is in the public domain; do with
5 * Copyright (C) 2018 Karel Zak <kzak@redhat.com>
8 * Simple functions to access files. Paths can be globally prefixed to read
9 * data from an alternative source (e.g. a /proc dump for regression tests).
11 * The paths is possible to format by printf-like way for functions with "f"
12 * postfix in the name (e.g. readf, openf, ... ul_path_readf_u64()).
14 * The ul_path_read_* API is possible to use without path_cxt handler. In this
15 * case is not possible to use global prefix and printf-like formatting.
25 #include "fileutils.h"
32 * Debug stuff (based on include/debug.h)
34 static UL_DEBUG_DEFINE_MASK(ulpath
);
35 UL_DEBUG_DEFINE_MASKNAMES(ulpath
) = UL_DEBUG_EMPTY_MASKNAMES
;
37 #define ULPATH_DEBUG_INIT (1 << 1)
38 #define ULPATH_DEBUG_CXT (1 << 2)
40 #define DBG(m, x) __UL_DBG(ulpath, ULPATH_DEBUG_, m, x)
41 #define ON_DBG(m, x) __UL_DBG_CALL(ulpath, ULPATH_DEBUG_, m, x)
43 #define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(ulpath)
46 void ul_path_init_debug(void)
48 if (ulpath_debug_mask
)
50 __UL_INIT_DEBUG_FROM_ENV(ulpath
, ULPATH_DEBUG_
, 0, ULPATH_DEBUG
);
53 struct path_cxt
*ul_new_path(const char *dir
, ...)
55 struct path_cxt
*pc
= calloc(1, sizeof(*pc
));
60 DBG(CXT
, ul_debugobj(pc
, "alloc"));
70 rc
= vasprintf(&pc
->dir_path
, dir
, ap
);
73 if (rc
< 0 || !pc
->dir_path
)
82 void ul_ref_path(struct path_cxt
*pc
)
88 void ul_unref_path(struct path_cxt
*pc
)
95 if (pc
->refcount
<= 0) {
96 DBG(CXT
, ul_debugobj(pc
, "dealloc"));
99 ul_path_close_dirfd(pc
);
106 int ul_path_set_prefix(struct path_cxt
*pc
, const char *prefix
)
110 assert(pc
->dir_fd
< 0);
120 DBG(CXT
, ul_debugobj(pc
, "new prefix: '%s'", p
));
124 const char *ul_path_get_prefix(struct path_cxt
*pc
)
126 return pc
? pc
->prefix
: NULL
;
129 int ul_path_set_dir(struct path_cxt
*pc
, const char *dir
)
139 if (pc
->dir_fd
>= 0) {
146 DBG(CXT
, ul_debugobj(pc
, "new dir: '%s'", p
));
150 const char *ul_path_get_dir(struct path_cxt
*pc
)
152 return pc
? pc
->dir_path
: NULL
;
155 int ul_path_set_dialect(struct path_cxt
*pc
, void *data
, void free_data(struct path_cxt
*))
158 pc
->free_dialect
= free_data
;
159 DBG(CXT
, ul_debugobj(pc
, "(re)set dialect"));
163 void *ul_path_get_dialect(struct path_cxt
*pc
)
165 return pc
? pc
->dialect
: NULL
;
168 int ul_path_set_enoent_redirect(struct path_cxt
*pc
, int (*func
)(struct path_cxt
*, const char *, int *))
170 pc
->redirect_on_enoent
= func
;
174 static const char *get_absdir(struct path_cxt
*pc
)
182 dirpath
= pc
->dir_path
;
188 rc
= snprintf(pc
->path_buffer
, sizeof(pc
->path_buffer
), "%s/%s", pc
->prefix
, dirpath
);
191 if ((size_t)rc
>= sizeof(pc
->path_buffer
)) {
192 errno
= ENAMETOOLONG
;
196 return pc
->path_buffer
;
199 int ul_path_is_accessible(struct path_cxt
*pc
)
207 path
= get_absdir(pc
);
210 return access(path
, F_OK
) == 0;
213 int ul_path_get_dirfd(struct path_cxt
*pc
)
216 assert(pc
->dir_path
);
218 if (pc
->dir_fd
< 0) {
219 const char *path
= get_absdir(pc
);
223 DBG(CXT
, ul_debugobj(pc
, "opening dir: '%s'", path
));
224 pc
->dir_fd
= open(path
, O_RDONLY
|O_CLOEXEC
);
230 /* Note that next ul_path_get_dirfd() will reopen the directory */
231 void ul_path_close_dirfd(struct path_cxt
*pc
)
235 if (pc
->dir_fd
>= 0) {
236 DBG(CXT
, ul_debugobj(pc
, "closing dir"));
242 int ul_path_isopen_dirfd(struct path_cxt
*pc
)
244 return pc
&& pc
->dir_fd
>= 0;
247 static const char *ul_path_mkpath(struct path_cxt
*pc
, const char *path
, va_list ap
)
253 rc
= vsnprintf(pc
->path_buffer
, sizeof(pc
->path_buffer
), path
, ap
);
260 if ((size_t)rc
>= sizeof(pc
->path_buffer
)) {
261 errno
= ENAMETOOLONG
;
265 return pc
->path_buffer
;
268 char *ul_path_get_abspath(struct path_cxt
*pc
, char *buf
, size_t bufsz
, const char *path
, ...)
273 const char *tail
= NULL
, *dirpath
= pc
->dir_path
;
276 tail
= ul_path_mkpath(pc
, path
, ap
);
279 if (dirpath
&& *dirpath
== '/')
281 if (tail
&& *tail
== '/')
284 rc
= snprintf(buf
, bufsz
, "%s/%s/%s",
285 pc
->prefix
? pc
->prefix
: "",
286 dirpath
? dirpath
: "",
289 if ((size_t)rc
>= bufsz
) {
290 errno
= ENAMETOOLONG
;
294 const char *tmp
= get_absdir(pc
);
298 xstrncpy(buf
, tmp
, bufsz
);
305 int ul_path_access(struct path_cxt
*pc
, int mode
, const char *path
)
310 rc
= access(path
, mode
);
311 DBG(CXT
, ul_debug("access '%s' [no context, rc=%d]", path
, rc
));
313 int dir
= ul_path_get_dirfd(pc
);
319 rc
= faccessat(dir
, path
, mode
, 0);
321 if (rc
&& errno
== ENOENT
322 && pc
->redirect_on_enoent
323 && pc
->redirect_on_enoent(pc
, path
, &dir
) == 0)
324 rc
= faccessat(dir
, path
, mode
, 0);
326 DBG(CXT
, ul_debugobj(pc
, "access: '%s' [rc=%d]", path
, rc
));
331 int ul_path_accessf(struct path_cxt
*pc
, int mode
, const char *path
, ...)
337 p
= ul_path_mkpath(pc
, path
, ap
);
340 return !p
? -errno
: ul_path_access(pc
, mode
, p
);
343 int ul_path_stat(struct path_cxt
*pc
, struct stat
*sb
, int flags
, const char *path
)
348 rc
= path
? stat(path
, sb
) : -EINVAL
;
349 DBG(CXT
, ul_debug("stat '%s' [no context, rc=%d]", path
, rc
));
351 int dir
= ul_path_get_dirfd(pc
);
357 rc
= fstatat(dir
, path
, sb
, flags
);
360 rc
= fstat(dir
, sb
); /* dir itself */
362 if (rc
&& errno
== ENOENT
364 && pc
->redirect_on_enoent
365 && pc
->redirect_on_enoent(pc
, path
, &dir
) == 0)
366 rc
= fstatat(dir
, path
, sb
, 0);
368 DBG(CXT
, ul_debugobj(pc
, "stat '%s' [rc=%d]", path
, rc
));
373 int ul_path_open(struct path_cxt
*pc
, int flags
, const char *path
)
380 fd
= open(path
, flags
);
381 DBG(CXT
, ul_debug("opening '%s' [no context]", path
));
384 int dir
= ul_path_get_dirfd(pc
);
391 fdx
= fd
= openat(dir
, path
, flags
);
393 if (fd
< 0 && errno
== ENOENT
394 && pc
->redirect_on_enoent
395 && pc
->redirect_on_enoent(pc
, path
, &dir
) == 0)
396 fd
= openat(dir
, path
, flags
);
398 DBG(CXT
, ul_debugobj(pc
, "opening '%s'%s", path
, fdx
!= fd
? " [redirected]" : ""));
403 int ul_path_vopenf(struct path_cxt
*pc
, int flags
, const char *path
, va_list ap
)
405 const char *p
= ul_path_mkpath(pc
, path
, ap
);
407 return !p
? -errno
: ul_path_open(pc
, flags
, p
);
410 int ul_path_openf(struct path_cxt
*pc
, int flags
, const char *path
, ...)
416 rc
= ul_path_vopenf(pc
, flags
, path
, ap
);
423 * Maybe stupid, but good enough ;-)
425 static int mode2flags(const char *mode
)
430 for (p
= mode
; p
&& *p
; p
++) {
431 if (*p
== 'r' && *(p
+ 1) == '+')
436 else if (*p
== 'w' && *(p
+ 1) == '+')
437 flags
|= O_RDWR
| O_TRUNC
;
439 flags
|= O_WRONLY
| O_TRUNC
;
441 else if (*p
== 'a' && *(p
+ 1) == '+')
442 flags
|= O_RDWR
| O_APPEND
;
444 flags
|= O_WRONLY
| O_APPEND
;
446 else if (*p
== *UL_CLOEXECSTR
)
454 FILE *ul_path_fopen(struct path_cxt
*pc
, const char *mode
, const char *path
)
456 int flags
= mode2flags(mode
);
457 int fd
= ul_path_open(pc
, flags
, path
);
462 return fdopen(fd
, mode
);
466 FILE *ul_path_vfopenf(struct path_cxt
*pc
, const char *mode
, const char *path
, va_list ap
)
468 const char *p
= ul_path_mkpath(pc
, path
, ap
);
470 return !p
? NULL
: ul_path_fopen(pc
, mode
, p
);
473 FILE *ul_path_fopenf(struct path_cxt
*pc
, const char *mode
, const char *path
, ...)
479 f
= ul_path_vfopenf(pc
, mode
, path
, ap
);
486 * Open directory @path in read-onl mode. If the path is NULL then duplicate FD
487 * to the directory addressed by @pc.
489 DIR *ul_path_opendir(struct path_cxt
*pc
, const char *path
)
495 fd
= ul_path_open(pc
, O_RDONLY
|O_CLOEXEC
, path
);
496 else if (pc
->dir_path
) {
499 DBG(CXT
, ul_debugobj(pc
, "duplicate dir path"));
500 dirfd
= ul_path_get_dirfd(pc
);
502 fd
= dup_fd_cloexec(dirfd
, STDERR_FILENO
+ 1);
520 * Open directory @path in read-onl mode. If the path is NULL then duplicate FD
521 * to the directory addressed by @pc.
523 DIR *ul_path_vopendirf(struct path_cxt
*pc
, const char *path
, va_list ap
)
525 const char *p
= ul_path_mkpath(pc
, path
, ap
);
527 return !p
? NULL
: ul_path_opendir(pc
, p
);
531 * Open directory @path in read-onl mode. If the path is NULL then duplicate FD
532 * to the directory addressed by @pc.
534 DIR *ul_path_opendirf(struct path_cxt
*pc
, const char *path
, ...)
540 dir
= ul_path_vopendirf(pc
, path
, ap
);
547 * If @path is NULL then readlink is called on @pc directory.
549 ssize_t
ul_path_readlink(struct path_cxt
*pc
, char *buf
, size_t bufsiz
, const char *path
)
555 const char *p
= get_absdir(pc
);
558 ssz
= readlink(p
, buf
, bufsiz
- 1);
560 dirfd
= ul_path_get_dirfd(pc
);
567 ssz
= readlinkat(dirfd
, path
, buf
, bufsiz
- 1);
576 * If @path is NULL then readlink is called on @pc directory.
578 ssize_t
ul_path_readlinkf(struct path_cxt
*pc
, char *buf
, size_t bufsiz
, const char *path
, ...)
584 p
= ul_path_mkpath(pc
, path
, ap
);
587 return !p
? -errno
: ul_path_readlink(pc
, buf
, bufsiz
, p
);
590 int ul_path_read(struct path_cxt
*pc
, char *buf
, size_t len
, const char *path
)
595 fd
= ul_path_open(pc
, O_RDONLY
|O_CLOEXEC
, path
);
599 DBG(CXT
, ul_debug(" reading '%s'", path
));
600 rc
= read_all(fd
, buf
, len
);
608 int ul_path_vreadf(struct path_cxt
*pc
, char *buf
, size_t len
, const char *path
, va_list ap
)
610 const char *p
= ul_path_mkpath(pc
, path
, ap
);
612 return !p
? -errno
: ul_path_read(pc
, buf
, len
, p
);
615 int ul_path_readf(struct path_cxt
*pc
, char *buf
, size_t len
, const char *path
, ...)
621 rc
= ul_path_vreadf(pc
, buf
, len
, path
, ap
);
629 * Returns newly allocated buffer with data from file. Maximal size is BUFSIZ
630 * (send patch if you need something bigger;-)
632 * Returns size of the string without \0, nothing is allocated if returns <= 0.
634 int ul_path_read_string(struct path_cxt
*pc
, char **str
, const char *path
)
643 rc
= ul_path_read(pc
, buf
, sizeof(buf
) - 1, path
);
647 /* Remove tailing newline (usual in sysfs) */
648 if (rc
> 0 && *(buf
+ rc
- 1) == '\n')
661 int ul_path_readf_string(struct path_cxt
*pc
, char **str
, const char *path
, ...)
667 p
= ul_path_mkpath(pc
, path
, ap
);
670 return !p
? -errno
: ul_path_read_string(pc
, str
, p
);
673 int ul_path_read_buffer(struct path_cxt
*pc
, char *buf
, size_t bufsz
, const char *path
)
675 int rc
= ul_path_read(pc
, buf
, bufsz
- 1, path
);
681 /* Remove tailing newline (usual in sysfs) */
682 if (*(buf
+ rc
- 1) == '\n')
691 int ul_path_readf_buffer(struct path_cxt
*pc
, char *buf
, size_t bufsz
, const char *path
, ...)
697 p
= ul_path_mkpath(pc
, path
, ap
);
700 return !p
? -errno
: ul_path_read_buffer(pc
, buf
, bufsz
, p
);
703 int ul_path_scanf(struct path_cxt
*pc
, const char *path
, const char *fmt
, ...)
709 f
= ul_path_fopen(pc
, "r" UL_CLOEXECSTR
, path
);
713 DBG(CXT
, ul_debug(" fscanf [%s] '%s'", fmt
, path
));
715 va_start(fmt_ap
, fmt
);
716 rc
= vfscanf(f
, fmt
, fmt_ap
);
723 int ul_path_scanff(struct path_cxt
*pc
, const char *path
, va_list ap
, const char *fmt
, ...)
729 f
= ul_path_vfopenf(pc
, "r" UL_CLOEXECSTR
, path
, ap
);
733 va_start(fmt_ap
, fmt
);
734 rc
= vfscanf(f
, fmt
, fmt_ap
);
742 int ul_path_read_s64(struct path_cxt
*pc
, int64_t *res
, const char *path
)
747 rc
= ul_path_scanf(pc
, path
, "%"SCNd64
, &x
);
755 int ul_path_readf_s64(struct path_cxt
*pc
, int64_t *res
, const char *path
, ...)
761 p
= ul_path_mkpath(pc
, path
, ap
);
764 return !p
? -errno
: ul_path_read_s64(pc
, res
, p
);
767 int ul_path_read_u64(struct path_cxt
*pc
, uint64_t *res
, const char *path
)
772 rc
= ul_path_scanf(pc
, path
, "%"SCNu64
, &x
);
780 int ul_path_readf_u64(struct path_cxt
*pc
, uint64_t *res
, const char *path
, ...)
786 p
= ul_path_mkpath(pc
, path
, ap
);
789 return !p
? -errno
: ul_path_read_u64(pc
, res
, p
);
792 int ul_path_read_s32(struct path_cxt
*pc
, int *res
, const char *path
)
796 rc
= ul_path_scanf(pc
, path
, "%d", &x
);
804 int ul_path_readf_s32(struct path_cxt
*pc
, int *res
, const char *path
, ...)
810 p
= ul_path_mkpath(pc
, path
, ap
);
813 return !p
? -errno
: ul_path_read_s32(pc
, res
, p
);
816 int ul_path_read_u32(struct path_cxt
*pc
, unsigned int *res
, const char *path
)
821 rc
= ul_path_scanf(pc
, path
, "%u", &x
);
829 int ul_path_readf_u32(struct path_cxt
*pc
, unsigned int *res
, const char *path
, ...)
835 p
= ul_path_mkpath(pc
, path
, ap
);
838 return !p
? -errno
: ul_path_read_u32(pc
, res
, p
);
841 int ul_path_read_majmin(struct path_cxt
*pc
, dev_t
*res
, const char *path
)
843 int rc
, maj
= 0, min
= 0;
845 rc
= ul_path_scanf(pc
, path
, "%d:%d", &maj
, &min
);
849 *res
= makedev(maj
, min
);
853 int ul_path_readf_majmin(struct path_cxt
*pc
, dev_t
*res
, const char *path
, ...)
859 p
= ul_path_mkpath(pc
, path
, ap
);
862 return !p
? -errno
: ul_path_read_majmin(pc
, res
, p
);
865 int ul_path_write_string(struct path_cxt
*pc
, const char *str
, const char *path
)
870 fd
= ul_path_open(pc
, O_WRONLY
|O_CLOEXEC
, path
);
874 rc
= write_all(fd
, str
, strlen(str
));
882 int ul_path_writef_string(struct path_cxt
*pc
, const char *str
, const char *path
, ...)
888 p
= ul_path_mkpath(pc
, path
, ap
);
891 return !p
? -errno
: ul_path_write_string(pc
, str
, p
);
894 int ul_path_write_s64(struct path_cxt
*pc
, int64_t num
, const char *path
)
896 char buf
[sizeof(stringify_value(LLONG_MAX
))];
900 fd
= ul_path_open(pc
, O_WRONLY
|O_CLOEXEC
, path
);
904 len
= snprintf(buf
, sizeof(buf
), "%" PRId64
, num
);
905 if (len
< 0 || (size_t) len
>= sizeof(buf
))
906 rc
= len
< 0 ? -errno
: -E2BIG
;
908 rc
= write_all(fd
, buf
, len
);
916 int ul_path_write_u64(struct path_cxt
*pc
, uint64_t num
, const char *path
)
918 char buf
[sizeof(stringify_value(ULLONG_MAX
))];
922 fd
= ul_path_open(pc
, O_WRONLY
|O_CLOEXEC
, path
);
926 len
= snprintf(buf
, sizeof(buf
), "%" PRIu64
, num
);
927 if (len
< 0 || (size_t) len
>= sizeof(buf
))
928 rc
= len
< 0 ? -errno
: -E2BIG
;
930 rc
= write_all(fd
, buf
, len
);
938 int ul_path_writef_u64(struct path_cxt
*pc
, uint64_t num
, const char *path
, ...)
944 p
= ul_path_mkpath(pc
, path
, ap
);
947 return !p
? -errno
: ul_path_write_u64(pc
, num
, p
);
951 int ul_path_count_dirents(struct path_cxt
*pc
, const char *path
)
956 dir
= ul_path_opendir(pc
, path
);
960 while (xreaddir(dir
)) r
++;
966 int ul_path_countf_dirents(struct path_cxt
*pc
, const char *path
, ...)
972 p
= ul_path_mkpath(pc
, path
, ap
);
975 return !p
? -errno
: ul_path_count_dirents(pc
, p
);
978 /* first call (when @sub is NULL) opens the directory, last call closes the diretory */
979 int ul_path_next_dirent(struct path_cxt
*pc
, DIR **sub
, const char *dirname
, struct dirent
**d
)
981 if (!pc
|| !sub
|| !d
)
985 *sub
= ul_path_opendir(pc
, dirname
);
1000 * Like fopen() but, @path is always prefixed by @prefix. This function is
1001 * useful in case when ul_path_* API is overkill.
1003 FILE *ul_prefix_fopen(const char *prefix
, const char *path
, const char *mode
)
1010 return fopen(path
, mode
);
1014 snprintf(buf
, sizeof(buf
), "%s/%s", prefix
, path
);
1015 return fopen(buf
, mode
);
1018 #ifdef HAVE_CPU_SET_T
1019 static int ul_path_cpuparse(struct path_cxt
*pc
, cpu_set_t
**set
, int maxcpus
, int islist
, const char *path
, va_list ap
)
1022 size_t setsize
, len
= maxcpus
* 7;
1032 f
= ul_path_vfopenf(pc
, "r" UL_CLOEXECSTR
, path
, ap
);
1038 rc
= fgets(buf
, len
, f
) == NULL
? -EIO
: 0;
1045 if (buf
[len
- 1] == '\n')
1046 buf
[len
- 1] = '\0';
1048 *set
= cpuset_alloc(maxcpus
, &setsize
, NULL
);
1055 if (cpulist_parse(buf
, *set
, setsize
, 0)) {
1060 if (cpumask_parse(buf
, *set
, setsize
)) {
1074 int ul_path_readf_cpuset(struct path_cxt
*pc
, cpu_set_t
**set
, int maxcpus
, const char *path
, ...)
1080 rc
= ul_path_cpuparse(pc
, set
, maxcpus
, 0, path
, ap
);
1086 int ul_path_readf_cpulist(struct path_cxt
*pc
, cpu_set_t
**set
, int maxcpus
, const char *path
, ...)
1092 rc
= ul_path_cpuparse(pc
, set
, maxcpus
, 1, path
, ap
);
1098 #endif /* HAVE_CPU_SET_T */
1101 #ifdef TEST_PROGRAM_PATH
1104 static void __attribute__((__noreturn__
)) usage(void)
1106 fprintf(stdout
, " %s [options] <dir> <command>\n\n", program_invocation_short_name
);
1107 fputs(" -p, --prefix <dir> redirect hardcoded paths to <dir>\n", stdout
);
1109 fputs(" Commands:\n", stdout
);
1110 fputs(" read-u64 <file> read uint64_t from file\n", stdout
);
1111 fputs(" read-s64 <file> read int64_t from file\n", stdout
);
1112 fputs(" read-u32 <file> read uint32_t from file\n", stdout
);
1113 fputs(" read-s32 <file> read int32_t from file\n", stdout
);
1114 fputs(" read-string <file> read string from file\n", stdout
);
1115 fputs(" read-majmin <file> read devno from file\n", stdout
);
1116 fputs(" read-link <file> read symlink\n", stdout
);
1117 fputs(" write-string <file> <str> write string from file\n", stdout
);
1118 fputs(" write-u64 <file> <str> write uint64_t from file\n", stdout
);
1123 int main(int argc
, char *argv
[])
1126 const char *prefix
= NULL
, *dir
, *file
, *command
;
1127 struct path_cxt
*pc
= NULL
;
1129 static const struct option longopts
[] = {
1130 { "prefix", 1, NULL
, 'p' },
1131 { "help", 0, NULL
, 'h' },
1132 { NULL
, 0, NULL
, 0 },
1135 while((c
= getopt_long(argc
, argv
, "p:h", longopts
, NULL
)) != -1) {
1144 err(EXIT_FAILURE
, "try --help");
1149 errx(EXIT_FAILURE
, "<dir> not defined");
1150 dir
= argv
[optind
++];
1152 ul_path_init_debug();
1154 pc
= ul_new_path("%s", dir
);
1156 err(EXIT_FAILURE
, "failed to initialize path context");
1158 ul_path_set_prefix(pc
, prefix
);
1161 errx(EXIT_FAILURE
, "<command> not defined");
1162 command
= argv
[optind
++];
1164 if (strcmp(command
, "read-u32") == 0) {
1168 errx(EXIT_FAILURE
, "<file> not defined");
1169 file
= argv
[optind
++];
1171 if (ul_path_read_u32(pc
, &res
, file
) != 0)
1172 err(EXIT_FAILURE
, "read u64 failed");
1173 printf("read: %s: %u\n", file
, res
);
1175 if (ul_path_readf_u32(pc
, &res
, "%s", file
) != 0)
1176 err(EXIT_FAILURE
, "readf u64 failed");
1177 printf("readf: %s: %u\n", file
, res
);
1179 } else if (strcmp(command
, "read-s32") == 0) {
1183 errx(EXIT_FAILURE
, "<file> not defined");
1184 file
= argv
[optind
++];
1186 if (ul_path_read_s32(pc
, &res
, file
) != 0)
1187 err(EXIT_FAILURE
, "read u64 failed");
1188 printf("read: %s: %d\n", file
, res
);
1190 if (ul_path_readf_s32(pc
, &res
, "%s", file
) != 0)
1191 err(EXIT_FAILURE
, "readf u64 failed");
1192 printf("readf: %s: %d\n", file
, res
);
1194 } else if (strcmp(command
, "read-u64") == 0) {
1198 errx(EXIT_FAILURE
, "<file> not defined");
1199 file
= argv
[optind
++];
1201 if (ul_path_read_u64(pc
, &res
, file
) != 0)
1202 err(EXIT_FAILURE
, "read u64 failed");
1203 printf("read: %s: %" PRIu64
"\n", file
, res
);
1205 if (ul_path_readf_u64(pc
, &res
, "%s", file
) != 0)
1206 err(EXIT_FAILURE
, "readf u64 failed");
1207 printf("readf: %s: %" PRIu64
"\n", file
, res
);
1209 } else if (strcmp(command
, "read-s64") == 0) {
1213 errx(EXIT_FAILURE
, "<file> not defined");
1214 file
= argv
[optind
++];
1216 if (ul_path_read_s64(pc
, &res
, file
) != 0)
1217 err(EXIT_FAILURE
, "read u64 failed");
1218 printf("read: %s: %" PRIu64
"\n", file
, res
);
1220 if (ul_path_readf_s64(pc
, &res
, "%s", file
) != 0)
1221 err(EXIT_FAILURE
, "readf u64 failed");
1222 printf("readf: %s: %" PRIu64
"\n", file
, res
);
1224 } else if (strcmp(command
, "read-majmin") == 0) {
1228 errx(EXIT_FAILURE
, "<file> not defined");
1229 file
= argv
[optind
++];
1231 if (ul_path_read_majmin(pc
, &res
, file
) != 0)
1232 err(EXIT_FAILURE
, "read maj:min failed");
1233 printf("read: %s: %d\n", file
, (int) res
);
1235 if (ul_path_readf_majmin(pc
, &res
, "%s", file
) != 0)
1236 err(EXIT_FAILURE
, "readf maj:min failed");
1237 printf("readf: %s: %d\n", file
, (int) res
);
1239 } else if (strcmp(command
, "read-string") == 0) {
1243 errx(EXIT_FAILURE
, "<file> not defined");
1244 file
= argv
[optind
++];
1246 if (ul_path_read_string(pc
, &res
, file
) <= 0)
1247 err(EXIT_FAILURE
, "read string failed");
1248 printf("read: %s: %s\n", file
, res
);
1250 if (ul_path_readf_string(pc
, &res
, "%s", file
) <= 0)
1251 err(EXIT_FAILURE
, "readf string failed");
1252 printf("readf: %s: %s\n", file
, res
);
1254 } else if (strcmp(command
, "read-link") == 0) {
1258 errx(EXIT_FAILURE
, "<file> not defined");
1259 file
= argv
[optind
++];
1261 if (ul_path_readlink(pc
, res
, sizeof(res
), file
) < 0)
1262 err(EXIT_FAILURE
, "read symlink failed");
1263 printf("read: %s: %s\n", file
, res
);
1265 if (ul_path_readlinkf(pc
, res
, sizeof(res
), "%s", file
) < 0)
1266 err(EXIT_FAILURE
, "readf symlink failed");
1267 printf("readf: %s: %s\n", file
, res
);
1269 } else if (strcmp(command
, "write-string") == 0) {
1272 if (optind
+ 1 == argc
)
1273 errx(EXIT_FAILURE
, "<file> <string> not defined");
1274 file
= argv
[optind
++];
1275 str
= argv
[optind
++];
1277 if (ul_path_write_string(pc
, str
, file
) != 0)
1278 err(EXIT_FAILURE
, "write string failed");
1279 if (ul_path_writef_string(pc
, str
, "%s", file
) != 0)
1280 err(EXIT_FAILURE
, "writef string failed");
1282 } else if (strcmp(command
, "write-u64") == 0) {
1285 if (optind
+ 1 == argc
)
1286 errx(EXIT_FAILURE
, "<file> <num> not defined");
1287 file
= argv
[optind
++];
1288 num
= strtoumax(argv
[optind
++], NULL
, 0);
1290 if (ul_path_write_u64(pc
, num
, file
) != 0)
1291 err(EXIT_FAILURE
, "write u64 failed");
1292 if (ul_path_writef_u64(pc
, num
, "%s", file
) != 0)
1293 err(EXIT_FAILURE
, "writef u64 failed");
1297 return EXIT_SUCCESS
;
1299 #endif /* TEST_PROGRAM_PATH */