Coverage Report

Created: 2026-01-16 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/lib/replace/replace.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   replacement routines for broken systems
4
   Copyright (C) Andrew Tridgell 1992-1998
5
   Copyright (C) Jelmer Vernooij 2005-2008
6
   Copyright (C) Matthieu Patou  2010
7
8
     ** NOTE! The following LGPL license applies to the replace
9
     ** library. This does NOT imply that all of Samba is released
10
     ** under the LGPL
11
12
   This library is free software; you can redistribute it and/or
13
   modify it under the terms of the GNU Lesser General Public
14
   License as published by the Free Software Foundation; either
15
   version 3 of the License, or (at your option) any later version.
16
17
   This library is distributed in the hope that it will be useful,
18
   but WITHOUT ANY WARRANTY; without even the implied warranty of
19
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20
   Lesser General Public License for more details.
21
22
   You should have received a copy of the GNU Lesser General Public
23
   License along with this library; if not, see <http://www.gnu.org/licenses/>.
24
*/
25
26
#include "replace.h"
27
28
#include "system/filesys.h"
29
#include "system/time.h"
30
#include "system/network.h"
31
#include "system/passwd.h"
32
#include "system/syslog.h"
33
#include "system/locale.h"
34
#include "system/wait.h"
35
36
#ifdef HAVE_SYS_SYSCALL_H
37
#include <sys/syscall.h>
38
#endif
39
40
#ifdef HAVE_SYS_PRCTL_H
41
#include <sys/prctl.h>
42
#endif
43
44
#ifdef _WIN32
45
#define mkdir(d,m) _mkdir(d)
46
#endif
47
48
void replace_dummy(void);
49
0
void replace_dummy(void) {}
50
51
#ifndef HAVE_FTRUNCATE
52
 /*******************************************************************
53
ftruncate for operating systems that don't have it
54
********************************************************************/
55
int rep_ftruncate(int f, off_t l)
56
{
57
#ifdef HAVE_CHSIZE
58
      return chsize(f,l);
59
#elif defined(F_FREESP)
60
      struct  flock   fl;
61
62
      fl.l_whence = 0;
63
      fl.l_len = 0;
64
      fl.l_start = l;
65
      fl.l_type = F_WRLCK;
66
      return fcntl(f, F_FREESP, &fl);
67
#else
68
#error "you must have a ftruncate function"
69
#endif
70
}
71
#endif /* HAVE_FTRUNCATE */
72
73
74
#ifndef HAVE_STRLCPY
75
/*
76
 * Like strncpy but does not 0 fill the buffer and always null
77
 * terminates. bufsize is the size of the destination buffer.
78
 * Returns the length of s.
79
 */
80
size_t rep_strlcpy(char *d, const char *s, size_t bufsize)
81
{
82
  size_t len = strlen(s);
83
  size_t ret = len;
84
85
  if (bufsize <= 0) {
86
    return 0;
87
  }
88
  if (len >= bufsize) {
89
    len = bufsize - 1;
90
  }
91
  memcpy(d, s, len);
92
  d[len] = 0;
93
  return ret;
94
}
95
#endif
96
97
#ifndef HAVE_STRLCAT
98
/* like strncat but does not 0 fill the buffer and always null
99
   terminates. bufsize is the length of the buffer, which should
100
   be one more than the maximum resulting string length */
101
size_t rep_strlcat(char *d, const char *s, size_t bufsize)
102
{
103
  size_t len1 = strnlen(d, bufsize);
104
  size_t len2 = strlen(s);
105
  size_t ret = len1 + len2;
106
107
  if (len1+len2 >= bufsize) {
108
    if (bufsize < (len1+1)) {
109
      return ret;
110
    }
111
    len2 = bufsize - (len1+1);
112
  }
113
  if (len2 > 0) {
114
    memcpy(d+len1, s, len2);
115
    d[len1+len2] = 0;
116
  }
117
  return ret;
118
}
119
#endif
120
121
#ifndef HAVE_MKTIME
122
/*******************************************************************
123
a mktime() replacement for those who don't have it - contributed by
124
C.A. Lademann <cal@zls.com>
125
Corrections by richard.kettlewell@kewill.com
126
********************************************************************/
127
128
#define  MINUTE  60
129
#define  HOUR    60*MINUTE
130
#define  DAY             24*HOUR
131
#define  YEAR    365*DAY
132
time_t rep_mktime(struct tm *t)
133
{
134
  struct tm       *u;
135
  time_t  epoch = 0;
136
  int n;
137
  int             mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
138
  y, m, i;
139
140
  if(t->tm_year < 70)
141
    return((time_t)-1);
142
143
  n = t->tm_year + 1900 - 1;
144
  epoch = (t->tm_year - 70) * YEAR +
145
    ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
146
147
  y = t->tm_year + 1900;
148
  m = 0;
149
150
  for(i = 0; i < t->tm_mon; i++) {
151
    epoch += mon [m] * DAY;
152
    if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
153
      epoch += DAY;
154
155
    if(++m > 11) {
156
      m = 0;
157
      y++;
158
    }
159
  }
160
161
  epoch += (t->tm_mday - 1) * DAY;
162
  epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
163
164
  if((u = localtime(&epoch)) != NULL) {
165
    t->tm_sec = u->tm_sec;
166
    t->tm_min = u->tm_min;
167
    t->tm_hour = u->tm_hour;
168
    t->tm_mday = u->tm_mday;
169
    t->tm_mon = u->tm_mon;
170
    t->tm_year = u->tm_year;
171
    t->tm_wday = u->tm_wday;
172
    t->tm_yday = u->tm_yday;
173
    t->tm_isdst = u->tm_isdst;
174
  }
175
176
  return(epoch);
177
}
178
#endif /* !HAVE_MKTIME */
179
180
181
#ifndef HAVE_INITGROUPS
182
/****************************************************************************
183
 some systems don't have an initgroups call
184
****************************************************************************/
185
int rep_initgroups(char *name, gid_t id)
186
{
187
#ifndef HAVE_SETGROUPS
188
  /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
189
  errno = ENOSYS;
190
  return -1;
191
#else /* HAVE_SETGROUPS */
192
193
#include <grp.h>
194
195
  gid_t *grouplst = NULL;
196
  int max_gr = NGROUPS_MAX;
197
  int ret;
198
  int    i,j;
199
  struct group *g;
200
  char   *gr;
201
202
  if((grouplst = malloc(sizeof(gid_t) * max_gr)) == NULL) {
203
    errno = ENOMEM;
204
    return -1;
205
  }
206
207
  grouplst[0] = id;
208
  i = 1;
209
  while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) {
210
    if (g->gr_gid == id)
211
      continue;
212
    j = 0;
213
    gr = g->gr_mem[0];
214
    while (gr && (*gr != (char)NULL)) {
215
      if (strcmp(name,gr) == 0) {
216
        grouplst[i] = g->gr_gid;
217
        i++;
218
        gr = (char *)NULL;
219
        break;
220
      }
221
      gr = g->gr_mem[++j];
222
    }
223
  }
224
  endgrent();
225
  ret = setgroups(i, grouplst);
226
  free(grouplst);
227
  return ret;
228
#endif /* HAVE_SETGROUPS */
229
}
230
#endif /* HAVE_INITGROUPS */
231
232
233
#ifndef HAVE_MEMMOVE
234
/*******************************************************************
235
safely copies memory, ensuring no overlap problems.
236
this is only used if the machine does not have its own memmove().
237
this is not the fastest algorithm in town, but it will do for our
238
needs.
239
********************************************************************/
240
void *rep_memmove(void *dest,const void *src,int size)
241
{
242
  unsigned long d,s;
243
  int i;
244
  if (dest==src || !size) return(dest);
245
246
  d = (unsigned long)dest;
247
  s = (unsigned long)src;
248
249
  if ((d >= (s+size)) || (s >= (d+size))) {
250
    /* no overlap */
251
    memcpy(dest,src,size);
252
    return(dest);
253
  }
254
255
  if (d < s) {
256
    /* we can forward copy */
257
    if (s-d >= sizeof(int) &&
258
        !(s%sizeof(int)) &&
259
        !(d%sizeof(int)) &&
260
        !(size%sizeof(int))) {
261
      /* do it all as words */
262
      int *idest = (int *)dest;
263
      int *isrc = (int *)src;
264
      size /= sizeof(int);
265
      for (i=0;i<size;i++) idest[i] = isrc[i];
266
    } else {
267
      /* simplest */
268
      char *cdest = (char *)dest;
269
      char *csrc = (char *)src;
270
      for (i=0;i<size;i++) cdest[i] = csrc[i];
271
    }
272
  } else {
273
    /* must backward copy */
274
    if (d-s >= sizeof(int) &&
275
        !(s%sizeof(int)) &&
276
        !(d%sizeof(int)) &&
277
        !(size%sizeof(int))) {
278
      /* do it all as words */
279
      int *idest = (int *)dest;
280
      int *isrc = (int *)src;
281
      size /= sizeof(int);
282
      for (i=size-1;i>=0;i--) idest[i] = isrc[i];
283
    } else {
284
      /* simplest */
285
      char *cdest = (char *)dest;
286
      char *csrc = (char *)src;
287
      for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
288
    }
289
  }
290
  return(dest);
291
}
292
#endif /* HAVE_MEMMOVE */
293
294
#ifndef HAVE_STRDUP
295
/****************************************************************************
296
duplicate a string
297
****************************************************************************/
298
char *rep_strdup(const char *s)
299
{
300
  size_t len;
301
  char *ret;
302
303
  if (!s) return(NULL);
304
305
  len = strlen(s)+1;
306
  ret = (char *)malloc(len);
307
  if (!ret) return(NULL);
308
  memcpy(ret,s,len);
309
  return(ret);
310
}
311
#endif /* HAVE_STRDUP */
312
313
#ifndef HAVE_SETLINEBUF
314
void rep_setlinebuf(FILE *stream)
315
{
316
  setvbuf(stream, (char *)NULL, _IOLBF, 0);
317
}
318
#endif /* HAVE_SETLINEBUF */
319
320
#ifndef HAVE_VSYSLOG
321
#ifdef HAVE_SYSLOG
322
void rep_vsyslog (int facility_priority, const char *format, va_list arglist)
323
{
324
  char *msg = NULL;
325
  vasprintf(&msg, format, arglist);
326
  if (!msg)
327
    return;
328
  syslog(facility_priority, "%s", msg);
329
  free(msg);
330
}
331
#endif /* HAVE_SYSLOG */
332
#endif /* HAVE_VSYSLOG */
333
334
#ifndef HAVE_STRNLEN
335
/**
336
 Some platforms don't have strnlen
337
**/
338
 size_t rep_strnlen(const char *s, size_t max)
339
{
340
        size_t len;
341
342
        for (len = 0; len < max; len++) {
343
                if (s[len] == '\0') {
344
                        break;
345
                }
346
        }
347
        return len;
348
}
349
#endif
350
351
#ifndef HAVE_STRNDUP
352
/**
353
 Some platforms don't have strndup.
354
**/
355
char *rep_strndup(const char *s, size_t n)
356
{
357
  char *ret;
358
359
  n = strnlen(s, n);
360
  ret = malloc(n+1);
361
  if (!ret)
362
    return NULL;
363
  memcpy(ret, s, n);
364
  ret[n] = 0;
365
366
  return ret;
367
}
368
#endif
369
370
#if !defined(HAVE_WAITPID) && defined(HAVE_WAIT4)
371
int rep_waitpid(pid_t pid,int *status,int options)
372
{
373
  return wait4(pid, status, options, NULL);
374
}
375
#endif
376
377
#ifndef HAVE_SETEUID
378
int rep_seteuid(uid_t euid)
379
{
380
#ifdef HAVE_SETRESUID
381
  return setresuid(-1, euid, -1);
382
#else
383
  errno = ENOSYS;
384
  return -1;
385
#endif
386
}
387
#endif
388
389
#ifndef HAVE_SETEGID
390
int rep_setegid(gid_t egid)
391
{
392
#ifdef HAVE_SETRESGID
393
  return setresgid(-1, egid, -1);
394
#else
395
  errno = ENOSYS;
396
  return -1;
397
#endif
398
}
399
#endif
400
401
/*******************************************************************
402
os/2 also doesn't have chroot
403
********************************************************************/
404
#ifndef HAVE_CHROOT
405
int rep_chroot(const char *dname)
406
{
407
  errno = ENOSYS;
408
  return -1;
409
}
410
#endif
411
412
/*****************************************************************
413
 Possibly replace mkstemp if it is broken.
414
*****************************************************************/
415
416
#ifndef HAVE_SECURE_MKSTEMP
417
int rep_mkstemp(char *template)
418
{
419
  /* have a reasonable go at emulating it. Hope that
420
     the system mktemp() isn't completely hopeless */
421
  mktemp(template);
422
  if (template[0] == 0)
423
    return -1;
424
  return open(template, O_CREAT|O_EXCL|O_RDWR, 0600);
425
}
426
#endif
427
428
#ifndef HAVE_MKDTEMP
429
char *rep_mkdtemp(char *template)
430
{
431
  char *dname;
432
433
  if ((dname = mktemp(template))) {
434
    if (mkdir(dname, 0700) >= 0) {
435
      return dname;
436
    }
437
  }
438
439
  return NULL;
440
}
441
#endif
442
443
/*****************************************************************
444
 Watch out: this is not thread safe.
445
*****************************************************************/
446
447
#ifndef HAVE_PREAD
448
ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset)
449
{
450
  if (lseek(__fd, __offset, SEEK_SET) != __offset) {
451
    return -1;
452
  }
453
  return read(__fd, __buf, __nbytes);
454
}
455
#endif
456
457
/*****************************************************************
458
 Watch out: this is not thread safe.
459
*****************************************************************/
460
461
#ifndef HAVE_PWRITE
462
ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset)
463
{
464
  if (lseek(__fd, __offset, SEEK_SET) != __offset) {
465
    return -1;
466
  }
467
  return write(__fd, __buf, __nbytes);
468
}
469
#endif
470
471
#ifndef HAVE_STRCASESTR
472
char *rep_strcasestr(const char *haystack, const char *needle)
473
{
474
  const char *s;
475
  size_t nlen = strlen(needle);
476
  for (s=haystack;*s;s++) {
477
    if (toupper(*needle) == toupper(*s) &&
478
        strncasecmp(s, needle, nlen) == 0) {
479
      return (char *)((uintptr_t)s);
480
    }
481
  }
482
  return NULL;
483
}
484
#endif
485
486
#ifndef HAVE_STRSEP
487
char *rep_strsep(char **pps, const char *delim)
488
{
489
  char *ret = *pps;
490
  char *p = *pps;
491
492
  if (p == NULL) {
493
    return NULL;
494
  }
495
  p += strcspn(p, delim);
496
  if (*p == '\0') {
497
    *pps = NULL;
498
  } else {
499
    *p = '\0';
500
    *pps = p + 1;
501
  }
502
  return ret;
503
}
504
#endif
505
506
#ifndef HAVE_STRTOK_R
507
/* based on GLIBC version, copyright Free Software Foundation */
508
char *rep_strtok_r(char *s, const char *delim, char **save_ptr)
509
{
510
  char *token;
511
512
  if (s == NULL) s = *save_ptr;
513
514
  s += strspn(s, delim);
515
  if (*s == '\0') {
516
    *save_ptr = s;
517
    return NULL;
518
  }
519
520
  token = s;
521
  s = strpbrk(token, delim);
522
  if (s == NULL) {
523
    *save_ptr = token + strlen(token);
524
  } else {
525
    *s = '\0';
526
    *save_ptr = s + 1;
527
  }
528
529
  return token;
530
}
531
#endif
532
533
534
#ifndef HAVE_STRTOLL
535
long long int rep_strtoll(const char *str, char **endptr, int base)
536
{
537
#ifdef HAVE_STRTOQ
538
  return strtoq(str, endptr, base);
539
#elif defined(HAVE___STRTOLL)
540
  return __strtoll(str, endptr, base);
541
#elif SIZEOF_LONG == SIZEOF_LONG_LONG
542
  return (long long int) strtol(str, endptr, base);
543
#else
544
# error "You need a strtoll function"
545
#endif
546
}
547
#else
548
#ifdef HAVE_BSD_STRTOLL
549
#undef strtoll
550
long long int rep_strtoll(const char *str, char **endptr, int base)
551
{
552
  int saved_errno = errno;
553
  long long int nb = strtoll(str, endptr, base);
554
  /* With glibc EINVAL is only returned if base is not ok */
555
  if (errno == EINVAL) {
556
    if (base == 0 || (base >1 && base <37)) {
557
      /* Base was ok so it's because we were not
558
       * able to make the conversion.
559
       * Let's reset errno.
560
       */
561
      errno = saved_errno;
562
    }
563
  }
564
  return nb;
565
}
566
#endif /* HAVE_BSD_STRTOLL */
567
#endif /* HAVE_STRTOLL */
568
569
570
#ifndef HAVE_STRTOULL
571
unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
572
{
573
#ifdef HAVE_STRTOUQ
574
  return strtouq(str, endptr, base);
575
#elif defined(HAVE___STRTOULL)
576
  return __strtoull(str, endptr, base);
577
#elif SIZEOF_LONG == SIZEOF_LONG_LONG
578
  return (unsigned long long int) strtoul(str, endptr, base);
579
#else
580
# error "You need a strtoull function"
581
#endif
582
}
583
#else
584
#ifdef HAVE_BSD_STRTOLL
585
#undef strtoull
586
unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
587
{
588
  int saved_errno = errno;
589
  unsigned long long int nb = strtoull(str, endptr, base);
590
  /* With glibc EINVAL is only returned if base is not ok */
591
  if (errno == EINVAL) {
592
    if (base == 0 || (base >1 && base <37)) {
593
      /* Base was ok so it's because we were not
594
       * able to make the conversion.
595
       * Let's reset errno.
596
       */
597
      errno = saved_errno;
598
    }
599
  }
600
  return nb;
601
}
602
#endif /* HAVE_BSD_STRTOLL */
603
#endif /* HAVE_STRTOULL */
604
605
#ifndef HAVE_SETENV
606
int rep_setenv(const char *name, const char *value, int overwrite)
607
{
608
  char *p;
609
  size_t l1, l2;
610
  int ret;
611
612
  if (!overwrite && getenv(name)) {
613
    return 0;
614
  }
615
616
  l1 = strlen(name);
617
  l2 = strlen(value);
618
619
  p = malloc(l1+l2+2);
620
  if (p == NULL) {
621
    return -1;
622
  }
623
  memcpy(p, name, l1);
624
  p[l1] = '=';
625
  memcpy(p+l1+1, value, l2);
626
  p[l1+l2+1] = 0;
627
628
  ret = putenv(p);
629
  if (ret != 0) {
630
    free(p);
631
  }
632
633
  return ret;
634
}
635
#endif
636
637
#ifndef HAVE_UNSETENV
638
int rep_unsetenv(const char *name)
639
{
640
  extern char **environ;
641
  size_t len = strlen(name);
642
  size_t i, count;
643
644
  if (environ == NULL || getenv(name) == NULL) {
645
    return 0;
646
  }
647
648
  for (i=0;environ[i];i++) /* noop */ ;
649
650
  count=i;
651
652
  for (i=0;i<count;) {
653
    if (strncmp(environ[i], name, len) == 0 && environ[i][len] == '=') {
654
      /* note: we do _not_ free the old variable here. It is unsafe to
655
         do so, as the pointer may not have come from malloc */
656
      memmove(&environ[i], &environ[i+1], (count-i)*sizeof(char *));
657
      count--;
658
    } else {
659
      i++;
660
    }
661
  }
662
663
  return 0;
664
}
665
#endif
666
667
#ifndef HAVE_UTIME
668
int rep_utime(const char *filename, const struct utimbuf *buf)
669
{
670
  errno = ENOSYS;
671
  return -1;
672
}
673
#endif
674
675
#ifndef HAVE_UTIMES
676
int rep_utimes(const char *filename, const struct timeval tv[2])
677
{
678
  struct utimbuf u;
679
680
  u.actime = tv[0].tv_sec;
681
  if (tv[0].tv_usec > 500000) {
682
    u.actime += 1;
683
  }
684
685
  u.modtime = tv[1].tv_sec;
686
  if (tv[1].tv_usec > 500000) {
687
    u.modtime += 1;
688
  }
689
690
  return utime(filename, &u);
691
}
692
#endif
693
694
#ifndef HAVE_DUP2
695
int rep_dup2(int oldfd, int newfd)
696
{
697
  errno = ENOSYS;
698
  return -1;
699
}
700
#endif
701
702
#ifndef HAVE_CHOWN
703
/**
704
chown isn't used much but OS/2 doesn't have it
705
**/
706
int rep_chown(const char *fname, uid_t uid, gid_t gid)
707
{
708
  errno = ENOSYS;
709
  return -1;
710
}
711
#endif
712
713
#ifndef HAVE_LINK
714
int rep_link(const char *oldpath, const char *newpath)
715
{
716
  errno = ENOSYS;
717
  return -1;
718
}
719
#endif
720
721
#ifndef HAVE_READLINK
722
int rep_readlink(const char *path, char *buf, size_t bufsiz)
723
{
724
  errno = ENOSYS;
725
  return -1;
726
}
727
#endif
728
729
#ifndef HAVE_SYMLINK
730
int rep_symlink(const char *oldpath, const char *newpath)
731
{
732
  errno = ENOSYS;
733
  return -1;
734
}
735
#endif
736
737
#ifndef HAVE_LCHOWN
738
int rep_lchown(const char *fname,uid_t uid,gid_t gid)
739
{
740
  errno = ENOSYS;
741
  return -1;
742
}
743
#endif
744
745
#ifndef HAVE_REALPATH
746
char *rep_realpath(const char *path, char *resolved_path)
747
{
748
  /* As realpath is not a system call we can't return ENOSYS. */
749
  errno = EINVAL;
750
  return NULL;
751
}
752
#endif
753
754
755
#ifndef HAVE_MEMMEM
756
void *rep_memmem(const void *haystack, size_t haystacklen,
757
     const void *needle, size_t needlelen)
758
{
759
  if (needlelen == 0) {
760
    return discard_const(haystack);
761
  }
762
  while (haystacklen >= needlelen) {
763
    char *p = (char *)memchr(haystack, *(const char *)needle,
764
           haystacklen-(needlelen-1));
765
    if (!p) return NULL;
766
    if (memcmp(p, needle, needlelen) == 0) {
767
      return p;
768
    }
769
    haystack = p+1;
770
    haystacklen -= (p - (const char *)haystack) + 1;
771
  }
772
  return NULL;
773
}
774
#endif
775
776
#if !defined(HAVE_VDPRINTF) || !defined(HAVE_C99_VSNPRINTF)
777
int rep_vdprintf(int fd, const char *format, va_list ap)
778
{
779
  char *s = NULL;
780
  int ret;
781
782
  vasprintf(&s, format, ap);
783
  if (s == NULL) {
784
    errno = ENOMEM;
785
    return -1;
786
  }
787
  ret = write(fd, s, strlen(s));
788
  free(s);
789
  return ret;
790
}
791
#endif
792
793
#if !defined(HAVE_DPRINTF) || !defined(HAVE_C99_VSNPRINTF)
794
int rep_dprintf(int fd, const char *format, ...)
795
{
796
  int ret;
797
  va_list ap;
798
799
  va_start(ap, format);
800
  ret = vdprintf(fd, format, ap);
801
  va_end(ap);
802
803
  return ret;
804
}
805
#endif
806
807
#ifndef HAVE_GET_CURRENT_DIR_NAME
808
char *rep_get_current_dir_name(void)
809
{
810
  char buf[PATH_MAX+1];
811
  char *p;
812
  p = getcwd(buf, sizeof(buf));
813
  if (p == NULL) {
814
    return NULL;
815
  }
816
  return strdup(p);
817
}
818
#endif
819
820
#ifndef HAVE_STRERROR_R
821
int rep_strerror_r(int errnum, char *buf, size_t buflen)
822
{
823
  char *s = strerror(errnum);
824
  if (strlen(s)+1 > buflen) {
825
    errno = ERANGE;
826
    return -1;
827
  }
828
  strncpy(buf, s, buflen);
829
  return 0;
830
}
831
#elif (!defined(STRERROR_R_XSI_NOT_GNU))
832
#undef strerror_r
833
int rep_strerror_r(int errnum, char *buf, size_t buflen)
834
0
{
835
0
  char *s = strerror_r(errnum, buf, buflen);
836
0
  if (s == NULL) {
837
    /* Shouldn't happen, should always get a string */
838
0
    return EINVAL;
839
0
  }
840
0
  if (s != buf) {
841
0
    strlcpy(buf, s, buflen);
842
0
    if (strlen(s) > buflen - 1) {
843
0
      return ERANGE;
844
0
    }
845
0
  }
846
0
  return 0;
847
848
0
}
849
#endif
850
851
#ifndef HAVE_CLOCK_GETTIME
852
int rep_clock_gettime(clockid_t clk_id, struct timespec *tp)
853
{
854
  struct timeval tval;
855
  switch (clk_id) {
856
    case 0: /* CLOCK_REALTIME :*/
857
#if defined(HAVE_GETTIMEOFDAY_TZ) || defined(HAVE_GETTIMEOFDAY_TZ_VOID)
858
      gettimeofday(&tval,NULL);
859
#else
860
      gettimeofday(&tval);
861
#endif
862
      tp->tv_sec = tval.tv_sec;
863
      tp->tv_nsec = tval.tv_usec * 1000;
864
      break;
865
    default:
866
      errno = EINVAL;
867
      return -1;
868
  }
869
  return 0;
870
}
871
#endif
872
873
#ifndef HAVE_MEMALIGN
874
void *rep_memalign( size_t align, size_t size )
875
{
876
#if defined(HAVE_POSIX_MEMALIGN)
877
  void *p = NULL;
878
  int ret = posix_memalign( &p, align, size );
879
  if ( ret == 0 )
880
    return p;
881
882
  return NULL;
883
#else
884
  /* On *BSD systems memaligns doesn't exist, but memory will
885
   * be aligned on allocations of > pagesize. */
886
#if defined(SYSCONF_SC_PAGESIZE)
887
  size_t pagesize = (size_t)sysconf(_SC_PAGESIZE);
888
#elif defined(HAVE_GETPAGESIZE)
889
  size_t pagesize = (size_t)getpagesize();
890
#else
891
  size_t pagesize = (size_t)-1;
892
#endif
893
  if (pagesize == (size_t)-1) {
894
    errno = ENOSYS;
895
    return NULL;
896
  }
897
  if (size < pagesize) {
898
    size = pagesize;
899
  }
900
  return malloc(size);
901
#endif
902
}
903
#endif
904
905
#ifndef HAVE_GETPEEREID
906
int rep_getpeereid(int s, uid_t *uid, gid_t *gid)
907
{
908
#if defined(HAVE_PEERCRED)
909
  struct ucred cred;
910
  socklen_t cred_len = sizeof(struct ucred);
911
  int ret;
912
913
#undef getsockopt
914
  ret = getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &cred_len);
915
  if (ret != 0) {
916
    return -1;
917
  }
918
919
  if (cred_len != sizeof(struct ucred)) {
920
    errno = EINVAL;
921
    return -1;
922
  }
923
924
  *uid = cred.uid;
925
  *gid = cred.gid;
926
  return 0;
927
#else
928
  errno = ENOSYS;
929
  return -1;
930
#endif
931
}
932
#endif
933
934
#ifndef HAVE_USLEEP
935
int rep_usleep(useconds_t sec)
936
{
937
  struct timeval tval;
938
  /*
939
   * Fake it with select...
940
   */
941
  tval.tv_sec = 0;
942
  tval.tv_usec = usecs/1000;
943
  select(0,NULL,NULL,NULL,&tval);
944
  return 0;
945
}
946
#endif /* HAVE_USLEEP */
947
948
#ifndef HAVE_SETPROCTITLE
949
void rep_setproctitle(const char *fmt, ...)
950
{
951
#if defined(HAVE_PRCTL) && defined(PR_SET_MM_MAP) && defined(__NR_brk)
952
  /*
953
   * Implementation based on setproctitle from lcx under LGPL-2.1+
954
   * https://github.com/lxc/lxc/
955
   *
956
   * Using PR_SET_MM_MAP requires CAP_SYS_RESOURCE.
957
   */
958
  static char *proctitle = NULL;
959
  char *tmp_proctitle = NULL;
960
  char buf[2048] = {0};
961
  char title[2048] = {0};
962
  va_list ap;
963
  char *ptr = NULL;
964
  FILE *f = NULL;
965
  size_t title_len;
966
  int ret = 0;
967
  struct prctl_mm_map prctl_map = {
968
    .exe_fd = -1,
969
  };
970
  long brk_val = 0;
971
  /* See `man proc_pid_stat.5` */
972
  unsigned long start_code = 0;            // 26
973
  unsigned long end_code = 0;              // 27
974
  unsigned long start_stack = 0;           // 28
975
976
  unsigned long start_data = 0;            // 45
977
  unsigned long end_data = 0;              // 46
978
  unsigned long start_brk = 0;             // 47
979
  unsigned long arg_start = 0;             // 48
980
  unsigned long arg_end = 0;               // 49
981
  unsigned long env_start = 0;             // 50
982
  unsigned long env_end = 0;               // 51
983
984
  f = fopen("/proc/self/stat", "r");
985
  if (f == NULL) {
986
    return;
987
  }
988
989
  ptr = fgets(buf, sizeof(buf), f);
990
  fclose(f);
991
  if (ptr == NULL) {
992
    return;
993
  }
994
995
  /*
996
   * Find the last ')' to skip the comm field which can contain spaces and
997
   * maybe ')'.
998
   */
999
  ptr = strrchr(buf, ')');
1000
  if (ptr == NULL || ptr[1] == '\0') {
1001
    return;
1002
  }
1003
  ptr += 2; // Skip ') '
1004
1005
  /* See `man proc_pid_stat.5` */
1006
  ret = sscanf(
1007
    ptr,
1008
    "%*c "        // 3 (state)
1009
    "%*d "        // 4 (ppid)
1010
    "%*d "        // 5 (pgrp)
1011
    "%*d "        // 6 (session)
1012
    "%*d "        // 7 (tty_nr)
1013
    "%*d "        // 8 (tpgid)
1014
    "%*u "        // 9 (flags)
1015
    "%*u "        // 10 (minflt)
1016
    "%*u "        // 11 (cminflt)
1017
    "%*u "        // 12 (majflt)
1018
    "%*u "        // 13 (cmajflt)
1019
    "%*u "        // 14 (utime)
1020
    "%*u "        // 15 (stime)
1021
    "%*d "        // 16 (cutime)
1022
    "%*d "        // 17 (cstime)
1023
    "%*d "        // 18 (priority)
1024
    "%*d "        // 19 (nice)
1025
    "%*d "        // 20 (num_threads)
1026
    "%*d "        // 21 (itrealvalue)
1027
    "%*u "        // 22 (starttime)
1028
    "%*u "        // 23 (vsize)
1029
    "%*d "        // 24 (rss)
1030
    "%*u "        // 25 (rsslim)
1031
    "%lu "        // 26 (start_code)
1032
    "%lu "        // 27 (end_code)
1033
    "%lu "        // 28 (start_stack)
1034
    "%*u "        // 29 (kstkesp)
1035
    "%*u "        // 30 (kstkeip)
1036
    "%*u "        // 31 (signal)
1037
    "%*u "        // 32 (blocked)
1038
    "%*u "        // 33 (sigignore)
1039
    "%*u "        // 34 (sigcatch)
1040
    "%*u "        // 35 (wchan)
1041
    "%*u "        // 36 (nswap)
1042
    "%*u "        // 37 (cnswap)
1043
    "%*d "        // 38 (exit_signal)
1044
    "%*d "        // 39 (processor)
1045
    "%*d "        // 40 (rt_priority)
1046
    "%*u "        // 41 (policy)
1047
    "%*u "        // 42 (delayacct_blkio_ticks)
1048
    "%*u "        // 43 (guest_time)
1049
    "%*d "        // 44 (cguest_time)
1050
    "%lu "        // 45 (start_data)
1051
    "%lu "        // 46 (end_data)
1052
    "%lu "        // 47 (start_brk)
1053
    "%lu "        // 48 (arg_start)
1054
    "%lu "        // 49 (arg_end)
1055
    "%lu "        // 50 (env_start)
1056
    "%lu",        // 51 (env_end)
1057
    &start_code,  // 26
1058
    &end_code,    // 27
1059
    &start_stack, // 28
1060
    &start_data,  // 45
1061
    &end_data,    // 46
1062
    &start_brk,   // 47
1063
    &arg_start,   // 48
1064
    &arg_end,     // 49
1065
    &env_start,   // 50
1066
    &env_end      // 51
1067
  );
1068
  if (ret != 10) {
1069
    return;
1070
  }
1071
1072
  va_start(ap, fmt);
1073
  ret = vsnprintf(title, sizeof(title), fmt, ap);
1074
  va_end(ap);
1075
  if (ret <= 0) {
1076
    return;
1077
  }
1078
  /*
1079
   * Include the null byte here, because in the calculations below
1080
   * we want to have room for it.
1081
   */
1082
  title_len = ret + 1;
1083
1084
  /* This will leak memory */
1085
  tmp_proctitle = realloc(proctitle, title_len);
1086
  if (tmp_proctitle == NULL) {
1087
    return;
1088
  }
1089
  proctitle = tmp_proctitle;
1090
1091
  arg_start = (uint64_t)proctitle;
1092
  arg_end = arg_start + title_len;
1093
1094
  brk_val = syscall(__NR_brk, 0);
1095
  if (brk_val < 0) {
1096
    return;
1097
  }
1098
1099
  prctl_map = (struct prctl_mm_map) {
1100
    .start_code = start_code,
1101
    .end_code = end_code,
1102
    .start_stack = start_stack,
1103
    .start_data = start_data,
1104
    .end_data = end_data,
1105
    .start_brk = start_brk,
1106
    .brk = brk_val,
1107
    .arg_start = arg_start,
1108
    .arg_end = arg_end,
1109
    .env_start = env_start,
1110
    .env_end = env_end,
1111
    .auxv = NULL,
1112
    .auxv_size = 0,
1113
    .exe_fd = -1,
1114
  };
1115
1116
  ret = prctl(PR_SET_MM,
1117
        PR_SET_MM_MAP,
1118
        (long)&prctl_map,
1119
        sizeof(prctl_map),
1120
        0);
1121
  if (ret == 0) {
1122
    strlcpy((char *)arg_start, title, title_len);
1123
  }
1124
#endif /* HAVE_PRCTL */
1125
}
1126
#endif
1127
1128
#ifndef HAVE_SETPROCTITLE_INIT
1129
void rep_setproctitle_init(int argc, char *argv[], char *envp[])
1130
{
1131
}
1132
#endif
1133
1134
#ifndef HAVE_MEMSET_EXPLICIT
1135
void *rep_memset_explicit(void *block, int c, size_t size)
1136
5.69M
{
1137
5.69M
  void *ptr = memset(block, c, size);
1138
5.69M
#ifdef HAVE_GCC_VOLATILE_MEMORY_PROTECTION
1139
  /* See http://llvm.org/bugs/show_bug.cgi?id=15495 */
1140
5.69M
  __asm__ volatile("" : : "g"(block) : "memory");
1141
5.69M
#endif /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */
1142
1143
5.69M
  return ptr;
1144
5.69M
}
1145
#endif
1146
1147
#ifndef HAVE_GETPROGNAME
1148
# ifndef HAVE_PROGRAM_INVOCATION_SHORT_NAME
1149
# define PROGNAME_SIZE 32
1150
static char rep_progname[PROGNAME_SIZE];
1151
# endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
1152
1153
const char *rep_getprogname(void)
1154
0
{
1155
0
#ifdef HAVE_PROGRAM_INVOCATION_SHORT_NAME
1156
0
  return program_invocation_short_name;
1157
#else /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
1158
  FILE *fp = NULL;
1159
  char cmdline[4096] = {0};
1160
  char *p = NULL;
1161
  pid_t pid;
1162
  size_t nread;
1163
  int len;
1164
  int rc;
1165
1166
  if (rep_progname[0] != '\0') {
1167
    return rep_progname;
1168
  }
1169
1170
  len = snprintf(rep_progname, sizeof(rep_progname), "%s", "<unknown>");
1171
  if (len <= 0) {
1172
    return NULL;
1173
  }
1174
1175
  pid = getpid();
1176
  if (pid <= 1 || pid == (pid_t)-1) {
1177
    return NULL;
1178
  }
1179
1180
  len = snprintf(cmdline,
1181
           sizeof(cmdline),
1182
           "/proc/%u/cmdline",
1183
           (unsigned int)pid);
1184
  if (len <= 0 || len == sizeof(cmdline)) {
1185
    return NULL;
1186
  }
1187
1188
  fp = fopen(cmdline, "r");
1189
  if (fp == NULL) {
1190
    return NULL;
1191
  }
1192
1193
  nread = fread(cmdline, 1, sizeof(cmdline) - 1, fp);
1194
1195
  rc = fclose(fp);
1196
  if (rc != 0) {
1197
    return NULL;
1198
  }
1199
1200
  if (nread == 0) {
1201
    return NULL;
1202
  }
1203
1204
  cmdline[nread] = '\0';
1205
1206
  p = strrchr(cmdline, '/');
1207
  if (p != NULL) {
1208
    p++;
1209
  } else {
1210
    p = cmdline;
1211
  }
1212
1213
  len = strlen(p);
1214
  if (len > PROGNAME_SIZE) {
1215
    p[PROGNAME_SIZE - 1] = '\0';
1216
  }
1217
1218
  (void)snprintf(rep_progname, sizeof(rep_progname), "%s", p);
1219
1220
  return rep_progname;
1221
#endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
1222
0
}
1223
#endif /* HAVE_GETPROGNAME */
1224
1225
#ifndef HAVE_COPY_FILE_RANGE
1226
ssize_t rep_copy_file_range(int fd_in,
1227
          loff_t *off_in,
1228
          int fd_out,
1229
          loff_t *off_out,
1230
          size_t len,
1231
          unsigned int flags)
1232
{
1233
# ifdef HAVE_SYSCALL_COPY_FILE_RANGE
1234
  return syscall(__NR_copy_file_range,
1235
           fd_in,
1236
           off_in,
1237
           fd_out,
1238
           off_out,
1239
           len,
1240
           flags);
1241
# endif /* HAVE_SYSCALL_COPY_FILE_RANGE */
1242
  errno = ENOSYS;
1243
  return -1;
1244
}
1245
#endif /* HAVE_COPY_FILE_RANGE */
1246
1247
#ifdef HAVE_LINUX_IOCTL
1248
# include <linux/fs.h>
1249
# include <sys/ioctl.h>
1250
#endif
1251
1252
ssize_t rep_copy_reflink(int src_fd,
1253
       off_t src_off,
1254
       int dst_fd,
1255
       off_t dst_off,
1256
       off_t to_copy)
1257
0
{
1258
0
#ifdef HAVE_LINUX_IOCTL
1259
0
  struct file_clone_range cr;
1260
1261
0
  cr = (struct file_clone_range) {
1262
0
    .src_fd = src_fd,
1263
0
    .src_offset = (uint64_t)src_off,
1264
0
    .dest_offset = (uint64_t)dst_off,
1265
0
    .src_length = (uint64_t)to_copy,
1266
0
  };
1267
1268
0
  return ioctl(dst_fd, FICLONERANGE, &cr);
1269
#else
1270
  errno = ENOSYS;
1271
  return -1;
1272
#endif
1273
0
}
1274
1275
#ifndef HAVE_OPENAT2
1276
1277
/* fallback known wellknown __NR_openat2 values */
1278
#ifndef __NR_openat2
1279
# if defined(LINUX) && defined(HAVE_SYS_SYSCALL_H)
1280
#  if defined(__i386__)
1281
#   define __NR_openat2 437
1282
#  elif defined(__x86_64__) && defined(__LP64__)
1283
0
#   define __NR_openat2 437 /* 437 0x1B5 */
1284
#  elif defined(__x86_64__) && defined(__ILP32__)
1285
#   define __NR_openat2 1073742261 /* 1073742261 0x400001B5 */
1286
#  elif defined(__aarch64__)
1287
#   define __NR_openat2 437
1288
#  elif defined(__arm__)
1289
#   define __NR_openat2 437
1290
#  elif defined(__sparc__)
1291
#   define __NR_openat2 437
1292
#  endif
1293
# endif /* defined(LINUX) && defined(HAVE_SYS_SYSCALL_H) */
1294
#endif /* !__NR_openat2 */
1295
1296
#ifdef DISABLE_OPATH
1297
/*
1298
 * systems without O_PATH also don't have openat2,
1299
 * so make sure we at a realistic combination.
1300
 */
1301
#undef __NR_openat2
1302
#endif /* DISABLE_OPATH */
1303
1304
long rep_openat2(int dirfd, const char *pathname,
1305
     struct open_how *how, size_t size)
1306
0
{
1307
0
#ifdef __NR_openat2
1308
#if _FILE_OFFSET_BITS == 64 && SIZE_MAX == 0xffffffffUL && defined(O_LARGEFILE)
1309
  struct open_how __how;
1310
1311
#if defined(O_PATH) && ! defined(DISABLE_OPATH)
1312
  if ((how->flags & O_PATH) == 0)
1313
#endif
1314
  {
1315
    if (sizeof(__how) == size) {
1316
      __how = *how;
1317
1318
      __how.flags |= O_LARGEFILE;
1319
      how = &__how;
1320
    }
1321
  }
1322
#endif
1323
1324
0
  return syscall(__NR_openat2,
1325
0
           dirfd,
1326
0
           pathname,
1327
0
           how,
1328
0
           size);
1329
#else
1330
  errno = ENOSYS;
1331
  return -1;
1332
#endif
1333
0
}
1334
#endif /* !HAVE_OPENAT2 */
1335
1336
#ifndef HAVE_RENAMEAT2
1337
1338
/* fallback to wellknown __NR_renameat2 values */
1339
#ifndef __NR_renameat2
1340
# if defined(LINUX) && defined(HAVE_SYS_SYSCALL_H)
1341
#  if defined(__i386__)
1342
#   define __NR_renameat2 353
1343
#  elif defined(__x86_64__) && defined(__LP64__)
1344
#   define __NR_renameat2 316 /* 316 0x13C */
1345
#  elif defined(__x86_64__) && defined(__ILP32__)
1346
#   define __NR_renameat2 1073742140 /* 1073742140 0x4000013C */
1347
#  elif defined(__aarch64__)
1348
#   define __NR_renameat2 276
1349
#  elif defined(__arm__)
1350
#   define __NR_renameat2 382
1351
#  elif defined(__sparc__)
1352
#   define __NR_renameat2 345
1353
#  endif
1354
# endif /* defined(LINUX) && defined(HAVE_SYS_SYSCALL_H) */
1355
#endif /* !__NR_renameat2 */
1356
1357
#ifdef DISABLE_OPATH
1358
/*
1359
 * systems without O_PATH also don't have renameat2,
1360
 * so make sure we at a realistic combination.
1361
 */
1362
#undef __NR_renameat2
1363
#endif /* DISABLE_OPATH */
1364
1365
int rep_renameat2(int __oldfd, const char *__old, int __newfd,
1366
      const char *__new, unsigned int __flags)
1367
{
1368
  if (__flags != 0) {
1369
#ifdef __NR_renameat2
1370
    int ret;
1371
1372
    ret = syscall(__NR_renameat2,
1373
            __oldfd,
1374
            __old,
1375
            __newfd,
1376
            __new,
1377
            __flags);
1378
    if (ret != -1 || errno != ENOSYS) {
1379
      /*
1380
       * if it's ENOSYS, we fallback
1381
       * to EINVAL below, otherwise
1382
       * we return what the kernel
1383
       * did.
1384
       */
1385
      return ret;
1386
    }
1387
#endif
1388
    errno = EINVAL;
1389
    return -1;
1390
  }
1391
1392
  return renameat(__oldfd, __old, __newfd, __new);
1393
}
1394
#endif /* ! HAVE_RENAMEAT2 */
1395
1396
const char hexchars_lower[] = "0123456789abcdef";
1397
const char hexchars_upper[] = "0123456789ABCDEF";