1 #define _LARGEFILE64_SOURCE	/* required for GLIBC to enable stat64 and friends */
2 #include "doassert.h"
3 #include <errno.h>
4 #include <signal.h>
5 #include <stdlib.h>
6 #include <limits.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <sys/types.h>
10 #include <regex.h>
11 #include <sys/stat.h>
12 #include <sys/time.h>
13 #include <time.h>
14 #include <unistd.h>
15 #include <glob.h>
16 #ifdef _POSIX_PRIORITY_SCHEDULING
17 #include <sched.h>
18 #endif
19 #include <pwd.h>
20 #include <sys/wait.h>
21 #include <fcntl.h>
22 #if defined(sun) || defined(__sun)
23 #include <sys/loadavg.h>
24 #endif
25 #include <dirent.h>
26 #include <ctype.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <fcntl.h>
30 
31 #include "version.h"
32 #include "error.h"
33 #include "mem.h"
34 #include "mt.h"
35 #include "term.h"
36 #include "globals.h"
37 #include "utils.h"
38 
39 
find_path_max(void)40 int find_path_max(void)
41 {
42 #ifdef PATH_MAX
43 	int path_max = PATH_MAX;
44 #else
45 	int path_max = pathconf("/", _PC_PATH_MAX);
46 	if (path_max <= 0)
47 	{
48 		if (errno) error_exit(TRUE, FALSE, "pathconf() failed\n");
49 
50 		path_max = 4096;
51 	}
52 	else
53 		path_max++; /* since its relative to root */
54 #endif
55 	if (path_max > 4096)
56 		path_max = 4096;
57 
58 	return path_max;
59 }
60 
myrand(int max)61 int myrand(int max)
62 {
63 	return (int)(((double)max * (double)rand()) / (double)RAND_MAX);
64 }
65 
WRITE(int fd,char * whereto,size_t len,char * for_whom)66 ssize_t WRITE(int fd, char *whereto, size_t len, char *for_whom)
67 {
68 	ssize_t cnt=0;
69 
70 	while(len>0)
71 	{
72 		ssize_t rc;
73 
74 		rc = write(fd, whereto, len);
75 
76 		if (rc == -1)
77 		{
78 			if (errno != EINTR && errno != EAGAIN)
79 				error_exit(TRUE, FALSE, "Problem writing to file descriptor while processing %s.\n", for_whom);
80 		}
81 		else if (rc == 0)
82 		{
83 			break;
84 		}
85 		else
86 		{
87 			whereto += rc;
88 			len -= rc;
89 			cnt += rc;
90 		}
91 	}
92 
93 	return cnt;
94 }
95 
get_load_values(double * v1,double * v2,double * v3)96 void get_load_values(double *v1, double *v2, double *v3)
97 {
98 #if !defined(__UCLIBC__) && (defined(__FreeBSD__) || defined(linux) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) || defined(__GNU__) || defined(__sun) || defined(sun))
99 #if defined(__GLIBC__) && ( __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2))
100 	/* Older glibc doesn't have getloadavg() - use sysinfo() */
101 	/* thanks to Ville Herva for this code! */
102 	double scale = 1 << SI_LOAD_SHIFT;
103 	struct sysinfo si;
104 
105 	if (sysinfo(&si) == -1)
106 	{
107 		/* let's exit: if these kind of system-
108 		 * calls start to fail, something must be
109 		 * really wrong
110 		 */
111 		error_exit(TRUE, FALSE, "sysinfo() failed\n");
112 	}
113 
114 	*v1 = (double)si.loads[0] / scale;
115 	*v2 = (double)si.loads[1] / scale;
116 	*v3 = (double)si.loads[2] / scale;
117 #else
118 	double loadavg[3];
119 	if (getloadavg(loadavg, 3) == -1)
120 	{
121 		/* see comment on sysinfo() */
122 		error_exit(TRUE, FALSE, "getloadavg() failed\n");
123 	}
124 	*v1 = loadavg[0];
125 	*v2 = loadavg[1];
126 	*v3 = loadavg[2];
127 #endif
128 #else
129 	*v1 = *v2 = *v3 = -1.0;
130 #endif
131 }
132 
get_vmsize(pid_t pid)133 int get_vmsize(pid_t pid)
134 {
135 	int vmsize = -1;
136 #if defined(linux)
137 	FILE *fh;
138 	int path_max = find_path_max();
139 	char *path = mymalloc(path_max);
140 
141 	assert(pid > 1);
142 
143 	snprintf(path, path_max, "/proc/%d/stat", pid);
144 
145 	fh = fopen(path, "r");
146 	if (fh)
147 	{
148 		char *dummystr = mymalloc(path_max);
149 		char dummychar;
150 		int dummy;
151 
152 		if (fscanf(fh, "%d %s %c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", &dummy, dummystr, &dummychar, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &vmsize) != 23)
153 			vmsize = -1;
154 
155 		fclose(fh);
156 
157 		myfree(dummystr);
158 	}
159 
160 	myfree(path);
161 #endif
162 
163 	return vmsize;
164 }
165 
mykillpg(pid_t pid,int sigtype)166 int mykillpg(pid_t pid, int sigtype)
167 {
168 #ifdef AIX
169 	return kill(pid, sigtype);
170 #else
171 	return killpg(pid, sigtype);
172 #endif
173 }
174 
175 /** stop_process
176  * - in:      int pid  pid of process
177  * - returns: nothing
178  * this function sends a TERM-signal to the given process, sleeps for 1000 microseconds
179  * and then sends a KILL-signal to the given process if it still exists. the TERM signal
180  * is sent so the process gets the possibility to gracefully exit. if it doesn't do that
181  * in 1000 microseconds, it is terminated
182  */
stop_process(pid_t pid)183 void stop_process(pid_t pid)
184 {
185 	assert(pid > 1);
186 
187 #ifndef __APPLE__
188 	if (mykillpg(pid, SIGTERM) == -1)
189 	{
190 		if (errno != ESRCH)
191 			error_exit(TRUE, FALSE, "Problem stopping child process with PID %d (SIGTERM).\n", pid);
192 	}
193 #endif
194 
195 	usleep(1000);
196 
197 	/* process still exists? */
198 	if (mykillpg(pid, SIGTERM) == 0)
199 	{
200 		/* sleep for a millisecond... */
201 		usleep(1000);
202 
203 		/* ...and then really terminate the process */
204 		if (mykillpg(pid, SIGKILL) == -1)
205 		{
206 #ifdef __APPLE__
207 			/* don't exit if the error is EPERM: macOS doesn't allow
208 			   you to kill a process that has been already killed
209 			   (i.e. zombies), which is what we did with the second
210 			   mykillpg above. */
211 			if (errno != ESRCH && errno != EPERM)
212 #else
213 			if (errno != ESRCH)
214 #endif
215 				error_exit(TRUE, FALSE, "Problem stopping child process with PID %d (SIGKILL).\n", pid);
216 		}
217 	}
218 #ifdef __APPLE__
219 	else if (errno != ESRCH && errno != EPERM)
220 #else
221 	else if (errno != ESRCH)
222 #endif
223 	{
224 		error_exit(TRUE, FALSE, "Problem stopping child process with PID %d (SIGTERM).\n", pid);
225 	}
226 
227 	/* wait for the last remainder of the died process to go away,
228 	 * otherwhise we'll find zombies on our way
229 	 */
230 	if (waitpid(pid, NULL, WNOHANG | WUNTRACED) == -1)
231 	{
232 		if (errno != ECHILD)
233 			error_exit(TRUE, FALSE, "waitpid() failed\n");
234 	}
235 
236 #ifdef __APPLE__
237 	/* since we ignored the case of a EPERM error above,
238 	   check if the process got stopped regardless or
239 	   if we actually failed to stop it */
240 	BOOL process_gone = FALSE;
241 	for (int i = 0; i < 10; i++)
242 	{
243 		if (i != 0)
244 			usleep(1000);
245 		if (mykillpg(pid, 0) == -1)
246 		{
247 				if (errno == ESRCH)
248 				{
249 						process_gone = TRUE;
250 						break;
251 				}
252 		}
253 	}
254 
255 	if (!process_gone)
256 		error_exit(TRUE, FALSE, "Could not confirm that child process with PID %d has been stopped.\n", pid);
257 #endif
258 }
259 
260 /** delete_array
261  * - in:      char **list array of strings to free
262  *            int n       number of strings in this array
263  * - returns: nothing
264  * this function frees an array of strings: all strings are freed and
265  * also the pointer-list itself is freed
266  */
delete_array(char ** list,int n)267 void delete_array(char **list, int n)
268 {
269 	int loop;
270 
271 	assert(n >= 0);
272 
273 	for(loop=n-1; loop>=0; loop--)
274 		myfree(list[loop]);
275 
276 	myfree(list);
277 }
278 
find_char_offset(char * str,char what)279 int find_char_offset(char *str, char what)
280 {
281 	char *pnt;
282 
283 	assert(what > 0);
284 
285 	pnt = strchr(str, what);
286 	if (!pnt)
287 		return -1;
288 
289 	return (int)(pnt - str);
290 }
291 
file_info(char * filename,off64_t * file_size,time_field_t tft,time_t * ts,mode_t * mode)292 int file_info(char *filename, off64_t *file_size, time_field_t tft, time_t *ts, mode_t *mode)
293 {
294 	struct stat64 buf;
295 
296 	if (stat64(filename, &buf) == -1)
297 	{
298 		if (errno != ENOENT)
299 			error_exit(TRUE, FALSE, "Error while obtaining details of file %s.\n", filename);
300 
301 		return -1;
302 	}
303 
304 	if (file_size)
305 		*file_size = buf.st_size;
306 
307 	if (ts)
308 	{
309 		if (tft == TT_ATIME)
310 			*ts = buf.st_atime;
311 		else if (tft == TT_MTIME)
312 			*ts = buf.st_mtime;
313 		else if (tft == TT_CTIME)
314 			*ts = buf.st_ctime;
315 		else
316 		{
317 			assert(tft == 0);
318 			*ts = 0;
319 		}
320 	}
321 
322 	if (mode)
323 		*mode = buf.st_mode;
324 
325 	return 0;
326 }
327 
file_exist(char * filename)328 int file_exist(char *filename)
329 {
330 	struct stat buf;
331 	int rc = stat(filename, &buf);
332 
333 	if (rc == -1 && errno != ENOENT)
334 		error_exit(TRUE, FALSE, "stat() on file %s failed.\n", filename);
335 
336 	return rc;
337 }
338 
convert_regexp_error(int error,const regex_t * preg)339 char * convert_regexp_error(int error, const regex_t *preg)
340 {
341 	/* errors are specified not to be longer then 256 characters */
342 	char *multitail_string = "MultiTail warning: regular expression failed, reason: ";
343 	int len = strlen(multitail_string);
344 	char *error_out = NULL;
345 	const int max_err_len = 256;
346 
347 	assert(error != 0);
348 
349 	if (error != REG_NOMATCH)
350 	{
351 		error_out = (char *)mymalloc(max_err_len + len + 1);
352 
353 		memcpy(error_out, multitail_string, len);
354 
355 		/* convert regexp error */
356 		regerror(error, preg, &error_out[len], max_err_len);
357 	}
358 
359 	return error_out;
360 }
361 
amount_to_str(long long int amount)362 char * amount_to_str(long long int amount)
363 {
364 	char *out = mymalloc(AMOUNT_STR_LEN);	/* ...XB\0 */
365 
366 	assert(amount >= 0);
367 
368 	if (amount >= M_GB)	/* GB */
369 		snprintf(out, AMOUNT_STR_LEN, "%dGB", (int)((amount + M_GB - 1) / M_GB));
370 	else if (amount >= M_MB)	/* MB */
371 		snprintf(out, AMOUNT_STR_LEN, "%dMB", (int)((amount + M_MB - 1) / M_MB));
372 	else if (amount >= M_KB)	/* KB */
373 		snprintf(out, AMOUNT_STR_LEN, "%dKB", (int)((amount + M_KB - 1) / M_KB));
374 	else
375 		snprintf(out, AMOUNT_STR_LEN, "%d", (int)(amount));
376 
377 	return out;
378 }
379 
getuserinfo(void)380 struct passwd *getuserinfo(void)
381 {
382 	return getpwuid(geteuid());
383 }
384 
getusername(void)385 char * getusername(void)
386 {
387 	static char username[128] = "???";
388 
389 	if (username[0] == '?')
390 	{
391 		char *logname = getenv("LOGNAME");
392 		if (logname)
393 		{
394 			strncpy(username, logname, 128);
395 			username[127] = 0x00;
396 		}
397 	}
398 
399 	if (username[0] == '?')
400 	{
401 		struct passwd *pw = getuserinfo();
402 
403 		if (pw)
404 		{
405 			strncpy(username, getuserinfo() -> pw_name, sizeof(username));
406 			username[sizeof(username) - 1] = 0x00;
407 		}
408 	}
409 
410 	return username;
411 }
412 
413 /* these are there because AIX/IRIX can return EINTR for those */
myopen(char * path,int mode)414 int myopen(char *path, int mode)
415 {
416 	int fd;
417 
418 	for(;;)
419 	{
420 		fd = open64(path, mode);
421 		if (fd == -1)
422 		{
423 			if (errno == EINTR || errno == EAGAIN) /* for AIX */
424 				continue;
425 
426 			return fd;
427 		}
428 
429 		break;
430 	}
431 
432 	return fd;
433 }
434 
myclose(int fd)435 int myclose(int fd)
436 {
437 	for(;;)
438 	{
439 		if (close(fd) == -1)
440 		{
441 			if (errno == EINTR || errno == EAGAIN) /* for AIX */
442 				continue;
443 
444 			return -1;
445 		}
446 
447 		return 0;
448 	}
449 }
450 
shorten_filename(char * in,int max_len)451 char * shorten_filename(char *in, int max_len)
452 {
453 	static char buffer[4096];
454 	int len = strlen(in);
455 	int cutlen, dummy;
456 
457 	assert(max_len >= 0);
458 
459 	if (len <= max_len)
460 		return in;
461 
462 	cutlen = (max_len - 3) / 2;
463 
464 	memcpy(buffer, in, cutlen);
465 	memcpy(&buffer[cutlen], "...", 3);
466 
467 	dummy = max_len - (cutlen + 3);
468 	memcpy(&buffer[cutlen + 3], &in[len - dummy], dummy + 1);
469 
470 	return buffer;
471 }
472 
get_ts(void)473 double get_ts(void)
474 {
475 	struct timeval ts;
476 
477 	if (gettimeofday(&ts, NULL) == -1)
478 		error_exit(TRUE, FALSE, "gettimeofday() failed");
479 
480 	return (((double)ts.tv_sec) + ((double)ts.tv_usec)/1000000.0);
481 }
482 
match_files(char * search_for,char ** path,char *** found,char ** isdir)483 int match_files(char *search_for, char **path, char ***found, char **isdir)
484 {
485 	DIR *dir;
486 	struct dirent *entry;
487 	char *cur_dir = mymalloc(find_path_max() + 1);
488 	char *fname;
489 	char **list = NULL;
490 	int nfound = 0;
491 	size_t fname_size;
492 	int path_len;
493 	int s1, s2;
494 	char *slash = strrchr(search_for, '/');
495 	if (slash)
496 	{
497 		fname = mystrdup(slash + 1);
498 		*(slash + 1) = 0x00;
499 		*path = mystrdup(search_for);
500 	}
501 	else
502 	{
503 		*path = mystrdup("./");
504 		fname = mystrdup(search_for);
505 	}
506 	fname_size = strlen(fname);
507 	path_len = strlen(*path);
508 
509 	dir = opendir(*path);
510 	if (!dir)
511 	{
512 		free(cur_dir);
513 		return 0;
514 	}
515 
516 	memcpy(cur_dir, *path, path_len + 1);
517 
518 	while((entry = readdir(dir)) != NULL)
519 	{
520 		if ((fname_size == 0 || strncmp(entry -> d_name, fname, fname_size) == 0) && strcmp(entry -> d_name, ".") != 0 &&
521 				strcmp(entry -> d_name, "..") != 0)
522 		{
523 			struct stat finfo;
524 
525 			/* get filename */
526 			list = (char **)myrealloc(list, (nfound + 1) * sizeof(char *));
527 			list[nfound] = mystrdup(entry -> d_name);
528 
529 			/* check if the file is a directory */
530 			*isdir = (char *)myrealloc(*isdir, (nfound + 1) * sizeof(char));
531 			strncpy(&cur_dir[path_len], entry -> d_name, max(0,find_path_max() - path_len));
532 			if (stat(cur_dir, &finfo) == -1)
533 			{
534 				if (errno != ENOENT)	/* file did not disappear? then something is very wrong */
535 					error_exit(TRUE, FALSE, "Error while invoking stat() %s.\n", cur_dir);
536 			}
537 			(*isdir)[nfound] = S_ISDIR(finfo.st_mode)?1:0;
538 
539 			nfound++;
540 		}
541 	}
542 
543 	if (closedir(dir) == -1)
544 		error_exit(TRUE, FALSE, "closedir() failed\n");
545 
546 	/*	qsort( (void *)list, (size_t)nfound, sizeof(char *), compare_filenames); */
547 	for(s1=0; s1<(nfound - 1); s1++)
548 	{
549 		for(s2=s1+1; s2<nfound; s2++)
550 		{
551 			if (strcasecmp(list[s2], list[s1]) < 0)
552 			{
553 				char *fdummy = list[s1], ddummy = (*isdir)[s1];
554 
555 				list[s1] = list[s2];
556 				(*isdir)[s1] = (*isdir)[s2];
557 				list[s2] = fdummy;
558 				(*isdir)[s2] = ddummy;
559 			}
560 		}
561 	}
562 
563 	*found = list;
564 
565 	myfree(fname);
566 	myfree(cur_dir);
567 
568 	return nfound;
569 }
570 
setup_for_childproc(int fd,char close_fd_0,char * term)571 void setup_for_childproc(int fd, char close_fd_0, char *term)
572 {
573 	int term_len = strlen(term) + 5;
574 	char *dummy = (char *)mymalloc(term_len + 1);
575 
576 	if (close_fd_0) if (-1 == myclose(0)) error_exit(TRUE, FALSE, "close() failed\n");
577 	if (-1 == myclose(1)) error_exit(TRUE, FALSE, "close() failed\n");
578 	if (-1 == myclose(2)) error_exit(TRUE, FALSE, "close() failed\n");
579 	if (close_fd_0) if (-1 == mydup(fd)) error_exit(TRUE, FALSE, "dup() failed\n");
580 	if (-1 == mydup(fd)) error_exit(TRUE, FALSE, "dup() failed\n");
581 	if (-1 == mydup(fd)) error_exit(TRUE, FALSE, "dup() failed\n");
582 
583 	/*
584 	 * not doing this: it also clears the 'PATH'
585 	 * I could make first do a getenv for PATH and then put it
586 	 * back after the clearenv, but what would be the point of
587 	 * doing the clearenv in the first place?
588 	 *
589 	 *	if (clearenv() == -1)
590 	 *	{
591 	 *		fprintf(stderr, "WARNING: could not clear environment variables: %s (%d)\n", strerror(errno), errno);
592 	 *		exit(1);
593 	 *	}
594 	 */
595 
596 	/* set terminal */
597 	assert(term != NULL);
598 	snprintf(dummy, term_len, "TERM=%s", term);
599 	if (putenv(dummy) == -1)
600 		fprintf(stderr, "setup_for_childproc: Could not set TERM environment-variable (%s): %s (%d)\n", dummy, strerror(errno), errno);
601 
602 	(void)umask(007);
603 }
604 
open_null(void)605 int open_null(void)
606 {
607 	int fd = myopen("/dev/null", O_RDWR);
608 	if (fd == -1)
609 		error_exit(TRUE, FALSE, "Failed to open file /dev/null.\n");
610 
611 	return fd;
612 }
613 
free_re(re * cur_re)614 void free_re(re *cur_re)
615 {
616 	if (cur_re)
617 	{
618 		myfree(cur_re -> regex_str);
619 		if (cur_re -> use_regex)
620 			regfree(&cur_re -> regex);
621 
622 		myfree(cur_re -> cmd);
623 	}
624 }
625 
find_most_recent_file(char * filespec,char * cur_file)626 char * find_most_recent_file(char *filespec, char *cur_file)
627 {
628 	glob_t files;
629 	char *selected_file = NULL;
630 	unsigned int loop;
631 	time_t prev_ts = (time_t)0;
632 
633 	/* get timestamp of previous file */
634 	if (cur_file)
635 	{
636 		if (file_info(cur_file, NULL, TT_MTIME, &prev_ts, NULL) == -1)
637 		{
638 			prev_ts = (time_t)0;
639 		}
640 	}
641 
642 	/* get list of files that match */
643 #if defined(__APPLE__) || defined(__CYGWIN__)
644 	if (glob(filespec, GLOB_ERR | GLOB_NOSORT, NULL, &files) != 0)
645 #else
646 	if (glob(filespec, GLOB_ERR | GLOB_NOSORT | GLOB_NOESCAPE, NULL, &files) != 0)
647 #endif
648 	{
649 		return NULL;
650 	}
651 
652 	/* see if any of them is more recent than the current one */
653 	for(loop=0; loop<files.gl_pathc; loop++)
654 	{
655 		time_t new_ts;
656 
657 		/* current file? then skip it */
658 		if (cur_file != NULL && strcmp(cur_file, files.gl_pathv[loop]) == 0)
659 			continue;
660 
661 		/* get the modificationtime of this found file */
662 		if (file_info(files.gl_pathv[loop], NULL, TT_MTIME, &new_ts, NULL) == -1)
663 		{
664 			new_ts = (time_t)0;
665 		}
666 
667 		/* more recent? */
668 		if (new_ts > prev_ts)
669 		{
670 			selected_file = files.gl_pathv[loop];
671 			prev_ts = new_ts;
672 		}
673 	}
674 
675 	/* found a file? then remember the filename */
676 	if (selected_file != NULL)
677 	{
678 		selected_file = mystrdup(selected_file);
679 	}
680 
681 	globfree(&files);
682 
683 	return selected_file;
684 }
685 
zerotomin(char c)686 char zerotomin(char c)
687 {
688 	if (c == 0)
689 		return 'n';
690 	if (c == 1)
691 		return 'y';
692 
693 	return c;
694 }
695 
find_next_par(char * start)696 char *find_next_par(char *start)
697 {
698 	char *dummy = strchr(start, ':');
699 	if (dummy)
700 	{
701 		*dummy = 0x00;
702 		dummy++;
703 	}
704 
705 	return dummy;
706 }
707 
mydup(int old_fd)708 int mydup(int old_fd)
709 {
710 	int new_fd = -1;
711 
712 	for(;;)
713 	{
714 		new_fd = dup(old_fd);
715 
716 		if (new_fd == -1)
717 		{
718 			if (errno == EINTR)
719 				continue;
720 
721 			error_exit(TRUE, FALSE, "dup() failed\n");
722 		}
723 
724 		break;
725 	}
726 
727 	return new_fd;
728 }
729 
term_t_to_string(term_t term)730 char * term_t_to_string(term_t term)
731 {
732 	switch(term)
733 	{
734 		case TERM_ANSI:
735 			return "ansi";
736 
737 		case TERM_XTERM:
738 			return "xterm";
739 
740 		case TERM_IGNORE:
741 			return "dumb";
742 	}
743 
744 	return "dumb";
745 }
746 
double_ts_to_str(dtime_t ts,char * format_str,char * dest,int dest_size)747 void double_ts_to_str(dtime_t ts, char *format_str, char *dest, int dest_size)
748 {
749 	time_t now = (time_t)ts;
750 	struct tm *ptm = localtime(&now);
751 	if (!ptm) error_exit(TRUE, FALSE, "localtime() failed\n");
752 
753 	assert(ts > 0);
754 	assert(dest_size > 0);
755 
756 	(void)strftime(dest, dest_size, format_str, ptm);
757 }
758 
get_now_ts(char * format_str,char * dest,int dest_size)759 void get_now_ts(char *format_str, char *dest, int dest_size)
760 {
761 	double_ts_to_str(get_ts(), format_str, dest, dest_size);
762 }
763 
duplicate_re_array(re * pre_in,int n_rein,re ** pre_out,int * n_reout)764 void duplicate_re_array(re *pre_in, int n_rein, re **pre_out, int *n_reout)
765 {
766 	int loop, old_n = *n_reout;
767 
768 	assert(n_rein >= 0);
769 
770 	*n_reout += n_rein;
771 	if (*n_reout)
772 	{
773 		*pre_out = (re *)myrealloc(*pre_out, (*n_reout) * sizeof(re));
774 
775 		for(loop=0; loop<n_rein; loop++)
776 		{
777 			memcpy(&(*pre_out)[loop + old_n], &pre_in[loop], sizeof(re));
778 
779 			memset(&(*pre_out)[loop + old_n].regex, 0x00, sizeof(regex_t));
780 			(*pre_out)[loop + old_n].regex_str = mystrdup(pre_in[loop].regex_str);
781 			compile_re(&(*pre_out)[loop + old_n].regex, (*pre_out)[loop + old_n].regex_str);
782 
783 			if (pre_in[loop].cmd)
784 				(*pre_out)[loop + old_n].cmd = mystrdup(pre_in[loop].cmd);
785 		}
786 	}
787 	else
788 	{
789 		*pre_out = NULL;
790 	}
791 }
792 
duplicate_es_array(strip_t * pes_in,int n_esin,strip_t ** pes_out,int * n_esout)793 void duplicate_es_array(strip_t *pes_in, int n_esin, strip_t **pes_out, int *n_esout)
794 {
795 	int loop, old_n = *n_esout;
796 
797 	assert(n_esin >= 0);
798 
799 	*n_esout += n_esin;
800 	*pes_out = (strip_t *)myrealloc(*pes_out, (*n_esout) * sizeof(strip_t));
801 
802 	for(loop=0; loop<n_esin; loop++)
803 	{
804 		memcpy(&(*pes_out)[loop + old_n], &pes_in[loop], sizeof(strip_t));
805 
806 		memset(&(*pes_out)[loop + old_n].regex, 0x00, sizeof(regex_t));
807 		if (pes_in[loop].type != STRIP_TYPE_COLUMN && pes_in[loop].type != STRIP_TYPE_RANGE)
808 		{
809 			(*pes_out)[loop + old_n].regex_str = mystrdup(pes_in[loop].regex_str);
810 
811 			compile_re(&(*pes_out)[loop + old_n].regex, (*pes_out)[loop + old_n].regex_str);
812 		}
813 
814 		if (pes_in[loop].del)
815 			(*pes_out)[loop + old_n].del = mystrdup(pes_in[loop].del);
816 	}
817 }
818 
find_filterscheme(char * name)819 int find_filterscheme(char *name)
820 {
821 	int loop;
822 
823 	for(loop=0; loop<n_fs; loop++)
824 	{
825 		if (strcmp(pfs[loop].fs_name, name) == 0)
826 			return loop;
827 	}
828 
829 	return -1;
830 }
831 
find_editscheme(char * name)832 int find_editscheme(char *name)
833 {
834 	int loop;
835 
836 	for(loop=0; loop<n_es; loop++)
837 	{
838 		if (strcmp(pes[loop].es_name, name) == 0)
839 			return loop;
840 	}
841 
842 	return -1;
843 }
844 
compile_re(regex_t * whereto,char * what)845 void compile_re(regex_t *whereto, char *what)
846 {
847 	/* compile & store regular expression */
848 	int rc = regcomp(whereto, what, REG_EXTENDED);
849 	if (rc != 0)
850 		error_exit(FALSE, FALSE, "Failed to compile regular expression '%s'.\nReason: %s\n", what, convert_regexp_error(rc, whereto));
851 }
852 
grow_mem_if_needed(char ** what,int * cur_len,int requested_len)853 void grow_mem_if_needed(char **what, int *cur_len, int requested_len)
854 {
855 	char changed = 0;
856 
857 	assert(requested_len > 0);
858 
859 	while(*cur_len < requested_len)
860 	{
861 		changed = 1;
862 
863 		if (*cur_len)
864 			(*cur_len) *= 2;
865 		else
866 			*cur_len = 128;
867 	}
868 
869 	if (changed)
870 		*what = myrealloc(*what, *cur_len);
871 }
872 
READ(int fd,char * where_to,int max_len,char * for_whom)873 int READ(int fd, char *where_to, int max_len, char *for_whom)
874 {
875 	assert(max_len > 0);
876 
877 	for(;;)
878 	{
879 		int rc = read(fd, where_to, max_len);
880 		if (rc >= 0)
881 			return rc;
882 
883 		if (errno != EINTR && errno != EAGAIN)
884 			error_exit(TRUE, FALSE, "Error writing to fd for %s.\n", for_whom);
885 	}
886 }
887 
get_value_arg(char * par,char * string,valcheck_t check)888 int get_value_arg(char *par, char *string, valcheck_t check)
889 {
890 	long int result;
891 	int len, loop;
892 	int multiplier = 1;
893 
894 	if (!string)
895 		error_exit(FALSE, FALSE, "%s needs a parameter.\n", par);
896 
897 	len = strlen(string);
898 
899 	for(loop=0; loop<len; loop++)
900 	{
901 		if (!isdigit(string[loop]))
902 		{
903 			char dummy = toupper(string[loop]);
904 
905 			if (toupper(string[loop + 1]) == 'B' && (dummy == 'K' || dummy == 'M' || dummy == 'G'))
906 			{
907 				if (dummy == 'K')
908 					multiplier = 1024;
909 				else if (dummy == 'M')
910 					multiplier = 1024 * 1024;
911 				else if (dummy == 'G')
912 					multiplier = 1024 * 1024 * 1024;
913 
914 				break;
915 			}
916 			else
917 				error_exit(FALSE, FALSE, "%s needs a value as parameter.\n", par);
918 		}
919 	}
920 
921 	result = strtol(string, NULL, 10);
922 
923 	if (result > INT_MAX || result == LONG_MIN || result == LONG_MAX)
924 		error_exit(FALSE, FALSE, "Value %s for parameter %s is too large.\n", string, par);
925 
926 	result *= multiplier;
927 
928 	if (check == VAL_ZERO_POSITIVE)
929 	{
930 		if (result < 0)
931 			error_exit(FALSE, FALSE, "Value for %s must be >= 0.\n", par);
932 	}
933 	else if (check == VAL_POSITIVE_NOT_1)
934 	{
935 		if (result < 0 || result == 1)
936 			error_exit(FALSE, FALSE, "Value for %s must be >= 0 and must not be 1.\n", par);
937 	}
938 	else if (check == VAL_POSITIVE)
939 	{
940 		if (result <= 0)
941 			error_exit(FALSE, FALSE, "Value for %s must be > 0.\n", par);
942 	}
943 	else
944 	{
945 		assert(0);
946 	}
947 
948 	return (int)result;
949 }
950 
add_to_iat(int_array_t * piat,int element)951 void add_to_iat(int_array_t *piat, int element)
952 {
953 	if (piat -> n == piat -> size)
954 	{
955 		piat -> size = USE_IF_SET(piat -> size, 8) * 2;
956 		piat -> elements = (int *)myrealloc(piat -> elements, piat -> size * sizeof(int));
957 	}
958 
959 	(piat -> elements)[piat -> n] = element;
960 	(piat -> n)++;
961 }
962 
get_iat_size(int_array_t * piat)963 int get_iat_size(int_array_t *piat)
964 {
965 	return piat -> n;
966 }
967 
init_iat(int_array_t * piat)968 void init_iat(int_array_t *piat)
969 {
970 	piat -> elements = NULL;
971 	piat -> size = piat -> n = 0;
972 }
973 
free_iat(int_array_t * piat)974 void free_iat(int_array_t *piat)
975 {
976 	myfree(piat -> elements);
977 
978 	init_iat(piat);
979 }
980 
get_iat_element(int_array_t * piat,int index)981 int get_iat_element(int_array_t *piat, int index)
982 {
983 	assert(index < piat -> n);
984 
985 	return (piat -> elements)[index];
986 }
987 
gethome(char * user)988 char *gethome(char *user)
989 {
990 	struct passwd *pw;
991 	if (user)
992 		pw = getpwnam(user);
993 	else
994 		pw = getpwuid(getuid());
995 	return mystrdup(pw->pw_dir);
996 }
997 
myrealpath(char * in)998 char *myrealpath(char *in)
999 {
1000 	char *home, *pin;
1001 	int home_len;
1002 	char *pout;
1003 
1004 	if (in[0] != '~')
1005 		return mystrdup(in);
1006 
1007 	if (in[1] != '/')
1008 	{
1009 		char *user;
1010 		char *slash = strchr(in, '/');
1011 		int len;
1012 
1013 		if (slash)
1014 		{
1015 			len = (int)((slash - in) - 1);
1016 			pin = slash + 1;
1017 		}
1018 		else
1019 		{
1020 			len = strlen(in) - 1;
1021 			pin = in + len + 1;
1022 		}
1023 
1024 		user = (char *)mymalloc(len + 1);
1025 		memcpy(user, &in[1], len);
1026 		user[len] = 0x00;
1027 
1028 		home = gethome(user);
1029 
1030 		myfree(user);
1031 	}
1032 	else
1033 	{
1034 		home = gethome(NULL);
1035 		pin = in + 1;
1036 	}
1037 
1038 	if (!home)
1039 		error_exit(FALSE, FALSE, "Cannot expand path %s:\nhome directory not found.\n", in);
1040 
1041 	home_len = strlen(home);
1042 	pout = (char *)mymalloc(home_len + strlen(in) + 1);
1043 
1044 	sprintf(pout, "%s/%s", home, pin);
1045 
1046 	myfree(home);
1047 
1048 	return pout;
1049 }
1050 
str_add(char ** to,const char * what,...)1051 void str_add(char **to, const char *what, ...)
1052 {
1053 	int len_to = *to ? strlen(*to) : 0;
1054 	char buffer[4096] = { 0 };
1055 	int len_what = 0;
1056 
1057         va_list ap;
1058 
1059 	/* FIXME: should vasprintf here: does other unixes have it? */
1060         va_start(ap, what);
1061         len_what = vsnprintf(buffer, sizeof buffer, what, ap);
1062         va_end(ap);
1063 
1064 	*to = (char *)realloc(*to, len_to + len_what + 1);
1065 
1066 	memcpy(&(*to)[len_to], buffer, len_what + 1);
1067 }
1068