1 // Copyright (C) 2015 James Buren
2 //
3 // This file is part of revdep.
4 //
5 // revdep is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // revdep is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with revdep. If not, see <http://www.gnu.org/licenses/>.
17
18 #define _IN_UTILITY_
19 #include "utility.h"
20 #include "global.h"
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <stdint.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <sys/stat.h>
29 #include <sys/mman.h>
30 #include <errno.h>
31 #include <gelf.h>
32 #include <zlib.h>
33
34 extern void *xmalloc(unsigned int bytes)
35 {
36 void *p;
37
38 if(bytes == 0)
39 {
40 logger(LOG_BRIEF, "%s: bytes is zero\n", __func__);
41 abort();
42 }
43
44 if((p = malloc(bytes)) == NULL)
45 {
46 logger(LOG_BRIEF, "%s: out of memory\n", __func__);
47 abort();
48 }
49
50 return p;
51 }
52
53 extern void *xrealloc(void *p, unsigned int bytes)
54 {
55 if(p == NULL)
56 {
57 logger(LOG_BRIEF, "%s: p is NULL\n", __func__);
58 abort();
59 }
60
61 if(bytes == 0)
62 {
63 logger(LOG_BRIEF, "%s: bytes is zero\n", __func__);
64 abort();
65 }
66
67 if((p = realloc(p, bytes)) == NULL)
68 {
69 logger(LOG_BRIEF, "%s: out of memory\n", __func__);
70 abort();
71 }
72
73 return p;
74 }
75
76 extern char *xstrdup(const char *in)
77 {
78 char *out;
79
80 if(in == NULL)
81 {
82 logger(LOG_BRIEF, "%s: s is NULL\n", __func__);
83 abort();
84 }
85
86 if((out = strdup(in)) == NULL)
87 {
88 logger(LOG_BRIEF, "%s: out of memory\n", __func__);
89 abort();
90 }
91
92 return out;
93 }
94
95 extern void logger(int level, const char *fmt, ...)
96 {
97 va_list args;
98
99 if(level > rd.verbose)
100 return;
101
102 va_start(args, fmt);
103
104 vfprintf(stdout, fmt, args);
105
106 va_end(args);
107 }
108
109 extern char *strtrim(char *s)
110 {
111 static const char SPACE[] = " \t\r\n\v\f";
112 unsigned int left;
113 unsigned int middle;
114 //unsigned int right;
115
116 left = strspn(s, SPACE);
117
118 middle = strcspn(s + left, SPACE);
119
120 //right = strspn(s + left + middle, SPACE);
121
122 memmove(s, s + left, middle);
123
124 s[middle] = '\0';
125
126 return s;
127 }
128
129 extern unsigned int string_crc32(const char *s)
130 {
131 unsigned int hash;
132
133 if(s == NULL || s[0] == '\0')
134 {
135 errno = EINVAL;
136 return -1;
137 }
138
139 hash = crc32(0, Z_NULL, 0);
140
141 hash = crc32(hash, (Bytef *) s, strlen(s) + 1);
142
143 return hash;
144 }
145
146 extern int open_file_in_memory(const char *path, char **text, unsigned int *length)
147 {
148 struct stat st;
149 int fd;
150
151 if(path == NULL || path[0] == '\0' || text == NULL || length == NULL)
152 {
153 errno = EINVAL;
154 return -1;
155 }
156
157 if((fd = open(path, O_RDONLY)) == -1)
158 {
159 return -1;
160 }
161
162 if(fstat(fd, &st) == -1)
163 {
164 close(fd);
165 return -1;
166 }
167
168 if((text[0] = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == NULL)
169 {
170 close(fd);
171 return -1;
172 }
173
174 // We don't need to keep the fd around.
175 close(fd);
176
177 length[0] = st.st_size;
178
179 return 0;
180 }
181
182 extern void close_file_in_memory(char *text, unsigned int length)
183 {
184 if(text == NULL || length == 0)
185 return;
186
187 munmap(text, length);
188 }
189
190 extern int parse_file_in_memory(char *text, parse_cb_t cb)
191 {
192 static const char RS[] = "\n\n";
193 static const char FS[] = "\n";
194 char *r_start;
195 char *r_end;
196 char *f_start;
197 char *f_end;
198 int record;
199 int field;
200
201 if(text == NULL || text[0] == '\0' || cb == NULL)
202 {
203 errno = EINVAL;
204 return -1;
205 }
206
207 inline int next_record(void)
208 {
209 // Test for EOF.
210 // Return EOF if so.
211 if(r_start[0] == '\0')
212 return -1;
213
214 // Test for RS.
215 // Skip RS if so.
216 if(strncmp(r_start, RS, strlen(RS)) == 0)
217 r_start += strlen(RS);
218
219 // Find the RS.
220 // If RS is not found, then use the end of the file.
221 if((r_end = strstr(r_start, RS)) == NULL)
222 r_end = r_start + strlen(r_start);
223
224 return 0;
225 }
226
227 inline int next_field(void)
228 {
229 // Test for RS and EOF.
230 // Return EOF if either is found.
231 if(strncmp(f_start, RS, strlen(RS)) == 0 || strcmp(f_start, FS) == 0 || f_start[0] == '\0')
232 return -1;
233
234 // Test for FS.
235 // Skip FS if so.
236 if(f_start[0] == FS[0])
237 f_start += 1;
238
239 // Find the FS.
240 // If FS is not found, then use the end of the file.
241 if((f_end = strchr(f_start, FS[0])) == NULL)
242 f_end = f_start + strlen(f_start);
243
244 return 0;
245 }
246
247 for( r_start = text, record = 0 ; next_record() == 0 ; r_start = r_end, ++record )
248 {
249 for( f_start = r_start, field = 0 ; next_field() == 0 ; f_start = f_end, ++field )
250 {
251 cb(record, field, f_start, f_end);
252 }
253 }
254
255 return 0;
256 }
257
258 extern int get_ld_for_file(const char *pkg, const char *path, const char **ld)
259 {
260 struct stat st;
261 int fd = -1;
262 Elf *elf = NULL;
263 GElf_Ehdr ehdr;
264 size_t i;
265 size_t phdrnum;
266 GElf_Phdr phdr;
267 int rv = -1;
268
269 if(pkg == NULL || pkg[0] == '\0' || path == NULL || path[0] == '\0' || ld == NULL)
270 {
271 errno = EINVAL;
272 goto bail;
273 }
274
275 if(lstat(path, &st) == -1)
276 {
277 logger(LOG_ERROR, "%s:%s: could not stat file\n", pkg, path);
278 goto bail;
279 }
280
281 if(!S_ISREG(st.st_mode))
282 {
283 goto bail;
284 }
285
286 if((fd = open(path, O_RDONLY)) == -1)
287 {
288 logger(LOG_ERROR, "%s:%s: could not open file\n", pkg, path);
289 goto bail;
290 }
291
292 if((elf = elf_begin(fd, ELF_C_READ_MMAP, NULL)) == NULL)
293 {
294 goto bail;
295 }
296
297 if(elf_kind(elf) != ELF_K_ELF)
298 {
299 goto bail;
300 }
301
302 if(gelf_getehdr(elf, &ehdr) == NULL)
303 {
304 goto bail;
305 }
306
307 // Check if file is executable or shared library
308 switch(ehdr.e_type)
309 {
310 case ET_EXEC:
311 break;
312
313 case ET_DYN:
314 break;
315
316 default:
317 goto bail;
318 }
319
320 // Check if file has SYSTEMV or LINUX ABI
321 switch(ehdr.e_ident[EI_OSABI])
322 {
323 case ELFOSABI_NONE:
324 break;
325
326 case ELFOSABI_LINUX:
327 break;
328
329 default:
330 goto bail;
331 }
332
333 // Check if file is supported by this host's architecture
334 switch(ehdr.e_machine)
335 {
336
337 #if defined(__i386__) || defined(__x86_64__)
338 case EM_386:
339 break;
340 #endif
341
342 #if defined(__x86_64__)
343 case EM_X86_64:
344 break;
345 #endif
346
347 #if defined(__arm__)
348 case EM_ARM:
349 break;
350 #endif
351
352 default:
353 goto bail;
354
355 }
356
357 // Check if file has a dynamic section
358 if(elf_getphdrnum(elf, &phdrnum) == -1)
359 {
360 goto bail;
361 }
362
363 for( i = 0 ; i < phdrnum ; ++i )
364 {
365 if(gelf_getphdr(elf, i, &phdr) != NULL && phdr.p_type == PT_DYNAMIC)
366 {
367 break;
368 }
369 }
370
371 // If true, then a dynamic section was not found.
372 if(i == phdrnum)
373 {
374 goto bail;
375 }
376
377 // Check if file has a known LD binary
378 switch(ehdr.e_ident[EI_CLASS])
379 {
380
381 #if defined(__i386__)
382 case ELFCLASS32:
383 ld[0] = "/lib/ld-linux.so.2";
384 break;
385 #elif defined(__x86_64__)
386 case ELFCLASS32:
387 ld[0] = "/lib32/ld-linux.so.2";
388 break;
389 case ELFCLASS64:
390 ld[0] = "/lib/ld-linux-x86-64.so.2";
391 break;
392 #elif defined(__arm__)
393 case ELFCLASS32:
394 ld[0] = "/lib/ld-linux-armhf.so.3";
395 break;
396 #else
397 #error "Unsupported Architecture"
398 #endif
399
400 default:
401 goto bail;
402
403 }
404
405 rv = 0;
406
407 bail:
408
409 if(elf != NULL)
410 elf_end(elf);
411
412 if(fd != -1)
413 close(fd);
414
415 return rv;
416 }
|