dynconfig: added SBINDIR and BINDIR as updated dynconfig variables
[nivanova/samba-autobuild/.git] / lib / replace / replace.c
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/passwd.h"
31 #include "system/syslog.h"
32 #include "system/locale.h"
33 #include "system/wait.h"
34
35 #ifdef _WIN32
36 #define mkdir(d,m) _mkdir(d)
37 #endif
38
39 void replace_dummy(void);
40 void replace_dummy(void) {}
41
42 #ifndef HAVE_FTRUNCATE
43  /*******************************************************************
44 ftruncate for operating systems that don't have it
45 ********************************************************************/
46 int rep_ftruncate(int f, off_t l)
47 {
48 #ifdef HAVE_CHSIZE
49       return chsize(f,l);
50 #elif defined(F_FREESP)
51       struct  flock   fl;
52
53       fl.l_whence = 0;
54       fl.l_len = 0;
55       fl.l_start = l;
56       fl.l_type = F_WRLCK;
57       return fcntl(f, F_FREESP, &fl);
58 #else
59 #error "you must have a ftruncate function"
60 #endif
61 }
62 #endif /* HAVE_FTRUNCATE */
63
64
65 #ifndef HAVE_STRLCPY
66 /* like strncpy but does not 0 fill the buffer and always null 
67    terminates. bufsize is the size of the destination buffer */
68 size_t rep_strlcpy(char *d, const char *s, size_t bufsize)
69 {
70         size_t len = strlen(s);
71         size_t ret = len;
72         if (bufsize <= 0) return 0;
73         if (len >= bufsize) len = bufsize-1;
74         memcpy(d, s, len);
75         d[len] = 0;
76         return ret;
77 }
78 #endif
79
80 #ifndef HAVE_STRLCAT
81 /* like strncat but does not 0 fill the buffer and always null 
82    terminates. bufsize is the length of the buffer, which should
83    be one more than the maximum resulting string length */
84 size_t rep_strlcat(char *d, const char *s, size_t bufsize)
85 {
86         size_t len1 = strlen(d);
87         size_t len2 = strlen(s);
88         size_t ret = len1 + len2;
89
90         if (len1+len2 >= bufsize) {
91                 if (bufsize < (len1+1)) {
92                         return ret;
93                 }
94                 len2 = bufsize - (len1+1);
95         }
96         if (len2 > 0) {
97                 memcpy(d+len1, s, len2);
98                 d[len1+len2] = 0;
99         }
100         return ret;
101 }
102 #endif
103
104 #ifndef HAVE_MKTIME
105 /*******************************************************************
106 a mktime() replacement for those who don't have it - contributed by 
107 C.A. Lademann <cal@zls.com>
108 Corrections by richard.kettlewell@kewill.com
109 ********************************************************************/
110
111 #define  MINUTE  60
112 #define  HOUR    60*MINUTE
113 #define  DAY             24*HOUR
114 #define  YEAR    365*DAY
115 time_t rep_mktime(struct tm *t)
116 {
117   struct tm       *u;
118   time_t  epoch = 0;
119   int n;
120   int             mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
121   y, m, i;
122
123   if(t->tm_year < 70)
124     return((time_t)-1);
125
126   n = t->tm_year + 1900 - 1;
127   epoch = (t->tm_year - 70) * YEAR + 
128     ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
129
130   y = t->tm_year + 1900;
131   m = 0;
132
133   for(i = 0; i < t->tm_mon; i++) {
134     epoch += mon [m] * DAY;
135     if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
136       epoch += DAY;
137     
138     if(++m > 11) {
139       m = 0;
140       y++;
141     }
142   }
143
144   epoch += (t->tm_mday - 1) * DAY;
145   epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
146   
147   if((u = localtime(&epoch)) != NULL) {
148     t->tm_sec = u->tm_sec;
149     t->tm_min = u->tm_min;
150     t->tm_hour = u->tm_hour;
151     t->tm_mday = u->tm_mday;
152     t->tm_mon = u->tm_mon;
153     t->tm_year = u->tm_year;
154     t->tm_wday = u->tm_wday;
155     t->tm_yday = u->tm_yday;
156     t->tm_isdst = u->tm_isdst;
157   }
158
159   return(epoch);
160 }
161 #endif /* !HAVE_MKTIME */
162
163
164 #ifndef HAVE_INITGROUPS
165 /****************************************************************************
166  some systems don't have an initgroups call 
167 ****************************************************************************/
168 int rep_initgroups(char *name, gid_t id)
169 {
170 #ifndef HAVE_SETGROUPS
171         /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
172         errno = ENOSYS;
173         return -1;
174 #else /* HAVE_SETGROUPS */
175
176 #include <grp.h>
177
178         gid_t *grouplst = NULL;
179         int max_gr = NGROUPS_MAX;
180         int ret;
181         int    i,j;
182         struct group *g;
183         char   *gr;
184         
185         if((grouplst = malloc(sizeof(gid_t) * max_gr)) == NULL) {
186                 errno = ENOMEM;
187                 return -1;
188         }
189
190         grouplst[0] = id;
191         i = 1;
192         while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) {
193                 if (g->gr_gid == id)
194                         continue;
195                 j = 0;
196                 gr = g->gr_mem[0];
197                 while (gr && (*gr != (char)NULL)) {
198                         if (strcmp(name,gr) == 0) {
199                                 grouplst[i] = g->gr_gid;
200                                 i++;
201                                 gr = (char *)NULL;
202                                 break;
203                         }
204                         gr = g->gr_mem[++j];
205                 }
206         }
207         endgrent();
208         ret = setgroups(i, grouplst);
209         free(grouplst);
210         return ret;
211 #endif /* HAVE_SETGROUPS */
212 }
213 #endif /* HAVE_INITGROUPS */
214
215
216 #if (defined(SecureWare) && defined(SCO))
217 /* This is needed due to needing the nap() function but we don't want
218    to include the Xenix libraries since that will break other things...
219    BTW: system call # 0x0c28 is the same as calling nap() */
220 long nap(long milliseconds) {
221          return syscall(0x0c28, milliseconds);
222  }
223 #endif
224
225
226 #ifndef HAVE_MEMMOVE
227 /*******************************************************************
228 safely copies memory, ensuring no overlap problems.
229 this is only used if the machine does not have its own memmove().
230 this is not the fastest algorithm in town, but it will do for our
231 needs.
232 ********************************************************************/
233 void *rep_memmove(void *dest,const void *src,int size)
234 {
235         unsigned long d,s;
236         int i;
237         if (dest==src || !size) return(dest);
238
239         d = (unsigned long)dest;
240         s = (unsigned long)src;
241
242         if ((d >= (s+size)) || (s >= (d+size))) {
243                 /* no overlap */
244                 memcpy(dest,src,size);
245                 return(dest);
246         }
247
248         if (d < s) {
249                 /* we can forward copy */
250                 if (s-d >= sizeof(int) && 
251                     !(s%sizeof(int)) && 
252                     !(d%sizeof(int)) && 
253                     !(size%sizeof(int))) {
254                         /* do it all as words */
255                         int *idest = (int *)dest;
256                         int *isrc = (int *)src;
257                         size /= sizeof(int);
258                         for (i=0;i<size;i++) idest[i] = isrc[i];
259                 } else {
260                         /* simplest */
261                         char *cdest = (char *)dest;
262                         char *csrc = (char *)src;
263                         for (i=0;i<size;i++) cdest[i] = csrc[i];
264                 }
265         } else {
266                 /* must backward copy */
267                 if (d-s >= sizeof(int) && 
268                     !(s%sizeof(int)) && 
269                     !(d%sizeof(int)) && 
270                     !(size%sizeof(int))) {
271                         /* do it all as words */
272                         int *idest = (int *)dest;
273                         int *isrc = (int *)src;
274                         size /= sizeof(int);
275                         for (i=size-1;i>=0;i--) idest[i] = isrc[i];
276                 } else {
277                         /* simplest */
278                         char *cdest = (char *)dest;
279                         char *csrc = (char *)src;
280                         for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
281                 }      
282         }
283         return(dest);
284 }
285 #endif /* HAVE_MEMMOVE */
286
287 #ifndef HAVE_STRDUP
288 /****************************************************************************
289 duplicate a string
290 ****************************************************************************/
291 char *rep_strdup(const char *s)
292 {
293         size_t len;
294         char *ret;
295
296         if (!s) return(NULL);
297
298         len = strlen(s)+1;
299         ret = (char *)malloc(len);
300         if (!ret) return(NULL);
301         memcpy(ret,s,len);
302         return(ret);
303 }
304 #endif /* HAVE_STRDUP */
305
306 #ifndef HAVE_SETLINEBUF
307 void rep_setlinebuf(FILE *stream)
308 {
309         setvbuf(stream, (char *)NULL, _IOLBF, 0);
310 }
311 #endif /* HAVE_SETLINEBUF */
312
313 #ifndef HAVE_VSYSLOG
314 #ifdef HAVE_SYSLOG
315 void rep_vsyslog (int facility_priority, const char *format, va_list arglist)
316 {
317         char *msg = NULL;
318         vasprintf(&msg, format, arglist);
319         if (!msg)
320                 return;
321         syslog(facility_priority, "%s", msg);
322         free(msg);
323 }
324 #endif /* HAVE_SYSLOG */
325 #endif /* HAVE_VSYSLOG */
326
327 #ifndef HAVE_STRNLEN
328 /**
329  Some platforms don't have strnlen
330 **/
331  size_t rep_strnlen(const char *s, size_t max)
332 {
333         size_t len;
334   
335         for (len = 0; len < max; len++) {
336                 if (s[len] == '\0') {
337                         break;
338                 }
339         }
340         return len;  
341 }
342 #endif
343   
344 #ifndef HAVE_STRNDUP
345 /**
346  Some platforms don't have strndup.
347 **/
348 char *rep_strndup(const char *s, size_t n)
349 {
350         char *ret;
351         
352         n = strnlen(s, n);
353         ret = malloc(n+1);
354         if (!ret)
355                 return NULL;
356         memcpy(ret, s, n);
357         ret[n] = 0;
358
359         return ret;
360 }
361 #endif
362
363 #if !defined(HAVE_WAITPID) && defined(HAVE_WAIT4)
364 int rep_waitpid(pid_t pid,int *status,int options)
365 {
366   return wait4(pid, status, options, NULL);
367 }
368 #endif
369
370 #ifndef HAVE_SETEUID
371 int rep_seteuid(uid_t euid)
372 {
373 #ifdef HAVE_SETRESUID
374         return setresuid(-1, euid, -1);
375 #else
376         errno = ENOSYS;
377         return -1;
378 #endif
379 }
380 #endif
381
382 #ifndef HAVE_SETEGID
383 int rep_setegid(gid_t egid)
384 {
385 #ifdef HAVE_SETRESGID
386         return setresgid(-1, egid, -1);
387 #else
388         errno = ENOSYS;
389         return -1;
390 #endif
391 }
392 #endif
393
394 /*******************************************************************
395 os/2 also doesn't have chroot
396 ********************************************************************/
397 #ifndef HAVE_CHROOT
398 int rep_chroot(const char *dname)
399 {
400         errno = ENOSYS;
401         return -1;
402 }
403 #endif
404
405 /*****************************************************************
406  Possibly replace mkstemp if it is broken.
407 *****************************************************************/  
408
409 #ifndef HAVE_SECURE_MKSTEMP
410 int rep_mkstemp(char *template)
411 {
412         /* have a reasonable go at emulating it. Hope that
413            the system mktemp() isn't completely hopeless */
414         char *p = mktemp(template);
415         if (!p)
416                 return -1;
417         return open(p, O_CREAT|O_EXCL|O_RDWR, 0600);
418 }
419 #endif
420
421 #ifndef HAVE_MKDTEMP
422 char *rep_mkdtemp(char *template)
423 {
424         char *dname;
425         
426         if ((dname = mktemp(template))) {
427                 if (mkdir(dname, 0700) >= 0) {
428                         return dname;
429                 }
430         }
431
432         return NULL;
433 }
434 #endif
435
436 /*****************************************************************
437  Watch out: this is not thread safe.
438 *****************************************************************/
439
440 #ifndef HAVE_PREAD
441 ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset)
442 {
443         if (lseek(__fd, __offset, SEEK_SET) != __offset) {
444                 return -1;
445         }
446         return read(__fd, __buf, __nbytes);
447 }
448 #endif
449
450 /*****************************************************************
451  Watch out: this is not thread safe.
452 *****************************************************************/
453
454 #ifndef HAVE_PWRITE
455 ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset)
456 {
457         if (lseek(__fd, __offset, SEEK_SET) != __offset) {
458                 return -1;
459         }
460         return write(__fd, __buf, __nbytes);
461 }
462 #endif
463
464 #ifndef HAVE_STRCASESTR
465 char *rep_strcasestr(const char *haystack, const char *needle)
466 {
467         const char *s;
468         size_t nlen = strlen(needle);
469         for (s=haystack;*s;s++) {
470                 if (toupper(*needle) == toupper(*s) &&
471                     strncasecmp(s, needle, nlen) == 0) {
472                         return (char *)((uintptr_t)s);
473                 }
474         }
475         return NULL;
476 }
477 #endif
478
479 #ifndef HAVE_STRTOK_R
480 /* based on GLIBC version, copyright Free Software Foundation */
481 char *rep_strtok_r(char *s, const char *delim, char **save_ptr)
482 {
483         char *token;
484
485         if (s == NULL) s = *save_ptr;
486
487         s += strspn(s, delim);
488         if (*s == '\0') {
489                 *save_ptr = s;
490                 return NULL;
491         }
492
493         token = s;
494         s = strpbrk(token, delim);
495         if (s == NULL) {
496                 *save_ptr = token + strlen(token);
497         } else {
498                 *s = '\0';
499                 *save_ptr = s + 1;
500         }
501
502         return token;
503 }
504 #endif
505
506
507 #ifndef HAVE_STRTOLL
508 long long int rep_strtoll(const char *str, char **endptr, int base)
509 {
510 #ifdef HAVE_STRTOQ
511         return strtoq(str, endptr, base);
512 #elif defined(HAVE___STRTOLL) 
513         return __strtoll(str, endptr, base);
514 #elif SIZEOF_LONG == SIZEOF_LONG_LONG
515         return (long long int) strtol(str, endptr, base);
516 #else
517 # error "You need a strtoll function"
518 #endif
519 }
520 #else
521 #ifdef HAVE_BSD_STRTOLL
522 #ifdef HAVE_STRTOQ
523 long long int rep_strtoll(const char *str, char **endptr, int base)
524 {
525         long long int nb = strtoq(str, endptr, base);
526         /* In linux EINVAL is only returned if base is not ok */
527         if (errno == EINVAL) {
528                 if (base == 0 || (base >1 && base <37)) {
529                         /* Base was ok so it's because we were not
530                          * able to make the convertion.
531                          * Let's reset errno.
532                          */
533                         errno = 0;
534                 }
535         }
536         return nb;
537 }
538 #else
539 #error "You need the strtoq function"
540 #endif /* HAVE_STRTOQ */
541 #endif /* HAVE_BSD_STRTOLL */
542 #endif /* HAVE_STRTOLL */
543
544
545 #ifndef HAVE_STRTOULL
546 unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
547 {
548 #ifdef HAVE_STRTOUQ
549         return strtouq(str, endptr, base);
550 #elif defined(HAVE___STRTOULL) 
551         return __strtoull(str, endptr, base);
552 #elif SIZEOF_LONG == SIZEOF_LONG_LONG
553         return (unsigned long long int) strtoul(str, endptr, base);
554 #else
555 # error "You need a strtoull function"
556 #endif
557 }
558 #else
559 #ifdef HAVE_BSD_STRTOLL
560 #ifdef HAVE_STRTOUQ
561 unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
562 {
563         unsigned long long int nb = strtouq(str, endptr, base);
564         /* In linux EINVAL is only returned if base is not ok */
565         if (errno == EINVAL) {
566                 if (base == 0 || (base >1 && base <37)) {
567                         /* Base was ok so it's because we were not
568                          * able to make the convertion.
569                          * Let's reset errno.
570                          */
571                         errno = 0;
572                 }
573         }
574         return nb;
575 }
576 #else
577 #error "You need the strtouq function"
578 #endif /* HAVE_STRTOUQ */
579 #endif /* HAVE_BSD_STRTOLL */
580 #endif /* HAVE_STRTOULL */
581
582 #ifndef HAVE_SETENV
583 int rep_setenv(const char *name, const char *value, int overwrite) 
584 {
585         char *p;
586         size_t l1, l2;
587         int ret;
588
589         if (!overwrite && getenv(name)) {
590                 return 0;
591         }
592
593         l1 = strlen(name);
594         l2 = strlen(value);
595
596         p = malloc(l1+l2+2);
597         if (p == NULL) {
598                 return -1;
599         }
600         memcpy(p, name, l1);
601         p[l1] = '=';
602         memcpy(p+l1+1, value, l2);
603         p[l1+l2+1] = 0;
604
605         ret = putenv(p);
606         if (ret != 0) {
607                 free(p);
608         }
609
610         return ret;
611 }
612 #endif
613
614 #ifndef HAVE_UNSETENV
615 int rep_unsetenv(const char *name)
616 {
617         extern char **environ;
618         size_t len = strlen(name);
619         size_t i, count;
620
621         if (environ == NULL || getenv(name) == NULL) {
622                 return 0;
623         }
624
625         for (i=0;environ[i];i++) /* noop */ ;
626
627         count=i;
628         
629         for (i=0;i<count;) {
630                 if (strncmp(environ[i], name, len) == 0 && environ[i][len] == '=') {
631                         /* note: we do _not_ free the old variable here. It is unsafe to 
632                            do so, as the pointer may not have come from malloc */
633                         memmove(&environ[i], &environ[i+1], (count-i)*sizeof(char *));
634                         count--;
635                 } else {
636                         i++;
637                 }
638         }
639
640         return 0;
641 }
642 #endif
643
644 #ifndef HAVE_UTIME
645 int rep_utime(const char *filename, const struct utimbuf *buf)
646 {
647         errno = ENOSYS;
648         return -1;
649 }
650 #endif
651
652 #ifndef HAVE_UTIMES
653 int rep_utimes(const char *filename, const struct timeval tv[2])
654 {
655         struct utimbuf u;
656
657         u.actime = tv[0].tv_sec;
658         if (tv[0].tv_usec > 500000) {
659                 u.actime += 1;
660         }
661
662         u.modtime = tv[1].tv_sec;
663         if (tv[1].tv_usec > 500000) {
664                 u.modtime += 1;
665         }
666
667         return utime(filename, &u);
668 }
669 #endif
670
671 #ifndef HAVE_DUP2
672 int rep_dup2(int oldfd, int newfd) 
673 {
674         errno = ENOSYS;
675         return -1;
676 }
677 #endif
678
679 #ifndef HAVE_CHOWN
680 /**
681 chown isn't used much but OS/2 doesn't have it
682 **/
683 int rep_chown(const char *fname, uid_t uid, gid_t gid)
684 {
685         errno = ENOSYS;
686         return -1;
687 }
688 #endif
689
690 #ifndef HAVE_LINK
691 int rep_link(const char *oldpath, const char *newpath)
692 {
693         errno = ENOSYS;
694         return -1;
695 }
696 #endif
697
698 #ifndef HAVE_READLINK
699 int rep_readlink(const char *path, char *buf, size_t bufsiz)
700 {
701         errno = ENOSYS;
702         return -1;
703 }
704 #endif
705
706 #ifndef HAVE_SYMLINK
707 int rep_symlink(const char *oldpath, const char *newpath)
708 {
709         errno = ENOSYS;
710         return -1;
711 }
712 #endif
713
714 #ifndef HAVE_LCHOWN
715 int rep_lchown(const char *fname,uid_t uid,gid_t gid)
716 {
717         errno = ENOSYS;
718         return -1;
719 }
720 #endif
721
722 #ifndef HAVE_REALPATH
723 char *rep_realpath(const char *path, char *resolved_path)
724 {
725         /* As realpath is not a system call we can't return ENOSYS. */
726         errno = EINVAL;
727         return NULL;
728 }
729 #endif
730
731
732 #ifndef HAVE_MEMMEM
733 void *rep_memmem(const void *haystack, size_t haystacklen,
734                  const void *needle, size_t needlelen)
735 {
736         if (needlelen == 0) {
737                 return discard_const(haystack);
738         }
739         while (haystacklen >= needlelen) {
740                 char *p = (char *)memchr(haystack, *(const char *)needle,
741                                          haystacklen-(needlelen-1));
742                 if (!p) return NULL;
743                 if (memcmp(p, needle, needlelen) == 0) {
744                         return p;
745                 }
746                 haystack = p+1;
747                 haystacklen -= (p - (const char *)haystack) + 1;
748         }
749         return NULL;
750 }
751 #endif
752
753 #ifndef HAVE_VDPRINTF
754 int rep_vdprintf(int fd, const char *format, va_list ap)
755 {
756         char *s = NULL;
757         int ret;
758
759         vasprintf(&s, format, ap);
760         if (s == NULL) {
761                 errno = ENOMEM;
762                 return -1;
763         }
764         ret = write(fd, s, strlen(s));
765         free(s);
766         return ret;
767 }
768 #endif
769
770 #ifndef HAVE_DPRINTF
771 int rep_dprintf(int fd, const char *format, ...)
772 {
773         int ret;
774         va_list ap;
775
776         va_start(ap, format);
777         ret = vdprintf(fd, format, ap);
778         va_end(ap);
779
780         return ret;
781 }
782 #endif
783
784 #ifndef HAVE_GET_CURRENT_DIR_NAME
785 char *rep_get_current_dir_name(void)
786 {
787         char buf[PATH_MAX+1];
788         char *p;
789         p = getcwd(buf, sizeof(buf));
790         if (p == NULL) {
791                 return NULL;
792         }
793         return strdup(p);
794 }
795 #endif
796
797 #if !defined(HAVE_STRERROR_R) || !defined(STRERROR_R_PROTO_COMPATIBLE)
798 int rep_strerror_r(int errnum, char *buf, size_t buflen)
799 {
800         char *s = strerror(errnum);
801         if (strlen(s)+1 > buflen) {
802                 errno = ERANGE;
803                 return -1;
804         }
805         strncpy(buf, s, buflen);
806         return 0;
807 }
808 #endif
809
810 #ifndef HAVE_CLOCK_GETTIME
811 int rep_clock_gettime(clockid_t clk_id, struct timespec *tp)
812 {
813         struct timeval tval;
814         switch (clk_id) {
815                 case 0: /* CLOCK_REALTIME :*/
816 #ifdef HAVE_GETTIMEOFDAY_TZ
817                         gettimeofday(&tval,NULL);
818 #else
819                         gettimeofday(&tval);
820 #endif
821                         tp->tv_sec = tval.tv_sec;
822                         tp->tv_nsec = tval.tv_usec * 1000;
823                         break;
824                 default:
825                         errno = EINVAL;
826                         return -1;
827         }
828         return 0;
829 }
830 #endif