• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2021 SUSE LLC <rpalethorpe@suse.com>
4  */
5 
6 #define _GNU_SOURCE
7 #include <stdio.h>
8 #include "lapi/fcntl.h"
9 #include "tst_safe_file_at.h"
10 
11 #define TST_NO_DEFAULT_MAIN
12 #include "tst_test.h"
13 
14 static char fd_path[PATH_MAX];
15 
tst_decode_fd(const int fd)16 const char *tst_decode_fd(const int fd)
17 {
18 	ssize_t ret;
19 	char proc_path[32];
20 
21 	if (fd < 0)
22 		return "!";
23 
24 	sprintf(proc_path, "/proc/self/fd/%d", fd);
25 	ret = readlink(proc_path, fd_path, sizeof(fd_path));
26 
27 	if (ret < 0)
28 		return "?";
29 
30 	fd_path[ret] = '\0';
31 
32 	return fd_path;
33 }
34 
safe_openat(const char * const file,const int lineno,const int dirfd,const char * const path,const int oflags,...)35 int safe_openat(const char *const file, const int lineno,
36 		const int dirfd, const char *const path, const int oflags, ...)
37 {
38 	va_list ap;
39 	int fd;
40 	mode_t mode;
41 
42 	va_start(ap, oflags);
43 	mode = va_arg(ap, int);
44 	va_end(ap);
45 
46 	fd = openat(dirfd, path, oflags, mode);
47 	if (fd > -1)
48 		return fd;
49 
50 	tst_brk_(file, lineno, TBROK | TERRNO,
51 		 "openat(%d<%s>, '%s', %o, %o)",
52 		 dirfd, tst_decode_fd(dirfd), path, oflags, mode);
53 
54 	return fd;
55 }
56 
safe_file_readat(const char * const file,const int lineno,const int dirfd,const char * const path,char * const buf,const size_t nbyte)57 ssize_t safe_file_readat(const char *const file, const int lineno,
58 			 const int dirfd, const char *const path,
59 			 char *const buf, const size_t nbyte)
60 {
61 	int fd = safe_openat(file, lineno, dirfd, path, O_RDONLY);
62 	ssize_t rval;
63 
64 	if (fd < 0)
65 		return -1;
66 
67 	rval = safe_read(file, lineno, NULL, 0, fd, buf, nbyte - 1);
68 	if (rval < 0)
69 		return -1;
70 
71 	close(fd);
72 	buf[rval] = '\0';
73 
74 	if (rval >= (ssize_t)nbyte - 1) {
75 		tst_brk_(file, lineno, TBROK,
76 			"Buffer length %zu too small to read %d<%s>/%s",
77 			nbyte, dirfd, tst_decode_fd(dirfd), path);
78 	}
79 
80 	return rval;
81 }
82 
tst_file_vprintfat(const int dirfd,const char * const path,const char * const fmt,va_list va)83 int tst_file_vprintfat(const int dirfd, const char *const path,
84 		       const char *const fmt, va_list va)
85 {
86 	const int fd = openat(dirfd, path, O_WRONLY);
87 	int ret, errno_cpy;
88 
89 	if (fd < 0)
90 		return -1;
91 
92 	ret = vdprintf(fd, fmt, va);
93 	errno_cpy = errno;
94 	close(fd);
95 
96 	if (ret < 0) {
97 		errno = errno_cpy;
98 		return -2;
99 	}
100 
101 	return ret;
102 }
103 
tst_file_printfat(const int dirfd,const char * const path,const char * const fmt,...)104 int tst_file_printfat(const int dirfd, const char *const path,
105 		      const char *const fmt, ...)
106 {
107 	va_list va;
108 	int rval;
109 
110 	va_start(va, fmt);
111 	rval = tst_file_vprintfat(dirfd, path, fmt, va);
112 	va_end(va);
113 
114 	return rval;
115 }
116 
safe_file_vprintfat(const char * const file,const int lineno,const int dirfd,const char * const path,const char * const fmt,va_list va)117 int safe_file_vprintfat(const char *const file, const int lineno,
118 			const int dirfd, const char *const path,
119 			const char *const fmt, va_list va)
120 {
121 	char buf[16];
122 	va_list vac;
123 	int rval, errno_cpy;
124 
125 	va_copy(vac, va);
126 
127 	rval = tst_file_vprintfat(dirfd, path, fmt, va);
128 
129 	if (rval == -2) {
130 		errno_cpy = errno;
131 		rval = vsnprintf(buf, sizeof(buf), fmt, vac);
132 		va_end(vac);
133 
134 		if (rval >= (ssize_t)sizeof(buf))
135 			strcpy(buf + sizeof(buf) - 5, "...");
136 		else if (rval < 0)
137 			buf[0] = '\0';
138 
139 		errno = errno_cpy;
140 		tst_brk_(file, lineno, TBROK | TERRNO,
141 			 "vdprintf(%d<%s>, '%s', '%s'<%s>)",
142 			 dirfd, tst_decode_fd(dirfd), path, fmt, buf);
143 		return -1;
144 	}
145 
146 	va_end(vac);
147 
148 	if (rval == -1) {
149 		tst_brk_(file, lineno, TBROK | TERRNO,
150 			"openat(%d<%s>, '%s', O_WRONLY)",
151 			dirfd, tst_decode_fd(dirfd), path);
152 	}
153 
154 	return rval;
155 }
156 
safe_file_printfat(const char * const file,const int lineno,const int dirfd,const char * const path,const char * const fmt,...)157 int safe_file_printfat(const char *const file, const int lineno,
158 		       const int dirfd, const char *const path,
159 		       const char *const fmt, ...)
160 {
161 	va_list va;
162 	int rval;
163 
164 	va_start(va, fmt);
165 	rval = safe_file_vprintfat(file, lineno, dirfd, path, fmt, va);
166 	va_end(va);
167 
168 	return rval;
169 }
170 
safe_unlinkat(const char * const file,const int lineno,const int dirfd,const char * const path,const int flags)171 int safe_unlinkat(const char *const file, const int lineno,
172 		  const int dirfd, const char *const path, const int flags)
173 {
174 	const int rval = unlinkat(dirfd, path, flags);
175 	const char *flags_sym;
176 
177 	if (!rval)
178 		return rval;
179 
180 	switch(flags) {
181 	case AT_REMOVEDIR:
182 		flags_sym = "AT_REMOVEDIR";
183 		break;
184 	case 0:
185 		flags_sym = "0";
186 		break;
187 	default:
188 		flags_sym = "?";
189 		break;
190 	}
191 
192 	tst_brk_(file, lineno, TBROK | TERRNO,
193 		 "unlinkat(%d<%s>, '%s', %s)",
194 		 dirfd, tst_decode_fd(dirfd), path, flags_sym);
195 
196 	return rval;
197 }
198