Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016, Citrix Systems, Inc.
3 : : *
4 : : * All rights reserved.
5 : : *
6 : : * Redistribution and use in source and binary forms, with or without
7 : : * modification, are permitted provided that the following conditions are met:
8 : : *
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer.
11 : : * 2. Redistributions in binary form must reproduce the above copyright
12 : : * notice, this list of conditions and the following disclaimer in the
13 : : * documentation and/or other materials provided with the distribution.
14 : : * 3. Neither the name of the copyright holder nor the names of its
15 : : * contributors may be used to endorse or promote products derived from
16 : : * this software without specific prior written permission.
17 : : *
18 : : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 : : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 : : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 : : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 : : * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 : : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 : : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 : : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 : : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 : : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 : : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : : */
30 : :
31 : : #ifdef HAVE_CONFIG_H
32 : : #include "config.h"
33 : : #endif
34 : :
35 : : #include <stdlib.h>
36 : : #include <errno.h>
37 : : #include <stdio.h>
38 : : #include <string.h>
39 : : #include <unistd.h>
40 : : #include <linux/fs.h>
41 : : #include <sys/stat.h>
42 : : #include <sys/mman.h>
43 : : #include <sys/ioctl.h>
44 : : #include <sys/resource.h>
45 : : #include <sys/utsname.h>
46 : : #include <arpa/inet.h>
47 : :
48 : : #ifdef __linux__
49 : : #include <linux/version.h>
50 : : #endif
51 : :
52 : : #define SYSLOG_NAMES
53 : : #include <syslog.h>
54 : : #include <stdarg.h>
55 : :
56 : : #include "tapdisk.h"
57 : : #include "tapdisk-log.h"
58 : : #include "tapdisk-utils.h"
59 : : #include "tapdisk-syslog.h"
60 : :
61 : : #define MIN(a,b) (((a) < (b)) ? (a) : (b))
62 : :
63 : : #define ASSERT(_p) \
64 : : if (!(_p)) { \
65 : : EPRINTF("%s:%d: FAILED ASSERTION: '%s'\n", \
66 : : __FILE__, __LINE__, #_p); \
67 : : td_panic(); \
68 : : }
69 : :
70 : : static int
71 : 0 : tapdisk_syslog_facility_by_name(const char *name)
72 : : {
73 : : int facility;
74 : : CODE *c;
75 : :
76 : 0 : facility = -1;
77 : :
78 [ # # ]: 0 : for (c = facilitynames; c->c_name != NULL; ++c)
79 [ # # ]: 0 : if (!strcmp(c->c_name, name)) {
80 : 0 : facility = c->c_val;
81 : 0 : break;
82 : : }
83 : :
84 : 0 : return facility;
85 : : }
86 : :
87 : : int
88 : 0 : tapdisk_syslog_facility(const char *arg)
89 : : {
90 : : int facility;
91 : : char *endptr;
92 : :
93 [ # # ]: 0 : if (arg) {
94 : 0 : facility = strtol(arg, &endptr, 0);
95 [ # # ]: 0 : if (*endptr == 0)
96 : 0 : return facility;
97 : :
98 : 0 : facility = tapdisk_syslog_facility_by_name(arg);
99 [ # # ]: 0 : if (facility >= 0)
100 : 0 : return facility;
101 : : }
102 : :
103 : : return LOG_DAEMON;
104 : : }
105 : :
106 : : char*
107 : 0 : tapdisk_syslog_ident(const char *name)
108 : : {
109 : : char ident[TD_SYSLOG_IDENT_MAX+1];
110 : : size_t size, len;
111 : : pid_t pid;
112 : :
113 : 0 : pid = getpid();
114 : 0 : size = sizeof(ident);
115 : 0 : len = 0;
116 : :
117 : 0 : len = snprintf(NULL, 0, "[%d]", pid);
118 : 0 : len = snprintf(ident, size - len, "%s", name);
119 : 0 : snprintf(ident + len, size - len, "[%d]", pid);
120 : :
121 : 0 : return strdup(ident);
122 : : }
123 : :
124 : : size_t
125 : 0 : tapdisk_syslog_strftime(char *buf, size_t size, const struct timeval *tv)
126 : : {
127 : 0 : const char *mon[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
128 : : "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
129 : : struct tm tm;
130 : :
131 : : /*
132 : : * TIMESTAMP := <Mmm> " " <dd> " " <hh> ":" <mm> ":" <ss>.
133 : : * Local time, no locales.
134 : : */
135 : :
136 : 0 : localtime_r(&tv->tv_sec, &tm);
137 : :
138 : 0 : return snprintf(buf, size, "%s %2d %02d:%02d:%02d",
139 : 0 : mon[tm.tm_mon], tm.tm_mday,
140 : : tm.tm_hour, tm.tm_min, tm.tm_sec);
141 : : }
142 : :
143 : : size_t
144 : 0 : tapdisk_syslog_strftv(char *buf, size_t size, const struct timeval *tv)
145 : : {
146 : : struct tm tm;
147 : :
148 : 0 : localtime_r(&tv->tv_sec, &tm);
149 : :
150 : 0 : return snprintf(buf, size, "[%02d:%02d:%02d.%03ld]",
151 : : tm.tm_hour, tm.tm_min, tm.tm_sec,
152 : 0 : (long)tv->tv_usec / 1000);
153 : : }
154 : :
155 : : int
156 : 0 : tapdisk_set_resource_limits(void)
157 : : {
158 : : int err;
159 : : struct rlimit rlim;
160 : :
161 : 0 : rlim.rlim_cur = RLIM_INFINITY;
162 : 0 : rlim.rlim_max = RLIM_INFINITY;
163 : :
164 : 0 : err = setrlimit(RLIMIT_MEMLOCK, &rlim);
165 [ # # ]: 0 : if (err == -1) {
166 : 0 : EPRINTF("RLIMIT_MEMLOCK failed: %d\n", errno);
167 : 0 : return -errno;
168 : : }
169 : :
170 : 0 : err = mlockall(MCL_CURRENT | MCL_FUTURE);
171 [ # # ]: 0 : if (err == -1) {
172 : 0 : EPRINTF("mlockall failed: %d\n", errno);
173 : 0 : return -errno;
174 : : }
175 : :
176 : : #define CORE_DUMP
177 : : #if defined(CORE_DUMP)
178 : 0 : err = setrlimit(RLIMIT_CORE, &rlim);
179 [ # # ]: 0 : if (err == -1)
180 : 0 : EPRINTF("RLIMIT_CORE failed: %d\n", errno);
181 : : #endif
182 : :
183 : : return 0;
184 : : }
185 : :
186 : : int
187 : 2 : tapdisk_namedup(char **dup, const char *name)
188 : : {
189 : 2 : *dup = NULL;
190 : :
191 [ + - ]: 2 : if (strnlen(name, MAX_NAME_LEN) >= MAX_NAME_LEN)
192 : : return -ENAMETOOLONG;
193 : :
194 : 2 : *dup = strdup(name);
195 [ + - ]: 2 : if (!*dup)
196 : : return -ENOMEM;
197 : :
198 : 2 : return 0;
199 : : }
200 : :
201 : : /*Get Image size, secsize*/
202 : : int
203 : 0 : tapdisk_get_image_size(int fd, uint64_t *_sectors, uint32_t *_sector_size)
204 : : {
205 : : struct stat stat;
206 : : uint64_t sectors, bytes;
207 : : uint32_t sector_size;
208 : :
209 : 0 : sectors = 0;
210 : 0 : sector_size = 0;
211 : 0 : *_sectors = 0;
212 : 0 : *_sector_size = 0;
213 : :
214 [ # # ]: 0 : if (fstat(fd, &stat)) {
215 : : DPRINTF("ERROR: fstat failed, Couldn't stat image");
216 : 0 : return -EINVAL;
217 : : }
218 : :
219 [ # # ]: 0 : if (S_ISBLK(stat.st_mode)) {
220 : : /*Accessing block device directly*/
221 [ # # ]: 0 : if (ioctl(fd,BLKGETSIZE64,&bytes)==0) {
222 : 0 : sectors = bytes >> SECTOR_SHIFT;
223 [ # # ]: 0 : } else if (ioctl(fd,BLKGETSIZE,§ors)!=0) {
224 : : DPRINTF("ERR: BLKGETSIZE and BLKGETSIZE64 failed, couldn't stat image");
225 : : return -EINVAL;
226 : : }
227 : :
228 : : /*Get the sector size*/
229 : : #if defined(BLKSSZGET)
230 : : {
231 : 0 : sector_size = DEFAULT_SECTOR_SIZE;
232 : 0 : ioctl(fd, BLKSSZGET, §or_size);
233 : :
234 [ # # ]: 0 : if (sector_size != DEFAULT_SECTOR_SIZE)
235 : 0 : DPRINTF("Note: sector size is %u (not %d)\n",
236 : : sector_size, DEFAULT_SECTOR_SIZE);
237 : : }
238 : : #else
239 : : sector_size = DEFAULT_SECTOR_SIZE;
240 : : #endif
241 : :
242 : : } else {
243 : : /*Local file? try fstat instead*/
244 : 0 : sectors = (stat.st_size >> SECTOR_SHIFT);
245 : 0 : sector_size = DEFAULT_SECTOR_SIZE;
246 : : }
247 : :
248 : 0 : if (sectors == 0) {
249 : : sectors = 16836057ULL;
250 : : sector_size = DEFAULT_SECTOR_SIZE;
251 : : }
252 : :
253 : : return 0;
254 : : }
255 : :
256 : : #ifdef __linux__
257 : :
258 : 0 : int tapdisk_linux_version(void)
259 : : {
260 : : struct utsname uts;
261 : : unsigned int version, patchlevel, sublevel;
262 : : int n, err;
263 : :
264 : 0 : err = uname(&uts);
265 [ # # ]: 0 : if (err)
266 : 0 : return -errno;
267 : :
268 : 0 : n = sscanf(uts.release, "%u.%u.%u", &version, &patchlevel, &sublevel);
269 [ # # ]: 0 : if (n != 3) {
270 : 0 : sublevel = 0;
271 : 0 : n = sscanf(uts.release, "%u.%u", &version, &patchlevel);
272 [ # # ]: 0 : if (n != 2)
273 : : return -ENOSYS;
274 : : }
275 : :
276 : 0 : return KERNEL_VERSION(version, patchlevel, sublevel);
277 : : }
278 : :
279 : : #else
280 : :
281 : : int tapdisk_linux_version(void)
282 : : {
283 : : return -ENOSYS;
284 : : }
285 : :
286 : : #endif
287 : :
288 : : #ifdef WORDS_BIGENDIAN
289 : : uint64_t ntohll(uint64_t a) {
290 : : return a;
291 : : }
292 : : #else
293 : 0 : uint64_t ntohll(uint64_t a) {
294 : 0 : uint32_t lo = a & 0xffffffff;
295 : 0 : uint32_t hi = a >> 32U;
296 : 0 : lo = ntohl(lo);
297 : 0 : hi = ntohl(hi);
298 : 0 : return ((uint64_t) lo) << 32U | hi;
299 : : }
300 : : #endif
301 : : #define htonll ntohll
302 : :
303 : :
304 : : /**
305 : : * Simplified version of snprintf that return 0 if everything has gone OK and
306 : : * +errno if not (including the buffer not being large enough to hold the
307 : : * string).
308 : : */
309 : : int
310 : 0 : tapdisk_snprintf(char *buf, int * const off, int * const size,
311 : : unsigned int depth, const char *format, ...) {
312 : :
313 : : int err, i;
314 : : va_list ap;
315 : :
316 [ # # ]: 0 : ASSERT(buf);
317 [ # # ]: 0 : ASSERT(off);
318 [ # # ]: 0 : ASSERT(size);
319 : :
320 [ # # ]: 0 : for (i = 0; i < depth; i++) {
321 : 0 : err = snprintf(buf + *off, *size, " ");
322 [ # # ]: 0 : if (err < 0)
323 : 0 : return errno;
324 : 0 : *off += err;
325 : 0 : *size -= err;
326 : : }
327 : :
328 : 0 : va_start(ap, format);
329 : 0 : err = vsnprintf(buf + *off, *size, format, ap);
330 : 0 : va_end(ap);
331 [ # # ]: 0 : if (err >= *size)
332 : : return ENOBUFS;
333 [ # # ]: 0 : else if (err < 0)
334 : 0 : return errno;
335 : 0 : *off += err;
336 : 0 : *size -= err;
337 : 0 : return 0;
338 : : }
339 : :
340 : : void
341 : 0 : shm_init(struct shm *shm) {
342 : :
343 [ # # ]: 0 : ASSERT(shm);
344 : :
345 : 0 : shm->path = NULL;
346 : 0 : shm->fd = -1;
347 : 0 : shm->mem = NULL;
348 : 0 : shm->size = 0;
349 : 0 : }
350 : :
351 : :
352 : : int
353 : 0 : shm_destroy(struct shm *shm) {
354 : :
355 : 0 : int err = 0;
356 : :
357 [ # # ]: 0 : ASSERT(shm);
358 : :
359 [ # # ]: 0 : if (shm->mem) {
360 : 0 : err = munmap(shm->mem, shm->size);
361 [ # # ]: 0 : if (err == -1) {
362 : 0 : err = errno;
363 : 0 : EPRINTF("failed to munmap %s: %s\n", shm->path,
364 : : strerror(err));
365 : : goto out;
366 : : }
367 : 0 : shm->mem = NULL;
368 : : }
369 : :
370 [ # # ]: 0 : if (shm->fd != -1) {
371 : : do {
372 : 0 : err = close(shm->fd);
373 [ # # ]: 0 : if (err)
374 : 0 : err = errno;
375 [ # # ]: 0 : } while (err == EINTR);
376 [ # # ]: 0 : if (err) {
377 : 0 : EPRINTF("failed to close %s: %s\n", shm->path, strerror(err));
378 : : goto out;
379 : : }
380 : 0 : shm->fd = -1;
381 : : }
382 : :
383 [ # # ]: 0 : if (shm->path) {
384 : 0 : err = unlink(shm->path);
385 [ # # ]: 0 : if (unlikely(err == -1)) {
386 : 0 : err = errno;
387 [ # # ]: 0 : if (unlikely(err != ENOENT))
388 : : goto out;
389 : : else
390 : 0 : err = 0;
391 : : }
392 : : }
393 : :
394 : : out:
395 : 0 : return err;
396 : : }
397 : :
398 : :
399 : : int
400 : 0 : shm_create(struct shm *shm) {
401 : :
402 : : int err;
403 : :
404 [ # # ]: 0 : ASSERT(shm);
405 [ # # ]: 0 : ASSERT(shm->path);
406 [ # # ]: 0 : ASSERT(shm->size);
407 : :
408 : 0 : shm->fd = open(shm->path, O_CREAT | O_TRUNC | O_RDWR | O_EXCL,
409 : : S_IRUSR | S_IWUSR);
410 [ # # ]: 0 : if (shm->fd == -1) {
411 : 0 : err = errno;
412 : 0 : EPRINTF("failed to open %s: %s\n", shm->path, strerror(err));
413 : : goto out;
414 : : }
415 : :
416 : 0 : err = ftruncate(shm->fd, shm->size);
417 [ # # ]: 0 : if (err == -1) {
418 : 0 : err = errno;
419 : 0 : EPRINTF("failed to truncate %s: %s\n", shm->path, strerror(err));
420 : : goto out;
421 : : }
422 : :
423 : 0 : shm->mem = mmap(NULL, shm->size, PROT_READ | PROT_WRITE, MAP_SHARED,
424 : : shm->fd, 0);
425 [ # # ]: 0 : if (shm->mem == MAP_FAILED) {
426 : 0 : err = errno;
427 : 0 : EPRINTF("failed to mmap %s: %s\n", shm->path, strerror(err));
428 : : goto out;
429 : : }
430 : :
431 : : out:
432 [ # # ]: 0 : if (err) {
433 : 0 : int err2 = shm_destroy(shm);
434 [ # # ]: 0 : if (err2)
435 : 0 : EPRINTF("failed to clean up failed shared memory file creation: "
436 : : "%s (error ignored)\n", strerror(-err2));
437 : : }
438 : 0 : return err;
439 : : }
|