xref: /netbsd-src/external/gpl3/binutils/dist/gprofng/src/util.cc (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* Copyright (C) 2021-2024 Free Software Foundation, Inc.
2    Contributed by Oracle.
3 
4    This file is part of GNU Binutils.
5 
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)
9    any later version.
10 
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.
15 
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.  */
20 
21 #include "config.h"
22 #include <sys/param.h>
23 #include <stdarg.h>
24 #include <unistd.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
33 
34 #include "util.h"
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
39 #include "vec.h"
40 
41 void
tsadd(timestruc_t * result,timestruc_t * time)42 tsadd (timestruc_t *result, timestruc_t *time)
43 {
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)
48     {
49       result->tv_nsec -= NANOSEC;
50       result->tv_sec++;
51     }
52 }
53 
54 void
tssub(timestruc_t * result,timestruc_t * time1,timestruc_t * time2)55 tssub (timestruc_t *result, timestruc_t *time1, timestruc_t *time2)
56 {
57   // This routine will store "time1" - "time2" in "result".
58 
59   if (time1->tv_nsec >= time2->tv_nsec)
60     {
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;
64       else
65 	{
66 	  result->tv_sec = -1;
67 	  result->tv_nsec = 0;
68 	}
69     }
70   else
71     {
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;
75       else
76 	{
77 	  result->tv_sec = -1;
78 	  result->tv_nsec = 0;
79 	}
80     }
81 }
82 
83 int
tscmp(timestruc_t * time1,timestruc_t * time2)84 tscmp (timestruc_t *time1, timestruc_t *time2)
85 {
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;
91   else
92     return time1->tv_sec > time2->tv_sec ? 1 : -1;
93 }
94 
95 void
int_max(int * maximum,int count)96 int_max (int *maximum, int count)
97 {
98   if (count > *maximum)
99     *maximum = count;
100 }
101 
102 double
to_double()103 TValue::to_double ()
104 {
105   switch (tag)
106     {
107     case VT_DOUBLE:
108       return (double) d;
109     case VT_INT:
110       return (double) i;
111     case VT_ULLONG:
112       return (double) ull;
113     case VT_LLONG:
114     case VT_ADDRESS:
115       return (double) ll;
116     case VT_FLOAT:
117       return (double) f;
118     case VT_SHORT:
119       return (double) s;
120     default:
121       return 0.0;
122     }
123 }
124 
125 int
to_int()126 TValue::to_int ()
127 {
128   switch (tag)
129     {
130     case VT_DOUBLE:
131       return (int) d;
132     case VT_INT:
133       return (int) i;
134     case VT_ULLONG:
135       return (int) ull;
136     case VT_LLONG:
137     case VT_ADDRESS:
138       return (int) ll;
139     case VT_FLOAT:
140       return (int) f;
141     case VT_SHORT:
142       return (int) s;
143     default:
144       return 0;
145     }
146 }
147 
148 size_t
get_len()149 TValue::get_len ()
150 {
151   char buf[256];
152   return strlen (to_str (buf, sizeof (buf)));
153 }
154 
155 char *
to_str(char * str,size_t strsz)156 TValue::to_str (char *str, size_t strsz)
157 {
158   switch (tag)
159     {
160     case VT_DOUBLE:
161       if (d == 0.)
162 	{
163 	  if (sign)
164 	    snprintf (str, strsz, NTXT ("+0.   "));
165 	  else
166 	    snprintf (str, strsz, NTXT ("0.   "));
167 	}
168       else if (sign)
169 	snprintf (str, strsz, NTXT ("%+.3lf"), d);
170       else
171 	snprintf (str, strsz, NTXT ("%.3lf"), d);
172       break;
173     case VT_INT:
174       snprintf (str, strsz, NTXT ("%u"), i);
175       break;
176     case VT_LLONG:
177       if (sign)
178 	snprintf (str, strsz, NTXT ("%+lld"), ll);
179       else
180 	snprintf (str, strsz, NTXT ("%lld"), ll);
181       break;
182     case VT_ULLONG:
183       snprintf (str, strsz, NTXT ("%llu"), ll);
184       break;
185     case VT_ADDRESS:
186       snprintf (str, strsz, NTXT ("%u:0x%08x"), ADDRESS_SEG (ll), ADDRESS_OFF (ll));
187       break;
188     case VT_FLOAT:
189       snprintf (str, strsz, NTXT ("%.3f"), f);
190       break;
191     case VT_SHORT:
192       snprintf (str, strsz, NTXT ("%hu"), s);
193       break;
194     case VT_LABEL:
195       return l; // 'str' is not used !!!
196     default:
197       *str = '\0';
198       break;
199     }
200 
201   return str;
202 }
203 
204 void
make_delta(TValue * v1,TValue * v2)205 TValue::make_delta (TValue *v1, TValue *v2)
206 {
207   assert (v1->tag == v2->tag);
208   tag = v1->tag;
209   sign = true;
210   switch (v1->tag)
211     {
212     case VT_INT:
213       i = v1->i - v2->i;
214       break;
215     case VT_LLONG:
216       ll = v1->ll - v2->ll;
217       break;
218     case VT_ULLONG:
219     case VT_ADDRESS:
220       tag = VT_LLONG;
221       ll = (long long) (v1->ull - v2->ull);
222       break;
223     case VT_FLOAT:
224       f = v1->f - v2->f;
225       break;
226     case VT_DOUBLE:
227       d = v1->d - v2->d;
228       break;
229     default:
230       assert (0);
231       break;
232     }
233 }
234 
235 void
make_ratio(TValue * v1,TValue * v2)236 TValue::make_ratio (TValue *v1, TValue *v2)
237 {
238   assert (v1->tag == v2->tag);
239   double x1 = v1->to_double ();
240   double x2 = v2->to_double ();
241   sign = false;
242   if (x1 == 0.)
243     {
244       // if the numerator is 0, the ratio is 1. or 0. only
245       d = (x2 == 0.) ? 1. : 0.;
246       tag = VT_DOUBLE;
247     }
248   else
249     {
250       // EUGENE replace 99.999 with a variable that is known by both DBE and GUI
251       if (x1 > 99.999 * x2)
252 	{
253 	  l = dbe_strdup (">99.999");
254 	  tag = VT_LABEL;
255 	}
256       else if (x1 < -99.999 * x2)
257 	{
258 	  l = dbe_strdup ("<-99.999");
259 	  tag = VT_LABEL;
260 	}
261       else
262 	{
263 	  d = x1 / x2;
264 	  tag = VT_DOUBLE;
265 	}
266     }
267 }
268 
269 int
compare(TValue * v)270 TValue::compare (TValue *v)
271 {
272   if (tag != v->tag)
273     { // Only for comparison (Ratio)
274       if (tag == VT_LABEL)
275 	{
276 	  if (v->tag == VT_LABEL)
277 	    return strcoll (l, v->l);
278 	  return 1;
279 	}
280       if (v->tag == VT_LABEL)
281 	return -1;
282       return ll < v->ll ? -1 : (ll == v->ll ? 0 : 1);
283     }
284   switch (tag)
285     {
286     case VT_SHORT:
287       return s < v->s ? -1 : (s == v->s ? 0 : 1);
288     case VT_INT:
289       return i < v->i ? -1 : (i == v->i ? 0 : 1);
290     case VT_FLOAT:
291       return f < v->f ? -1 : (f == v->f ? 0 : 1);
292     case VT_DOUBLE:
293       return d < v->d ? -1 : (d == v->d ? 0 : 1);
294     case VT_LABEL:
295       return strcoll (l, v->l);
296     case VT_LLONG:
297     case VT_ULLONG:
298     case VT_ADDRESS:
299     case VT_HRTIME:
300     default:
301       return (ll < v->ll) ? -1 : ((ll == v->ll) ? 0 : 1);
302     }
303 }
304 
305 char *
strstr_r(char * s1,const char * s2)306 strstr_r (char *s1, const char *s2)
307 {
308   char *str = NULL;
309   for (char *s = s1; s;)
310     {
311       s = strstr (s, s2);
312       if (s)
313 	{
314 	  str = s;
315 	  s++;
316 	}
317     }
318   return str;
319 }
320 
321 // reversal order of strpbrk
322 
323 char *
strrpbrk(const char * string,const char * brkset)324 strrpbrk (const char *string, const char *brkset)
325 {
326   const char *p;
327   const char *s;
328   for (s = string + strlen (string) - 1; s >= string; s--)
329     {
330       for (p = brkset; *p != '\0' && *p != *s; ++p)
331 	;
332       if (*p != '\0')
333 	return ((char *) s);
334     }
335   return NULL;
336 }
337 
338 char *
read_line(FILE * fptr)339 read_line (FILE *fptr)
340 {
341   // get an input line, no size limit
342   int line_sz = 128; // starting size
343   char *line = (char *) malloc (line_sz);
344 
345   // read as much of the line as will fit in memory
346   line[0] = 0;
347   int len = 0;
348   for (;;)
349     {
350       while (fgets (line + len, line_sz - len, fptr) != NULL)
351 	{
352 	  len = (int) strlen (line);
353 	  if (len == 0 || line[len - 1] == '\n')
354 	    break;
355 	  // increase the buffer
356 	  char *lineNew = (char *) malloc (2 * line_sz);
357 	  strncpy (lineNew, line, line_sz);
358 	  lineNew[line_sz] = '\0';
359 	  free (line);
360 	  line = lineNew;
361 	  line_sz *= 2;
362 	  if (line == NULL)
363 	    {
364 	      fprintf (stderr, GTXT ("   Line too long -- out of memory; exiting\n"));
365 	      exit (1);
366 	    }
367 	}
368       if (len == 0)
369 	{
370 	  free (line);
371 	  return NULL;
372 	}
373       // see if there's a continuation line
374       if ((len >= 2) && (line[len - 1] == '\n') && (line[len - 2] == '\\'))
375 	{
376 	  // remove the trailing \ and the \n, and keep going
377 	  line[len - 2] = 0;
378 	  len -= 2;
379 	}
380       else
381 	break;
382     }
383   return line; // expecting the caller to free it
384 }
385 
386 Vector<char *> *
split_str(char * str,char delimiter)387 split_str (char *str, char delimiter)
388 {
389   Vector<char *> *v = new Vector<char *>;
390   for (char *s = str; s;)
391     {
392       if (*s == '"')
393 	{
394 	  char *next_s = NULL;
395 	  char *tok = parse_qstring (s, &next_s);
396 	  if (tok && *tok != '\0')
397 	    v->append (tok);
398 	  if (*next_s)
399 	    s = next_s + 1;
400 	  else
401 	    s = NULL;
402 	}
403       else
404 	{
405 	  char *next_s = strchr (s, delimiter);
406 	  if (next_s)
407 	    {
408 	      if (next_s != s)
409 		v->append (dbe_strndup (s, next_s - s));
410 	      s = next_s + 1;
411 	    }
412 	  else
413 	    {
414 	      if (*s != '\0')
415 		v->append (dbe_strdup (s));
416 	      s = NULL;
417 	    }
418 	}
419     }
420   return v;
421 }
422 
423 // get quoted string
424 char *
parse_qstring(char * in_str,char ** endptr)425 parse_qstring (char *in_str, char **endptr)
426 {
427   int i;
428   char c, c2;
429   char term;
430   char csnum[2 * MAXPATHLEN];
431 
432   // Skip any leading blanks or tabs
433   while (*in_str == '\t' || *in_str == ' ')
434     in_str++;
435 
436   int gtxt = 0;
437   if (*in_str == 'G' && *(in_str + 1) == 'T' && *(in_str + 2) == 'X'
438       && *(in_str + 3) == 'T' && *(in_str + 4) == '(')
439     {
440       gtxt = 1;
441       in_str += 5;
442     }
443   // non-quoted string
444   if (*in_str == '"')
445     term = '"';
446   else if (*in_str == '\'')
447     term = '\'';
448   else
449     return strtok_r (in_str, NTXT (" "), endptr);
450 
451   StringBuilder sb;
452   while ((c = *(++in_str)) != '\0')
453     {
454       if (c == term) // the closing quote
455 	break;
456       if (c == '\\')
457 	{ // handle any escaped characters
458 	  c2 = *(++in_str);
459 	  switch (c2)
460 	    {
461 	    case '\"':
462 	      sb.append ('\"');
463 	      break;
464 	    case '\'':
465 	      sb.append ('\'');
466 	      break;
467 	    case '\\':
468 	      sb.append ('\\');
469 	      break;
470 	    case 't':
471 	      sb.append ('\t');
472 	      break;
473 	    case 'r':
474 	      sb.append ('\r');
475 	      break;
476 	    case 'b':
477 	      sb.append ('\b');
478 	      break;
479 	    case 'f':
480 	      sb.append ('\f');
481 	      break;
482 	    case 'n':
483 	      sb.append ('\n');
484 	      break;
485 	    default:
486 	      if ((c2 >= '0') && (c2 <= '9'))
487 		{
488 		  for (i = 0; i < MAXPATHLEN; i++)
489 		    {
490 		      if (((c2 < '0') || (c2 > '9')) && (c2 != 'x') &&
491 			  ((c2 < 'a') || (c2 > 'f')) &&
492 			  ((c2 < 'A') || (c2 > 'F')))
493 			{
494 			  csnum[i] = '\0';
495 			  --in_str;
496 			  break;
497 			}
498 		      else
499 			{
500 			  csnum[i] = c2;
501 			  c2 = *(++in_str);
502 			}
503 		    }
504 		  sb.append ((char) strtoul (csnum, endptr, 0));
505 		}
506 	      else
507 		sb.append (c2);
508 	      break;
509 	    }
510 	}
511       else
512 	sb.append (c);
513     }
514   if (c == term && gtxt && *in_str == ')')
515     in_str++;
516   if (*in_str == '\0')
517     *endptr = in_str;
518   else
519     *endptr = in_str + 1;
520   return sb.toString ();
521 }
522 
523 // parse a file name of the form name`name2`
524 // returns name
525 // stores the pointer to named in fcontext
526 // returns NULL if the string is not properly formatted
527 char *
parse_fname(char * in_str,char ** fcontext)528 parse_fname (char *in_str, char **fcontext)
529 {
530   *fcontext = NULL;
531   int ch = '`';
532   if (in_str == NULL)
533     return NULL;
534   char *copy = strdup (in_str);
535   char *p = strchr (copy, ch);
536   if (p != NULL)
537     {
538       // yes, there's an embedded file name
539       *p = '\0';
540       p++;
541       // now find the terminating single quote
542       char *p1 = strchr (p, ch);
543       if (p1 == NULL)
544 	{
545 	  // if we don't have the closing `, the format is incorrect
546 	  free (copy);
547 	  return NULL;
548 	}
549       //remove the closing quote
550       *p1 = '\0';
551       // see if there's anything following it
552       if (*(p1 + 1) != 0)
553 	{
554 	  // error in format
555 	  free (copy);
556 	  return NULL;
557 	}
558       free (*fcontext);
559       *fcontext = strdup (p);
560     }
561   return copy;
562 }
563 
564 int
get_paren(const char * name)565 get_paren (const char *name)
566 {
567   char buf[8192];
568   char *ptr;
569   int temp_level1, temp_level2;
570 
571   temp_level1 = temp_level2 = 0;
572   snprintf (buf, sizeof (buf), NTXT ("%s"), name);
573   while ((ptr = strrpbrk (buf, "><)(")) != NULL)
574     {
575       if (*ptr == '>')
576 	temp_level1++;
577       else if (*ptr == '<')
578 	temp_level1--;
579       else if (*ptr == ')')
580 	temp_level2++;
581       else
582 	{
583 	  temp_level2--;
584 	  if (temp_level1 <= 0 && temp_level2 <= 0)
585 	    return (int) (ptr - buf);
586 	}
587       *ptr = '\0';
588     }
589   return -1;
590 }
591 
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
641 };
642 
643 uint64_t
crc64(const char * str,size_t len)644 crc64 (const char *str, size_t len)
645 {
646   uint64_t res = 0LL;
647   for (size_t i = 0; i < len; i++)
648     {
649       unsigned char b = (unsigned char) ((res >> 56) ^ *str++);
650       res = res << 8;
651       res ^= masks [b];
652     }
653   return res;
654 }
655 
656 /**
657  * Canonize path inside the string provided by the argument
658  * @param path
659  * @return path
660  */
661 char *
canonical_path(char * path)662 canonical_path (char *path)
663 {
664   char *s1, *s2;
665   if (!path)
666     return path;
667   s1 = path;
668   s2 = path;
669   while (*s1)
670     {
671       if (*s1 == '.' && s1[1] == '/')
672 	{ // remove .///
673 	  for (s1++; *s1; s1++)
674 	    if (*s1 != '/')
675 	      break;
676 	}
677       else if (*s1 == '/')
678 	{ // replace /// with /
679 	  *(s2++) = *s1;
680 	  for (s1++; *s1; s1++)
681 	    if (*s1 != '/')
682 	      break;
683 	}
684       else
685 	{
686 	  while (*s1)
687 	    { // copy file or directory name
688 	      if (*s1 == '/')
689 		break;
690 	      *(s2++) = *(s1++);
691 	    }
692 	}
693     }
694   *s2 = 0;
695   if (s2 != path && (s2 - 1) != path && s2[-1] == '/')  // remove last /
696     *(s2 - 1) = 0;
697   return path;
698 }
699 
700 char *
get_relative_path(char * name)701 get_relative_path (char *name)
702 {
703   if (*name == '/' && theApplication)
704     {
705       char *cwd = theApplication->get_cur_dir ();
706       if (cwd)
707 	{
708 	  size_t len = strlen (cwd);
709 	  if (len > 0 && len < strlen (name) && name[len] == '/'
710 	      && strncmp (cwd, name, len) == 0)
711 	    {
712 	      for (name += len + 1; *name == '/'; name++)
713 		;
714 	      return name;
715 	    }
716 	}
717     }
718   return name;
719 }
720 
721 /**
722  * Generate a relative link name from path_from to path_to
723  * Example:
724  * path_from=a/b/c/d
725  * path_to=a/b/e/f/g
726  * lname=../../e/f/g
727  * @param path_to
728  * @param path_from
729  * @return lname - relative link
730  */
731 char *
get_relative_link(const char * path_from,const char * path_to)732 get_relative_link (const char *path_from, const char *path_to)
733 {
734   if (!path_to)
735     path_to = ".";
736   if (!path_from)
737     path_from = ".";
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++)
747     {
748       if (s1[i] != s2[i]) break;
749       if (s1[i] == 0) break;
750       if (s1[i] == '/')
751 	{
752 	  common_slashes++;
753 	  last_common_slash = i;
754 	}
755     }
756   // find slashes in remaining path_to
757   int slashes = 0;
758   for (int i = last_common_slash + 1; i < l; i++)
759     {
760       if (s1[i] == '/')
761 	{
762 	  // Exclude "/./" case
763 	  if (i > last_common_slash + 2)
764 	    {
765 	      if (s1[i - 1] == '.' && s1[i - 2] == '/')
766 		continue;
767 	    }
768 	  else if (i > 0 && s1[i - 1] == '.')
769 	    continue;
770 	  slashes++;
771 	}
772     }
773   // generate relative path
774   StringBuilder sb;
775   for (int i = 0; i < slashes; i++)
776     sb.append ("../");
777   sb.append (s2 + last_common_slash + 1);
778   char *lname = sb.toString ();
779   free (s1);
780   free (s2);
781   return lname;
782 }
783 
784 char *
get_prog_name(int basename)785 get_prog_name (int basename)
786 {
787   char *nm = NULL;
788   if (theApplication)
789     {
790       nm = theApplication->get_name ();
791       if (nm && basename)
792 	nm = get_basename (nm);
793     }
794   return nm;
795 }
796 
797 char *
dbe_strndup(const char * str,size_t len)798 dbe_strndup (const char *str, size_t len)
799 {
800   if (str == NULL)
801     return NULL;
802   char *s = (char *) malloc (len + 1);
803   strncpy (s, str, len);
804   s[len] = '\0';
805   return s;
806 }
807 
808 char *
dbe_sprintf(const char * fmt,...)809 dbe_sprintf (const char *fmt, ...)
810 {
811   char buffer[256];
812   int buf_size;
813   va_list vp;
814 
815   va_start (vp, fmt);
816   buf_size = vsnprintf (buffer, sizeof (buffer), fmt, vp) + 1;
817   va_end (vp);
818   if (buf_size < (int) sizeof (buffer))
819     {
820       if (buf_size <= 1)
821 	buffer[0] = 0;
822       return strdup (buffer);
823     }
824 
825   va_start (vp, fmt);
826   char *buf = (char *) malloc (buf_size);
827   vsnprintf (buf, buf_size, fmt, vp);
828   va_end (vp);
829   return buf;
830 }
831 
832 ssize_t
dbe_write(int f,const char * fmt,...)833 dbe_write (int f, const char *fmt, ...)
834 {
835   char buffer[256];
836   int buf_size;
837   va_list vp;
838 
839   va_start (vp, fmt);
840   buf_size = vsnprintf (buffer, sizeof (buffer), fmt, vp) + 1;
841   va_end (vp);
842   if (buf_size < (int) sizeof (buffer))
843     {
844       if (buf_size <= 1)
845 	buffer[0] = 0;
846       return write (f, buffer, strlen (buffer));
847     }
848 
849   va_start (vp, fmt);
850   char *buf = (char *) malloc (buf_size);
851   vsnprintf (buf, buf_size, fmt, vp);
852   va_end (vp);
853   ssize_t val = write (f, buf, strlen (buf));
854   free (buf);
855   return val;
856 }
857 
858 /* Worker Threads to avoid hanging on file servers */
859 
860 /*
861  * Thread states
862  */
863 enum
864 {
865   THREAD_START,
866   THREAD_STARTED,
867   THREAD_CANCEL,
868   THREAD_CANCELED,
869   THREAD_CREATE,
870   THREAD_NOT_CREATED,
871   THREAD_FINISHED
872 };
873 
874 /*
875  * Communication structure
876  */
877 struct worker_thread_info
878 {
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   dbe_stat_t statbuf;       /* File info from stat64() */
884   const char *path;         /* File */
885 };
886 
887 static pthread_mutex_t worker_thread_lock = PTHREAD_MUTEX_INITIALIZER;
888 static int worker_thread_number = 0;
889 /**
890  * Call stat64() on current worker thread
891  * Check if control is not THREAD_CANCEL
892  * If control is THREAD_CANCEL return (exit thread)
893  * @param *wt_info
894  */
895 static void *
dbe_stat_on_thread(void * arg)896 dbe_stat_on_thread (void *arg)
897 {
898   struct worker_thread_info *wt_info = (struct worker_thread_info *) arg;
899   pthread_mutex_lock (&worker_thread_lock);
900   {
901     if (wt_info->control != THREAD_START)
902       {
903 	// Already too late
904 	pthread_mutex_unlock (&worker_thread_lock);
905 	return 0;
906       }
907     wt_info->control = THREAD_STARTED;
908   }
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);
913   {
914     if (wt_info->control == THREAD_CANCEL)
915       {
916 	// Too late.
917 	pthread_mutex_unlock (&worker_thread_lock);
918 	free (wt_info);
919 	return 0;
920       }
921     wt_info->result = st;
922     wt_info->control = THREAD_FINISHED;
923   }
924   pthread_mutex_unlock (&worker_thread_lock);
925   return 0;
926 }
927 
928 /**
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
932  * @param path
933  * @param wt_info
934  * @return thread state
935  */
936 static int
dbe_dispatch_on_thread(const char * path,struct worker_thread_info * wt_info)937 dbe_dispatch_on_thread (const char *path, struct worker_thread_info *wt_info)
938 {
939   wt_info->result = 0;
940   wt_info->control = THREAD_START;
941   pthread_attr_t attr;
942   /* Initialize thread creation attributes */
943   int res = pthread_attr_init (&attr);
944   if (res != 0)
945     {
946       wt_info->control = THREAD_NOT_CREATED;
947       return THREAD_NOT_CREATED;
948     }
949   wt_info->thread_id = 0;
950   wt_info->path = path;
951   // Lock
952   pthread_mutex_lock (&worker_thread_lock);
953   worker_thread_number++;
954   wt_info->thread_num = worker_thread_number;
955   // Unlock
956   pthread_mutex_unlock (&worker_thread_lock);
957   // Create thread
958   res = pthread_create (&wt_info->thread_id, &attr, &dbe_stat_on_thread, wt_info);
959   if (res != 0)
960     {
961       wt_info->control = THREAD_NOT_CREATED;
962       pthread_attr_destroy (&attr);
963       return THREAD_NOT_CREATED;
964     }
965   // Wait for the thread to finish
966   res = 0;
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++)
971     {
972       if (THREAD_FINISHED == wt_info->control)
973 	break; // We are done
974       usleep (deltausec);
975     }
976   // Lock
977   pthread_mutex_lock (&worker_thread_lock);
978   if (THREAD_FINISHED != wt_info->control)
979     {
980       // Cancel thread
981       wt_info->control = THREAD_CANCEL; // Cannot use wt_info after that!
982       res = THREAD_CANCEL;
983     }
984   // Unlock
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
992   void *resources = 0;
993   res = pthread_join (wt_info->thread_id, &resources);
994   free (resources); /* Free memory allocated by thread */
995   return THREAD_FINISHED;
996 }
997 
998 static pthread_mutex_t dirnames_lock = PTHREAD_MUTEX_INITIALIZER;
999 static Map<const char*, int> *dirnamesMap = NULL;
1000 
1001 #define DIR_STATUS_EXISTS 0
1002 #define DIR_STATUS_UNKNOWN 2
1003 
1004 /**
1005  * Check if this directory name is known
1006  * Return:
1007  * @param path
1008  *  0 - known, exists
1009  *  1 - known, does not exist
1010  *  2 - not known
1011  */
1012 static int
check_dirname(const char * path)1013 check_dirname (const char *path)
1014 {
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;
1020   if (path && *path)
1021     {
1022       char *fn = dbe_strdup (path);
1023       char *dn = dirname (fn);
1024       if (dn && *dn)
1025 	res = dirnamesMap->get (dn);
1026       free (fn);
1027     }
1028   return res;
1029 }
1030 
1031 /**
1032  * Save directory name and its status
1033  * @param path
1034  * @param status
1035  * @return
1036  */
1037 static void
extract_and_save_dirname(const char * path,int status)1038 extract_and_save_dirname (const char *path, int status)
1039 {
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);
1045   if (fn && *fn != 0)
1046     {
1047       char *dn = dirname (fn);
1048       if (dn && (*dn != 0))
1049 	{
1050 	  int st = 0; // exists
1051 	  if (0 != status)
1052 	    st = 1; // does not exist
1053 	  dirnamesMap->put (dn, st);
1054 	}
1055     }
1056   free (fn);
1057 }
1058 
1059 // get status for specified file
1060 static int
dbe_stat_internal(const char * path,dbe_stat_t * sbuf,bool file_only)1061 dbe_stat_internal (const char *path, dbe_stat_t *sbuf, bool file_only)
1062 {
1063   dbe_stat_t statbuf;
1064   int dir_status = check_dirname (path);
1065   if (dir_status == DIR_STATUS_UNKNOWN)
1066     {
1067       // Try to use a worker thread
1068       if (theApplication->get_number_of_worker_threads () > 0)
1069 	{
1070 	  struct worker_thread_info *wt_info;
1071 	  wt_info = (worker_thread_info *) calloc (1, sizeof (worker_thread_info));
1072 	  if (wt_info != NULL)
1073 	    {
1074 	      int res = dbe_dispatch_on_thread (path, wt_info);
1075 	      if (THREAD_FINISHED == res)
1076 		{
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
1082 		  if (sbuf != NULL)
1083 		    *sbuf = wt_info->statbuf;
1084 		  free (wt_info);
1085 		  return st;
1086 		}
1087 	      else
1088 		{
1089 		  if (THREAD_CANCEL == res)
1090 		    {
1091 		      // Worker thread hung. Cannot free wt_info.
1092 		      // Allocated memory will be freed by worker thread.
1093 		      // save directory
1094 		      extract_and_save_dirname (path, 1);
1095 		      return 1; // stat64 failed
1096 		    }
1097 		  else  // THREAD_NOT_CREATED - continue on current thread
1098 		    free (wt_info);
1099 		}
1100 	    }
1101 	}
1102     }
1103   else if (dir_status != DIR_STATUS_EXISTS)
1104     return -1; // does not exist
1105   if (sbuf == NULL)
1106     sbuf = &statbuf;
1107   int st = stat64 (path, sbuf);
1108   Dprintf (DEBUG_DBE_FILE, NTXT ("dbe_stat %d '%s'\n"), st, path);
1109   if (st == -1)
1110     return -1;
1111   else if (file_only && S_ISREG (sbuf->st_mode) == 0)
1112     return -1; // It is not ordinary file
1113   return st;
1114 }
1115 
1116 // get status for the regular file
1117 
1118 int
dbe_stat_file(const char * path,dbe_stat_t * sbuf)1119 dbe_stat_file (const char *path, dbe_stat_t *sbuf)
1120 {
1121   int res = dbe_stat_internal (path, sbuf, true);
1122   return res;
1123 }
1124 
1125 // get status for specified file
1126 
1127 int
dbe_stat(const char * path,dbe_stat_t * sbuf)1128 dbe_stat (const char *path, dbe_stat_t *sbuf)
1129 {
1130   int res = dbe_stat_internal (path, sbuf, false);
1131   return res;
1132 }
1133 
1134 /**
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
1139  * @param path
1140  * @param format
1141  * @return char * files
1142  */
1143 char *
dbe_read_dir(const char * path,const char * format)1144 dbe_read_dir (const char *path, const char *format)
1145 {
1146   StringBuilder sb;
1147   DIR *dir = opendir (path);
1148   if (dir == NULL)
1149     return sb.toString ();
1150   int format_aF = 0;
1151   if (!strcmp (format, NTXT ("/bin/ls -aF")))
1152     format_aF = 1;
1153   struct dirent *entry = NULL;
1154   if (format != NULL)
1155     {
1156       while ((entry = readdir (dir)) != NULL)
1157 	{
1158 	  sb.append (entry->d_name);
1159 	  if (format_aF)
1160 	    {
1161 	      const char *attr = NTXT ("@"); // Link
1162 	      dbe_stat_t sbuf;
1163 	      sbuf.st_mode = 0;
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)
1168 		{ // Readable
1169 		  if (S_ISDIR (sbuf.st_mode) != 0)  // Directory
1170 		    attr = NTXT ("/");
1171 		  else if (S_ISREG (sbuf.st_mode) != 0) // Regular file
1172 		    attr = NTXT ("");
1173 		}
1174 	      sb.append (attr);
1175 	    }
1176 	  sb.append (NTXT ("\n"));
1177 	}
1178     }
1179   closedir (dir);
1180   return sb.toString ();
1181 }
1182 
1183 /**
1184  * Gets list of processes according to the specified format
1185  * Supported formats:
1186  * "/bin/ps -ef" - see 'man ps' for details
1187  * @param format
1188  * @return char * processes
1189  */
1190 char *
dbe_get_processes(const char * format)1191 dbe_get_processes (const char *format)
1192 {
1193   StringBuilder sb;
1194   if (!strcmp (format, NTXT ("/bin/ps -ef")))
1195     {
1196       char buf[BUFSIZ];
1197       FILE *ptr = popen (format, "r");
1198       if (ptr != NULL)
1199 	{
1200 	  while (fgets (buf, BUFSIZ, ptr) != NULL)
1201 	    sb.append (buf);
1202 	  pclose (ptr);
1203 	}
1204     }
1205   return sb.toString ();
1206 }
1207 
1208 /**
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"
1214  * @param pathname
1215  * @return result
1216  */
1217 char *
dbe_create_directories(const char * pathname)1218 dbe_create_directories (const char *pathname)
1219 {
1220   StringBuilder sb;
1221   char *makedir = dbe_sprintf (NTXT ("/bin/mkdir -p %s 2>&1"), pathname);
1222   char out[BUFSIZ];
1223   FILE *ptr = popen (makedir, "r");
1224   if (ptr != NULL)
1225     {
1226       while (fgets (out, BUFSIZ, ptr) != NULL)
1227 	sb.append (out);
1228       pclose (ptr);
1229     }
1230   free (makedir);
1231   DIR *dir = opendir (pathname);
1232   if (dir != NULL)
1233     {
1234       closedir (dir);
1235       return NULL; // success
1236     }
1237   else
1238     sb.append (NTXT ("\nError: Cannot open directory\n")); // DEBUG
1239   return sb.toString (); // error
1240 }
1241 
1242 /**
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
1248  * @param pathname
1249  * @return result
1250  */
1251 char *
dbe_delete_file(const char * pathname)1252 dbe_delete_file (const char *pathname)
1253 {
1254   StringBuilder sb;
1255   char *cmd = NULL;
1256   dbe_stat_t sbuf;
1257   sbuf.st_mode = 0;
1258   int st = dbe_stat (pathname, &sbuf);
1259   if (st == 0)
1260     { // Exists
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);
1265     }
1266   else
1267     return NULL; // Nothing to remove
1268   if (cmd != NULL)
1269     {
1270       char out[BUFSIZ];
1271       FILE *ptr = popen (cmd, "r");
1272       if (ptr != NULL)
1273 	{
1274 	  while (fgets (out, BUFSIZ, ptr) != NULL)
1275 	    sb.append (out);
1276 	  pclose (ptr);
1277 	}
1278       free (cmd);
1279     }
1280   else
1281     sb.sprintf (NTXT ("Error: cannot remove %s - not a regular file and not a directory\n"), pathname);
1282   return sb.toString ();
1283 }
1284 
1285 char *
dbe_xml2str(const char * s)1286 dbe_xml2str (const char *s)
1287 {
1288   if (s == NULL)
1289     return NULL;
1290   StringBuilder sb;
1291   while (*s)
1292     {
1293       if (*s == '&')
1294 	{
1295 	  if (strncmp (s, NTXT ("&nbsp;"), 6) == 0)
1296 	    {
1297 	      sb.append (' ');
1298 	      s += 6;
1299 	      continue;
1300 	    }
1301 	  else if (strncmp (s, NTXT ("&quot;"), 6) == 0)
1302 	    {
1303 	      sb.append ('"');
1304 	      s += 6;
1305 	      continue;
1306 	    }
1307 	  else if (strncmp (s, NTXT ("&amp;"), 5) == 0)
1308 	    {
1309 	      sb.append ('&');
1310 	      s += 5;
1311 	      continue;
1312 	    }
1313 	  else if (strncmp (s, NTXT ("&lt;"), 4) == 0)
1314 	    {
1315 	      sb.append ('<');
1316 	      s += 4;
1317 	      continue;
1318 	    }
1319 	  else if (strncmp (s, NTXT ("&gt;"), 4) == 0)
1320 	    {
1321 	      sb.append ('>');
1322 	      s += 4;
1323 	      continue;
1324 	    }
1325 	}
1326       sb.append (*s);
1327       s++;
1328     }
1329   return sb.toString ();
1330 }
1331 
1332 void
swapByteOrder(void * p,size_t sz)1333 swapByteOrder (void *p, size_t sz)
1334 {
1335   if (sz == 8)
1336     {
1337       uint64_t *pv = (uint64_t *) p;
1338       uint64_t v = *pv;
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);
1343       *pv = v;
1344     }
1345   else if (sz == 4)
1346     {
1347       uint32_t *pv = (uint32_t *) p;
1348       uint32_t v = *pv;
1349       v = (v >> 24) | (v << 24) | ((v & 0x0000FF00) << 8) | ((v >> 8) & 0x0000FF00);
1350       *pv = v;
1351     }
1352   else if (sz == 2)
1353     {
1354       uint16_t *pv = (uint16_t *) p;
1355       uint16_t v = *pv;
1356       v = (v >> 8) | (v << 8);
1357       *pv = v;
1358     }
1359 }
1360 
1361 void
destroy(void * vec)1362 destroy (void *vec)
1363 {
1364   if (vec == NULL)
1365     return;
1366   Vector<void*> *array = (Vector<void*>*)vec;
1367   switch (array->type ())
1368     {
1369     case VEC_STRING:
1370       ((Vector<char *>*)array)->destroy ();
1371       break;
1372     case VEC_VOIDARR:
1373     case VEC_STRINGARR:
1374     case VEC_INTARR:
1375     case VEC_BOOLARR:
1376     case VEC_LLONGARR:
1377     case VEC_DOUBLEARR:
1378       for (long i = 0; i < array->size (); i++)
1379 	destroy (array->fetch (i));
1380       break;
1381     case VEC_INTEGER:
1382     case VEC_CHAR:
1383     case VEC_BOOL:
1384     case VEC_DOUBLE:
1385     case VEC_LLONG:
1386     default:
1387       break;
1388     }
1389   delete array;
1390 }
1391 
1392 int64_t
read_from_file(int fd,void * buffer,int64_t nbyte)1393 read_from_file (int fd, void *buffer, int64_t nbyte)
1394 {
1395   int64_t cnt = 0;
1396   char *buf = (char *) buffer;
1397   while (nbyte > 0)
1398     { // Sometimes system cannot read 'nbyte'
1399       ssize_t n = read (fd, (void *) (buf + cnt), (size_t) nbyte);
1400       if (n <= 0)
1401 	break;
1402       nbyte -= n;
1403       cnt += n;
1404     }
1405   return cnt;
1406 }
1407 
1408 /**
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
1413  */
1414 char *
dbe_create_symlink_to_path(const char * path,const char * dir)1415 dbe_create_symlink_to_path (const char *path, const char *dir)
1416 {
1417   char *symbolic_link = NULL;
1418   if (NULL == path || NULL == dir)
1419     return NULL;
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);
1424   if (len <= 4)
1425     return NULL; // Unknown situation
1426   if (strcmp ((path + len - 4), "/bin") != 0)   // Unknown situation
1427     return NULL;
1428   int max = 99; // Just an arbitrary number
1429   for (int i = 1; i <= max; i++)
1430     {
1431       // Try to create symbolic link
1432       char *d = dbe_sprintf ("%s/%d", dir, i);
1433       if (NULL == d)
1434 	return NULL;
1435       res = mkdir (d, 0777);
1436       symbolic_link = dbe_sprintf ("%s/%s", d, "bin");
1437       free (d);
1438       if (NULL == symbolic_link) // Not enough memory
1439 	return NULL;
1440       res = symlink (path, symbolic_link);
1441       if (res == 0)     // Link is created - use it.
1442 	break;
1443       // Check if such link already exists
1444       int e = errno;
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.
1449 	break;
1450       if (i == max)
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));
1454 	  fflush (stderr);
1455 	}
1456       free (symbolic_link);
1457       symbolic_link = NULL;
1458     }
1459   return symbolic_link;
1460 }
1461 
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
1465 //
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
1470 //
1471 // layout is from the POSIX.2 Rationale
1472 
1473 static uint32_t crctab_posix[256] = {
1474   0x00000000L,
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
1526 };
1527 
1528 static void
m_crcposix(uint32_t * crcp,unsigned char * bp,uint32_t n)1529 m_crcposix (uint32_t *crcp, unsigned char *bp, uint32_t n)
1530 {
1531   while (n-- > 0)
1532     *crcp = (*crcp << 8) ^ crctab_posix[(unsigned char) ((*crcp >> 24)^*bp++)];
1533 }
1534 
1535 // Do CRC-POSIX function by calling a library entry point that has a
1536 // slightly different calling sequence.
1537 static uint32_t
docrcposix(uint32_t crcval,unsigned char * bp,uint32_t n)1538 docrcposix (uint32_t crcval, unsigned char *bp, uint32_t n)
1539 {
1540   m_crcposix (&crcval, bp, n);
1541   return (crcval);
1542 }
1543 
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.
1547 static uint32_t
postprocess(uint32_t S,long long n)1548 postprocess (uint32_t S, long long n)
1549 {
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)];
1554   uint32_t i;
1555   for (i = 0; n != 0; n >>= 8, ++i)
1556     char_n[i] = (unsigned char) (n & 0xFF);
1557   return (~docrcposix (S, char_n, i));
1558 }
1559 
1560 uint32_t
get_cksum(const char * pathname,char ** errmsg)1561 get_cksum (const char * pathname, char ** errmsg)
1562 {
1563   int fd = open (pathname, O_RDONLY);
1564   if (fd < 0)
1565     {
1566       if (errmsg)
1567 	*errmsg = dbe_sprintf (GTXT ("*** Warning: Error opening file for reading: %s"), pathname);
1568       return 0; // error
1569     }
1570   uint32_t crcval = 0;
1571   long long bytes = 0;
1572   int64_t n;
1573   unsigned char buf[4096];
1574   while ((n = read_from_file (fd, (char *) buf, sizeof (buf))) > 0)
1575     {
1576       bytes += n;
1577       crcval = docrcposix (crcval, buf, n);
1578     }
1579   close (fd);
1580   crcval = postprocess (crcval, bytes);
1581   return crcval;
1582 }
1583