1 /* Copyright (C) 2021 Free Software Foundation, Inc.
4 This file is part of GNU Binutils.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
22 #include <sys/param.h>
25 #include <dirent.h> // readdir()
26 #include <sys/param.h> // MAXPATHLEN
27 #include <pthread.h> // mutex
28 #include <libgen.h> // dirname
29 #include <sys/types.h> // open
30 #include <sys/stat.h> // open
31 #include <errno.h> // errno
32 #include <fcntl.h> // open
35 #include "dbe_structs.h"
36 #include "StringBuilder.h"
37 #include "StringMap.h" // For directory names
38 #include "Application.h" // Only for get_prog_name
42 tsadd (timestruc_t *result, timestruc_t *time)
44 // This routine will add "time" to "result".
45 result->tv_sec += time->tv_sec;
46 result->tv_nsec += time->tv_nsec;
47 if (result->tv_nsec >= NANOSEC)
49 result->tv_nsec -= NANOSEC;
55 tssub (timestruc_t *result, timestruc_t *time1, timestruc_t *time2)
57 // This routine will store "time1" - "time2" in "result".
59 if (time1->tv_nsec >= time2->tv_nsec)
61 result->tv_nsec = time1->tv_nsec - time2->tv_nsec;
62 if (time1->tv_sec >= time2->tv_sec)
63 result->tv_sec = time1->tv_sec - time2->tv_sec;
72 result->tv_nsec = time1->tv_nsec + NANOSEC - time2->tv_nsec;
73 if (time1->tv_sec - 1 >= time2->tv_sec)
74 result->tv_sec = time1->tv_sec - 1 - time2->tv_sec;
84 tscmp (timestruc_t *time1, timestruc_t *time2)
86 // This routine will return 1 if "time1" is greater than "time2"
87 // and 0 if "time1" is equal to "time2" and -1 otherwise.
88 if (time1->tv_sec == time2->tv_sec)
89 return time1->tv_nsec > time2->tv_nsec ? 1 :
90 time1->tv_nsec == time2->tv_nsec ? 0 : -1;
92 return time1->tv_sec > time2->tv_sec ? 1 : -1;
96 int_max (int *maximum, int count)
152 return strlen (to_str (buf, sizeof (buf)));
156 TValue::to_str (char *str, size_t strsz)
164 snprintf (str, strsz, NTXT ("+0. "));
166 snprintf (str, strsz, NTXT ("0. "));
169 snprintf (str, strsz, NTXT ("%+.3lf"), d);
171 snprintf (str, strsz, NTXT ("%.3lf"), d);
174 snprintf (str, strsz, NTXT ("%u"), i);
178 snprintf (str, strsz, NTXT ("%+lld"), ll);
180 snprintf (str, strsz, NTXT ("%lld"), ll);
183 snprintf (str, strsz, NTXT ("%llu"), ll);
186 snprintf (str, strsz, NTXT ("%u:0x%08x"), ADDRESS_SEG (ll), ADDRESS_OFF (ll));
189 snprintf (str, strsz, NTXT ("%.3f"), f);
192 snprintf (str, strsz, NTXT ("%hu"), s);
195 return l; // 'str' is not used !!!
205 TValue::make_delta (TValue *v1, TValue *v2)
207 assert (v1->tag == v2->tag);
216 ll = v1->ll - v2->ll;
221 ll = (long long) (v1->ull - v2->ull);
236 TValue::make_ratio (TValue *v1, TValue *v2)
238 assert (v1->tag == v2->tag);
239 double x1 = v1->to_double ();
240 double x2 = v2->to_double ();
244 // if the numerator is 0, the ratio is 1. or 0. only
245 d = (x2 == 0.) ? 1. : 0.;
250 // EUGENE replace 99.999 with a variable that is known by both DBE and GUI
251 if (x1 > 99.999 * x2)
253 l = dbe_strdup (">99.999");
256 else if (x1 < -99.999 * x2)
258 l = dbe_strdup ("<-99.999");
270 TValue::compare (TValue *v)
273 { // Only for comparison (Ratio)
276 if (v->tag == VT_LABEL)
277 return strcoll (l, v->l);
280 if (v->tag == VT_LABEL)
282 return ll < v->ll ? -1 : (ll == v->ll ? 0 : 1);
287 return s < v->s ? -1 : (s == v->s ? 0 : 1);
289 return i < v->i ? -1 : (i == v->i ? 0 : 1);
291 return f < v->f ? -1 : (f == v->f ? 0 : 1);
293 return d < v->d ? -1 : (d == v->d ? 0 : 1);
295 return strcoll (l, v->l);
301 return (ll < v->ll) ? -1 : ((ll == v->ll) ? 0 : 1);
306 strstr_r (char *s1, const char *s2)
309 for (char *s = s1; s;)
321 // reversal order of strpbrk
324 strrpbrk (const char *string, const char *brkset)
328 for (s = string + strlen (string) - 1; s >= string; s--)
330 for (p = brkset; *p != '\0' && *p != *s; ++p)
339 read_line (FILE *fptr)
341 // get an input line, no size limit
342 int line_sz = 128; // starting size
343 char *line = (char *) malloc (line_sz);
345 // read as much of the line as will fit in memory
350 while (fgets (line + len, line_sz - len, fptr) != NULL)
352 len = (int) strlen (line);
353 if (len == 0 || line[len - 1] == '\n')
355 // increase the buffer
356 char *lineNew = (char *) malloc (2 * line_sz);
357 strncpy (lineNew, line, line_sz);
358 lineNew[line_sz] = '\0';
364 fprintf (stderr, GTXT (" Line too long -- out of memory; exiting\n"));
373 // see if there's a continuation line
374 if ((len >= 2) && (line[len - 1] == '\n') && (line[len - 2] == '\\'))
376 // remove the trailing \ and the \n, and keep going
383 return line; // expecting the caller to free it
387 split_str (char *str, char delimiter)
389 Vector<char *> *v = new Vector<char *>;
390 for (char *s = str; s;)
395 char *tok = parse_qstring (s, &next_s);
396 if (tok && *tok != '\0')
405 char *next_s = strchr (s, delimiter);
409 v->append (dbe_strndup (s, next_s - s));
415 v->append (dbe_strdup (s));
425 parse_qstring (char *in_str, char **endptr)
430 char csnum[2 * MAXPATHLEN];
432 // Skip any leading blanks or tabs
433 while (*in_str == '\t' || *in_str == ' ')
437 if (*in_str == 'G' && *(in_str + 1) == 'T' && *(in_str + 2) == 'X'
438 && *(in_str + 3) == 'T' && *(in_str + 4) == '(')
446 else if (*in_str == '\'')
449 return strtok_r (in_str, NTXT (" "), endptr);
452 while ((c = *(++in_str)) != '\0')
454 if (c == term) // the closing quote
457 { // handle any escaped characters
486 if ((c2 >= '0') && (c2 <= '9'))
488 for (i = 0; i < MAXPATHLEN; i++)
490 if (((c2 < '0') || (c2 > '9')) && (c2 != 'x') &&
491 ((c2 < 'a') || (c2 > 'f')) &&
492 ((c2 < 'A') || (c2 > 'F')))
504 sb.append ((char) strtoul (csnum, endptr, 0));
514 if (c == term && gtxt && *in_str == ')')
519 *endptr = in_str + 1;
520 return sb.toString ();
523 // parse a file name of the form name`name2`
525 // stores the pointer to named in fcontext
526 // returns NULL if the string is not properly formatted
528 parse_fname (char *in_str, char **fcontext)
534 char *copy = strdup (in_str);
535 char *p = strchr (copy, ch);
538 // yes, there's an embedded file name
541 // now find the terminating single quote
542 char *p1 = strchr (p, ch);
545 // if we don't have the closing `, the format is incorrect
549 //remove the closing quote
551 // see if there's anything following it
559 *fcontext = strdup (p);
565 get_paren (const char *name)
569 int temp_level1, temp_level2;
571 temp_level1 = temp_level2 = 0;
572 snprintf (buf, sizeof (buf), NTXT ("%s"), name);
573 while ((ptr = strrpbrk (buf, "><)(")) != NULL)
577 else if (*ptr == '<')
579 else if (*ptr == ')')
584 if (temp_level1 <= 0 && temp_level2 <= 0)
585 return (int) (ptr - buf);
592 // CRC-64 based on x^64 + x^11 + x^2 + x + 1 polynomial.
593 // This algorithm doesn't perform well but is short and
594 // readable. We currently use it for a small amount of
595 // short strings. Should this change, another algorithm
596 // with better performance is to be used instead.
597 static uint64_t masks[256] = {
598 /* 0 */ 0x000000, 0x000807, 0x00100e, 0x001809, 0x00201c, 0x00281b,
599 /* 6 */ 0x003012, 0x003815, 0x004038, 0x00483f, 0x005036, 0x005831,
600 /* 12 */ 0x006024, 0x006823, 0x00702a, 0x00782d, 0x008070, 0x008877,
601 /* 18 */ 0x00907e, 0x009879, 0x00a06c, 0x00a86b, 0x00b062, 0x00b865,
602 /* 24 */ 0x00c048, 0x00c84f, 0x00d046, 0x00d841, 0x00e054, 0x00e853,
603 /* 30 */ 0x00f05a, 0x00f85d, 0x0100e0, 0x0108e7, 0x0110ee, 0x0118e9,
604 /* 36 */ 0x0120fc, 0x0128fb, 0x0130f2, 0x0138f5, 0x0140d8, 0x0148df,
605 /* 42 */ 0x0150d6, 0x0158d1, 0x0160c4, 0x0168c3, 0x0170ca, 0x0178cd,
606 /* 48 */ 0x018090, 0x018897, 0x01909e, 0x019899, 0x01a08c, 0x01a88b,
607 /* 54 */ 0x01b082, 0x01b885, 0x01c0a8, 0x01c8af, 0x01d0a6, 0x01d8a1,
608 /* 60 */ 0x01e0b4, 0x01e8b3, 0x01f0ba, 0x01f8bd, 0x0201c0, 0x0209c7,
609 /* 66 */ 0x0211ce, 0x0219c9, 0x0221dc, 0x0229db, 0x0231d2, 0x0239d5,
610 /* 72 */ 0x0241f8, 0x0249ff, 0x0251f6, 0x0259f1, 0x0261e4, 0x0269e3,
611 /* 78 */ 0x0271ea, 0x0279ed, 0x0281b0, 0x0289b7, 0x0291be, 0x0299b9,
612 /* 84 */ 0x02a1ac, 0x02a9ab, 0x02b1a2, 0x02b9a5, 0x02c188, 0x02c98f,
613 /* 90 */ 0x02d186, 0x02d981, 0x02e194, 0x02e993, 0x02f19a, 0x02f99d,
614 /* 96 */ 0x030120, 0x030927, 0x03112e, 0x031929, 0x03213c, 0x03293b,
615 /* 102 */ 0x033132, 0x033935, 0x034118, 0x03491f, 0x035116, 0x035911,
616 /* 108 */ 0x036104, 0x036903, 0x03710a, 0x03790d, 0x038150, 0x038957,
617 /* 114 */ 0x03915e, 0x039959, 0x03a14c, 0x03a94b, 0x03b142, 0x03b945,
618 /* 120 */ 0x03c168, 0x03c96f, 0x03d166, 0x03d961, 0x03e174, 0x03e973,
619 /* 126 */ 0x03f17a, 0x03f97d, 0x040380, 0x040b87, 0x04138e, 0x041b89,
620 /* 132 */ 0x04239c, 0x042b9b, 0x043392, 0x043b95, 0x0443b8, 0x044bbf,
621 /* 138 */ 0x0453b6, 0x045bb1, 0x0463a4, 0x046ba3, 0x0473aa, 0x047bad,
622 /* 144 */ 0x0483f0, 0x048bf7, 0x0493fe, 0x049bf9, 0x04a3ec, 0x04abeb,
623 /* 150 */ 0x04b3e2, 0x04bbe5, 0x04c3c8, 0x04cbcf, 0x04d3c6, 0x04dbc1,
624 /* 156 */ 0x04e3d4, 0x04ebd3, 0x04f3da, 0x04fbdd, 0x050360, 0x050b67,
625 /* 162 */ 0x05136e, 0x051b69, 0x05237c, 0x052b7b, 0x053372, 0x053b75,
626 /* 168 */ 0x054358, 0x054b5f, 0x055356, 0x055b51, 0x056344, 0x056b43,
627 /* 174 */ 0x05734a, 0x057b4d, 0x058310, 0x058b17, 0x05931e, 0x059b19,
628 /* 180 */ 0x05a30c, 0x05ab0b, 0x05b302, 0x05bb05, 0x05c328, 0x05cb2f,
629 /* 186 */ 0x05d326, 0x05db21, 0x05e334, 0x05eb33, 0x05f33a, 0x05fb3d,
630 /* 192 */ 0x060240, 0x060a47, 0x06124e, 0x061a49, 0x06225c, 0x062a5b,
631 /* 198 */ 0x063252, 0x063a55, 0x064278, 0x064a7f, 0x065276, 0x065a71,
632 /* 204 */ 0x066264, 0x066a63, 0x06726a, 0x067a6d, 0x068230, 0x068a37,
633 /* 210 */ 0x06923e, 0x069a39, 0x06a22c, 0x06aa2b, 0x06b222, 0x06ba25,
634 /* 216 */ 0x06c208, 0x06ca0f, 0x06d206, 0x06da01, 0x06e214, 0x06ea13,
635 /* 222 */ 0x06f21a, 0x06fa1d, 0x0702a0, 0x070aa7, 0x0712ae, 0x071aa9,
636 /* 228 */ 0x0722bc, 0x072abb, 0x0732b2, 0x073ab5, 0x074298, 0x074a9f,
637 /* 234 */ 0x075296, 0x075a91, 0x076284, 0x076a83, 0x07728a, 0x077a8d,
638 /* 240 */ 0x0782d0, 0x078ad7, 0x0792de, 0x079ad9, 0x07a2cc, 0x07aacb,
639 /* 246 */ 0x07b2c2, 0x07bac5, 0x07c2e8, 0x07caef, 0x07d2e6, 0x07dae1,
640 /* 252 */ 0x07e2f4, 0x07eaf3, 0x07f2fa, 0x07fafd
644 crc64 (const char *str, size_t len)
647 for (size_t i = 0; i < len; i++)
649 unsigned char b = (unsigned char) ((res >> 56) ^ *str++);
657 * Canonize path inside the string provided by the argument
662 canonical_path (char *path)
671 if (*s1 == '.' && s1[1] == '/')
673 for (s1++; *s1; s1++)
678 { // replace /// with /
680 for (s1++; *s1; s1++)
687 { // copy file or directory name
695 if (s2 != path && (s2 - 1) != path && s2[-1] == '/') // remove last /
701 get_relative_path (char *name)
703 if (*name == '/' && theApplication)
705 char *cwd = theApplication->get_cur_dir ();
708 size_t len = strlen (cwd);
709 if (len > 0 && len < strlen (name) && name[len] == '/'
710 && strncmp (cwd, name, len) == 0)
712 for (name += len + 1; *name == '/'; name++)
722 * Generate a relative link name from path_from to path_to
729 * @return lname - relative link
732 get_relative_link (const char *path_from, const char *path_to)
738 char *s1 = dbe_strdup (path_to);
739 s1 = canonical_path (s1);
740 char *s2 = dbe_strdup (path_from);
741 s2 = canonical_path (s2);
742 long l = dbe_sstrlen (s1);
743 // try to find common directories
744 int common_slashes = 0;
745 int last_common_slash = -1;
746 for (int i = 0; i < l; i++)
748 if (s1[i] != s2[i]) break;
749 if (s1[i] == 0) break;
753 last_common_slash = i;
756 // find slashes in remaining path_to
758 for (int i = last_common_slash + 1; i < l; i++)
762 // Exclude "/./" case
763 if (i > last_common_slash + 2)
765 if (s1[i - 1] == '.' && s1[i - 2] == '/')
768 else if (i > 0 && s1[i - 1] == '.')
773 // generate relative path
775 for (int i = 0; i < slashes; i++)
777 sb.append (s2 + last_common_slash + 1);
778 char *lname = sb.toString ();
785 get_prog_name (int basename)
790 nm = theApplication->get_name ();
792 nm = get_basename (nm);
798 dbe_strndup (const char *str, size_t len)
802 char *s = (char *) malloc (len + 1);
803 strncpy (s, str, len);
809 dbe_sprintf (const char *fmt, ...)
816 buf_size = vsnprintf (buffer, sizeof (buffer), fmt, vp) + 1;
818 if (buf_size < (int) sizeof (buffer))
822 return strdup (buffer);
826 char *buf = (char *) malloc (buf_size);
827 vsnprintf (buf, buf_size, fmt, vp);
833 dbe_write (int f, const char *fmt, ...)
840 buf_size = vsnprintf (buffer, sizeof (buffer), fmt, vp) + 1;
842 if (buf_size < (int) sizeof (buffer))
846 return write (f, buffer, strlen (buffer));
850 char *buf = (char *) malloc (buf_size);
851 vsnprintf (buf, buf_size, fmt, vp);
853 ssize_t val = write (f, buf, strlen (buf));
858 /* Worker Threads to avoid hanging on file servers */
875 * Communication structure
877 struct worker_thread_info
879 pthread_t thread_id; /* ID returned by pthread_create() */
880 int thread_num; /* Application-defined thread # */
881 volatile int control; /* Thread state */
882 volatile int result; /* Return status */
883 struct stat64 statbuf; /* File info from stat64() */
884 const char *path; /* File */
887 static pthread_mutex_t worker_thread_lock = PTHREAD_MUTEX_INITIALIZER;
888 static int worker_thread_number = 0;
890 * Call stat64() on current worker thread
891 * Check if control is not THREAD_CANCEL
892 * If control is THREAD_CANCEL return (exit thread)
896 dbe_stat_on_thread (void *arg)
898 struct worker_thread_info *wt_info = (struct worker_thread_info *) arg;
899 pthread_mutex_lock (&worker_thread_lock);
901 if (wt_info->control != THREAD_START)
904 pthread_mutex_unlock (&worker_thread_lock);
907 wt_info->control = THREAD_STARTED;
909 pthread_mutex_unlock (&worker_thread_lock);
910 const char * path = wt_info->path;
911 int st = stat64 (path, &(wt_info->statbuf));
912 pthread_mutex_lock (&worker_thread_lock);
914 if (wt_info->control == THREAD_CANCEL)
917 pthread_mutex_unlock (&worker_thread_lock);
921 wt_info->result = st;
922 wt_info->control = THREAD_FINISHED;
924 pthread_mutex_unlock (&worker_thread_lock);
929 * Create a worker thread to call specified function
930 * Wait for its result, but not longer than 5 seconds
931 * If the timeout happens, tell the thread to cancel
934 * @return thread state
937 dbe_dispatch_on_thread (const char *path, struct worker_thread_info *wt_info)
940 wt_info->control = THREAD_START;
942 /* Initialize thread creation attributes */
943 int res = pthread_attr_init (&attr);
946 wt_info->control = THREAD_NOT_CREATED;
947 return THREAD_NOT_CREATED;
949 wt_info->thread_id = 0;
950 wt_info->path = path;
952 pthread_mutex_lock (&worker_thread_lock);
953 worker_thread_number++;
954 wt_info->thread_num = worker_thread_number;
956 pthread_mutex_unlock (&worker_thread_lock);
958 res = pthread_create (&wt_info->thread_id, &attr, &dbe_stat_on_thread, wt_info);
961 wt_info->control = THREAD_NOT_CREATED;
962 pthread_attr_destroy (&attr);
963 return THREAD_NOT_CREATED;
965 // Wait for the thread to finish
967 useconds_t maxusec = 5000000; // 5 seconds
968 useconds_t deltausec = 1000; // 1 millisecond
969 int max = maxusec / deltausec;
970 for (int i = 0; i < max; i++)
972 if (THREAD_FINISHED == wt_info->control)
973 break; // We are done
977 pthread_mutex_lock (&worker_thread_lock);
978 if (THREAD_FINISHED != wt_info->control)
981 wt_info->control = THREAD_CANCEL; // Cannot use wt_info after that!
985 pthread_mutex_unlock (&worker_thread_lock);
986 // Destroy the thread attributes object, since it is no longer needed
987 pthread_attr_destroy (&attr);
988 // Report that thread was canceled
989 if (THREAD_CANCEL == res)
990 return res; /* Cannot free memory allocated by thread */
991 // Free all thread resources
993 res = pthread_join (wt_info->thread_id, &resources);
994 free (resources); /* Free memory allocated by thread */
995 return THREAD_FINISHED;
998 static pthread_mutex_t dirnames_lock = PTHREAD_MUTEX_INITIALIZER;
999 static Map<const char*, int> *dirnamesMap = NULL;
1001 #define DIR_STATUS_EXISTS 0
1002 #define DIR_STATUS_UNKNOWN 2
1005 * Check if this directory name is known
1009 * 1 - known, does not exist
1013 check_dirname (const char *path)
1015 pthread_mutex_lock (&dirnames_lock);
1016 if (NULL == dirnamesMap)
1017 dirnamesMap = new StringMap<int>(128, 128);
1018 pthread_mutex_unlock (&dirnames_lock);
1019 int res = DIR_STATUS_UNKNOWN;
1022 char *fn = dbe_strdup (path);
1023 char *dn = dirname (fn);
1025 res = dirnamesMap->get (dn);
1032 * Save directory name and its status
1038 extract_and_save_dirname (const char *path, int status)
1040 pthread_mutex_lock (&dirnames_lock);
1041 if (NULL == dirnamesMap)
1042 dirnamesMap = new StringMap<int>(128, 128);
1043 pthread_mutex_unlock (&dirnames_lock);
1044 char *fn = dbe_strdup (path);
1047 char *dn = dirname (fn);
1048 if (dn && (*dn != 0))
1050 int st = 0; // exists
1052 st = 1; // does not exist
1053 dirnamesMap->put (dn, st);
1059 // get status for specified file
1061 dbe_stat_internal (const char *path, struct stat64 *sbuf, bool file_only)
1063 struct stat64 statbuf;
1064 int dir_status = check_dirname (path);
1065 if (dir_status == DIR_STATUS_UNKNOWN)
1067 // Try to use a worker thread
1068 if (theApplication->get_number_of_worker_threads () > 0)
1070 struct worker_thread_info *wt_info;
1071 wt_info = (worker_thread_info *) calloc (1, sizeof (worker_thread_info));
1072 if (wt_info != NULL)
1074 int res = dbe_dispatch_on_thread (path, wt_info);
1075 if (THREAD_FINISHED == res)
1077 int st = wt_info->result;
1078 extract_and_save_dirname (path, st);
1079 if (st == 0 && file_only)
1080 if (S_ISREG ((wt_info->statbuf).st_mode) == 0)
1081 st = -1; // It is not a regular file
1083 *sbuf = wt_info->statbuf;
1089 if (THREAD_CANCEL == res)
1091 // Worker thread hung. Cannot free wt_info.
1092 // Allocated memory will be freed by worker thread.
1094 extract_and_save_dirname (path, 1);
1095 return 1; // stat64 failed
1097 else // THREAD_NOT_CREATED - continue on current thread
1103 else if (dir_status != DIR_STATUS_EXISTS)
1104 return -1; // does not exist
1107 int st = stat64 (path, sbuf);
1108 Dprintf (DEBUG_DBE_FILE, NTXT ("dbe_stat %d '%s'\n"), st, path);
1111 else if (file_only && S_ISREG (sbuf->st_mode) == 0)
1112 return -1; // It is not ordinary file
1116 // get status for the regular file
1119 dbe_stat_file (const char *path, struct stat64 *sbuf)
1121 int res = dbe_stat_internal (path, sbuf, true);
1125 // get status for specified file
1128 dbe_stat (const char *path, struct stat64 *sbuf)
1130 int res = dbe_stat_internal (path, sbuf, false);
1135 * Reads directory and prepares list of files according to the specified format
1136 * Supported formats:
1137 * "/bin/ls -a" - see 'man ls' for details
1138 * "/bin/ls -aF" - see 'man ls' for details
1141 * @return char * files
1144 dbe_read_dir (const char *path, const char *format)
1147 DIR *dir = opendir (path);
1149 return sb.toString ();
1151 if (!strcmp (format, NTXT ("/bin/ls -aF")))
1153 struct dirent *entry = NULL;
1156 while ((entry = readdir (dir)) != NULL)
1158 sb.append (entry->d_name);
1161 const char *attr = NTXT ("@"); // Link
1164 char filename[MAXPATHLEN + 1];
1165 snprintf (filename, sizeof (filename), NTXT ("%s/%s"), path, entry->d_name);
1166 dbe_stat (filename, &sbuf);
1167 if (S_IREAD & sbuf.st_mode)
1169 if (S_ISDIR (sbuf.st_mode) != 0) // Directory
1171 else if (S_ISREG (sbuf.st_mode) != 0) // Regular file
1176 sb.append (NTXT ("\n"));
1180 return sb.toString ();
1184 * Gets list of processes according to the specified format
1185 * Supported formats:
1186 * "/bin/ps -ef" - see 'man ps' for details
1188 * @return char * processes
1191 dbe_get_processes (const char *format)
1194 if (!strcmp (format, NTXT ("/bin/ps -ef")))
1197 FILE *ptr = popen (format, "r");
1200 while (fgets (buf, BUFSIZ, ptr) != NULL)
1205 return sb.toString ();
1209 * Creates the directory named by the specified path name, including any
1210 * necessary but nonexistent parent directories.
1211 * Uses system utility "/bin/mkdir -p"
1212 * Temporary limitation: path name should not contain spaces.
1213 * Returns message from "/bin/mkdir -p"
1218 dbe_create_directories (const char *pathname)
1221 char *makedir = dbe_sprintf (NTXT ("/bin/mkdir -p %s 2>&1"), pathname);
1223 FILE *ptr = popen (makedir, "r");
1226 while (fgets (out, BUFSIZ, ptr) != NULL)
1231 DIR *dir = opendir (pathname);
1235 return NULL; // success
1238 sb.append (NTXT ("\nError: Cannot open directory\n")); // DEBUG
1239 return sb.toString (); // error
1243 * Deletes the file or the directory named by the specified path name.
1244 * If this pathname denotes a directory, then the directory must be empty in order to be deleted.
1245 * Uses system utility "/bin/rm" or "/bin/rmdir"
1246 * Temporary limitation: path name should not contain spaces.
1247 * Returns error message from system utility
1252 dbe_delete_file (const char *pathname)
1258 int st = dbe_stat (pathname, &sbuf);
1261 if (S_ISDIR (sbuf.st_mode) != 0) // Directory
1262 cmd = dbe_sprintf (NTXT ("/bin/rmdir %s 2>&1"), pathname);
1263 else if (S_ISREG (sbuf.st_mode) != 0) // Regular file
1264 cmd = dbe_sprintf (NTXT ("/bin/rm %s 2>&1"), pathname);
1267 return NULL; // Nothing to remove
1271 FILE *ptr = popen (cmd, "r");
1274 while (fgets (out, BUFSIZ, ptr) != NULL)
1281 sb.sprintf (NTXT ("Error: cannot remove %s - not a regular file and not a directory\n"), pathname);
1282 return sb.toString ();
1286 dbe_xml2str (const char *s)
1295 if (strncmp (s, NTXT (" "), 6) == 0)
1301 else if (strncmp (s, NTXT ("""), 6) == 0)
1307 else if (strncmp (s, NTXT ("&"), 5) == 0)
1313 else if (strncmp (s, NTXT ("<"), 4) == 0)
1319 else if (strncmp (s, NTXT (">"), 4) == 0)
1329 return sb.toString ();
1333 swapByteOrder (void *p, size_t sz)
1337 uint64_t *pv = (uint64_t *) p;
1339 v = ((v & 0x00000000FF000000) << 8) | ((v >> 8) & 0x00000000FF000000) |
1340 ((v & 0x0000000000FF0000) << 24) | ((v >> 24) & 0x0000000000FF0000) |
1341 ((v & 0x000000000000FF00) << 40) | ((v >> 40) & 0x000000000000FF00) |
1342 (v >> 56) | (v << 56);
1347 uint32_t *pv = (uint32_t *) p;
1349 v = (v >> 24) | (v << 24) | ((v & 0x0000FF00) << 8) | ((v >> 8) & 0x0000FF00);
1354 uint16_t *pv = (uint16_t *) p;
1356 v = (v >> 8) | (v << 8);
1366 Vector<void*> *array = (Vector<void*>*)vec;
1367 switch (array->type ())
1370 ((Vector<char *>*)array)->destroy ();
1378 for (long i = 0; i < array->size (); i++)
1379 destroy (array->fetch (i));
1393 read_from_file (int fd, void *buffer, int64_t nbyte)
1396 char *buf = (char *) buffer;
1398 { // Sometimes system cannot read 'nbyte'
1399 ssize_t n = read (fd, (void *) (buf + cnt), (size_t) nbyte);
1409 * Create symbolic link to the path
1410 * @param path - path with spaces
1411 * @param dir - directory where the link should be created
1412 * @return symbolic link
1415 dbe_create_symlink_to_path (const char *path, const char *dir)
1417 char *symbolic_link = NULL;
1418 if (NULL == path || NULL == dir)
1420 int res = mkdir (dir, 0777);
1421 if (res != 0 && dbe_stat (dir, NULL) != 0)
1422 return NULL; // Cannot create directory
1423 long len = dbe_sstrlen (path);
1425 return NULL; // Unknown situation
1426 if (strcmp ((path + len - 4), "/bin") != 0) // Unknown situation
1428 int max = 99; // Just an arbitrary number
1429 for (int i = 1; i <= max; i++)
1431 // Try to create symbolic link
1432 char *d = dbe_sprintf ("%s/%d", dir, i);
1435 res = mkdir (d, 0777);
1436 symbolic_link = dbe_sprintf ("%s/%s", d, "bin");
1438 if (NULL == symbolic_link) // Not enough memory
1440 res = symlink (path, symbolic_link);
1441 if (res == 0) // Link is created - use it.
1443 // Check if such link already exists
1445 char buf[MAXPATHLEN + 1];
1446 memset (buf, 0, MAXPATHLEN + 1);
1447 ssize_t n = readlink (symbolic_link, buf, MAXPATHLEN);
1448 if (n == len && strcmp (path, buf) == 0) // Link is correct - use it.
1451 { // report the error
1452 fprintf (stderr, GTXT ("Error: symlink(%s, %s) returned error: %d\n"), path, symbolic_link, res);
1453 fprintf (stderr, GTXT ("Error: errno=%d (%s)\n"), e, strerror (e));
1456 free (symbolic_link);
1457 symbolic_link = NULL;
1459 return symbolic_link;
1462 // Compute checksum for specified file.
1463 // This code is from usr/src/cmd/cksum.c, adapted for us
1464 // crcposix -- compute posix.2 compatable 32 bit CRC
1466 // The POSIX.2 (draft 10) CRC algorithm.
1467 // This is a 32 bit CRC with polynomial
1468 // x**32 + x**26 + x**23 + x**22 + x**16 + x**12 + x**11 + x**10 +
1469 // x**8 + x**7 + x**5 + x**4 + x**2 + x**1 + x**0
1471 // layout is from the POSIX.2 Rationale
1473 static uint32_t crctab_posix[256] = {
1475 0x04C11DB7L, 0x09823B6EL, 0x0D4326D9L, 0x130476DCL, 0x17C56B6BL,
1476 0x1A864DB2L, 0x1E475005L, 0x2608EDB8L, 0x22C9F00FL, 0x2F8AD6D6L,
1477 0x2B4BCB61L, 0x350C9B64L, 0x31CD86D3L, 0x3C8EA00AL, 0x384FBDBDL,
1478 0x4C11DB70L, 0x48D0C6C7L, 0x4593E01EL, 0x4152FDA9L, 0x5F15ADACL,
1479 0x5BD4B01BL, 0x569796C2L, 0x52568B75L, 0x6A1936C8L, 0x6ED82B7FL,
1480 0x639B0DA6L, 0x675A1011L, 0x791D4014L, 0x7DDC5DA3L, 0x709F7B7AL,
1481 0x745E66CDL, 0x9823B6E0L, 0x9CE2AB57L, 0x91A18D8EL, 0x95609039L,
1482 0x8B27C03CL, 0x8FE6DD8BL, 0x82A5FB52L, 0x8664E6E5L, 0xBE2B5B58L,
1483 0xBAEA46EFL, 0xB7A96036L, 0xB3687D81L, 0xAD2F2D84L, 0xA9EE3033L,
1484 0xA4AD16EAL, 0xA06C0B5DL, 0xD4326D90L, 0xD0F37027L, 0xDDB056FEL,
1485 0xD9714B49L, 0xC7361B4CL, 0xC3F706FBL, 0xCEB42022L, 0xCA753D95L,
1486 0xF23A8028L, 0xF6FB9D9FL, 0xFBB8BB46L, 0xFF79A6F1L, 0xE13EF6F4L,
1487 0xE5FFEB43L, 0xE8BCCD9AL, 0xEC7DD02DL, 0x34867077L, 0x30476DC0L,
1488 0x3D044B19L, 0x39C556AEL, 0x278206ABL, 0x23431B1CL, 0x2E003DC5L,
1489 0x2AC12072L, 0x128E9DCFL, 0x164F8078L, 0x1B0CA6A1L, 0x1FCDBB16L,
1490 0x018AEB13L, 0x054BF6A4L, 0x0808D07DL, 0x0CC9CDCAL, 0x7897AB07L,
1491 0x7C56B6B0L, 0x71159069L, 0x75D48DDEL, 0x6B93DDDBL, 0x6F52C06CL,
1492 0x6211E6B5L, 0x66D0FB02L, 0x5E9F46BFL, 0x5A5E5B08L, 0x571D7DD1L,
1493 0x53DC6066L, 0x4D9B3063L, 0x495A2DD4L, 0x44190B0DL, 0x40D816BAL,
1494 0xACA5C697L, 0xA864DB20L, 0xA527FDF9L, 0xA1E6E04EL, 0xBFA1B04BL,
1495 0xBB60ADFCL, 0xB6238B25L, 0xB2E29692L, 0x8AAD2B2FL, 0x8E6C3698L,
1496 0x832F1041L, 0x87EE0DF6L, 0x99A95DF3L, 0x9D684044L, 0x902B669DL,
1497 0x94EA7B2AL, 0xE0B41DE7L, 0xE4750050L, 0xE9362689L, 0xEDF73B3EL,
1498 0xF3B06B3BL, 0xF771768CL, 0xFA325055L, 0xFEF34DE2L, 0xC6BCF05FL,
1499 0xC27DEDE8L, 0xCF3ECB31L, 0xCBFFD686L, 0xD5B88683L, 0xD1799B34L,
1500 0xDC3ABDEDL, 0xD8FBA05AL, 0x690CE0EEL, 0x6DCDFD59L, 0x608EDB80L,
1501 0x644FC637L, 0x7A089632L, 0x7EC98B85L, 0x738AAD5CL, 0x774BB0EBL,
1502 0x4F040D56L, 0x4BC510E1L, 0x46863638L, 0x42472B8FL, 0x5C007B8AL,
1503 0x58C1663DL, 0x558240E4L, 0x51435D53L, 0x251D3B9EL, 0x21DC2629L,
1504 0x2C9F00F0L, 0x285E1D47L, 0x36194D42L, 0x32D850F5L, 0x3F9B762CL,
1505 0x3B5A6B9BL, 0x0315D626L, 0x07D4CB91L, 0x0A97ED48L, 0x0E56F0FFL,
1506 0x1011A0FAL, 0x14D0BD4DL, 0x19939B94L, 0x1D528623L, 0xF12F560EL,
1507 0xF5EE4BB9L, 0xF8AD6D60L, 0xFC6C70D7L, 0xE22B20D2L, 0xE6EA3D65L,
1508 0xEBA91BBCL, 0xEF68060BL, 0xD727BBB6L, 0xD3E6A601L, 0xDEA580D8L,
1509 0xDA649D6FL, 0xC423CD6AL, 0xC0E2D0DDL, 0xCDA1F604L, 0xC960EBB3L,
1510 0xBD3E8D7EL, 0xB9FF90C9L, 0xB4BCB610L, 0xB07DABA7L, 0xAE3AFBA2L,
1511 0xAAFBE615L, 0xA7B8C0CCL, 0xA379DD7BL, 0x9B3660C6L, 0x9FF77D71L,
1512 0x92B45BA8L, 0x9675461FL, 0x8832161AL, 0x8CF30BADL, 0x81B02D74L,
1513 0x857130C3L, 0x5D8A9099L, 0x594B8D2EL, 0x5408ABF7L, 0x50C9B640L,
1514 0x4E8EE645L, 0x4A4FFBF2L, 0x470CDD2BL, 0x43CDC09CL, 0x7B827D21L,
1515 0x7F436096L, 0x7200464FL, 0x76C15BF8L, 0x68860BFDL, 0x6C47164AL,
1516 0x61043093L, 0x65C52D24L, 0x119B4BE9L, 0x155A565EL, 0x18197087L,
1517 0x1CD86D30L, 0x029F3D35L, 0x065E2082L, 0x0B1D065BL, 0x0FDC1BECL,
1518 0x3793A651L, 0x3352BBE6L, 0x3E119D3FL, 0x3AD08088L, 0x2497D08DL,
1519 0x2056CD3AL, 0x2D15EBE3L, 0x29D4F654L, 0xC5A92679L, 0xC1683BCEL,
1520 0xCC2B1D17L, 0xC8EA00A0L, 0xD6AD50A5L, 0xD26C4D12L, 0xDF2F6BCBL,
1521 0xDBEE767CL, 0xE3A1CBC1L, 0xE760D676L, 0xEA23F0AFL, 0xEEE2ED18L,
1522 0xF0A5BD1DL, 0xF464A0AAL, 0xF9278673L, 0xFDE69BC4L, 0x89B8FD09L,
1523 0x8D79E0BEL, 0x803AC667L, 0x84FBDBD0L, 0x9ABC8BD5L, 0x9E7D9662L,
1524 0x933EB0BBL, 0x97FFAD0CL, 0xAFB010B1L, 0xAB710D06L, 0xA6322BDFL,
1525 0xA2F33668L, 0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L
1529 m_crcposix (uint32_t *crcp, unsigned char *bp, uint32_t n)
1532 *crcp = (*crcp << 8) ^ crctab_posix[(unsigned char) ((*crcp >> 24)^*bp++)];
1535 // Do CRC-POSIX function by calling a library entry point that has a
1536 // slightly different calling sequence.
1538 docrcposix (uint32_t crcval, unsigned char *bp, uint32_t n)
1540 m_crcposix (&crcval, bp, n);
1544 // Sum algorithms require various kinds of post-processing.
1545 // The 'S' and 'R' variables are from the POSIX.2 (Draft 8?) description
1546 // of the "sum" utility.
1548 postprocess (uint32_t S, long long n)
1550 // POSIX tacks on significant bytes of the length so that
1551 // different length sequences of '\0' have different sums;
1552 // then it complements sum.
1553 unsigned char char_n[sizeof (n)];
1555 for (i = 0; n != 0; n >>= 8, ++i)
1556 char_n[i] = (unsigned char) (n & 0xFF);
1557 return (~docrcposix (S, char_n, i));
1561 get_cksum (const char * pathname, char ** errmsg)
1563 int fd = open (pathname, O_RDONLY);
1567 *errmsg = dbe_sprintf (GTXT ("*** Warning: Error opening file for reading: %s"), pathname);
1570 uint32_t crcval = 0;
1571 long long bytes = 0;
1573 unsigned char buf[4096];
1574 while ((n = read_from_file (fd, (char *) buf, sizeof (buf))) > 0)
1577 crcval = docrcposix (crcval, buf, n);
1580 crcval = postprocess (crcval, bytes);