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