1 /* Simple subrs. 2 Copyright (C) 2019-2020 Free Software Foundation, Inc. 3 4 This file is part of libctf. 5 6 libctf is free software; you can redistribute it and/or modify it under 7 the terms of the GNU General Public License as published by the Free 8 Software Foundation; either version 3, or (at your option) any later 9 version. 10 11 This program is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 See the GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; see the file COPYING. If not see 18 <http://www.gnu.org/licenses/>. */ 19 20 #include <ctf-impl.h> 21 #ifdef HAVE_MMAP 22 #include <sys/mman.h> 23 #endif 24 #include <sys/types.h> 25 #include <stdarg.h> 26 #include <string.h> 27 #include <unistd.h> 28 29 int _libctf_version = CTF_VERSION; /* Library client version. */ 30 int _libctf_debug = 0; /* Debugging messages enabled. */ 31 32 /* Private, read-only mmap from a file, with fallback to copying. 33 34 No handling of page-offset issues at all: the caller must allow for that. */ 35 36 _libctf_malloc_ void * 37 ctf_mmap (size_t length, size_t offset, int fd) 38 { 39 void *data; 40 41 #ifdef HAVE_MMAP 42 data = mmap (NULL, length, PROT_READ, MAP_PRIVATE, fd, offset); 43 if (data == MAP_FAILED) 44 data = NULL; 45 #else 46 if ((data = malloc (length)) != NULL) 47 { 48 if (ctf_pread (fd, data, length, offset) <= 0) 49 { 50 free (data); 51 data = NULL; 52 } 53 } 54 #endif 55 return data; 56 } 57 58 void 59 ctf_munmap (void *buf, size_t length _libctf_unused_) 60 { 61 #ifdef HAVE_MMAP 62 (void) munmap (buf, length); 63 #else 64 free (buf); 65 #endif 66 } 67 68 ssize_t 69 ctf_pread (int fd, void *buf, ssize_t count, off_t offset) 70 { 71 ssize_t len; 72 size_t acc = 0; 73 char *data = (char *) buf; 74 75 #ifdef HAVE_PREAD 76 while (count > 0) 77 { 78 errno = 0; 79 if (((len = pread (fd, data, count, offset)) < 0) && 80 errno != EINTR) 81 return len; 82 if (errno == EINTR) 83 continue; 84 85 acc += len; 86 if (len == 0) /* EOF. */ 87 return acc; 88 89 count -= len; 90 offset += len; 91 data += len; 92 } 93 return acc; 94 #else 95 off_t orig_off; 96 97 if ((orig_off = lseek (fd, 0, SEEK_CUR)) < 0) 98 return -1; 99 if ((lseek (fd, offset, SEEK_SET)) < 0) 100 return -1; 101 102 while (count > 0) 103 { 104 errno = 0; 105 if (((len = read (fd, data, count)) < 0) && 106 errno != EINTR) 107 return len; 108 if (errno == EINTR) 109 continue; 110 111 acc += len; 112 if (len == 0) /* EOF. */ 113 break; 114 115 count -= len; 116 data += len; 117 } 118 if ((lseek (fd, orig_off, SEEK_SET)) < 0) 119 return -1; /* offset is smashed. */ 120 #endif 121 122 return acc; 123 } 124 125 const char * 126 ctf_strerror (int err) 127 { 128 return (const char *) (strerror (err)); 129 } 130 131 /* Set the CTF library client version to the specified version. If version is 132 zero, we just return the default library version number. */ 133 int 134 ctf_version (int version) 135 { 136 if (version < 0) 137 { 138 errno = EINVAL; 139 return -1; 140 } 141 142 if (version > 0) 143 { 144 /* Dynamic version switching is not presently supported. */ 145 if (version != CTF_VERSION) 146 { 147 errno = ENOTSUP; 148 return -1; 149 } 150 ctf_dprintf ("ctf_version: client using version %d\n", version); 151 _libctf_version = version; 152 } 153 154 return _libctf_version; 155 } 156 157 void 158 libctf_init_debug (void) 159 { 160 static int inited; 161 if (!inited) 162 { 163 _libctf_debug = getenv ("LIBCTF_DEBUG") != NULL; 164 inited = 1; 165 } 166 } 167 168 void ctf_setdebug (int debug) 169 { 170 /* Ensure that libctf_init_debug() has been called, so that we don't get our 171 debugging-on-or-off smashed by the next call. */ 172 173 libctf_init_debug(); 174 _libctf_debug = debug; 175 ctf_dprintf ("CTF debugging set to %i\n", debug); 176 } 177 178 int ctf_getdebug (void) 179 { 180 return _libctf_debug; 181 } 182 183 _libctf_printflike_ (1, 2) 184 void ctf_dprintf (const char *format, ...) 185 { 186 if (_libctf_debug) 187 { 188 va_list alist; 189 190 va_start (alist, format); 191 fflush (stdout); 192 (void) fputs ("libctf DEBUG: ", stderr); 193 (void) vfprintf (stderr, format, alist); 194 va_end (alist); 195 } 196 } 197