summaryrefslogtreecommitdiff
path: root/revdep/utility.c
blob: 67247e1ae9f28ff6fcf90c0eebea1706b27545f4 (plain)
    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 }

Generated by cgit