Make Samba3 pass the RAW-LOCK test as Windows.
[amitay/samba.git] / source3 / lib / system.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Samba system utilities
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Jeremy Allison  1998-2005
6    Copyright (C) Timur Bakeyev        2005
7    Copyright (C) Bjoern Jacke    2006-2007
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24
25 #ifdef HAVE_SYS_PRCTL_H
26 #include <sys/prctl.h>
27 #endif
28
29 /*
30    The idea is that this file will eventually have wrappers around all
31    important system calls in samba. The aims are:
32
33    - to enable easier porting by putting OS dependent stuff in here
34
35    - to allow for hooks into other "pseudo-filesystems"
36
37    - to allow easier integration of things like the japanese extensions
38
39    - to support the philosophy of Samba to expose the features of
40      the OS within the SMB model. In general whatever file/printer/variable
41      expansions/etc make sense to the OS should be acceptable to Samba.
42 */
43
44
45
46 /*******************************************************************
47  A wrapper for memalign
48 ********************************************************************/
49
50 void *sys_memalign( size_t align, size_t size )
51 {
52 #if defined(HAVE_POSIX_MEMALIGN)
53         void *p = NULL;
54         int ret = posix_memalign( &p, align, size );
55         if ( ret == 0 )
56                 return p;
57
58         return NULL;
59 #elif defined(HAVE_MEMALIGN)
60         return memalign( align, size );
61 #else
62         /* On *BSD systems memaligns doesn't exist, but memory will
63          * be aligned on allocations of > pagesize. */
64 #if defined(SYSCONF_SC_PAGESIZE)
65         size_t pagesize = (size_t)sysconf(_SC_PAGESIZE);
66 #elif defined(HAVE_GETPAGESIZE)
67         size_t pagesize = (size_t)getpagesize();
68 #else
69         size_t pagesize = (size_t)-1;
70 #endif
71         if (pagesize == (size_t)-1) {
72                 DEBUG(0,("memalign functionalaity not available on this platform!\n"));
73                 return NULL;
74         }
75         if (size < pagesize) {
76                 size = pagesize;
77         }
78         return SMB_MALLOC(size);
79 #endif
80 }
81
82 /*******************************************************************
83  A wrapper for usleep in case we don't have one.
84 ********************************************************************/
85
86 int sys_usleep(long usecs)
87 {
88 #ifndef HAVE_USLEEP
89         struct timeval tval;
90 #endif
91
92         /*
93          * We need this braindamage as the glibc usleep
94          * is not SPEC1170 complient... grumble... JRA.
95          */
96
97         if(usecs < 0 || usecs > 999999) {
98                 errno = EINVAL;
99                 return -1;
100         }
101
102 #if HAVE_USLEEP
103         usleep(usecs);
104         return 0;
105 #else /* HAVE_USLEEP */
106         /*
107          * Fake it with select...
108          */
109         tval.tv_sec = 0;
110         tval.tv_usec = usecs/1000;
111         select(0,NULL,NULL,NULL,&tval);
112         return 0;
113 #endif /* HAVE_USLEEP */
114 }
115
116 /*******************************************************************
117 A read wrapper that will deal with EINTR.
118 ********************************************************************/
119
120 ssize_t sys_read(int fd, void *buf, size_t count)
121 {
122         ssize_t ret;
123
124         do {
125                 ret = read(fd, buf, count);
126         } while (ret == -1 && errno == EINTR);
127         return ret;
128 }
129
130 /*******************************************************************
131 A write wrapper that will deal with EINTR.
132 ********************************************************************/
133
134 ssize_t sys_write(int fd, const void *buf, size_t count)
135 {
136         ssize_t ret;
137
138         do {
139                 ret = write(fd, buf, count);
140         } while (ret == -1 && errno == EINTR);
141         return ret;
142 }
143
144 /*******************************************************************
145 A writev wrapper that will deal with EINTR.
146 ********************************************************************/
147
148 ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt)
149 {
150         ssize_t ret;
151
152 #if 0
153         /* Try to confuse write_data_iov a bit */
154         if ((random() % 5) == 0) {
155                 return sys_write(fd, iov[0].iov_base, iov[0].iov_len);
156         }
157         if (iov[0].iov_len > 1) {
158                 return sys_write(fd, iov[0].iov_base,
159                                  (random() % (iov[0].iov_len-1)) + 1);
160         }
161 #endif
162
163         do {
164                 ret = writev(fd, iov, iovcnt);
165         } while (ret == -1 && errno == EINTR);
166         return ret;
167 }
168
169 /*******************************************************************
170 A pread wrapper that will deal with EINTR and 64-bit file offsets.
171 ********************************************************************/
172
173 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
174 ssize_t sys_pread(int fd, void *buf, size_t count, SMB_OFF_T off)
175 {
176         ssize_t ret;
177
178         do {
179 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_PREAD64)
180                 ret = pread64(fd, buf, count, off);
181 #else
182                 ret = pread(fd, buf, count, off);
183 #endif
184         } while (ret == -1 && errno == EINTR);
185         return ret;
186 }
187 #endif
188
189 /*******************************************************************
190 A write wrapper that will deal with EINTR and 64-bit file offsets.
191 ********************************************************************/
192
193 #if defined(HAVE_PWRITE) || defined(HAVE_PWRITE64)
194 ssize_t sys_pwrite(int fd, const void *buf, size_t count, SMB_OFF_T off)
195 {
196         ssize_t ret;
197
198         do {
199 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_PWRITE64)
200                 ret = pwrite64(fd, buf, count, off);
201 #else
202                 ret = pwrite(fd, buf, count, off);
203 #endif
204         } while (ret == -1 && errno == EINTR);
205         return ret;
206 }
207 #endif
208
209 /*******************************************************************
210 A send wrapper that will deal with EINTR.
211 ********************************************************************/
212
213 ssize_t sys_send(int s, const void *msg, size_t len, int flags)
214 {
215         ssize_t ret;
216
217         do {
218                 ret = send(s, msg, len, flags);
219         } while (ret == -1 && errno == EINTR);
220         return ret;
221 }
222
223 /*******************************************************************
224 A sendto wrapper that will deal with EINTR.
225 ********************************************************************/
226
227 ssize_t sys_sendto(int s,  const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
228 {
229         ssize_t ret;
230
231         do {
232                 ret = sendto(s, msg, len, flags, to, tolen);
233         } while (ret == -1 && errno == EINTR);
234         return ret;
235 }
236
237 /*******************************************************************
238 A recv wrapper that will deal with EINTR.
239 ********************************************************************/
240
241 ssize_t sys_recv(int fd, void *buf, size_t count, int flags)
242 {
243         ssize_t ret;
244
245         do {
246                 ret = recv(fd, buf, count, flags);
247         } while (ret == -1 && errno == EINTR);
248         return ret;
249 }
250
251 /*******************************************************************
252 A recvfrom wrapper that will deal with EINTR.
253 ********************************************************************/
254
255 ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
256 {
257         ssize_t ret;
258
259         do {
260                 ret = recvfrom(s, buf, len, flags, from, fromlen);
261         } while (ret == -1 && errno == EINTR);
262         return ret;
263 }
264
265 /*******************************************************************
266 A fcntl wrapper that will deal with EINTR.
267 ********************************************************************/
268
269 int sys_fcntl_ptr(int fd, int cmd, void *arg)
270 {
271         int ret;
272
273         do {
274                 ret = fcntl(fd, cmd, arg);
275         } while (ret == -1 && errno == EINTR);
276         return ret;
277 }
278
279 /*******************************************************************
280 A fcntl wrapper that will deal with EINTR.
281 ********************************************************************/
282
283 int sys_fcntl_long(int fd, int cmd, long arg)
284 {
285         int ret;
286
287         do {
288                 ret = fcntl(fd, cmd, arg);
289         } while (ret == -1 && errno == EINTR);
290         return ret;
291 }
292
293 /****************************************************************************
294  Get/Set all the possible time fields from a stat struct as a timespec.
295 ****************************************************************************/
296
297 static struct timespec get_atimespec(const struct stat *pst)
298 {
299 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
300         struct timespec ret;
301
302         /* Old system - no ns timestamp. */
303         ret.tv_sec = pst->st_atime;
304         ret.tv_nsec = 0;
305         return ret;
306 #else
307 #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
308         return pst->st_atim;
309 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
310         struct timespec ret;
311         ret.tv_sec = pst->st_atime;
312         ret.tv_nsec = pst->st_atimensec;
313         return ret;
314 #elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
315         struct timespec ret;
316         ret.tv_sec = pst->st_atime;
317         ret.tv_nsec = pst->st_atime_n;
318         return ret;
319 #elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
320         struct timespec ret;
321         ret.tv_sec = pst->st_atime;
322         ret.tv_nsec = pst->st_uatime * 1000;
323         return ret;
324 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
325         return pst->st_atimespec;
326 #else
327 #error  CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
328 #endif
329 #endif
330 }
331
332 static struct timespec get_mtimespec(const struct stat *pst)
333 {
334 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
335         struct timespec ret;
336
337         /* Old system - no ns timestamp. */
338         ret.tv_sec = pst->st_mtime;
339         ret.tv_nsec = 0;
340         return ret;
341 #else
342 #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
343         return pst->st_mtim;
344 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
345         struct timespec ret;
346         ret.tv_sec = pst->st_mtime;
347         ret.tv_nsec = pst->st_mtimensec;
348         return ret;
349 #elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
350         struct timespec ret;
351         ret.tv_sec = pst->st_mtime;
352         ret.tv_nsec = pst->st_mtime_n;
353         return ret;
354 #elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
355         struct timespec ret;
356         ret.tv_sec = pst->st_mtime;
357         ret.tv_nsec = pst->st_umtime * 1000;
358         return ret;
359 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
360         return pst->st_mtimespec;
361 #else
362 #error  CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
363 #endif
364 #endif
365 }
366
367 static struct timespec get_ctimespec(const struct stat *pst)
368 {
369 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
370         struct timespec ret;
371
372         /* Old system - no ns timestamp. */
373         ret.tv_sec = pst->st_ctime;
374         ret.tv_nsec = 0;
375         return ret;
376 #else
377 #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
378         return pst->st_ctim;
379 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
380         struct timespec ret;
381         ret.tv_sec = pst->st_ctime;
382         ret.tv_nsec = pst->st_ctimensec;
383         return ret;
384 #elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
385         struct timespec ret;
386         ret.tv_sec = pst->st_ctime;
387         ret.tv_nsec = pst->st_ctime_n;
388         return ret;
389 #elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
390         struct timespec ret;
391         ret.tv_sec = pst->st_ctime;
392         ret.tv_nsec = pst->st_uctime * 1000;
393         return ret;
394 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
395         return pst->st_ctimespec;
396 #else
397 #error  CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
398 #endif
399 #endif
400 }
401
402 /****************************************************************************
403  Return the best approximation to a 'create time' under UNIX from a stat
404  structure.
405 ****************************************************************************/
406
407 static struct timespec calc_create_time_stat(const struct stat *st)
408 {
409         struct timespec ret, ret1;
410         struct timespec c_time = get_ctimespec(st);
411         struct timespec m_time = get_mtimespec(st);
412         struct timespec a_time = get_atimespec(st);
413
414         ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
415         ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
416
417         if(!null_timespec(ret1)) {
418                 return ret1;
419         }
420
421         /*
422          * One of ctime, mtime or atime was zero (probably atime).
423          * Just return MIN(ctime, mtime).
424          */
425         return ret;
426 }
427
428 /****************************************************************************
429  Return the best approximation to a 'create time' under UNIX from a stat_ex
430  structure.
431 ****************************************************************************/
432
433 static struct timespec calc_create_time_stat_ex(const struct stat_ex *st)
434 {
435         struct timespec ret, ret1;
436         struct timespec c_time = st->st_ex_ctime;
437         struct timespec m_time = st->st_ex_mtime;
438         struct timespec a_time = st->st_ex_atime;
439
440         ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
441         ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
442
443         if(!null_timespec(ret1)) {
444                 return ret1;
445         }
446
447         /*
448          * One of ctime, mtime or atime was zero (probably atime).
449          * Just return MIN(ctime, mtime).
450          */
451         return ret;
452 }
453
454 /****************************************************************************
455  Return the 'create time' from a stat struct if it exists (birthtime) or else
456  use the best approximation.
457 ****************************************************************************/
458
459 static void make_create_timespec(const struct stat *pst, struct stat_ex *dst,
460                                  bool fake_dir_create_times)
461 {
462         if (S_ISDIR(pst->st_mode) && fake_dir_create_times) {
463                 dst->st_ex_btime.tv_sec = 315493200L;          /* 1/1/1980 */
464                 dst->st_ex_btime.tv_nsec = 0;
465         }
466
467         dst->st_ex_calculated_birthtime = false;
468
469 #if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
470         dst->st_ex_btime = pst->st_birthtimespec;
471 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC)
472         dst->st_ex_btime.tv_sec = pst->st_birthtime;
473         dst->st_ex_btime.tv_nsec = pst->st_birthtimenspec;
474 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
475         dst->st_ex_btime.tv_sec = pst->st_birthtime;
476         dst->st_ex_btime.tv_nsec = 0;
477 #else
478         dst->st_ex_btime = calc_create_time_stat(pst);
479         dst->st_ex_calculated_birthtime = true;
480 #endif
481
482         /* Deal with systems that don't initialize birthtime correctly.
483          * Pointed out by SATOH Fumiyasu <fumiyas@osstech.jp>.
484          */
485         if (null_timespec(dst->st_ex_btime)) {
486                 dst->st_ex_btime = calc_create_time_stat(pst);
487                 dst->st_ex_calculated_birthtime = true;
488         }
489 }
490
491 /****************************************************************************
492  If we update a timestamp in a stat_ex struct we may have to recalculate
493  the birthtime. For now only implement this for write time, but we may
494  also need to do it for atime and ctime. JRA.
495 ****************************************************************************/
496
497 void update_stat_ex_mtime(struct stat_ex *dst,
498                                 struct timespec write_ts)
499 {
500         dst->st_ex_mtime = write_ts;
501
502         /* We may have to recalculate btime. */
503         if (dst->st_ex_calculated_birthtime) {
504                 dst->st_ex_btime = calc_create_time_stat_ex(dst);
505         }
506 }
507
508 void update_stat_ex_create_time(struct stat_ex *dst,
509                                 struct timespec create_time)
510 {
511         dst->st_ex_btime = create_time;
512         dst->st_ex_calculated_birthtime = false;
513 }
514
515 static void init_stat_ex_from_stat (struct stat_ex *dst,
516                                     const struct stat *src,
517                                     bool fake_dir_create_times)
518 {
519         dst->st_ex_dev = src->st_dev;
520         dst->st_ex_ino = src->st_ino;
521         dst->st_ex_mode = src->st_mode;
522         dst->st_ex_nlink = src->st_nlink;
523         dst->st_ex_uid = src->st_uid;
524         dst->st_ex_gid = src->st_gid;
525         dst->st_ex_rdev = src->st_rdev;
526         dst->st_ex_size = src->st_size;
527         dst->st_ex_atime = get_atimespec(src);
528         dst->st_ex_mtime = get_mtimespec(src);
529         dst->st_ex_ctime = get_ctimespec(src);
530         make_create_timespec(src, dst, fake_dir_create_times);
531         dst->st_ex_blksize = src->st_blksize;
532         dst->st_ex_blocks = src->st_blocks;
533
534 #ifdef HAVE_STAT_ST_FLAGS
535         dst->st_ex_flags = src->st_flags;
536 #else
537         dst->st_ex_flags = 0;
538 #endif
539 }
540
541 /*******************************************************************
542 A stat() wrapper that will deal with 64 bit filesizes.
543 ********************************************************************/
544
545 int sys_stat(const char *fname, SMB_STRUCT_STAT *sbuf,
546              bool fake_dir_create_times)
547 {
548         int ret;
549 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
550         ret = stat64(fname, sbuf);
551 #else
552         struct stat statbuf;
553         ret = stat(fname, &statbuf);
554 #endif
555         if (ret == 0) {
556                 /* we always want directories to appear zero size */
557                 if (S_ISDIR(statbuf.st_mode)) {
558                         statbuf.st_size = 0;
559                 }
560                 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
561         }
562         return ret;
563 }
564
565 /*******************************************************************
566  An fstat() wrapper that will deal with 64 bit filesizes.
567 ********************************************************************/
568
569 int sys_fstat(int fd, SMB_STRUCT_STAT *sbuf, bool fake_dir_create_times)
570 {
571         int ret;
572 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
573         ret = fstat64(fd, sbuf);
574 #else
575         struct stat statbuf;
576         ret = fstat(fd, &statbuf);
577 #endif
578         if (ret == 0) {
579                 /* we always want directories to appear zero size */
580                 if (S_ISDIR(statbuf.st_mode)) {
581                         statbuf.st_size = 0;
582                 }
583                 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
584         }
585         return ret;
586 }
587
588 /*******************************************************************
589  An lstat() wrapper that will deal with 64 bit filesizes.
590 ********************************************************************/
591
592 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf,
593               bool fake_dir_create_times)
594 {
595         int ret;
596 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
597         ret = lstat64(fname, sbuf);
598 #else
599         struct stat statbuf;
600         ret = lstat(fname, &statbuf);
601 #endif
602         if (ret == 0) {
603                 /* we always want directories to appear zero size */
604                 if (S_ISDIR(statbuf.st_mode)) {
605                         statbuf.st_size = 0;
606                 }
607                 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
608         }
609         return ret;
610 }
611
612 /*******************************************************************
613  An posix_fallocate() wrapper that will deal with 64 bit filesizes.
614 ********************************************************************/
615 #if defined(HAVE_POSIX_FALLOCATE64) || defined(HAVE_POSIX_FALLOCATE)
616 int sys_posix_fallocate(int fd, SMB_OFF_T offset, SMB_OFF_T len)
617 {
618 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_POSIX_FALLOCATE64)
619         return posix_fallocate64(fd, offset, len);
620 #else
621         return posix_fallocate(fd, offset, len);
622 #endif
623 }
624 #endif
625
626 /*******************************************************************
627  An ftruncate() wrapper that will deal with 64 bit filesizes.
628 ********************************************************************/
629
630 int sys_ftruncate(int fd, SMB_OFF_T offset)
631 {
632 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
633         return ftruncate64(fd, offset);
634 #else
635         return ftruncate(fd, offset);
636 #endif
637 }
638
639 /*******************************************************************
640  An lseek() wrapper that will deal with 64 bit filesizes.
641 ********************************************************************/
642
643 SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
644 {
645 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
646         return lseek64(fd, offset, whence);
647 #else
648         return lseek(fd, offset, whence);
649 #endif
650 }
651
652 /*******************************************************************
653  An fseek() wrapper that will deal with 64 bit filesizes.
654 ********************************************************************/
655
656 int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence)
657 {
658 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64)
659         return fseek64(fp, offset, whence);
660 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEKO64)
661         return fseeko64(fp, offset, whence);
662 #else
663         return fseek(fp, offset, whence);
664 #endif
665 }
666
667 /*******************************************************************
668  An ftell() wrapper that will deal with 64 bit filesizes.
669 ********************************************************************/
670
671 SMB_OFF_T sys_ftell(FILE *fp)
672 {
673 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64)
674         return (SMB_OFF_T)ftell64(fp);
675 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELLO64)
676         return (SMB_OFF_T)ftello64(fp);
677 #else
678         return (SMB_OFF_T)ftell(fp);
679 #endif
680 }
681
682 /*******************************************************************
683  A creat() wrapper that will deal with 64 bit filesizes.
684 ********************************************************************/
685
686 int sys_creat(const char *path, mode_t mode)
687 {
688 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CREAT64)
689         return creat64(path, mode);
690 #else
691         /*
692          * If creat64 isn't defined then ensure we call a potential open64.
693          * JRA.
694          */
695         return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
696 #endif
697 }
698
699 /*******************************************************************
700  An open() wrapper that will deal with 64 bit filesizes.
701 ********************************************************************/
702
703 int sys_open(const char *path, int oflag, mode_t mode)
704 {
705 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPEN64)
706         return open64(path, oflag, mode);
707 #else
708         return open(path, oflag, mode);
709 #endif
710 }
711
712 /*******************************************************************
713  An fopen() wrapper that will deal with 64 bit filesizes.
714 ********************************************************************/
715
716 FILE *sys_fopen(const char *path, const char *type)
717 {
718 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_FOPEN64)
719         return fopen64(path, type);
720 #else
721         return fopen(path, type);
722 #endif
723 }
724
725
726 /*******************************************************************
727  A flock() wrapper that will perform the kernel flock.
728 ********************************************************************/
729
730 void kernel_flock(int fd, uint32 share_mode, uint32 access_mask)
731 {
732 #if HAVE_KERNEL_SHARE_MODES
733         int kernel_mode = 0;
734         if (share_mode == FILE_SHARE_WRITE) {
735                 kernel_mode = LOCK_MAND|LOCK_WRITE;
736         } else if (share_mode == FILE_SHARE_READ) {
737                 kernel_mode = LOCK_MAND|LOCK_READ;
738         } else if (share_mode == FILE_SHARE_NONE) {
739                 kernel_mode = LOCK_MAND;
740         }
741         if (kernel_mode) {
742                 flock(fd, kernel_mode);
743         }
744 #endif
745         ;
746 }
747
748
749
750 /*******************************************************************
751  An opendir wrapper that will deal with 64 bit filesizes.
752 ********************************************************************/
753
754 SMB_STRUCT_DIR *sys_opendir(const char *name)
755 {
756 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPENDIR64)
757         return opendir64(name);
758 #else
759         return opendir(name);
760 #endif
761 }
762
763 /*******************************************************************
764  A readdir wrapper that will deal with 64 bit filesizes.
765 ********************************************************************/
766
767 SMB_STRUCT_DIRENT *sys_readdir(SMB_STRUCT_DIR *dirp)
768 {
769 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
770         return readdir64(dirp);
771 #else
772         return readdir(dirp);
773 #endif
774 }
775
776 /*******************************************************************
777  A seekdir wrapper that will deal with 64 bit filesizes.
778 ********************************************************************/
779
780 void sys_seekdir(SMB_STRUCT_DIR *dirp, long offset)
781 {
782 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_SEEKDIR64)
783         seekdir64(dirp, offset);
784 #else
785         seekdir(dirp, offset);
786 #endif
787 }
788
789 /*******************************************************************
790  A telldir wrapper that will deal with 64 bit filesizes.
791 ********************************************************************/
792
793 long sys_telldir(SMB_STRUCT_DIR *dirp)
794 {
795 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_TELLDIR64)
796         return (long)telldir64(dirp);
797 #else
798         return (long)telldir(dirp);
799 #endif
800 }
801
802 /*******************************************************************
803  A rewinddir wrapper that will deal with 64 bit filesizes.
804 ********************************************************************/
805
806 void sys_rewinddir(SMB_STRUCT_DIR *dirp)
807 {
808 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_REWINDDIR64)
809         rewinddir64(dirp);
810 #else
811         rewinddir(dirp);
812 #endif
813 }
814
815 /*******************************************************************
816  A close wrapper that will deal with 64 bit filesizes.
817 ********************************************************************/
818
819 int sys_closedir(SMB_STRUCT_DIR *dirp)
820 {
821 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CLOSEDIR64)
822         return closedir64(dirp);
823 #else
824         return closedir(dirp);
825 #endif
826 }
827
828 /*******************************************************************
829  An mknod() wrapper that will deal with 64 bit filesizes.
830 ********************************************************************/
831
832 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
833 {
834 #if defined(HAVE_MKNOD) || defined(HAVE_MKNOD64)
835 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_MKNOD64) && defined(HAVE_DEV64_T)
836         return mknod64(path, mode, dev);
837 #else
838         return mknod(path, mode, dev);
839 #endif
840 #else
841         /* No mknod system call. */
842         errno = ENOSYS;
843         return -1;
844 #endif
845 }
846
847 /*******************************************************************
848 The wait() calls vary between systems
849 ********************************************************************/
850
851 int sys_waitpid(pid_t pid,int *status,int options)
852 {
853 #ifdef HAVE_WAITPID
854         return waitpid(pid,status,options);
855 #else /* HAVE_WAITPID */
856         return wait4(pid, status, options, NULL);
857 #endif /* HAVE_WAITPID */
858 }
859
860 /*******************************************************************
861  System wrapper for getwd
862 ********************************************************************/
863
864 char *sys_getwd(char *s)
865 {
866         char *wd;
867 #ifdef HAVE_GETCWD
868         wd = (char *)getcwd(s, PATH_MAX);
869 #else
870         wd = (char *)getwd(s);
871 #endif
872         return wd;
873 }
874
875 #if defined(HAVE_POSIX_CAPABILITIES)
876
877 /**************************************************************************
878  Try and abstract process capabilities (for systems that have them).
879 ****************************************************************************/
880
881 /* Set the POSIX capabilities needed for the given purpose into the effective
882  * capability set of the current process. Make sure they are always removed
883  * from the inheritable set, because there is no circumstance in which our
884  * children should inherit our elevated privileges.
885  */
886 static bool set_process_capability(enum smbd_capability capability,
887                                    bool enable)
888 {
889         cap_value_t cap_vals[2] = {0};
890         int num_cap_vals = 0;
891
892         cap_t cap;
893
894 #if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
895         /* On Linux, make sure that any capabilities we grab are sticky
896          * across UID changes. We expect that this would allow us to keep both
897          * the effective and permitted capability sets, but as of circa 2.6.16,
898          * only the permitted set is kept. It is a bug (which we work around)
899          * that the effective set is lost, but we still require the effective
900          * set to be kept.
901          */
902         if (!prctl(PR_GET_KEEPCAPS)) {
903                 prctl(PR_SET_KEEPCAPS, 1);
904         }
905 #endif
906
907         cap = cap_get_proc();
908         if (cap == NULL) {
909                 DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
910                         strerror(errno)));
911                 return False;
912         }
913
914         switch (capability) {
915                 case KERNEL_OPLOCK_CAPABILITY:
916 #ifdef CAP_NETWORK_MGT
917                         /* IRIX has CAP_NETWORK_MGT for oplocks. */
918                         cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
919 #endif
920                         break;
921                 case DMAPI_ACCESS_CAPABILITY:
922 #ifdef CAP_DEVICE_MGT
923                         /* IRIX has CAP_DEVICE_MGT for DMAPI access. */
924                         cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
925 #elif CAP_MKNOD
926                         /* Linux has CAP_MKNOD for DMAPI access. */
927                         cap_vals[num_cap_vals++] = CAP_MKNOD;
928 #endif
929                         break;
930                 case LEASE_CAPABILITY:
931 #ifdef CAP_LEASE
932                         cap_vals[num_cap_vals++] = CAP_LEASE;
933 #endif
934                         break;
935         }
936
937         SMB_ASSERT(num_cap_vals <= ARRAY_SIZE(cap_vals));
938
939         if (num_cap_vals == 0) {
940                 cap_free(cap);
941                 return True;
942         }
943
944         cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
945                 enable ? CAP_SET : CAP_CLEAR);
946
947         /* We never want to pass capabilities down to our children, so make
948          * sure they are not inherited.
949          */
950         cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
951
952         if (cap_set_proc(cap) == -1) {
953                 DEBUG(0, ("set_process_capability: cap_set_proc failed: %s\n",
954                         strerror(errno)));
955                 cap_free(cap);
956                 return False;
957         }
958
959         cap_free(cap);
960         return True;
961 }
962
963 #endif /* HAVE_POSIX_CAPABILITIES */
964
965 /****************************************************************************
966  Gain the oplock capability from the kernel if possible.
967 ****************************************************************************/
968
969 void set_effective_capability(enum smbd_capability capability)
970 {
971 #if defined(HAVE_POSIX_CAPABILITIES)
972         set_process_capability(capability, True);
973 #endif /* HAVE_POSIX_CAPABILITIES */
974 }
975
976 void drop_effective_capability(enum smbd_capability capability)
977 {
978 #if defined(HAVE_POSIX_CAPABILITIES)
979         set_process_capability(capability, False);
980 #endif /* HAVE_POSIX_CAPABILITIES */
981 }
982
983 /**************************************************************************
984  Wrapper for random().
985 ****************************************************************************/
986
987 long sys_random(void)
988 {
989 #if defined(HAVE_RANDOM)
990         return (long)random();
991 #elif defined(HAVE_RAND)
992         return (long)rand();
993 #else
994         DEBUG(0,("Error - no random function available !\n"));
995         exit(1);
996 #endif
997 }
998
999 /**************************************************************************
1000  Wrapper for srandom().
1001 ****************************************************************************/
1002
1003 void sys_srandom(unsigned int seed)
1004 {
1005 #if defined(HAVE_SRANDOM)
1006         srandom(seed);
1007 #elif defined(HAVE_SRAND)
1008         srand(seed);
1009 #else
1010         DEBUG(0,("Error - no srandom function available !\n"));
1011         exit(1);
1012 #endif
1013 }
1014
1015 /**************************************************************************
1016  Returns equivalent to NGROUPS_MAX - using sysconf if needed.
1017 ****************************************************************************/
1018
1019 int groups_max(void)
1020 {
1021 #if defined(SYSCONF_SC_NGROUPS_MAX)
1022         int ret = sysconf(_SC_NGROUPS_MAX);
1023         return (ret == -1) ? NGROUPS_MAX : ret;
1024 #else
1025         return NGROUPS_MAX;
1026 #endif
1027 }
1028
1029 /**************************************************************************
1030  Wrap setgroups and getgroups for systems that declare getgroups() as
1031  returning an array of gid_t, but actuall return an array of int.
1032 ****************************************************************************/
1033
1034 #if defined(HAVE_BROKEN_GETGROUPS)
1035 static int sys_broken_getgroups(int setlen, gid_t *gidset)
1036 {
1037         GID_T gid;
1038         GID_T *group_list;
1039         int i, ngroups;
1040
1041         if(setlen == 0) {
1042                 return getgroups(setlen, &gid);
1043         }
1044
1045         /*
1046          * Broken case. We need to allocate a
1047          * GID_T array of size setlen.
1048          */
1049
1050         if(setlen < 0) {
1051                 errno = EINVAL; 
1052                 return -1;
1053         } 
1054
1055         if (setlen == 0)
1056                 setlen = groups_max();
1057
1058         if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
1059                 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
1060                 return -1;
1061         }
1062
1063         if((ngroups = getgroups(setlen, group_list)) < 0) {
1064                 int saved_errno = errno;
1065                 SAFE_FREE(group_list);
1066                 errno = saved_errno;
1067                 return -1;
1068         }
1069
1070         for(i = 0; i < ngroups; i++)
1071                 gidset[i] = (gid_t)group_list[i];
1072
1073         SAFE_FREE(group_list);
1074         return ngroups;
1075 }
1076
1077 static int sys_broken_setgroups(int setlen, gid_t *gidset)
1078 {
1079         GID_T *group_list;
1080         int i ; 
1081
1082         if (setlen == 0)
1083                 return 0 ;
1084
1085         if (setlen < 0 || setlen > groups_max()) {
1086                 errno = EINVAL; 
1087                 return -1;   
1088         }
1089
1090         /*
1091          * Broken case. We need to allocate a
1092          * GID_T array of size setlen.
1093          */
1094
1095         if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
1096                 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
1097                 return -1;    
1098         }
1099
1100         for(i = 0; i < setlen; i++) 
1101                 group_list[i] = (GID_T) gidset[i]; 
1102
1103         if(setgroups(setlen, group_list) != 0) {
1104                 int saved_errno = errno;
1105                 SAFE_FREE(group_list);
1106                 errno = saved_errno;
1107                 return -1;
1108         }
1109
1110         SAFE_FREE(group_list);
1111         return 0 ;
1112 }
1113
1114 #endif /* HAVE_BROKEN_GETGROUPS */
1115
1116 /* This is a list of systems that require the first GID passed to setgroups(2)
1117  * to be the effective GID. If your system is one of these, add it here.
1118  */
1119 #if defined (FREEBSD) || defined (DARWINOS)
1120 #define USE_BSD_SETGROUPS
1121 #endif
1122
1123 #if defined(USE_BSD_SETGROUPS)
1124 /* Depending on the particular BSD implementation, the first GID that is
1125  * passed to setgroups(2) will either be ignored or will set the credential's
1126  * effective GID. In either case, the right thing to do is to guarantee that
1127  * gidset[0] is the effective GID.
1128  */
1129 static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
1130 {
1131         gid_t *new_gidset = NULL;
1132         int max;
1133         int ret;
1134
1135         /* setgroups(2) will fail with EINVAL if we pass too many groups. */
1136         max = groups_max();
1137
1138         /* No group list, just make sure we are setting the efective GID. */
1139         if (setlen == 0) {
1140                 return setgroups(1, &primary_gid);
1141         }
1142
1143         /* If the primary gid is not the first array element, grow the array
1144          * and insert it at the front.
1145          */
1146         if (gidset[0] != primary_gid) {
1147                 new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
1148                 if (new_gidset == NULL) {
1149                         return -1;
1150                 }
1151
1152                 memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
1153                 new_gidset[0] = primary_gid;
1154                 setlen++;
1155         }
1156
1157         if (setlen > max) {
1158                 DEBUG(3, ("forced to truncate group list from %d to %d\n",
1159                         setlen, max));
1160                 setlen = max;
1161         }
1162
1163 #if defined(HAVE_BROKEN_GETGROUPS)
1164         ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
1165 #else
1166         ret = setgroups(setlen, new_gidset ? new_gidset : gidset);
1167 #endif
1168
1169         if (new_gidset) {
1170                 int errsav = errno;
1171                 SAFE_FREE(new_gidset);
1172                 errno = errsav;
1173         }
1174
1175         return ret;
1176 }
1177
1178 #endif /* USE_BSD_SETGROUPS */
1179
1180 /**************************************************************************
1181  Wrapper for getgroups. Deals with broken (int) case.
1182 ****************************************************************************/
1183
1184 int sys_getgroups(int setlen, gid_t *gidset)
1185 {
1186 #if defined(HAVE_BROKEN_GETGROUPS)
1187         return sys_broken_getgroups(setlen, gidset);
1188 #else
1189         return getgroups(setlen, gidset);
1190 #endif
1191 }
1192
1193 /**************************************************************************
1194  Wrapper for setgroups. Deals with broken (int) case and BSD case.
1195 ****************************************************************************/
1196
1197 int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
1198 {
1199 #if !defined(HAVE_SETGROUPS)
1200         errno = ENOSYS;
1201         return -1;
1202 #endif /* HAVE_SETGROUPS */
1203
1204 #if defined(USE_BSD_SETGROUPS)
1205         return sys_bsd_setgroups(primary_gid, setlen, gidset);
1206 #elif defined(HAVE_BROKEN_GETGROUPS)
1207         return sys_broken_setgroups(setlen, gidset);
1208 #else
1209         return setgroups(setlen, gidset);
1210 #endif
1211 }
1212
1213 /**************************************************************************
1214  Wrappers for setpwent(), getpwent() and endpwent()
1215 ****************************************************************************/
1216
1217 void sys_setpwent(void)
1218 {
1219         setpwent();
1220 }
1221
1222 struct passwd *sys_getpwent(void)
1223 {
1224         return getpwent();
1225 }
1226
1227 void sys_endpwent(void)
1228 {
1229         endpwent();
1230 }
1231
1232 /**************************************************************************
1233  Wrappers for getpwnam(), getpwuid(), getgrnam(), getgrgid()
1234 ****************************************************************************/
1235
1236
1237 struct passwd *sys_getpwnam(const char *name)
1238 {
1239         return getpwnam(name);
1240 }
1241
1242 struct passwd *sys_getpwuid(uid_t uid)
1243 {
1244         return getpwuid(uid);
1245 }
1246
1247 struct group *sys_getgrnam(const char *name)
1248 {
1249         return getgrnam(name);
1250 }
1251
1252 struct group *sys_getgrgid(gid_t gid)
1253 {
1254         return getgrgid(gid);
1255 }
1256
1257 /**************************************************************************
1258  Extract a command into an arg list.
1259 ****************************************************************************/
1260
1261 static char **extract_args(TALLOC_CTX *mem_ctx, const char *command)
1262 {
1263         char *trunc_cmd;
1264         char *saveptr;
1265         char *ptr;
1266         int argcl;
1267         char **argl = NULL;
1268         int i;
1269
1270         if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
1271                 DEBUG(0, ("talloc failed\n"));
1272                 goto nomem;
1273         }
1274
1275         if(!(ptr = strtok_r(trunc_cmd, " \t", &saveptr))) {
1276                 TALLOC_FREE(trunc_cmd);
1277                 errno = EINVAL;
1278                 return NULL;
1279         }
1280
1281         /*
1282          * Count the args.
1283          */
1284
1285         for( argcl = 1; ptr; ptr = strtok_r(NULL, " \t", &saveptr))
1286                 argcl++;
1287
1288         TALLOC_FREE(trunc_cmd);
1289
1290         if (!(argl = TALLOC_ARRAY(mem_ctx, char *, argcl + 1))) {
1291                 goto nomem;
1292         }
1293
1294         /*
1295          * Now do the extraction.
1296          */
1297
1298         if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
1299                 goto nomem;
1300         }
1301
1302         ptr = strtok_r(trunc_cmd, " \t", &saveptr);
1303         i = 0;
1304
1305         if (!(argl[i++] = talloc_strdup(argl, ptr))) {
1306                 goto nomem;
1307         }
1308
1309         while((ptr = strtok_r(NULL, " \t", &saveptr)) != NULL) {
1310
1311                 if (!(argl[i++] = talloc_strdup(argl, ptr))) {
1312                         goto nomem;
1313                 }
1314         }
1315
1316         argl[i++] = NULL;
1317         TALLOC_FREE(trunc_cmd);
1318         return argl;
1319
1320  nomem:
1321         DEBUG(0, ("talloc failed\n"));
1322         TALLOC_FREE(trunc_cmd);
1323         TALLOC_FREE(argl);
1324         errno = ENOMEM;
1325         return NULL;
1326 }
1327
1328 /**************************************************************************
1329  Wrapper for popen. Safer as it doesn't search a path.
1330  Modified from the glibc sources.
1331  modified by tridge to return a file descriptor. We must kick our FILE* habit
1332 ****************************************************************************/
1333
1334 typedef struct _popen_list
1335 {
1336         int fd;
1337         pid_t child_pid;
1338         struct _popen_list *next;
1339 } popen_list;
1340
1341 static popen_list *popen_chain;
1342
1343 int sys_popen(const char *command)
1344 {
1345         int parent_end, child_end;
1346         int pipe_fds[2];
1347         popen_list *entry = NULL;
1348         char **argl = NULL;
1349
1350         if (pipe(pipe_fds) < 0)
1351                 return -1;
1352
1353         parent_end = pipe_fds[0];
1354         child_end = pipe_fds[1];
1355
1356         if (!*command) {
1357                 errno = EINVAL;
1358                 goto err_exit;
1359         }
1360
1361         if((entry = SMB_MALLOC_P(popen_list)) == NULL)
1362                 goto err_exit;
1363
1364         ZERO_STRUCTP(entry);
1365
1366         /*
1367          * Extract the command and args into a NULL terminated array.
1368          */
1369
1370         if(!(argl = extract_args(NULL, command)))
1371                 goto err_exit;
1372
1373         entry->child_pid = sys_fork();
1374
1375         if (entry->child_pid == -1) {
1376                 goto err_exit;
1377         }
1378
1379         if (entry->child_pid == 0) {
1380
1381                 /*
1382                  * Child !
1383                  */
1384
1385                 int child_std_end = STDOUT_FILENO;
1386                 popen_list *p;
1387
1388                 close(parent_end);
1389                 if (child_end != child_std_end) {
1390                         dup2 (child_end, child_std_end);
1391                         close (child_end);
1392                 }
1393
1394                 /*
1395                  * POSIX.2:  "popen() shall ensure that any streams from previous
1396                  * popen() calls that remain open in the parent process are closed
1397                  * in the new child process."
1398                  */
1399
1400                 for (p = popen_chain; p; p = p->next)
1401                         close(p->fd);
1402
1403                 execv(argl[0], argl);
1404                 _exit (127);
1405         }
1406
1407         /*
1408          * Parent.
1409          */
1410
1411         close (child_end);
1412         TALLOC_FREE(argl);
1413
1414         /* Link into popen_chain. */
1415         entry->next = popen_chain;
1416         popen_chain = entry;
1417         entry->fd = parent_end;
1418
1419         return entry->fd;
1420
1421 err_exit:
1422
1423         SAFE_FREE(entry);
1424         SAFE_FREE(argl);
1425         close(pipe_fds[0]);
1426         close(pipe_fds[1]);
1427         return -1;
1428 }
1429
1430 /**************************************************************************
1431  Wrapper for pclose. Modified from the glibc sources.
1432 ****************************************************************************/
1433
1434 int sys_pclose(int fd)
1435 {
1436         int wstatus;
1437         popen_list **ptr = &popen_chain;
1438         popen_list *entry = NULL;
1439         pid_t wait_pid;
1440         int status = -1;
1441
1442         /* Unlink from popen_chain. */
1443         for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1444                 if ((*ptr)->fd == fd) {
1445                         entry = *ptr;
1446                         *ptr = (*ptr)->next;
1447                         status = 0;
1448                         break;
1449                 }
1450         }
1451
1452         if (status < 0 || close(entry->fd) < 0)
1453                 return -1;
1454
1455         /*
1456          * As Samba is catching and eating child process
1457          * exits we don't really care about the child exit
1458          * code, a -1 with errno = ECHILD will do fine for us.
1459          */
1460
1461         do {
1462                 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1463         } while (wait_pid == -1 && errno == EINTR);
1464
1465         SAFE_FREE(entry);
1466
1467         if (wait_pid == -1)
1468                 return -1;
1469         return wstatus;
1470 }
1471
1472 /**************************************************************************
1473  Wrapper for Admin Logs.
1474 ****************************************************************************/
1475
1476  void sys_adminlog(int priority, const char *format_str, ...) 
1477 {
1478         va_list ap;
1479         int ret;
1480         char *msgbuf = NULL;
1481
1482         va_start( ap, format_str );
1483         ret = vasprintf( &msgbuf, format_str, ap );
1484         va_end( ap );
1485
1486         if (ret == -1)
1487                 return;
1488
1489 #if defined(HAVE_SYSLOG)
1490         syslog( priority, "%s", msgbuf );
1491 #else
1492         DEBUG(0,("%s", msgbuf ));
1493 #endif
1494         SAFE_FREE(msgbuf);
1495 }
1496
1497 /******** Solaris EA helper function prototypes ********/
1498 #ifdef HAVE_ATTROPEN
1499 #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
1500 static int solaris_write_xattr(int attrfd, const char *value, size_t size);
1501 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
1502 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
1503 static int solaris_unlinkat(int attrdirfd, const char *name);
1504 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
1505 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
1506 #endif
1507
1508 /**************************************************************************
1509  Wrappers for extented attribute calls. Based on the Linux package with
1510  support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
1511 ****************************************************************************/
1512
1513 ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size)
1514 {
1515 #if defined(HAVE_GETXATTR)
1516 #ifndef XATTR_ADD_OPT
1517         return getxattr(path, name, value, size);
1518 #else
1519         int options = 0;
1520         return getxattr(path, name, value, size, 0, options);
1521 #endif
1522 #elif defined(HAVE_GETEA)
1523         return getea(path, name, value, size);
1524 #elif defined(HAVE_EXTATTR_GET_FILE)
1525         char *s;
1526         ssize_t retval;
1527         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1528                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1529         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1530         /*
1531          * The BSD implementation has a nasty habit of silently truncating
1532          * the returned value to the size of the buffer, so we have to check
1533          * that the buffer is large enough to fit the returned value.
1534          */
1535         if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1536                 if(retval > size) {
1537                         errno = ERANGE;
1538                         return -1;
1539                 }
1540                 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
1541                         return retval;
1542         }
1543
1544         DEBUG(10,("sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno)));
1545         return -1;
1546 #elif defined(HAVE_ATTR_GET)
1547         int retval, flags = 0;
1548         int valuelength = (int)size;
1549         char *attrname = strchr(name,'.') + 1;
1550
1551         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1552
1553         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1554
1555         return retval ? retval : valuelength;
1556 #elif defined(HAVE_ATTROPEN)
1557         ssize_t ret = -1;
1558         int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
1559         if (attrfd >= 0) {
1560                 ret = solaris_read_xattr(attrfd, value, size);
1561                 close(attrfd);
1562         }
1563         return ret;
1564 #else
1565         errno = ENOSYS;
1566         return -1;
1567 #endif
1568 }
1569
1570 ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size)
1571 {
1572 #if defined(HAVE_LGETXATTR)
1573         return lgetxattr(path, name, value, size);
1574 #elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
1575         int options = XATTR_NOFOLLOW;
1576         return getxattr(path, name, value, size, 0, options);
1577 #elif defined(HAVE_LGETEA)
1578         return lgetea(path, name, value, size);
1579 #elif defined(HAVE_EXTATTR_GET_LINK)
1580         char *s;
1581         ssize_t retval;
1582         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1583                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1584         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1585
1586         if((retval=extattr_get_link(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1587                 if(retval > size) {
1588                         errno = ERANGE;
1589                         return -1;
1590                 }
1591                 if((retval=extattr_get_link(path, attrnamespace, attrname, value, size)) >= 0)
1592                         return retval;
1593         }
1594
1595         DEBUG(10,("sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno)));
1596         return -1;
1597 #elif defined(HAVE_ATTR_GET)
1598         int retval, flags = ATTR_DONTFOLLOW;
1599         int valuelength = (int)size;
1600         char *attrname = strchr(name,'.') + 1;
1601
1602         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1603
1604         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1605
1606         return retval ? retval : valuelength;
1607 #elif defined(HAVE_ATTROPEN)
1608         ssize_t ret = -1;
1609         int attrfd = solaris_attropen(path, name, O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1610         if (attrfd >= 0) {
1611                 ret = solaris_read_xattr(attrfd, value, size);
1612                 close(attrfd);
1613         }
1614         return ret;
1615 #else
1616         errno = ENOSYS;
1617         return -1;
1618 #endif
1619 }
1620
1621 ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size)
1622 {
1623 #if defined(HAVE_FGETXATTR)
1624 #ifndef XATTR_ADD_OPT
1625         return fgetxattr(filedes, name, value, size);
1626 #else
1627         int options = 0;
1628         return fgetxattr(filedes, name, value, size, 0, options);
1629 #endif
1630 #elif defined(HAVE_FGETEA)
1631         return fgetea(filedes, name, value, size);
1632 #elif defined(HAVE_EXTATTR_GET_FD)
1633         char *s;
1634         ssize_t retval;
1635         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1636                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1637         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1638
1639         if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
1640                 if(retval > size) {
1641                         errno = ERANGE;
1642                         return -1;
1643                 }
1644                 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
1645                         return retval;
1646         }
1647
1648         DEBUG(10,("sys_fgetxattr: extattr_get_fd() failed with: %s\n", strerror(errno)));
1649         return -1;
1650 #elif defined(HAVE_ATTR_GETF)
1651         int retval, flags = 0;
1652         int valuelength = (int)size;
1653         char *attrname = strchr(name,'.') + 1;
1654
1655         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1656
1657         retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
1658
1659         return retval ? retval : valuelength;
1660 #elif defined(HAVE_ATTROPEN)
1661         ssize_t ret = -1;
1662         int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
1663         if (attrfd >= 0) {
1664                 ret = solaris_read_xattr(attrfd, value, size);
1665                 close(attrfd);
1666         }
1667         return ret;
1668 #else
1669         errno = ENOSYS;
1670         return -1;
1671 #endif
1672 }
1673
1674 #if defined(HAVE_EXTATTR_LIST_FILE)
1675
1676 #define EXTATTR_PREFIX(s)       (s), (sizeof((s))-1)
1677
1678 static struct {
1679         int space;
1680         const char *name;
1681         size_t len;
1682
1683 extattr[] = {
1684         { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
1685         { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
1686 };
1687
1688 typedef union {
1689         const char *path;
1690         int filedes;
1691 } extattr_arg;
1692
1693 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
1694 {
1695         ssize_t list_size, total_size = 0;
1696         int i, t, len;
1697         char *buf;
1698         /* Iterate through extattr(2) namespaces */
1699         for(t = 0; t < (sizeof(extattr)/sizeof(extattr[0])); t++) {
1700                 switch(type) {
1701 #if defined(HAVE_EXTATTR_LIST_FILE)
1702                         case 0:
1703                                 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
1704                                 break;
1705 #endif
1706 #if defined(HAVE_EXTATTR_LIST_LINK)
1707                         case 1:
1708                                 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
1709                                 break;
1710 #endif
1711 #if defined(HAVE_EXTATTR_LIST_FD)
1712                         case 2:
1713                                 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
1714                                 break;
1715 #endif
1716                         default:
1717                                 errno = ENOSYS;
1718                                 return -1;
1719                 }
1720                 /* Some error happend. Errno should be set by the previous call */
1721                 if(list_size < 0)
1722                         return -1;
1723                 /* No attributes */
1724                 if(list_size == 0)
1725                         continue;
1726                 /* XXX: Call with an empty buffer may be used to calculate
1727                    necessary buffer size. Unfortunately, we can't say, how
1728                    many attributes were returned, so here is the potential
1729                    problem with the emulation.
1730                 */
1731                 if(list == NULL) {
1732                         /* Take the worse case of one char attribute names - 
1733                            two bytes per name plus one more for sanity.
1734                         */
1735                         total_size += list_size + (list_size/2 + 1)*extattr[t].len;
1736                         continue;
1737                 }
1738                 /* Count necessary offset to fit namespace prefixes */
1739                 len = 0;
1740                 for(i = 0; i < list_size; i += list[i] + 1)
1741                         len += extattr[t].len;
1742
1743                 total_size += list_size + len;
1744                 /* Buffer is too small to fit the results */
1745                 if(total_size > size) {
1746                         errno = ERANGE;
1747                         return -1;
1748                 }
1749                 /* Shift results back, so we can prepend prefixes */
1750                 buf = memmove(list + len, list, list_size);
1751
1752                 for(i = 0; i < list_size; i += len + 1) {
1753                         len = buf[i];
1754                         strncpy(list, extattr[t].name, extattr[t].len + 1);
1755                         list += extattr[t].len;
1756                         strncpy(list, buf + i + 1, len);
1757                         list[len] = '\0';
1758                         list += len + 1;
1759                 }
1760                 size -= total_size;
1761         }
1762         return total_size;
1763 }
1764
1765 #endif
1766
1767 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1768 static char attr_buffer[ATTR_MAX_VALUELEN];
1769
1770 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
1771 {
1772         int retval = 0, index;
1773         attrlist_cursor_t *cursor = 0;
1774         int total_size = 0;
1775         attrlist_t * al = (attrlist_t *)attr_buffer;
1776         attrlist_ent_t *ae;
1777         size_t ent_size, left = size;
1778         char *bp = list;
1779
1780         while (True) {
1781             if (filedes)
1782                 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1783             else
1784                 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1785             if (retval) break;
1786             for (index = 0; index < al->al_count; index++) {
1787                 ae = ATTR_ENTRY(attr_buffer, index);
1788                 ent_size = strlen(ae->a_name) + sizeof("user.");
1789                 if (left >= ent_size) {
1790                     strncpy(bp, "user.", sizeof("user."));
1791                     strncat(bp, ae->a_name, ent_size - sizeof("user."));
1792                     bp += ent_size;
1793                     left -= ent_size;
1794                 } else if (size) {
1795                     errno = ERANGE;
1796                     retval = -1;
1797                     break;
1798                 }
1799                 total_size += ent_size;
1800             }
1801             if (al->al_more == 0) break;
1802         }
1803         if (retval == 0) {
1804             flags |= ATTR_ROOT;
1805             cursor = 0;
1806             while (True) {
1807                 if (filedes)
1808                     retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1809                 else
1810                     retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1811                 if (retval) break;
1812                 for (index = 0; index < al->al_count; index++) {
1813                     ae = ATTR_ENTRY(attr_buffer, index);
1814                     ent_size = strlen(ae->a_name) + sizeof("system.");
1815                     if (left >= ent_size) {
1816                         strncpy(bp, "system.", sizeof("system."));
1817                         strncat(bp, ae->a_name, ent_size - sizeof("system."));
1818                         bp += ent_size;
1819                         left -= ent_size;
1820                     } else if (size) {
1821                         errno = ERANGE;
1822                         retval = -1;
1823                         break;
1824                     }
1825                     total_size += ent_size;
1826                 }
1827                 if (al->al_more == 0) break;
1828             }
1829         }
1830         return (ssize_t)(retval ? retval : total_size);
1831 }
1832
1833 #endif
1834
1835 ssize_t sys_listxattr (const char *path, char *list, size_t size)
1836 {
1837 #if defined(HAVE_LISTXATTR)
1838 #ifndef XATTR_ADD_OPT
1839         return listxattr(path, list, size);
1840 #else
1841         int options = 0;
1842         return listxattr(path, list, size, options);
1843 #endif
1844 #elif defined(HAVE_LISTEA)
1845         return listea(path, list, size);
1846 #elif defined(HAVE_EXTATTR_LIST_FILE)
1847         extattr_arg arg;
1848         arg.path = path;
1849         return bsd_attr_list(0, arg, list, size);
1850 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1851         return irix_attr_list(path, 0, list, size, 0);
1852 #elif defined(HAVE_ATTROPEN)
1853         ssize_t ret = -1;
1854         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
1855         if (attrdirfd >= 0) {
1856                 ret = solaris_list_xattr(attrdirfd, list, size);
1857                 close(attrdirfd);
1858         }
1859         return ret;
1860 #else
1861         errno = ENOSYS;
1862         return -1;
1863 #endif
1864 }
1865
1866 ssize_t sys_llistxattr (const char *path, char *list, size_t size)
1867 {
1868 #if defined(HAVE_LLISTXATTR)
1869         return llistxattr(path, list, size);
1870 #elif defined(HAVE_LISTXATTR) && defined(XATTR_ADD_OPT)
1871         int options = XATTR_NOFOLLOW;
1872         return listxattr(path, list, size, options);
1873 #elif defined(HAVE_LLISTEA)
1874         return llistea(path, list, size);
1875 #elif defined(HAVE_EXTATTR_LIST_LINK)
1876         extattr_arg arg;
1877         arg.path = path;
1878         return bsd_attr_list(1, arg, list, size);
1879 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1880         return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
1881 #elif defined(HAVE_ATTROPEN)
1882         ssize_t ret = -1;
1883         int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1884         if (attrdirfd >= 0) {
1885                 ret = solaris_list_xattr(attrdirfd, list, size);
1886                 close(attrdirfd);
1887         }
1888         return ret;
1889 #else
1890         errno = ENOSYS;
1891         return -1;
1892 #endif
1893 }
1894
1895 ssize_t sys_flistxattr (int filedes, char *list, size_t size)
1896 {
1897 #if defined(HAVE_FLISTXATTR)
1898 #ifndef XATTR_ADD_OPT
1899         return flistxattr(filedes, list, size);
1900 #else
1901         int options = 0;
1902         return flistxattr(filedes, list, size, options);
1903 #endif
1904 #elif defined(HAVE_FLISTEA)
1905         return flistea(filedes, list, size);
1906 #elif defined(HAVE_EXTATTR_LIST_FD)
1907         extattr_arg arg;
1908         arg.filedes = filedes;
1909         return bsd_attr_list(2, arg, list, size);
1910 #elif defined(HAVE_ATTR_LISTF)
1911         return irix_attr_list(NULL, filedes, list, size, 0);
1912 #elif defined(HAVE_ATTROPEN)
1913         ssize_t ret = -1;
1914         int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
1915         if (attrdirfd >= 0) {
1916                 ret = solaris_list_xattr(attrdirfd, list, size);
1917                 close(attrdirfd);
1918         }
1919         return ret;
1920 #else
1921         errno = ENOSYS;
1922         return -1;
1923 #endif
1924 }
1925
1926 int sys_removexattr (const char *path, const char *name)
1927 {
1928 #if defined(HAVE_REMOVEXATTR)
1929 #ifndef XATTR_ADD_OPT
1930         return removexattr(path, name);
1931 #else
1932         int options = 0;
1933         return removexattr(path, name, options);
1934 #endif
1935 #elif defined(HAVE_REMOVEEA)
1936         return removeea(path, name);
1937 #elif defined(HAVE_EXTATTR_DELETE_FILE)
1938         char *s;
1939         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1940                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1941         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1942
1943         return extattr_delete_file(path, attrnamespace, attrname);
1944 #elif defined(HAVE_ATTR_REMOVE)
1945         int flags = 0;
1946         char *attrname = strchr(name,'.') + 1;
1947
1948         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1949
1950         return attr_remove(path, attrname, flags);
1951 #elif defined(HAVE_ATTROPEN)
1952         int ret = -1;
1953         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
1954         if (attrdirfd >= 0) {
1955                 ret = solaris_unlinkat(attrdirfd, name);
1956                 close(attrdirfd);
1957         }
1958         return ret;
1959 #else
1960         errno = ENOSYS;
1961         return -1;
1962 #endif
1963 }
1964
1965 int sys_lremovexattr (const char *path, const char *name)
1966 {
1967 #if defined(HAVE_LREMOVEXATTR)
1968         return lremovexattr(path, name);
1969 #elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
1970         int options = XATTR_NOFOLLOW;
1971         return removexattr(path, name, options);
1972 #elif defined(HAVE_LREMOVEEA)
1973         return lremoveea(path, name);
1974 #elif defined(HAVE_EXTATTR_DELETE_LINK)
1975         char *s;
1976         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1977                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1978         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1979
1980         return extattr_delete_link(path, attrnamespace, attrname);
1981 #elif defined(HAVE_ATTR_REMOVE)
1982         int flags = ATTR_DONTFOLLOW;
1983         char *attrname = strchr(name,'.') + 1;
1984
1985         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1986
1987         return attr_remove(path, attrname, flags);
1988 #elif defined(HAVE_ATTROPEN)
1989         int ret = -1;
1990         int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1991         if (attrdirfd >= 0) {
1992                 ret = solaris_unlinkat(attrdirfd, name);
1993                 close(attrdirfd);
1994         }
1995         return ret;
1996 #else
1997         errno = ENOSYS;
1998         return -1;
1999 #endif
2000 }
2001
2002 int sys_fremovexattr (int filedes, const char *name)
2003 {
2004 #if defined(HAVE_FREMOVEXATTR)
2005 #ifndef XATTR_ADD_OPT
2006         return fremovexattr(filedes, name);
2007 #else
2008         int options = 0;
2009         return fremovexattr(filedes, name, options);
2010 #endif
2011 #elif defined(HAVE_FREMOVEEA)
2012         return fremoveea(filedes, name);
2013 #elif defined(HAVE_EXTATTR_DELETE_FD)
2014         char *s;
2015         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2016                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2017         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2018
2019         return extattr_delete_fd(filedes, attrnamespace, attrname);
2020 #elif defined(HAVE_ATTR_REMOVEF)
2021         int flags = 0;
2022         char *attrname = strchr(name,'.') + 1;
2023
2024         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
2025
2026         return attr_removef(filedes, attrname, flags);
2027 #elif defined(HAVE_ATTROPEN)
2028         int ret = -1;
2029         int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
2030         if (attrdirfd >= 0) {
2031                 ret = solaris_unlinkat(attrdirfd, name);
2032                 close(attrdirfd);
2033         }
2034         return ret;
2035 #else
2036         errno = ENOSYS;
2037         return -1;
2038 #endif
2039 }
2040
2041 int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
2042 {
2043 #if defined(HAVE_SETXATTR)
2044 #ifndef XATTR_ADD_OPT
2045         return setxattr(path, name, value, size, flags);
2046 #else
2047         int options = 0;
2048         return setxattr(path, name, value, size, 0, options);
2049 #endif
2050 #elif defined(HAVE_SETEA)
2051         return setea(path, name, value, size, flags);
2052 #elif defined(HAVE_EXTATTR_SET_FILE)
2053         char *s;
2054         int retval = 0;
2055         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2056                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2057         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2058         if (flags) {
2059                 /* Check attribute existence */
2060                 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
2061                 if (retval < 0) {
2062                         /* REPLACE attribute, that doesn't exist */
2063                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
2064                                 errno = ENOATTR;
2065                                 return -1;
2066                         }
2067                         /* Ignore other errors */
2068                 }
2069                 else {
2070                         /* CREATE attribute, that already exists */
2071                         if (flags & XATTR_CREATE) {
2072                                 errno = EEXIST;
2073                                 return -1;
2074                         }
2075                 }
2076         }
2077         retval = extattr_set_file(path, attrnamespace, attrname, value, size);
2078         return (retval < 0) ? -1 : 0;
2079 #elif defined(HAVE_ATTR_SET)
2080         int myflags = 0;
2081         char *attrname = strchr(name,'.') + 1;
2082
2083         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2084         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2085         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2086
2087         return attr_set(path, attrname, (const char *)value, size, myflags);
2088 #elif defined(HAVE_ATTROPEN)
2089         int ret = -1;
2090         int myflags = O_RDWR;
2091         int attrfd;
2092         if (flags & XATTR_CREATE) myflags |= O_EXCL;
2093         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2094         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2095         if (attrfd >= 0) {
2096                 ret = solaris_write_xattr(attrfd, value, size);
2097                 close(attrfd);
2098         }
2099         return ret;
2100 #else
2101         errno = ENOSYS;
2102         return -1;
2103 #endif
2104 }
2105
2106 int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags)
2107 {
2108 #if defined(HAVE_LSETXATTR)
2109         return lsetxattr(path, name, value, size, flags);
2110 #elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
2111         int options = XATTR_NOFOLLOW;
2112         return setxattr(path, name, value, size, 0, options);
2113 #elif defined(LSETEA)
2114         return lsetea(path, name, value, size, flags);
2115 #elif defined(HAVE_EXTATTR_SET_LINK)
2116         char *s;
2117         int retval = 0;
2118         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2119                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2120         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2121         if (flags) {
2122                 /* Check attribute existence */
2123                 retval = extattr_get_link(path, attrnamespace, attrname, NULL, 0);
2124                 if (retval < 0) {
2125                         /* REPLACE attribute, that doesn't exist */
2126                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
2127                                 errno = ENOATTR;
2128                                 return -1;
2129                         }
2130                         /* Ignore other errors */
2131                 }
2132                 else {
2133                         /* CREATE attribute, that already exists */
2134                         if (flags & XATTR_CREATE) {
2135                                 errno = EEXIST;
2136                                 return -1;
2137                         }
2138                 }
2139         }
2140
2141         retval = extattr_set_link(path, attrnamespace, attrname, value, size);
2142         return (retval < 0) ? -1 : 0;
2143 #elif defined(HAVE_ATTR_SET)
2144         int myflags = ATTR_DONTFOLLOW;
2145         char *attrname = strchr(name,'.') + 1;
2146
2147         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2148         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2149         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2150
2151         return attr_set(path, attrname, (const char *)value, size, myflags);
2152 #elif defined(HAVE_ATTROPEN)
2153         int ret = -1;
2154         int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW;
2155         int attrfd;
2156         if (flags & XATTR_CREATE) myflags |= O_EXCL;
2157         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2158         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2159         if (attrfd >= 0) {
2160                 ret = solaris_write_xattr(attrfd, value, size);
2161                 close(attrfd);
2162         }
2163         return ret;
2164 #else
2165         errno = ENOSYS;
2166         return -1;
2167 #endif
2168 }
2169
2170 int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
2171 {
2172 #if defined(HAVE_FSETXATTR)
2173 #ifndef XATTR_ADD_OPT
2174         return fsetxattr(filedes, name, value, size, flags);
2175 #else
2176         int options = 0;
2177         return fsetxattr(filedes, name, value, size, 0, options);
2178 #endif
2179 #elif defined(HAVE_FSETEA)
2180         return fsetea(filedes, name, value, size, flags);
2181 #elif defined(HAVE_EXTATTR_SET_FD)
2182         char *s;
2183         int retval = 0;
2184         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2185                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2186         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2187         if (flags) {
2188                 /* Check attribute existence */
2189                 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
2190                 if (retval < 0) {
2191                         /* REPLACE attribute, that doesn't exist */
2192                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
2193                                 errno = ENOATTR;
2194                                 return -1;
2195                         }
2196                         /* Ignore other errors */
2197                 }
2198                 else {
2199                         /* CREATE attribute, that already exists */
2200                         if (flags & XATTR_CREATE) {
2201                                 errno = EEXIST;
2202                                 return -1;
2203                         }
2204                 }
2205         }
2206         retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
2207         return (retval < 0) ? -1 : 0;
2208 #elif defined(HAVE_ATTR_SETF)
2209         int myflags = 0;
2210         char *attrname = strchr(name,'.') + 1;
2211
2212         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2213         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2214         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2215
2216         return attr_setf(filedes, attrname, (const char *)value, size, myflags);
2217 #elif defined(HAVE_ATTROPEN)
2218         int ret = -1;
2219         int myflags = O_RDWR | O_XATTR;
2220         int attrfd;
2221         if (flags & XATTR_CREATE) myflags |= O_EXCL;
2222         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2223         attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2224         if (attrfd >= 0) {
2225                 ret = solaris_write_xattr(attrfd, value, size);
2226                 close(attrfd);
2227         }
2228         return ret;
2229 #else
2230         errno = ENOSYS;
2231         return -1;
2232 #endif
2233 }
2234
2235 /**************************************************************************
2236  helper functions for Solaris' EA support
2237 ****************************************************************************/
2238 #ifdef HAVE_ATTROPEN
2239 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
2240 {
2241         struct stat sbuf;
2242
2243         if (fstat(attrfd, &sbuf) == -1) {
2244                 errno = ENOATTR;
2245                 return -1;
2246         }
2247
2248         /* This is to return the current size of the named extended attribute */
2249         if (size == 0) {
2250                 return sbuf.st_size;
2251         }
2252
2253         /* check size and read xattr */
2254         if (sbuf.st_size > size) {
2255                 errno = ERANGE;
2256                 return -1;
2257         }
2258
2259         return read(attrfd, value, sbuf.st_size);
2260 }
2261
2262 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
2263 {
2264         ssize_t len = 0;
2265         DIR *dirp;
2266         struct dirent *de;
2267         int newfd = dup(attrdirfd);
2268         /* CAUTION: The originating file descriptor should not be
2269                     used again following the call to fdopendir().
2270                     For that reason we dup() the file descriptor
2271                     here to make things more clear. */
2272         dirp = fdopendir(newfd);
2273
2274         while ((de = readdir(dirp))) {
2275                 size_t listlen = strlen(de->d_name);
2276                 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
2277                         /* we don't want "." and ".." here: */
2278                         DEBUG(10,("skipped EA %s\n",de->d_name));
2279                         continue;
2280                 }
2281
2282                 if (size == 0) {
2283                         /* return the current size of the list of extended attribute names*/
2284                         len += listlen + 1;
2285                 } else {
2286                         /* check size and copy entrieÑ• + nul into list. */
2287                         if ((len + listlen + 1) > size) {
2288                                 errno = ERANGE;
2289                                 len = -1;
2290                                 break;
2291                         } else {
2292                                 safe_strcpy(list + len, de->d_name, listlen);
2293                                 len += listlen;
2294                                 list[len] = '\0';
2295                                 ++len;
2296                         }
2297                 }
2298         }
2299
2300         if (closedir(dirp) == -1) {
2301                 DEBUG(0,("closedir dirp failed: %s\n",strerror(errno)));
2302                 return -1;
2303         }
2304         return len;
2305 }
2306
2307 static int solaris_unlinkat(int attrdirfd, const char *name)
2308 {
2309         if (unlinkat(attrdirfd, name, 0) == -1) {
2310                 if (errno == ENOENT) {
2311                         errno = ENOATTR;
2312                 }
2313                 return -1;
2314         }
2315         return 0;
2316 }
2317
2318 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
2319 {
2320         int filedes = attropen(path, attrpath, oflag, mode);
2321         if (filedes == -1) {
2322                 DEBUG(10,("attropen FAILED: path: %s, name: %s, errno: %s\n",path,attrpath,strerror(errno)));
2323                 if (errno == EINVAL) {
2324                         errno = ENOTSUP;
2325                 } else {
2326                         errno = ENOATTR;
2327                 }
2328         }
2329         return filedes;
2330 }
2331
2332 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
2333 {
2334         int filedes = openat(fildes, path, oflag, mode);
2335         if (filedes == -1) {
2336                 DEBUG(10,("openat FAILED: fd: %d, path: %s, errno: %s\n",filedes,path,strerror(errno)));
2337                 if (errno == EINVAL) {
2338                         errno = ENOTSUP;
2339                 } else {
2340                         errno = ENOATTR;
2341                 }
2342         }
2343         return filedes;
2344 }
2345
2346 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
2347 {
2348         if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
2349                 return 0;
2350         } else {
2351                 DEBUG(10,("solaris_write_xattr FAILED!\n"));
2352                 return -1;
2353         }
2354 }
2355 #endif /*HAVE_ATTROPEN*/
2356
2357
2358 /****************************************************************************
2359  Return the major devicenumber for UNIX extensions.
2360 ****************************************************************************/
2361
2362 uint32 unix_dev_major(SMB_DEV_T dev)
2363 {
2364 #if defined(HAVE_DEVICE_MAJOR_FN)
2365         return (uint32)major(dev);
2366 #else
2367         return (uint32)(dev >> 8);
2368 #endif
2369 }
2370
2371 /****************************************************************************
2372  Return the minor devicenumber for UNIX extensions.
2373 ****************************************************************************/
2374
2375 uint32 unix_dev_minor(SMB_DEV_T dev)
2376 {
2377 #if defined(HAVE_DEVICE_MINOR_FN)
2378         return (uint32)minor(dev);
2379 #else
2380         return (uint32)(dev & 0xff);
2381 #endif
2382 }
2383
2384 #if defined(WITH_AIO)
2385
2386 /*******************************************************************
2387  An aio_read wrapper that will deal with 64-bit sizes.
2388 ********************************************************************/
2389
2390 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2391 {
2392 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_READ64)
2393         return aio_read64(aiocb);
2394 #elif defined(HAVE_AIO_READ)
2395         return aio_read(aiocb);
2396 #else
2397         errno = ENOSYS;
2398         return -1;
2399 #endif
2400 }
2401
2402 /*******************************************************************
2403  An aio_write wrapper that will deal with 64-bit sizes.
2404 ********************************************************************/
2405
2406 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2407 {
2408 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_WRITE64)
2409         return aio_write64(aiocb);
2410 #elif defined(HAVE_AIO_WRITE)
2411         return aio_write(aiocb);
2412 #else
2413         errno = ENOSYS;
2414         return -1;
2415 #endif
2416 }
2417
2418 /*******************************************************************
2419  An aio_return wrapper that will deal with 64-bit sizes.
2420 ********************************************************************/
2421
2422 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2423 {
2424 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_RETURN64)
2425         return aio_return64(aiocb);
2426 #elif defined(HAVE_AIO_RETURN)
2427         return aio_return(aiocb);
2428 #else
2429         errno = ENOSYS;
2430         return -1;
2431 #endif
2432 }
2433
2434 /*******************************************************************
2435  An aio_cancel wrapper that will deal with 64-bit sizes.
2436 ********************************************************************/
2437
2438 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2439 {
2440 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_CANCEL64)
2441         return aio_cancel64(fd, aiocb);
2442 #elif defined(HAVE_AIO_CANCEL)
2443         return aio_cancel(fd, aiocb);
2444 #else
2445         errno = ENOSYS;
2446         return -1;
2447 #endif
2448 }
2449
2450 /*******************************************************************
2451  An aio_error wrapper that will deal with 64-bit sizes.
2452 ********************************************************************/
2453
2454 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2455 {
2456 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_ERROR64)
2457         return aio_error64(aiocb);
2458 #elif defined(HAVE_AIO_ERROR)
2459         return aio_error(aiocb);
2460 #else
2461         errno = ENOSYS;
2462         return -1;
2463 #endif
2464 }
2465
2466 /*******************************************************************
2467  An aio_fsync wrapper that will deal with 64-bit sizes.
2468 ********************************************************************/
2469
2470 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2471 {
2472 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_FSYNC64)
2473         return aio_fsync64(op, aiocb);
2474 #elif defined(HAVE_AIO_FSYNC)
2475         return aio_fsync(op, aiocb);
2476 #else
2477         errno = ENOSYS;
2478         return -1;
2479 #endif
2480 }
2481
2482 /*******************************************************************
2483  An aio_fsync wrapper that will deal with 64-bit sizes.
2484 ********************************************************************/
2485
2486 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2487 {
2488 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_SUSPEND64)
2489         return aio_suspend64(cblist, n, timeout);
2490 #elif defined(HAVE_AIO_FSYNC)
2491         return aio_suspend(cblist, n, timeout);
2492 #else
2493         errno = ENOSYS;
2494         return -1;
2495 #endif
2496 }
2497 #else /* !WITH_AIO */
2498
2499 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2500 {
2501         errno = ENOSYS;
2502         return -1;
2503 }
2504
2505 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2506 {
2507         errno = ENOSYS;
2508         return -1;
2509 }
2510
2511 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2512 {
2513         errno = ENOSYS;
2514         return -1;
2515 }
2516
2517 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2518 {
2519         errno = ENOSYS;
2520         return -1;
2521 }
2522
2523 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2524 {
2525         errno = ENOSYS;
2526         return -1;
2527 }
2528
2529 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2530 {
2531         errno = ENOSYS;
2532         return -1;
2533 }
2534
2535 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2536 {
2537         errno = ENOSYS;
2538         return -1;
2539 }
2540 #endif /* WITH_AIO */
2541
2542 int sys_getpeereid( int s, uid_t *uid)
2543 {
2544 #if defined(HAVE_PEERCRED)
2545         struct ucred cred;
2546         socklen_t cred_len = sizeof(struct ucred);
2547         int ret;
2548
2549         ret = getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &cred_len);
2550         if (ret != 0) {
2551                 return -1;
2552         }
2553
2554         if (cred_len != sizeof(struct ucred)) {
2555                 errno = EINVAL;
2556                 return -1;
2557         }
2558
2559         *uid = cred.uid;
2560         return 0;
2561 #else
2562         errno = ENOSYS;
2563         return -1;
2564 #endif
2565 }
2566
2567 int sys_getnameinfo(const struct sockaddr *psa,
2568                         socklen_t salen,
2569                         char *host,
2570                         size_t hostlen,
2571                         char *service,
2572                         size_t servlen,
2573                         int flags)
2574 {
2575         /*
2576          * For Solaris we must make sure salen is the
2577          * correct length for the incoming sa_family.
2578          */
2579
2580         if (salen == sizeof(struct sockaddr_storage)) {
2581                 salen = sizeof(struct sockaddr_in);
2582 #if defined(HAVE_IPV6)
2583                 if (psa->sa_family == AF_INET6) {
2584                         salen = sizeof(struct sockaddr_in6);
2585                 }
2586 #endif
2587         }
2588         return getnameinfo(psa, salen, host, hostlen, service, servlen, flags);
2589 }
2590
2591 int sys_connect(int fd, const struct sockaddr * addr)
2592 {
2593         socklen_t salen = -1;
2594
2595         if (addr->sa_family == AF_INET) {
2596             salen = sizeof(struct sockaddr_in);
2597         } else if (addr->sa_family == AF_UNIX) {
2598             salen = sizeof(struct sockaddr_un);
2599         }
2600 #if defined(HAVE_IPV6)
2601         else if (addr->sa_family == AF_INET6) {
2602             salen = sizeof(struct sockaddr_in6);
2603         }
2604 #endif
2605
2606         return connect(fd, addr, salen);
2607 }