root/lib/replace/replace.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. replace_dummy
  2. rep_ftruncate
  3. rep_strlcpy
  4. rep_strlcat
  5. rep_mktime
  6. rep_initgroups
  7. nap
  8. rep_memmove
  9. rep_strdup
  10. rep_setlinebuf
  11. rep_vsyslog
  12. rep_strnlen
  13. rep_strndup
  14. rep_waitpid
  15. rep_seteuid
  16. rep_setegid
  17. rep_chroot
  18. rep_mkstemp
  19. rep_mkdtemp
  20. rep_pread
  21. rep_pwrite
  22. rep_strcasestr
  23. rep_strtok_r
  24. rep_strtoll
  25. rep_strtoull
  26. rep_setenv
  27. rep_unsetenv
  28. rep_utime
  29. rep_utimes
  30. rep_dup2
  31. rep_chown
  32. rep_link
  33. rep_readlink
  34. rep_symlink
  35. rep_lchown
  36. rep_realpath

   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 
   7      ** NOTE! The following LGPL license applies to the replace
   8      ** library. This does NOT imply that all of Samba is released
   9      ** under the LGPL
  10    
  11    This library is free software; you can redistribute it and/or
  12    modify it under the terms of the GNU Lesser General Public
  13    License as published by the Free Software Foundation; either
  14    version 3 of the License, or (at your option) any later version.
  15 
  16    This library is distributed in the hope that it will be useful,
  17    but WITHOUT ANY WARRANTY; without even the implied warranty of
  18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  19    Lesser General Public License for more details.
  20 
  21    You should have received a copy of the GNU Lesser General Public
  22    License along with this library; if not, see <http://www.gnu.org/licenses/>.
  23 */
  24 
  25 #include "replace.h"
  26 
  27 #include "system/filesys.h"
  28 #include "system/time.h"
  29 #include "system/passwd.h"
  30 #include "system/syslog.h"
  31 #include "system/locale.h"
  32 #include "system/wait.h"
  33 
  34 void replace_dummy(void);
  35 void replace_dummy(void) {}
     /* [<][>][^][v][top][bottom][index][help] */
  36 
  37 #ifndef HAVE_FTRUNCATE
  38  /*******************************************************************
  39 ftruncate for operating systems that don't have it
  40 ********************************************************************/
  41 int rep_ftruncate(int f, off_t l)
     /* [<][>][^][v][top][bottom][index][help] */
  42 {
  43 #ifdef HAVE_CHSIZE
  44       return chsize(f,l);
  45 #elif defined(F_FREESP)
  46       struct  flock   fl;
  47 
  48       fl.l_whence = 0;
  49       fl.l_len = 0;
  50       fl.l_start = l;
  51       fl.l_type = F_WRLCK;
  52       return fcntl(f, F_FREESP, &fl);
  53 #else
  54 #error "you must have a ftruncate function"
  55 #endif
  56 }
  57 #endif /* HAVE_FTRUNCATE */
  58 
  59 
  60 #ifndef HAVE_STRLCPY
  61 /* like strncpy but does not 0 fill the buffer and always null 
  62    terminates. bufsize is the size of the destination buffer */
  63 size_t rep_strlcpy(char *d, const char *s, size_t bufsize)
     /* [<][>][^][v][top][bottom][index][help] */
  64 {
  65         size_t len = strlen(s);
  66         size_t ret = len;
  67         if (bufsize <= 0) return 0;
  68         if (len >= bufsize) len = bufsize-1;
  69         memcpy(d, s, len);
  70         d[len] = 0;
  71         return ret;
  72 }
  73 #endif
  74 
  75 #ifndef HAVE_STRLCAT
  76 /* like strncat but does not 0 fill the buffer and always null 
  77    terminates. bufsize is the length of the buffer, which should
  78    be one more than the maximum resulting string length */
  79 size_t rep_strlcat(char *d, const char *s, size_t bufsize)
     /* [<][>][^][v][top][bottom][index][help] */
  80 {
  81         size_t len1 = strlen(d);
  82         size_t len2 = strlen(s);
  83         size_t ret = len1 + len2;
  84 
  85         if (len1+len2 >= bufsize) {
  86                 if (bufsize < (len1+1)) {
  87                         return ret;
  88                 }
  89                 len2 = bufsize - (len1+1);
  90         }
  91         if (len2 > 0) {
  92                 memcpy(d+len1, s, len2);
  93                 d[len1+len2] = 0;
  94         }
  95         return ret;
  96 }
  97 #endif
  98 
  99 #ifndef HAVE_MKTIME
 100 /*******************************************************************
 101 a mktime() replacement for those who don't have it - contributed by 
 102 C.A. Lademann <cal@zls.com>
 103 Corrections by richard.kettlewell@kewill.com
 104 ********************************************************************/
 105 
 106 #define  MINUTE  60
 107 #define  HOUR    60*MINUTE
 108 #define  DAY             24*HOUR
 109 #define  YEAR    365*DAY
 110 time_t rep_mktime(struct tm *t)
     /* [<][>][^][v][top][bottom][index][help] */
 111 {
 112   struct tm       *u;
 113   time_t  epoch = 0;
 114   int n;
 115   int             mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
 116   y, m, i;
 117 
 118   if(t->tm_year < 70)
 119     return((time_t)-1);
 120 
 121   n = t->tm_year + 1900 - 1;
 122   epoch = (t->tm_year - 70) * YEAR + 
 123     ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
 124 
 125   y = t->tm_year + 1900;
 126   m = 0;
 127 
 128   for(i = 0; i < t->tm_mon; i++) {
 129     epoch += mon [m] * DAY;
 130     if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
 131       epoch += DAY;
 132     
 133     if(++m > 11) {
 134       m = 0;
 135       y++;
 136     }
 137   }
 138 
 139   epoch += (t->tm_mday - 1) * DAY;
 140   epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
 141   
 142   if((u = localtime(&epoch)) != NULL) {
 143     t->tm_sec = u->tm_sec;
 144     t->tm_min = u->tm_min;
 145     t->tm_hour = u->tm_hour;
 146     t->tm_mday = u->tm_mday;
 147     t->tm_mon = u->tm_mon;
 148     t->tm_year = u->tm_year;
 149     t->tm_wday = u->tm_wday;
 150     t->tm_yday = u->tm_yday;
 151     t->tm_isdst = u->tm_isdst;
 152   }
 153 
 154   return(epoch);
 155 }
 156 #endif /* !HAVE_MKTIME */
 157 
 158 
 159 #ifndef HAVE_INITGROUPS
 160 /****************************************************************************
 161  some systems don't have an initgroups call 
 162 ****************************************************************************/
 163 int rep_initgroups(char *name, gid_t id)
     /* [<][>][^][v][top][bottom][index][help] */
 164 {
 165 #ifndef HAVE_SETGROUPS
 166         /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
 167         errno = ENOSYS;
 168         return -1;
 169 #else /* HAVE_SETGROUPS */
 170 
 171 #include <grp.h>
 172 
 173         gid_t *grouplst = NULL;
 174         int max_gr = NGROUPS_MAX;
 175         int ret;
 176         int    i,j;
 177         struct group *g;
 178         char   *gr;
 179         
 180         if((grouplst = malloc(sizeof(gid_t) * max_gr)) == NULL) {
 181                 errno = ENOMEM;
 182                 return -1;
 183         }
 184 
 185         grouplst[0] = id;
 186         i = 1;
 187         while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) {
 188                 if (g->gr_gid == id)
 189                         continue;
 190                 j = 0;
 191                 gr = g->gr_mem[0];
 192                 while (gr && (*gr != (char)NULL)) {
 193                         if (strcmp(name,gr) == 0) {
 194                                 grouplst[i] = g->gr_gid;
 195                                 i++;
 196                                 gr = (char *)NULL;
 197                                 break;
 198                         }
 199                         gr = g->gr_mem[++j];
 200                 }
 201         }
 202         endgrent();
 203         ret = setgroups(i, grouplst);
 204         free(grouplst);
 205         return ret;
 206 #endif /* HAVE_SETGROUPS */
 207 }
 208 #endif /* HAVE_INITGROUPS */
 209 
 210 
 211 #if (defined(SecureWare) && defined(SCO))
 212 /* This is needed due to needing the nap() function but we don't want
 213    to include the Xenix libraries since that will break other things...
 214    BTW: system call # 0x0c28 is the same as calling nap() */
 215 long nap(long milliseconds) {
     /* [<][>][^][v][top][bottom][index][help] */
 216          return syscall(0x0c28, milliseconds);
 217  }
 218 #endif
 219 
 220 
 221 #ifndef HAVE_MEMMOVE
 222 /*******************************************************************
 223 safely copies memory, ensuring no overlap problems.
 224 this is only used if the machine does not have its own memmove().
 225 this is not the fastest algorithm in town, but it will do for our
 226 needs.
 227 ********************************************************************/
 228 void *rep_memmove(void *dest,const void *src,int size)
     /* [<][>][^][v][top][bottom][index][help] */
 229 {
 230         unsigned long d,s;
 231         int i;
 232         if (dest==src || !size) return(dest);
 233 
 234         d = (unsigned long)dest;
 235         s = (unsigned long)src;
 236 
 237         if ((d >= (s+size)) || (s >= (d+size))) {
 238                 /* no overlap */
 239                 memcpy(dest,src,size);
 240                 return(dest);
 241         }
 242 
 243         if (d < s) {
 244                 /* we can forward copy */
 245                 if (s-d >= sizeof(int) && 
 246                     !(s%sizeof(int)) && 
 247                     !(d%sizeof(int)) && 
 248                     !(size%sizeof(int))) {
 249                         /* do it all as words */
 250                         int *idest = (int *)dest;
 251                         int *isrc = (int *)src;
 252                         size /= sizeof(int);
 253                         for (i=0;i<size;i++) idest[i] = isrc[i];
 254                 } else {
 255                         /* simplest */
 256                         char *cdest = (char *)dest;
 257                         char *csrc = (char *)src;
 258                         for (i=0;i<size;i++) cdest[i] = csrc[i];
 259                 }
 260         } else {
 261                 /* must backward copy */
 262                 if (d-s >= sizeof(int) && 
 263                     !(s%sizeof(int)) && 
 264                     !(d%sizeof(int)) && 
 265                     !(size%sizeof(int))) {
 266                         /* do it all as words */
 267                         int *idest = (int *)dest;
 268                         int *isrc = (int *)src;
 269                         size /= sizeof(int);
 270                         for (i=size-1;i>=0;i--) idest[i] = isrc[i];
 271                 } else {
 272                         /* simplest */
 273                         char *cdest = (char *)dest;
 274                         char *csrc = (char *)src;
 275                         for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
 276                 }      
 277         }
 278         return(dest);
 279 }
 280 #endif /* HAVE_MEMMOVE */
 281 
 282 #ifndef HAVE_STRDUP
 283 /****************************************************************************
 284 duplicate a string
 285 ****************************************************************************/
 286 char *rep_strdup(const char *s)
     /* [<][>][^][v][top][bottom][index][help] */
 287 {
 288         size_t len;
 289         char *ret;
 290 
 291         if (!s) return(NULL);
 292 
 293         len = strlen(s)+1;
 294         ret = (char *)malloc(len);
 295         if (!ret) return(NULL);
 296         memcpy(ret,s,len);
 297         return(ret);
 298 }
 299 #endif /* HAVE_STRDUP */
 300 
 301 #ifndef HAVE_SETLINEBUF
 302 void rep_setlinebuf(FILE *stream)
     /* [<][>][^][v][top][bottom][index][help] */
 303 {
 304         setvbuf(stream, (char *)NULL, _IOLBF, 0);
 305 }
 306 #endif /* HAVE_SETLINEBUF */
 307 
 308 #ifndef HAVE_VSYSLOG
 309 #ifdef HAVE_SYSLOG
 310 void rep_vsyslog (int facility_priority, const char *format, va_list arglist)
     /* [<][>][^][v][top][bottom][index][help] */
 311 {
 312         char *msg = NULL;
 313         vasprintf(&msg, format, arglist);
 314         if (!msg)
 315                 return;
 316         syslog(facility_priority, "%s", msg);
 317         free(msg);
 318 }
 319 #endif /* HAVE_SYSLOG */
 320 #endif /* HAVE_VSYSLOG */
 321 
 322 #ifndef HAVE_STRNLEN
 323 /**
 324  Some platforms don't have strnlen
 325 **/
 326  size_t rep_strnlen(const char *s, size_t max)
     /* [<][>][^][v][top][bottom][index][help] */
 327 {
 328         size_t len;
 329   
 330         for (len = 0; len < max; len++) {
 331                 if (s[len] == '\0') {
 332                         break;
 333                 }
 334         }
 335         return len;  
 336 }
 337 #endif
 338   
 339 #ifndef HAVE_STRNDUP
 340 /**
 341  Some platforms don't have strndup.
 342 **/
 343 char *rep_strndup(const char *s, size_t n)
     /* [<][>][^][v][top][bottom][index][help] */
 344 {
 345         char *ret;
 346         
 347         n = strnlen(s, n);
 348         ret = malloc(n+1);
 349         if (!ret)
 350                 return NULL;
 351         memcpy(ret, s, n);
 352         ret[n] = 0;
 353 
 354         return ret;
 355 }
 356 #endif
 357 
 358 #ifndef HAVE_WAITPID
 359 int rep_waitpid(pid_t pid,int *status,int options)
     /* [<][>][^][v][top][bottom][index][help] */
 360 {
 361   return wait4(pid, status, options, NULL);
 362 }
 363 #endif
 364 
 365 #ifndef HAVE_SETEUID
 366 int rep_seteuid(uid_t euid)
     /* [<][>][^][v][top][bottom][index][help] */
 367 {
 368 #ifdef HAVE_SETRESUID
 369         return setresuid(-1, euid, -1);
 370 #else
 371 #  error "You need a seteuid function"
 372 #endif
 373 }
 374 #endif
 375 
 376 #ifndef HAVE_SETEGID
 377 int rep_setegid(gid_t egid)
     /* [<][>][^][v][top][bottom][index][help] */
 378 {
 379 #ifdef HAVE_SETRESGID
 380         return setresgid(-1, egid, -1);
 381 #else
 382 #  error "You need a setegid function"
 383 #endif
 384 }
 385 #endif
 386 
 387 /*******************************************************************
 388 os/2 also doesn't have chroot
 389 ********************************************************************/
 390 #ifndef HAVE_CHROOT
 391 int rep_chroot(const char *dname)
     /* [<][>][^][v][top][bottom][index][help] */
 392 {
 393         errno = ENOSYS;
 394         return -1;
 395 }
 396 #endif
 397 
 398 /*****************************************************************
 399  Possibly replace mkstemp if it is broken.
 400 *****************************************************************/  
 401 
 402 #ifndef HAVE_SECURE_MKSTEMP
 403 int rep_mkstemp(char *template)
     /* [<][>][^][v][top][bottom][index][help] */
 404 {
 405         /* have a reasonable go at emulating it. Hope that
 406            the system mktemp() isn't completly hopeless */
 407         char *p = mktemp(template);
 408         if (!p)
 409                 return -1;
 410         return open(p, O_CREAT|O_EXCL|O_RDWR, 0600);
 411 }
 412 #endif
 413 
 414 #ifndef HAVE_MKDTEMP
 415 char *rep_mkdtemp(char *template)
     /* [<][>][^][v][top][bottom][index][help] */
 416 {
 417         char *dname;
 418         
 419         if ((dname = mktemp(template))) {
 420                 if (mkdir(dname, 0700) >= 0) {
 421                         return dname;
 422                 }
 423         }
 424 
 425         return NULL;
 426 }
 427 #endif
 428 
 429 /*****************************************************************
 430  Watch out: this is not thread safe.
 431 *****************************************************************/
 432 
 433 #ifndef HAVE_PREAD
 434 ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset)
     /* [<][>][^][v][top][bottom][index][help] */
 435 {
 436         if (lseek(__fd, __offset, SEEK_SET) != __offset) {
 437                 return -1;
 438         }
 439         return read(__fd, __buf, __nbytes);
 440 }
 441 #endif
 442 
 443 /*****************************************************************
 444  Watch out: this is not thread safe.
 445 *****************************************************************/
 446 
 447 #ifndef HAVE_PWRITE
 448 ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset)
     /* [<][>][^][v][top][bottom][index][help] */
 449 {
 450         if (lseek(__fd, __offset, SEEK_SET) != __offset) {
 451                 return -1;
 452         }
 453         return write(__fd, __buf, __nbytes);
 454 }
 455 #endif
 456 
 457 #ifndef HAVE_STRCASESTR
 458 char *rep_strcasestr(const char *haystack, const char *needle)
     /* [<][>][^][v][top][bottom][index][help] */
 459 {
 460         const char *s;
 461         size_t nlen = strlen(needle);
 462         for (s=haystack;*s;s++) {
 463                 if (toupper(*needle) == toupper(*s) &&
 464                     strncasecmp(s, needle, nlen) == 0) {
 465                         return (char *)((uintptr_t)s);
 466                 }
 467         }
 468         return NULL;
 469 }
 470 #endif
 471 
 472 #ifndef HAVE_STRTOK_R
 473 /* based on GLIBC version, copyright Free Software Foundation */
 474 char *rep_strtok_r(char *s, const char *delim, char **save_ptr)
     /* [<][>][^][v][top][bottom][index][help] */
 475 {
 476         char *token;
 477 
 478         if (s == NULL) s = *save_ptr;
 479 
 480         s += strspn(s, delim);
 481         if (*s == '\0') {
 482                 *save_ptr = s;
 483                 return NULL;
 484         }
 485 
 486         token = s;
 487         s = strpbrk(token, delim);
 488         if (s == NULL) {
 489                 *save_ptr = token + strlen(token);
 490         } else {
 491                 *s = '\0';
 492                 *save_ptr = s + 1;
 493         }
 494 
 495         return token;
 496 }
 497 #endif
 498 
 499 #ifndef HAVE_STRTOLL
 500 long long int rep_strtoll(const char *str, char **endptr, int base)
     /* [<][>][^][v][top][bottom][index][help] */
 501 {
 502 #ifdef HAVE_STRTOQ
 503         return strtoq(str, endptr, base);
 504 #elif defined(HAVE___STRTOLL) 
 505         return __strtoll(str, endptr, base);
 506 #elif SIZEOF_LONG == SIZEOF_LONG_LONG
 507         return (long long int) strtol(str, endptr, base);
 508 #else
 509 # error "You need a strtoll function"
 510 #endif
 511 }
 512 #endif
 513 
 514 
 515 #ifndef HAVE_STRTOULL
 516 unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
     /* [<][>][^][v][top][bottom][index][help] */
 517 {
 518 #ifdef HAVE_STRTOUQ
 519         return strtouq(str, endptr, base);
 520 #elif defined(HAVE___STRTOULL) 
 521         return __strtoull(str, endptr, base);
 522 #elif SIZEOF_LONG == SIZEOF_LONG_LONG
 523         return (unsigned long long int) strtoul(str, endptr, base);
 524 #else
 525 # error "You need a strtoull function"
 526 #endif
 527 }
 528 #endif
 529 
 530 #ifndef HAVE_SETENV
 531 int rep_setenv(const char *name, const char *value, int overwrite) 
     /* [<][>][^][v][top][bottom][index][help] */
 532 {
 533         char *p;
 534         size_t l1, l2;
 535         int ret;
 536 
 537         if (!overwrite && getenv(name)) {
 538                 return 0;
 539         }
 540 
 541         l1 = strlen(name);
 542         l2 = strlen(value);
 543 
 544         p = malloc(l1+l2+2);
 545         if (p == NULL) {
 546                 return -1;
 547         }
 548         memcpy(p, name, l1);
 549         p[l1] = '=';
 550         memcpy(p+l1+1, value, l2);
 551         p[l1+l2+1] = 0;
 552 
 553         ret = putenv(p);
 554         if (ret != 0) {
 555                 free(p);
 556         }
 557 
 558         return ret;
 559 }
 560 #endif
 561 
 562 #ifndef HAVE_UNSETENV
 563 int rep_unsetenv(const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
 564 {
 565         extern char **environ;
 566         size_t len = strlen(name);
 567         size_t i, count;
 568 
 569         if (environ == NULL || getenv(name) == NULL) {
 570                 return 0;
 571         }
 572 
 573         for (i=0;environ[i];i++) /* noop */ ;
 574 
 575         count=i;
 576         
 577         for (i=0;i<count;) {
 578                 if (strncmp(environ[i], name, len) == 0 && environ[i][len] == '=') {
 579                         /* note: we do _not_ free the old variable here. It is unsafe to 
 580                            do so, as the pointer may not have come from malloc */
 581                         memmove(&environ[i], &environ[i+1], (count-i)*sizeof(char *));
 582                         count--;
 583                 } else {
 584                         i++;
 585                 }
 586         }
 587 
 588         return 0;
 589 }
 590 #endif
 591 
 592 #ifndef HAVE_UTIME
 593 int rep_utime(const char *filename, const struct utimbuf *buf)
     /* [<][>][^][v][top][bottom][index][help] */
 594 {
 595         errno = ENOSYS;
 596         return -1;
 597 }
 598 #endif
 599 
 600 #ifndef HAVE_UTIMES
 601 int rep_utimes(const char *filename, const struct timeval tv[2])
     /* [<][>][^][v][top][bottom][index][help] */
 602 {
 603         struct utimbuf u;
 604 
 605         u.actime = tv[0].tv_sec;
 606         if (tv[0].tv_usec > 500000) {
 607                 u.actime += 1;
 608         }
 609 
 610         u.modtime = tv[1].tv_sec;
 611         if (tv[1].tv_usec > 500000) {
 612                 u.modtime += 1;
 613         }
 614 
 615         return utime(filename, &u);
 616 }
 617 #endif
 618 
 619 #ifndef HAVE_DUP2
 620 int rep_dup2(int oldfd, int newfd) 
     /* [<][>][^][v][top][bottom][index][help] */
 621 {
 622         errno = ENOSYS;
 623         return -1;
 624 }
 625 #endif
 626 
 627 #ifndef HAVE_CHOWN
 628 /**
 629 chown isn't used much but OS/2 doesn't have it
 630 **/
 631 int rep_chown(const char *fname, uid_t uid, gid_t gid)
     /* [<][>][^][v][top][bottom][index][help] */
 632 {
 633         errno = ENOSYS;
 634         return -1;
 635 }
 636 #endif
 637 
 638 #ifndef HAVE_LINK
 639 int rep_link(const char *oldpath, const char *newpath)
     /* [<][>][^][v][top][bottom][index][help] */
 640 {
 641         errno = ENOSYS;
 642         return -1;
 643 }
 644 #endif
 645 
 646 #ifndef HAVE_READLINK
 647 int rep_readlink(const char *path, char *buf, size_t bufsiz)
     /* [<][>][^][v][top][bottom][index][help] */
 648 {
 649         errno = ENOSYS;
 650         return -1;
 651 }
 652 #endif
 653 
 654 #ifndef HAVE_SYMLINK
 655 int rep_symlink(const char *oldpath, const char *newpath)
     /* [<][>][^][v][top][bottom][index][help] */
 656 {
 657         errno = ENOSYS;
 658         return -1;
 659 }
 660 #endif
 661 
 662 #ifndef HAVE_LCHOWN
 663 int rep_lchown(const char *fname,uid_t uid,gid_t gid)
     /* [<][>][^][v][top][bottom][index][help] */
 664 {
 665         errno = ENOSYS;
 666         return -1;
 667 }
 668 #endif
 669 
 670 #ifndef HAVE_REALPATH
 671 char *rep_realpath(const char *path, char *resolved_path)
     /* [<][>][^][v][top][bottom][index][help] */
 672 {
 673         /* As realpath is not a system call we can't return ENOSYS. */
 674         errno = EINVAL;
 675         return NULL;
 676 }
 677 #endif

/* [<][>][^][v][top][bottom][index][help] */