2 * Simple functions to access files. Paths can be globally prefixed to read
3 * data from an alternative source (e.g. a /proc dump for regression tests).
5 * The paths is possible to format by printf-like way for functions with "f"
6 * postfix in the name (e.g. readf, openf, ... ul_path_readf_u64()).
8 * The ul_path_read_* API is possible to use without path_cxt handler. In this
9 * case is not possible to use global prefix and printf-like formatting.
11 * No copyright is claimed. This code is in the public domain; do with
14 * Written by Karel Zak <kzak@redhat.com> [February 2018]
24 #include "fileutils.h"
31 * Debug stuff (based on include/debug.h)
33 static UL_DEBUG_DEFINE_MASK(ulpath
);
34 UL_DEBUG_DEFINE_MASKNAMES(ulpath
) = UL_DEBUG_EMPTY_MASKNAMES
;
36 #define ULPATH_DEBUG_INIT (1 << 1)
37 #define ULPATH_DEBUG_CXT (1 << 2)
39 #define DBG(m, x) __UL_DBG(ulpath, ULPATH_DEBUG_, m, x)
40 #define ON_DBG(m, x) __UL_DBG_CALL(ulpath, ULPATH_DEBUG_, m, x)
42 #define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(ulpath)
45 void ul_path_init_debug(void)
47 if (ulpath_debug_mask
)
49 __UL_INIT_DEBUG_FROM_ENV(ulpath
, ULPATH_DEBUG_
, 0, ULPATH_DEBUG
);
52 struct path_cxt
*ul_new_path(const char *dir
, ...)
54 struct path_cxt
*pc
= calloc(1, sizeof(*pc
));
59 DBG(CXT
, ul_debugobj(pc
, "alloc"));
69 rc
= vasprintf(&pc
->dir_path
, dir
, ap
);
72 if (rc
< 0 || !pc
->dir_path
)
81 void ul_ref_path(struct path_cxt
*pc
)
87 void ul_unref_path(struct path_cxt
*pc
)
94 if (pc
->refcount
<= 0) {
95 DBG(CXT
, ul_debugobj(pc
, "dealloc"));
98 ul_path_close_dirfd(pc
);
105 int ul_path_set_prefix(struct path_cxt
*pc
, const char *prefix
)
109 assert(pc
->dir_fd
< 0);
119 DBG(CXT
, ul_debugobj(pc
, "new prefix: '%s'", p
));
123 const char *ul_path_get_prefix(struct path_cxt
*pc
)
125 return pc
? pc
->prefix
: NULL
;
128 int ul_path_set_dir(struct path_cxt
*pc
, const char *dir
)
138 if (pc
->dir_fd
>= 0) {
145 DBG(CXT
, ul_debugobj(pc
, "new dir: '%s'", p
));
149 const char *ul_path_get_dir(struct path_cxt
*pc
)
151 return pc
? pc
->dir_path
: NULL
;
154 int ul_path_set_dialect(struct path_cxt
*pc
, void *data
, void free_data(struct path_cxt
*))
157 pc
->free_dialect
= free_data
;
158 DBG(CXT
, ul_debugobj(pc
, "(re)set dialect"));
162 void *ul_path_get_dialect(struct path_cxt
*pc
)
164 return pc
? pc
->dialect
: NULL
;
167 int ul_path_set_enoent_redirect(struct path_cxt
*pc
, int (*func
)(struct path_cxt
*, const char *, int *))
169 pc
->redirect_on_enoent
= func
;
173 static const char *get_absdir(struct path_cxt
*pc
)
181 dirpath
= pc
->dir_path
;
187 rc
= snprintf(pc
->path_buffer
, sizeof(pc
->path_buffer
), "%s/%s", pc
->prefix
, dirpath
);
190 if ((size_t)rc
>= sizeof(pc
->path_buffer
)) {
191 errno
= ENAMETOOLONG
;
195 return pc
->path_buffer
;
198 int ul_path_get_dirfd(struct path_cxt
*pc
)
201 assert(pc
->dir_path
);
203 if (pc
->dir_fd
< 0) {
204 const char *path
= get_absdir(pc
);
208 DBG(CXT
, ul_debugobj(pc
, "opening dir: '%s'", path
));
209 pc
->dir_fd
= open(path
, O_RDONLY
|O_CLOEXEC
);
215 /* Note that next ul_path_get_dirfd() will reopen the directory */
216 void ul_path_close_dirfd(struct path_cxt
*pc
)
220 if (pc
->dir_fd
>= 0) {
221 DBG(CXT
, ul_debugobj(pc
, "closing dir: '%s'", pc
->dir_path
));
227 int ul_path_isopen_dirfd(struct path_cxt
*pc
)
229 return pc
&& pc
->dir_fd
>= 0;
232 static const char *ul_path_mkpath(struct path_cxt
*pc
, const char *path
, va_list ap
)
238 rc
= vsnprintf(pc
->path_buffer
, sizeof(pc
->path_buffer
), path
, ap
);
245 if ((size_t)rc
>= sizeof(pc
->path_buffer
)) {
246 errno
= ENAMETOOLONG
;
250 return pc
->path_buffer
;
253 char *ul_path_get_abspath(struct path_cxt
*pc
, char *buf
, size_t bufsz
, const char *path
, ...)
258 const char *tail
= NULL
, *dirpath
= pc
->dir_path
;
261 tail
= ul_path_mkpath(pc
, path
, ap
);
264 if (dirpath
&& *dirpath
== '/')
266 if (tail
&& *tail
== '/')
269 rc
= snprintf(buf
, bufsz
, "%s/%s/%s",
270 pc
->prefix
? pc
->prefix
: "",
271 dirpath
? dirpath
: "",
274 if ((size_t)rc
>= bufsz
) {
275 errno
= ENAMETOOLONG
;
279 const char *tmp
= get_absdir(pc
);
283 xstrncpy(buf
, tmp
, bufsz
);
290 int ul_path_access(struct path_cxt
*pc
, int mode
, const char *path
)
294 dir
= ul_path_get_dirfd(pc
);
298 DBG(CXT
, ul_debugobj(pc
, "access: '%s'", path
));
299 rc
= faccessat(dir
, path
, mode
, 0);
301 if (rc
&& errno
== ENOENT
302 && pc
->redirect_on_enoent
303 && pc
->redirect_on_enoent(pc
, path
, &dir
) == 0)
304 rc
= faccessat(dir
, path
, mode
, 0);
308 int ul_path_accessf(struct path_cxt
*pc
, int mode
, const char *path
, ...)
314 p
= ul_path_mkpath(pc
, path
, ap
);
317 return !p
? -errno
: ul_path_access(pc
, mode
, p
);
320 int ul_path_open(struct path_cxt
*pc
, int flags
, const char *path
)
325 fd
= open(path
, flags
);
326 DBG(CXT
, ul_debug("opening '%s' [no context]", path
));
329 int dir
= ul_path_get_dirfd(pc
);
333 fdx
= fd
= openat(dir
, path
, flags
);
335 if (fd
< 0 && errno
== ENOENT
336 && pc
->redirect_on_enoent
337 && pc
->redirect_on_enoent(pc
, path
, &dir
) == 0)
338 fd
= openat(dir
, path
, flags
);
340 DBG(CXT
, ul_debugobj(pc
, "opening '%s'%s", path
, fdx
!= fd
? " [redirected]" : ""));
345 int ul_path_vopenf(struct path_cxt
*pc
, int flags
, const char *path
, va_list ap
)
347 const char *p
= ul_path_mkpath(pc
, path
, ap
);
349 return !p
? -errno
: ul_path_open(pc
, flags
, p
);
352 int ul_path_openf(struct path_cxt
*pc
, int flags
, const char *path
, ...)
358 rc
= ul_path_vopenf(pc
, flags
, path
, ap
);
365 * Maybe stupid, but good enough ;-)
367 static int mode2flags(const char *mode
)
372 for (p
= mode
; p
&& *p
; p
++) {
373 if (*p
== 'r' && *(p
+ 1) == '+')
378 else if (*p
== 'w' && *(p
+ 1) == '+')
379 flags
|= O_RDWR
| O_TRUNC
;
381 flags
|= O_WRONLY
| O_TRUNC
;
383 else if (*p
== 'a' && *(p
+ 1) == '+')
384 flags
|= O_RDWR
| O_APPEND
;
386 flags
|= O_WRONLY
| O_APPEND
;
388 else if (*p
== *UL_CLOEXECSTR
)
396 FILE *ul_path_fopen(struct path_cxt
*pc
, const char *mode
, const char *path
)
398 int flags
= mode2flags(mode
);
399 int fd
= ul_path_open(pc
, flags
, path
);
404 return fdopen(fd
, mode
);
408 FILE *ul_path_vfopenf(struct path_cxt
*pc
, const char *mode
, const char *path
, va_list ap
)
410 const char *p
= ul_path_mkpath(pc
, path
, ap
);
412 return !p
? NULL
: ul_path_fopen(pc
, mode
, p
);
415 FILE *ul_path_fopenf(struct path_cxt
*pc
, const char *mode
, const char *path
, ...)
421 f
= ul_path_vfopenf(pc
, mode
, path
, ap
);
428 * Open directory @path in read-onl mode. If the path is NULL then duplicate FD
429 * to the directory addressed by @pc.
431 DIR *ul_path_opendir(struct path_cxt
*pc
, const char *path
)
437 fd
= ul_path_open(pc
, O_RDONLY
|O_CLOEXEC
, path
);
438 else if (pc
->dir_path
) {
441 DBG(CXT
, ul_debugobj(pc
, "duplicate dir path"));
442 dirfd
= ul_path_get_dirfd(pc
);
444 fd
= dup_fd_cloexec(dirfd
, STDERR_FILENO
+ 1);
462 * Open directory @path in read-onl mode. If the path is NULL then duplicate FD
463 * to the directory addressed by @pc.
465 DIR *ul_path_vopendirf(struct path_cxt
*pc
, const char *path
, va_list ap
)
467 const char *p
= ul_path_mkpath(pc
, path
, ap
);
469 return !p
? NULL
: ul_path_opendir(pc
, p
);
473 * Open directory @path in read-onl mode. If the path is NULL then duplicate FD
474 * to the directory addressed by @pc.
476 DIR *ul_path_opendirf(struct path_cxt
*pc
, const char *path
, ...)
482 dir
= ul_path_vopendirf(pc
, path
, ap
);
489 * If @path is NULL then readlink is called on @pc directory.
491 ssize_t
ul_path_readlink(struct path_cxt
*pc
, char *buf
, size_t bufsiz
, const char *path
)
496 const char *p
= get_absdir(pc
);
499 return readlink(p
, buf
, bufsiz
);
502 dirfd
= ul_path_get_dirfd(pc
);
506 return readlinkat(dirfd
, path
, buf
, bufsiz
);
510 * If @path is NULL then readlink is called on @pc directory.
512 ssize_t
ul_path_readlinkf(struct path_cxt
*pc
, char *buf
, size_t bufsiz
, const char *path
, ...)
518 p
= ul_path_mkpath(pc
, path
, ap
);
521 return !p
? -errno
: ul_path_readlink(pc
, buf
, bufsiz
, p
);
524 int ul_path_read(struct path_cxt
*pc
, char *buf
, size_t len
, const char *path
)
529 fd
= ul_path_open(pc
, O_RDONLY
|O_CLOEXEC
, path
);
533 DBG(CXT
, ul_debug(" reading '%s'", path
));
534 rc
= read_all(fd
, buf
, len
);
542 int ul_path_vreadf(struct path_cxt
*pc
, char *buf
, size_t len
, const char *path
, va_list ap
)
544 const char *p
= ul_path_mkpath(pc
, path
, ap
);
546 return !p
? -errno
: ul_path_read(pc
, buf
, len
, p
);
549 int ul_path_readf(struct path_cxt
*pc
, char *buf
, size_t len
, const char *path
, ...)
555 rc
= ul_path_vreadf(pc
, buf
, len
, path
, ap
);
563 * Returns newly allocated buffer with data from file. Maximal size is BUFSIZ
564 * (send patch if you need something bigger;-)
566 * Returns size of the string!
568 int ul_path_read_string(struct path_cxt
*pc
, char **str
, const char *path
)
577 rc
= ul_path_read(pc
, buf
, sizeof(buf
) - 1, path
);
581 /* Remove tailing newline (usual in sysfs) */
582 if (rc
> 0 && *(buf
+ rc
- 1) == '\n')
593 int ul_path_readf_string(struct path_cxt
*pc
, char **str
, const char *path
, ...)
599 p
= ul_path_mkpath(pc
, path
, ap
);
602 return !p
? -errno
: ul_path_read_string(pc
, str
, p
);
605 int ul_path_read_buffer(struct path_cxt
*pc
, char *buf
, size_t bufsz
, const char *path
)
607 int rc
= ul_path_read(pc
, buf
, bufsz
- 1, path
);
611 /* Remove tailing newline (usual in sysfs) */
612 if (rc
> 0 && *(buf
+ rc
- 1) == '\n')
620 int ul_path_readf_buffer(struct path_cxt
*pc
, char *buf
, size_t bufsz
, const char *path
, ...)
626 p
= ul_path_mkpath(pc
, path
, ap
);
629 return !p
? -errno
: ul_path_read_buffer(pc
, buf
, bufsz
, p
);
632 int ul_path_scanf(struct path_cxt
*pc
, const char *path
, const char *fmt
, ...)
638 f
= ul_path_fopen(pc
, "r" UL_CLOEXECSTR
, path
);
642 DBG(CXT
, ul_debug(" fscanf [%s] '%s'", fmt
, path
));
644 va_start(fmt_ap
, fmt
);
645 rc
= vfscanf(f
, fmt
, fmt_ap
);
652 int ul_path_scanff(struct path_cxt
*pc
, const char *path
, va_list ap
, const char *fmt
, ...)
658 f
= ul_path_vfopenf(pc
, "r" UL_CLOEXECSTR
, path
, ap
);
662 va_start(fmt_ap
, fmt
);
663 rc
= vfscanf(f
, fmt
, fmt_ap
);
671 int ul_path_read_s64(struct path_cxt
*pc
, int64_t *res
, const char *path
)
676 rc
= ul_path_scanf(pc
, path
, "%"SCNd64
, &x
);
684 int ul_path_readf_s64(struct path_cxt
*pc
, int64_t *res
, const char *path
, ...)
690 p
= ul_path_mkpath(pc
, path
, ap
);
693 return !p
? -errno
: ul_path_read_s64(pc
, res
, p
);
696 int ul_path_read_u64(struct path_cxt
*pc
, uint64_t *res
, const char *path
)
701 rc
= ul_path_scanf(pc
, path
, "%"SCNu64
, &x
);
709 int ul_path_readf_u64(struct path_cxt
*pc
, uint64_t *res
, const char *path
, ...)
715 p
= ul_path_mkpath(pc
, path
, ap
);
718 return !p
? -errno
: ul_path_read_u64(pc
, res
, p
);
721 int ul_path_read_s32(struct path_cxt
*pc
, int *res
, const char *path
)
725 rc
= ul_path_scanf(pc
, path
, "%d", &x
);
733 int ul_path_readf_s32(struct path_cxt
*pc
, int *res
, const char *path
, ...)
739 p
= ul_path_mkpath(pc
, path
, ap
);
742 return !p
? -errno
: ul_path_read_s32(pc
, res
, p
);
745 int ul_path_read_u32(struct path_cxt
*pc
, unsigned int *res
, const char *path
)
750 rc
= ul_path_scanf(pc
, path
, "%u", &x
);
758 int ul_path_readf_u32(struct path_cxt
*pc
, unsigned int *res
, const char *path
, ...)
764 p
= ul_path_mkpath(pc
, path
, ap
);
767 return !p
? -errno
: ul_path_read_u32(pc
, res
, p
);
770 int ul_path_read_majmin(struct path_cxt
*pc
, dev_t
*res
, const char *path
)
774 rc
= ul_path_scanf(pc
, path
, "%d:%d", &maj
, &min
);
778 *res
= makedev(maj
, min
);
782 int ul_path_readf_majmin(struct path_cxt
*pc
, dev_t
*res
, const char *path
, ...)
788 p
= ul_path_mkpath(pc
, path
, ap
);
791 return !p
? -errno
: ul_path_read_majmin(pc
, res
, p
);
794 int ul_path_write_string(struct path_cxt
*pc
, const char *str
, const char *path
)
799 fd
= ul_path_open(pc
, O_WRONLY
|O_CLOEXEC
, path
);
803 rc
= write_all(fd
, str
, strlen(str
));
811 int ul_path_writef_string(struct path_cxt
*pc
, const char *str
, const char *path
, ...)
817 p
= ul_path_mkpath(pc
, path
, ap
);
820 return !p
? -errno
: ul_path_write_string(pc
, str
, p
);
823 int ul_path_write_s64(struct path_cxt
*pc
, int64_t num
, const char *path
)
825 char buf
[sizeof(stringify_value(LLONG_MAX
))];
829 fd
= ul_path_open(pc
, O_WRONLY
|O_CLOEXEC
, path
);
833 len
= snprintf(buf
, sizeof(buf
), "%" PRId64
, num
);
834 if (len
< 0 || (size_t) len
>= sizeof(buf
))
835 rc
= len
< 0 ? -errno
: -E2BIG
;
837 rc
= write_all(fd
, buf
, len
);
845 int ul_path_write_u64(struct path_cxt
*pc
, uint64_t num
, const char *path
)
847 char buf
[sizeof(stringify_value(ULLONG_MAX
))];
851 fd
= ul_path_open(pc
, O_WRONLY
|O_CLOEXEC
, path
);
855 len
= snprintf(buf
, sizeof(buf
), "%" PRIu64
, num
);
856 if (len
< 0 || (size_t) len
>= sizeof(buf
))
857 rc
= len
< 0 ? -errno
: -E2BIG
;
859 rc
= write_all(fd
, buf
, len
);
867 int ul_path_writef_u64(struct path_cxt
*pc
, uint64_t num
, const char *path
, ...)
873 p
= ul_path_mkpath(pc
, path
, ap
);
876 return !p
? -errno
: ul_path_write_u64(pc
, num
, p
);
880 int ul_path_count_dirents(struct path_cxt
*pc
, const char *path
)
885 dir
= ul_path_opendir(pc
, path
);
889 while (xreaddir(dir
)) r
++;
895 int ul_path_countf_dirents(struct path_cxt
*pc
, const char *path
, ...)
901 p
= ul_path_mkpath(pc
, path
, ap
);
904 return !p
? -errno
: ul_path_count_dirents(pc
, p
);
908 * Like fopen() but, @path is always prefixed by @prefix. This function is
909 * useful in case when ul_path_* API is overkill.
911 FILE *ul_prefix_fopen(const char *prefix
, const char *path
, const char *mode
)
918 return fopen(path
, mode
);
922 snprintf(buf
, sizeof(buf
), "%s/%s", prefix
, path
);
923 return fopen(buf
, mode
);
926 #ifdef HAVE_CPU_SET_T
927 static int ul_path_cpuparse(struct path_cxt
*pc
, cpu_set_t
**set
, int maxcpus
, int islist
, const char *path
, va_list ap
)
930 size_t setsize
, len
= maxcpus
* 7;
936 f
= ul_path_vfopenf(pc
, "r" UL_CLOEXECSTR
, path
, ap
);
940 rc
= fgets(buf
, len
, f
) == NULL
? -errno
: 0;
947 if (buf
[len
- 1] == '\n')
950 *set
= cpuset_alloc(maxcpus
, &setsize
, NULL
);
955 if (cpulist_parse(buf
, *set
, setsize
, 0)) {
960 if (cpumask_parse(buf
, *set
, setsize
)) {
968 int ul_path_readf_cpuset(struct path_cxt
*pc
, cpu_set_t
**set
, int maxcpus
, const char *path
, ...)
974 rc
= ul_path_cpuparse(pc
, set
, maxcpus
, 0, path
, ap
);
980 int ul_path_readf_cpulist(struct path_cxt
*pc
, cpu_set_t
**set
, int maxcpus
, const char *path
, ...)
986 rc
= ul_path_cpuparse(pc
, set
, maxcpus
, 1, path
, ap
);
992 #endif /* HAVE_CPU_SET_T */
995 #ifdef TEST_PROGRAM_PATH
998 static void __attribute__((__noreturn__
)) usage(void)
1000 fprintf(stdout
, " %s [options] <dir> <command>\n\n", program_invocation_short_name
);
1001 fputs(" -p, --prefix <dir> redirect hardcoded paths to <dir>\n", stdout
);
1003 fputs(" Commands:\n", stdout
);
1004 fputs(" read-u64 <file> read uint64_t from file\n", stdout
);
1005 fputs(" read-s64 <file> read int64_t from file\n", stdout
);
1006 fputs(" read-u32 <file> read uint32_t from file\n", stdout
);
1007 fputs(" read-s32 <file> read int32_t from file\n", stdout
);
1008 fputs(" read-string <file> read string from file\n", stdout
);
1009 fputs(" read-majmin <file> read devno from file\n", stdout
);
1010 fputs(" read-link <file> read symlink\n", stdout
);
1011 fputs(" write-string <file> <str> write string from file\n", stdout
);
1012 fputs(" write-u64 <file> <str> write uint64_t from file\n", stdout
);
1017 int main(int argc
, char *argv
[])
1020 const char *prefix
= NULL
, *dir
, *file
, *command
;
1021 struct path_cxt
*pc
= NULL
;
1023 static const struct option longopts
[] = {
1024 { "prefix", 1, NULL
, 'p' },
1025 { "help", 0, NULL
, 'h' },
1026 { NULL
, 0, NULL
, 0 },
1029 while((c
= getopt_long(argc
, argv
, "p:h", longopts
, NULL
)) != -1) {
1038 err(EXIT_FAILURE
, "try --help");
1043 errx(EXIT_FAILURE
, "<dir> not defined");
1044 dir
= argv
[optind
++];
1046 ul_path_init_debug();
1048 pc
= ul_new_path(dir
);
1050 err(EXIT_FAILURE
, "failed to initialize path context");
1052 ul_path_set_prefix(pc
, prefix
);
1055 errx(EXIT_FAILURE
, "<command> not defined");
1056 command
= argv
[optind
++];
1058 if (strcmp(command
, "read-u32") == 0) {
1062 errx(EXIT_FAILURE
, "<file> not defined");
1063 file
= argv
[optind
++];
1065 if (ul_path_read_u32(pc
, &res
, file
) != 0)
1066 err(EXIT_FAILURE
, "read u64 failed");
1067 printf("read: %s: %u\n", file
, res
);
1069 if (ul_path_readf_u32(pc
, &res
, "%s", file
) != 0)
1070 err(EXIT_FAILURE
, "readf u64 failed");
1071 printf("readf: %s: %u\n", file
, res
);
1073 } else if (strcmp(command
, "read-s32") == 0) {
1077 errx(EXIT_FAILURE
, "<file> not defined");
1078 file
= argv
[optind
++];
1080 if (ul_path_read_s32(pc
, &res
, file
) != 0)
1081 err(EXIT_FAILURE
, "read u64 failed");
1082 printf("read: %s: %d\n", file
, res
);
1084 if (ul_path_readf_s32(pc
, &res
, "%s", file
) != 0)
1085 err(EXIT_FAILURE
, "readf u64 failed");
1086 printf("readf: %s: %d\n", file
, res
);
1088 } else if (strcmp(command
, "read-u64") == 0) {
1092 errx(EXIT_FAILURE
, "<file> not defined");
1093 file
= argv
[optind
++];
1095 if (ul_path_read_u64(pc
, &res
, file
) != 0)
1096 err(EXIT_FAILURE
, "read u64 failed");
1097 printf("read: %s: %" PRIu64
"\n", file
, res
);
1099 if (ul_path_readf_u64(pc
, &res
, "%s", file
) != 0)
1100 err(EXIT_FAILURE
, "readf u64 failed");
1101 printf("readf: %s: %" PRIu64
"\n", file
, res
);
1103 } else if (strcmp(command
, "read-s64") == 0) {
1107 errx(EXIT_FAILURE
, "<file> not defined");
1108 file
= argv
[optind
++];
1110 if (ul_path_read_s64(pc
, &res
, file
) != 0)
1111 err(EXIT_FAILURE
, "read u64 failed");
1112 printf("read: %s: %" PRIu64
"\n", file
, res
);
1114 if (ul_path_readf_s64(pc
, &res
, "%s", file
) != 0)
1115 err(EXIT_FAILURE
, "readf u64 failed");
1116 printf("readf: %s: %" PRIu64
"\n", file
, res
);
1118 } else if (strcmp(command
, "read-majmin") == 0) {
1122 errx(EXIT_FAILURE
, "<file> not defined");
1123 file
= argv
[optind
++];
1125 if (ul_path_read_majmin(pc
, &res
, file
) != 0)
1126 err(EXIT_FAILURE
, "read maj:min failed");
1127 printf("read: %s: %d\n", file
, (int) res
);
1129 if (ul_path_readf_majmin(pc
, &res
, "%s", file
) != 0)
1130 err(EXIT_FAILURE
, "readf maj:min failed");
1131 printf("readf: %s: %d\n", file
, (int) res
);
1133 } else if (strcmp(command
, "read-string") == 0) {
1137 errx(EXIT_FAILURE
, "<file> not defined");
1138 file
= argv
[optind
++];
1140 if (ul_path_read_string(pc
, &res
, file
) < 0)
1141 err(EXIT_FAILURE
, "read string failed");
1142 printf("read: %s: %s\n", file
, res
);
1144 if (ul_path_readf_string(pc
, &res
, "%s", file
) < 0)
1145 err(EXIT_FAILURE
, "readf string failed");
1146 printf("readf: %s: %s\n", file
, res
);
1148 } else if (strcmp(command
, "read-link") == 0) {
1152 errx(EXIT_FAILURE
, "<file> not defined");
1153 file
= argv
[optind
++];
1155 if (ul_path_readlink(pc
, res
, sizeof(res
), file
) < 0)
1156 err(EXIT_FAILURE
, "read symlink failed");
1157 printf("read: %s: %s\n", file
, res
);
1159 if (ul_path_readlinkf(pc
, res
, sizeof(res
), "%s", file
) < 0)
1160 err(EXIT_FAILURE
, "readf symlink failed");
1161 printf("readf: %s: %s\n", file
, res
);
1163 } else if (strcmp(command
, "write-string") == 0) {
1166 if (optind
+ 1 == argc
)
1167 errx(EXIT_FAILURE
, "<file> <string> not defined");
1168 file
= argv
[optind
++];
1169 str
= argv
[optind
++];
1171 if (ul_path_write_string(pc
, str
, file
) != 0)
1172 err(EXIT_FAILURE
, "write string failed");
1173 if (ul_path_writef_string(pc
, str
, "%s", file
) != 0)
1174 err(EXIT_FAILURE
, "writef string failed");
1176 } else if (strcmp(command
, "write-u64") == 0) {
1179 if (optind
+ 1 == argc
)
1180 errx(EXIT_FAILURE
, "<file> <num> not defined");
1181 file
= argv
[optind
++];
1182 num
= strtoumax(argv
[optind
++], NULL
, 0);
1184 if (ul_path_write_u64(pc
, num
, file
) != 0)
1185 err(EXIT_FAILURE
, "write u64 failed");
1186 if (ul_path_writef_u64(pc
, num
, "%s", file
) != 0)
1187 err(EXIT_FAILURE
, "writef u64 failed");
1191 return EXIT_SUCCESS
;
1193 #endif /* TEST_PROGRAM_PATH */