Add dependency of bin/smbfilter to libwbclient.
[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 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
516 static void init_stat_ex_from_stat (struct stat_ex *dst,
517                                     const struct stat64 *src,
518                                     bool fake_dir_create_times)
519 #else
520 static void init_stat_ex_from_stat (struct stat_ex *dst,
521                                     const struct stat *src,
522                                     bool fake_dir_create_times)
523 #endif
524 {
525         dst->st_ex_dev = src->st_dev;
526         dst->st_ex_ino = src->st_ino;
527         dst->st_ex_mode = src->st_mode;
528         dst->st_ex_nlink = src->st_nlink;
529         dst->st_ex_uid = src->st_uid;
530         dst->st_ex_gid = src->st_gid;
531         dst->st_ex_rdev = src->st_rdev;
532         dst->st_ex_size = src->st_size;
533         dst->st_ex_atime = get_atimespec(src);
534         dst->st_ex_mtime = get_mtimespec(src);
535         dst->st_ex_ctime = get_ctimespec(src);
536         make_create_timespec(src, dst, fake_dir_create_times);
537         dst->st_ex_blksize = src->st_blksize;
538         dst->st_ex_blocks = src->st_blocks;
539
540 #ifdef HAVE_STAT_ST_FLAGS
541         dst->st_ex_flags = src->st_flags;
542 #else
543         dst->st_ex_flags = 0;
544 #endif
545 }
546
547 /*******************************************************************
548 A stat() wrapper that will deal with 64 bit filesizes.
549 ********************************************************************/
550
551 int sys_stat(const char *fname, SMB_STRUCT_STAT *sbuf,
552              bool fake_dir_create_times)
553 {
554         int ret;
555 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
556         struct stat64 statbuf;
557         ret = stat64(fname, &statbuf);
558 #else
559         struct stat statbuf;
560         ret = stat(fname, &statbuf);
561 #endif
562         if (ret == 0) {
563                 /* we always want directories to appear zero size */
564                 if (S_ISDIR(statbuf.st_mode)) {
565                         statbuf.st_size = 0;
566                 }
567                 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
568         }
569         return ret;
570 }
571
572 /*******************************************************************
573  An fstat() wrapper that will deal with 64 bit filesizes.
574 ********************************************************************/
575
576 int sys_fstat(int fd, SMB_STRUCT_STAT *sbuf, bool fake_dir_create_times)
577 {
578         int ret;
579 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
580         struct stat64 statbuf;
581         ret = fstat64(fd, &statbuf);
582 #else
583         struct stat statbuf;
584         ret = fstat(fd, &statbuf);
585 #endif
586         if (ret == 0) {
587                 /* we always want directories to appear zero size */
588                 if (S_ISDIR(statbuf.st_mode)) {
589                         statbuf.st_size = 0;
590                 }
591                 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
592         }
593         return ret;
594 }
595
596 /*******************************************************************
597  An lstat() wrapper that will deal with 64 bit filesizes.
598 ********************************************************************/
599
600 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf,
601               bool fake_dir_create_times)
602 {
603         int ret;
604 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
605         struct stat64 statbuf;
606         ret = lstat64(fname, &statbuf);
607 #else
608         struct stat statbuf;
609         ret = lstat(fname, &statbuf);
610 #endif
611         if (ret == 0) {
612                 /* we always want directories to appear zero size */
613                 if (S_ISDIR(statbuf.st_mode)) {
614                         statbuf.st_size = 0;
615                 }
616                 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
617         }
618         return ret;
619 }
620
621 /*******************************************************************
622  An posix_fallocate() wrapper that will deal with 64 bit filesizes.
623 ********************************************************************/
624 int sys_posix_fallocate(int fd, SMB_OFF_T offset, SMB_OFF_T len)
625 {
626 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_POSIX_FALLOCATE64) && !defined(HAVE_BROKEN_POSIX_FALLOCATE)
627         return posix_fallocate64(fd, offset, len);
628 #elif defined(HAVE_POSIX_FALLOCATE) && !defined(HAVE_BROKEN_POSIX_FALLOCATE)
629         return posix_fallocate(fd, offset, len);
630 #else
631         return ENOSYS;
632 #endif
633 }
634
635 /*******************************************************************
636  An ftruncate() wrapper that will deal with 64 bit filesizes.
637 ********************************************************************/
638
639 int sys_ftruncate(int fd, SMB_OFF_T offset)
640 {
641 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
642         return ftruncate64(fd, offset);
643 #else
644         return ftruncate(fd, offset);
645 #endif
646 }
647
648 /*******************************************************************
649  An lseek() wrapper that will deal with 64 bit filesizes.
650 ********************************************************************/
651
652 SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
653 {
654 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
655         return lseek64(fd, offset, whence);
656 #else
657         return lseek(fd, offset, whence);
658 #endif
659 }
660
661 /*******************************************************************
662  An fseek() wrapper that will deal with 64 bit filesizes.
663 ********************************************************************/
664
665 int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence)
666 {
667 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64)
668         return fseek64(fp, offset, whence);
669 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEKO64)
670         return fseeko64(fp, offset, whence);
671 #else
672         return fseek(fp, offset, whence);
673 #endif
674 }
675
676 /*******************************************************************
677  An ftell() wrapper that will deal with 64 bit filesizes.
678 ********************************************************************/
679
680 SMB_OFF_T sys_ftell(FILE *fp)
681 {
682 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64)
683         return (SMB_OFF_T)ftell64(fp);
684 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELLO64)
685         return (SMB_OFF_T)ftello64(fp);
686 #else
687         return (SMB_OFF_T)ftell(fp);
688 #endif
689 }
690
691 /*******************************************************************
692  A creat() wrapper that will deal with 64 bit filesizes.
693 ********************************************************************/
694
695 int sys_creat(const char *path, mode_t mode)
696 {
697 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CREAT64)
698         return creat64(path, mode);
699 #else
700         /*
701          * If creat64 isn't defined then ensure we call a potential open64.
702          * JRA.
703          */
704         return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
705 #endif
706 }
707
708 /*******************************************************************
709  An open() wrapper that will deal with 64 bit filesizes.
710 ********************************************************************/
711
712 int sys_open(const char *path, int oflag, mode_t mode)
713 {
714 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPEN64)
715         return open64(path, oflag, mode);
716 #else
717         return open(path, oflag, mode);
718 #endif
719 }
720
721 /*******************************************************************
722  An fopen() wrapper that will deal with 64 bit filesizes.
723 ********************************************************************/
724
725 FILE *sys_fopen(const char *path, const char *type)
726 {
727 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_FOPEN64)
728         return fopen64(path, type);
729 #else
730         return fopen(path, type);
731 #endif
732 }
733
734
735 /*******************************************************************
736  A flock() wrapper that will perform the kernel flock.
737 ********************************************************************/
738
739 void kernel_flock(int fd, uint32 share_mode, uint32 access_mask)
740 {
741 #if HAVE_KERNEL_SHARE_MODES
742         int kernel_mode = 0;
743         if (share_mode == FILE_SHARE_WRITE) {
744                 kernel_mode = LOCK_MAND|LOCK_WRITE;
745         } else if (share_mode == FILE_SHARE_READ) {
746                 kernel_mode = LOCK_MAND|LOCK_READ;
747         } else if (share_mode == FILE_SHARE_NONE) {
748                 kernel_mode = LOCK_MAND;
749         }
750         if (kernel_mode) {
751                 flock(fd, kernel_mode);
752         }
753 #endif
754         ;
755 }
756
757
758
759 /*******************************************************************
760  An opendir wrapper that will deal with 64 bit filesizes.
761 ********************************************************************/
762
763 SMB_STRUCT_DIR *sys_opendir(const char *name)
764 {
765 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPENDIR64)
766         return opendir64(name);
767 #else
768         return opendir(name);
769 #endif
770 }
771
772 /*******************************************************************
773  A readdir wrapper that will deal with 64 bit filesizes.
774 ********************************************************************/
775
776 SMB_STRUCT_DIRENT *sys_readdir(SMB_STRUCT_DIR *dirp)
777 {
778 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
779         return readdir64(dirp);
780 #else
781         return readdir(dirp);
782 #endif
783 }
784
785 /*******************************************************************
786  A seekdir wrapper that will deal with 64 bit filesizes.
787 ********************************************************************/
788
789 void sys_seekdir(SMB_STRUCT_DIR *dirp, long offset)
790 {
791 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_SEEKDIR64)
792         seekdir64(dirp, offset);
793 #else
794         seekdir(dirp, offset);
795 #endif
796 }
797
798 /*******************************************************************
799  A telldir wrapper that will deal with 64 bit filesizes.
800 ********************************************************************/
801
802 long sys_telldir(SMB_STRUCT_DIR *dirp)
803 {
804 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_TELLDIR64)
805         return (long)telldir64(dirp);
806 #else
807         return (long)telldir(dirp);
808 #endif
809 }
810
811 /*******************************************************************
812  A rewinddir wrapper that will deal with 64 bit filesizes.
813 ********************************************************************/
814
815 void sys_rewinddir(SMB_STRUCT_DIR *dirp)
816 {
817 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_REWINDDIR64)
818         rewinddir64(dirp);
819 #else
820         rewinddir(dirp);
821 #endif
822 }
823
824 /*******************************************************************
825  A close wrapper that will deal with 64 bit filesizes.
826 ********************************************************************/
827
828 int sys_closedir(SMB_STRUCT_DIR *dirp)
829 {
830 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CLOSEDIR64)
831         return closedir64(dirp);
832 #else
833         return closedir(dirp);
834 #endif
835 }
836
837 /*******************************************************************
838  An mknod() wrapper that will deal with 64 bit filesizes.
839 ********************************************************************/
840
841 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
842 {
843 #if defined(HAVE_MKNOD) || defined(HAVE_MKNOD64)
844 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_MKNOD64) && defined(HAVE_DEV64_T)
845         return mknod64(path, mode, dev);
846 #else
847         return mknod(path, mode, dev);
848 #endif
849 #else
850         /* No mknod system call. */
851         errno = ENOSYS;
852         return -1;
853 #endif
854 }
855
856 /*******************************************************************
857 The wait() calls vary between systems
858 ********************************************************************/
859
860 int sys_waitpid(pid_t pid,int *status,int options)
861 {
862 #ifdef HAVE_WAITPID
863         return waitpid(pid,status,options);
864 #else /* HAVE_WAITPID */
865         return wait4(pid, status, options, NULL);
866 #endif /* HAVE_WAITPID */
867 }
868
869 /*******************************************************************
870  System wrapper for getwd
871 ********************************************************************/
872
873 char *sys_getwd(char *s)
874 {
875         char *wd;
876 #ifdef HAVE_GETCWD
877         wd = (char *)getcwd(s, PATH_MAX);
878 #else
879         wd = (char *)getwd(s);
880 #endif
881         return wd;
882 }
883
884 #if defined(HAVE_POSIX_CAPABILITIES)
885
886 /**************************************************************************
887  Try and abstract process capabilities (for systems that have them).
888 ****************************************************************************/
889
890 /* Set the POSIX capabilities needed for the given purpose into the effective
891  * capability set of the current process. Make sure they are always removed
892  * from the inheritable set, because there is no circumstance in which our
893  * children should inherit our elevated privileges.
894  */
895 static bool set_process_capability(enum smbd_capability capability,
896                                    bool enable)
897 {
898         cap_value_t cap_vals[2] = {0};
899         int num_cap_vals = 0;
900
901         cap_t cap;
902
903 #if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
904         /* On Linux, make sure that any capabilities we grab are sticky
905          * across UID changes. We expect that this would allow us to keep both
906          * the effective and permitted capability sets, but as of circa 2.6.16,
907          * only the permitted set is kept. It is a bug (which we work around)
908          * that the effective set is lost, but we still require the effective
909          * set to be kept.
910          */
911         if (!prctl(PR_GET_KEEPCAPS)) {
912                 prctl(PR_SET_KEEPCAPS, 1);
913         }
914 #endif
915
916         cap = cap_get_proc();
917         if (cap == NULL) {
918                 DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
919                         strerror(errno)));
920                 return False;
921         }
922
923         switch (capability) {
924                 case KERNEL_OPLOCK_CAPABILITY:
925 #ifdef CAP_NETWORK_MGT
926                         /* IRIX has CAP_NETWORK_MGT for oplocks. */
927                         cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
928 #endif
929                         break;
930                 case DMAPI_ACCESS_CAPABILITY:
931 #ifdef CAP_DEVICE_MGT
932                         /* IRIX has CAP_DEVICE_MGT for DMAPI access. */
933                         cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
934 #elif CAP_MKNOD
935                         /* Linux has CAP_MKNOD for DMAPI access. */
936                         cap_vals[num_cap_vals++] = CAP_MKNOD;
937 #endif
938                         break;
939                 case LEASE_CAPABILITY:
940 #ifdef CAP_LEASE
941                         cap_vals[num_cap_vals++] = CAP_LEASE;
942 #endif
943                         break;
944         }
945
946         SMB_ASSERT(num_cap_vals <= ARRAY_SIZE(cap_vals));
947
948         if (num_cap_vals == 0) {
949                 cap_free(cap);
950                 return True;
951         }
952
953         cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
954                 enable ? CAP_SET : CAP_CLEAR);
955
956         /* We never want to pass capabilities down to our children, so make
957          * sure they are not inherited.
958          */
959         cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
960
961         if (cap_set_proc(cap) == -1) {
962                 DEBUG(0, ("set_process_capability: cap_set_proc failed: %s\n",
963                         strerror(errno)));
964                 cap_free(cap);
965                 return False;
966         }
967
968         cap_free(cap);
969         return True;
970 }
971
972 #endif /* HAVE_POSIX_CAPABILITIES */
973
974 /****************************************************************************
975  Gain the oplock capability from the kernel if possible.
976 ****************************************************************************/
977
978 void set_effective_capability(enum smbd_capability capability)
979 {
980 #if defined(HAVE_POSIX_CAPABILITIES)
981         set_process_capability(capability, True);
982 #endif /* HAVE_POSIX_CAPABILITIES */
983 }
984
985 void drop_effective_capability(enum smbd_capability capability)
986 {
987 #if defined(HAVE_POSIX_CAPABILITIES)
988         set_process_capability(capability, False);
989 #endif /* HAVE_POSIX_CAPABILITIES */
990 }
991
992 /**************************************************************************
993  Wrapper for random().
994 ****************************************************************************/
995
996 long sys_random(void)
997 {
998 #if defined(HAVE_RANDOM)
999         return (long)random();
1000 #elif defined(HAVE_RAND)
1001         return (long)rand();
1002 #else
1003         DEBUG(0,("Error - no random function available !\n"));
1004         exit(1);
1005 #endif
1006 }
1007
1008 /**************************************************************************
1009  Wrapper for srandom().
1010 ****************************************************************************/
1011
1012 void sys_srandom(unsigned int seed)
1013 {
1014 #if defined(HAVE_SRANDOM)
1015         srandom(seed);
1016 #elif defined(HAVE_SRAND)
1017         srand(seed);
1018 #else
1019         DEBUG(0,("Error - no srandom function available !\n"));
1020         exit(1);
1021 #endif
1022 }
1023
1024 /**************************************************************************
1025  Returns equivalent to NGROUPS_MAX - using sysconf if needed.
1026 ****************************************************************************/
1027
1028 int groups_max(void)
1029 {
1030 #if defined(SYSCONF_SC_NGROUPS_MAX)
1031         int ret = sysconf(_SC_NGROUPS_MAX);
1032         return (ret == -1) ? NGROUPS_MAX : ret;
1033 #else
1034         return NGROUPS_MAX;
1035 #endif
1036 }
1037
1038 /**************************************************************************
1039  Wrap setgroups and getgroups for systems that declare getgroups() as
1040  returning an array of gid_t, but actuall return an array of int.
1041 ****************************************************************************/
1042
1043 #if defined(HAVE_BROKEN_GETGROUPS)
1044 static int sys_broken_getgroups(int setlen, gid_t *gidset)
1045 {
1046         GID_T gid;
1047         GID_T *group_list;
1048         int i, ngroups;
1049
1050         if(setlen == 0) {
1051                 return getgroups(setlen, &gid);
1052         }
1053
1054         /*
1055          * Broken case. We need to allocate a
1056          * GID_T array of size setlen.
1057          */
1058
1059         if(setlen < 0) {
1060                 errno = EINVAL; 
1061                 return -1;
1062         } 
1063
1064         if (setlen == 0)
1065                 setlen = groups_max();
1066
1067         if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
1068                 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
1069                 return -1;
1070         }
1071
1072         if((ngroups = getgroups(setlen, group_list)) < 0) {
1073                 int saved_errno = errno;
1074                 SAFE_FREE(group_list);
1075                 errno = saved_errno;
1076                 return -1;
1077         }
1078
1079         for(i = 0; i < ngroups; i++)
1080                 gidset[i] = (gid_t)group_list[i];
1081
1082         SAFE_FREE(group_list);
1083         return ngroups;
1084 }
1085
1086 static int sys_broken_setgroups(int setlen, gid_t *gidset)
1087 {
1088         GID_T *group_list;
1089         int i ; 
1090
1091         if (setlen == 0)
1092                 return 0 ;
1093
1094         if (setlen < 0 || setlen > groups_max()) {
1095                 errno = EINVAL; 
1096                 return -1;   
1097         }
1098
1099         /*
1100          * Broken case. We need to allocate a
1101          * GID_T array of size setlen.
1102          */
1103
1104         if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
1105                 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
1106                 return -1;    
1107         }
1108
1109         for(i = 0; i < setlen; i++) 
1110                 group_list[i] = (GID_T) gidset[i]; 
1111
1112         if(setgroups(setlen, group_list) != 0) {
1113                 int saved_errno = errno;
1114                 SAFE_FREE(group_list);
1115                 errno = saved_errno;
1116                 return -1;
1117         }
1118
1119         SAFE_FREE(group_list);
1120         return 0 ;
1121 }
1122
1123 #endif /* HAVE_BROKEN_GETGROUPS */
1124
1125 /* This is a list of systems that require the first GID passed to setgroups(2)
1126  * to be the effective GID. If your system is one of these, add it here.
1127  */
1128 #if defined (FREEBSD) || defined (DARWINOS)
1129 #define USE_BSD_SETGROUPS
1130 #endif
1131
1132 #if defined(USE_BSD_SETGROUPS)
1133 /* Depending on the particular BSD implementation, the first GID that is
1134  * passed to setgroups(2) will either be ignored or will set the credential's
1135  * effective GID. In either case, the right thing to do is to guarantee that
1136  * gidset[0] is the effective GID.
1137  */
1138 static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
1139 {
1140         gid_t *new_gidset = NULL;
1141         int max;
1142         int ret;
1143
1144         /* setgroups(2) will fail with EINVAL if we pass too many groups. */
1145         max = groups_max();
1146
1147         /* No group list, just make sure we are setting the efective GID. */
1148         if (setlen == 0) {
1149                 return setgroups(1, &primary_gid);
1150         }
1151
1152         /* If the primary gid is not the first array element, grow the array
1153          * and insert it at the front.
1154          */
1155         if (gidset[0] != primary_gid) {
1156                 new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
1157                 if (new_gidset == NULL) {
1158                         return -1;
1159                 }
1160
1161                 memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
1162                 new_gidset[0] = primary_gid;
1163                 setlen++;
1164         }
1165
1166         if (setlen > max) {
1167                 DEBUG(3, ("forced to truncate group list from %d to %d\n",
1168                         setlen, max));
1169                 setlen = max;
1170         }
1171
1172 #if defined(HAVE_BROKEN_GETGROUPS)
1173         ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
1174 #else
1175         ret = setgroups(setlen, new_gidset ? new_gidset : gidset);
1176 #endif
1177
1178         if (new_gidset) {
1179                 int errsav = errno;
1180                 SAFE_FREE(new_gidset);
1181                 errno = errsav;
1182         }
1183
1184         return ret;
1185 }
1186
1187 #endif /* USE_BSD_SETGROUPS */
1188
1189 /**************************************************************************
1190  Wrapper for getgroups. Deals with broken (int) case.
1191 ****************************************************************************/
1192
1193 int sys_getgroups(int setlen, gid_t *gidset)
1194 {
1195 #if defined(HAVE_BROKEN_GETGROUPS)
1196         return sys_broken_getgroups(setlen, gidset);
1197 #else
1198         return getgroups(setlen, gidset);
1199 #endif
1200 }
1201
1202 /**************************************************************************
1203  Wrapper for setgroups. Deals with broken (int) case and BSD case.
1204 ****************************************************************************/
1205
1206 int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
1207 {
1208 #if !defined(HAVE_SETGROUPS)
1209         errno = ENOSYS;
1210         return -1;
1211 #endif /* HAVE_SETGROUPS */
1212
1213 #if defined(USE_BSD_SETGROUPS)
1214         return sys_bsd_setgroups(primary_gid, setlen, gidset);
1215 #elif defined(HAVE_BROKEN_GETGROUPS)
1216         return sys_broken_setgroups(setlen, gidset);
1217 #else
1218         return setgroups(setlen, gidset);
1219 #endif
1220 }
1221
1222 /**************************************************************************
1223  Wrappers for setpwent(), getpwent() and endpwent()
1224 ****************************************************************************/
1225
1226 void sys_setpwent(void)
1227 {
1228         setpwent();
1229 }
1230
1231 struct passwd *sys_getpwent(void)
1232 {
1233         return getpwent();
1234 }
1235
1236 void sys_endpwent(void)
1237 {
1238         endpwent();
1239 }
1240
1241 /**************************************************************************
1242  Wrappers for getpwnam(), getpwuid(), getgrnam(), getgrgid()
1243 ****************************************************************************/
1244
1245
1246 struct passwd *sys_getpwnam(const char *name)
1247 {
1248         return getpwnam(name);
1249 }
1250
1251 struct passwd *sys_getpwuid(uid_t uid)
1252 {
1253         return getpwuid(uid);
1254 }
1255
1256 struct group *sys_getgrnam(const char *name)
1257 {
1258         return getgrnam(name);
1259 }
1260
1261 struct group *sys_getgrgid(gid_t gid)
1262 {
1263         return getgrgid(gid);
1264 }
1265
1266 /**************************************************************************
1267  Extract a command into an arg list.
1268 ****************************************************************************/
1269
1270 static char **extract_args(TALLOC_CTX *mem_ctx, const char *command)
1271 {
1272         char *trunc_cmd;
1273         char *saveptr;
1274         char *ptr;
1275         int argcl;
1276         char **argl = NULL;
1277         int i;
1278
1279         if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
1280                 DEBUG(0, ("talloc failed\n"));
1281                 goto nomem;
1282         }
1283
1284         if(!(ptr = strtok_r(trunc_cmd, " \t", &saveptr))) {
1285                 TALLOC_FREE(trunc_cmd);
1286                 errno = EINVAL;
1287                 return NULL;
1288         }
1289
1290         /*
1291          * Count the args.
1292          */
1293
1294         for( argcl = 1; ptr; ptr = strtok_r(NULL, " \t", &saveptr))
1295                 argcl++;
1296
1297         TALLOC_FREE(trunc_cmd);
1298
1299         if (!(argl = TALLOC_ARRAY(mem_ctx, char *, argcl + 1))) {
1300                 goto nomem;
1301         }
1302
1303         /*
1304          * Now do the extraction.
1305          */
1306
1307         if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
1308                 goto nomem;
1309         }
1310
1311         ptr = strtok_r(trunc_cmd, " \t", &saveptr);
1312         i = 0;
1313
1314         if (!(argl[i++] = talloc_strdup(argl, ptr))) {
1315                 goto nomem;
1316         }
1317
1318         while((ptr = strtok_r(NULL, " \t", &saveptr)) != NULL) {
1319
1320                 if (!(argl[i++] = talloc_strdup(argl, ptr))) {
1321                         goto nomem;
1322                 }
1323         }
1324
1325         argl[i++] = NULL;
1326         TALLOC_FREE(trunc_cmd);
1327         return argl;
1328
1329  nomem:
1330         DEBUG(0, ("talloc failed\n"));
1331         TALLOC_FREE(trunc_cmd);
1332         TALLOC_FREE(argl);
1333         errno = ENOMEM;
1334         return NULL;
1335 }
1336
1337 /**************************************************************************
1338  Wrapper for popen. Safer as it doesn't search a path.
1339  Modified from the glibc sources.
1340  modified by tridge to return a file descriptor. We must kick our FILE* habit
1341 ****************************************************************************/
1342
1343 typedef struct _popen_list
1344 {
1345         int fd;
1346         pid_t child_pid;
1347         struct _popen_list *next;
1348 } popen_list;
1349
1350 static popen_list *popen_chain;
1351
1352 int sys_popen(const char *command)
1353 {
1354         int parent_end, child_end;
1355         int pipe_fds[2];
1356         popen_list *entry = NULL;
1357         char **argl = NULL;
1358
1359         if (pipe(pipe_fds) < 0)
1360                 return -1;
1361
1362         parent_end = pipe_fds[0];
1363         child_end = pipe_fds[1];
1364
1365         if (!*command) {
1366                 errno = EINVAL;
1367                 goto err_exit;
1368         }
1369
1370         if((entry = SMB_MALLOC_P(popen_list)) == NULL)
1371                 goto err_exit;
1372
1373         ZERO_STRUCTP(entry);
1374
1375         /*
1376          * Extract the command and args into a NULL terminated array.
1377          */
1378
1379         if(!(argl = extract_args(NULL, command)))
1380                 goto err_exit;
1381
1382         entry->child_pid = sys_fork();
1383
1384         if (entry->child_pid == -1) {
1385                 goto err_exit;
1386         }
1387
1388         if (entry->child_pid == 0) {
1389
1390                 /*
1391                  * Child !
1392                  */
1393
1394                 int child_std_end = STDOUT_FILENO;
1395                 popen_list *p;
1396
1397                 close(parent_end);
1398                 if (child_end != child_std_end) {
1399                         dup2 (child_end, child_std_end);
1400                         close (child_end);
1401                 }
1402
1403                 /*
1404                  * POSIX.2:  "popen() shall ensure that any streams from previous
1405                  * popen() calls that remain open in the parent process are closed
1406                  * in the new child process."
1407                  */
1408
1409                 for (p = popen_chain; p; p = p->next)
1410                         close(p->fd);
1411
1412                 execv(argl[0], argl);
1413                 _exit (127);
1414         }
1415
1416         /*
1417          * Parent.
1418          */
1419
1420         close (child_end);
1421         TALLOC_FREE(argl);
1422
1423         /* Link into popen_chain. */
1424         entry->next = popen_chain;
1425         popen_chain = entry;
1426         entry->fd = parent_end;
1427
1428         return entry->fd;
1429
1430 err_exit:
1431
1432         SAFE_FREE(entry);
1433         SAFE_FREE(argl);
1434         close(pipe_fds[0]);
1435         close(pipe_fds[1]);
1436         return -1;
1437 }
1438
1439 /**************************************************************************
1440  Wrapper for pclose. Modified from the glibc sources.
1441 ****************************************************************************/
1442
1443 int sys_pclose(int fd)
1444 {
1445         int wstatus;
1446         popen_list **ptr = &popen_chain;
1447         popen_list *entry = NULL;
1448         pid_t wait_pid;
1449         int status = -1;
1450
1451         /* Unlink from popen_chain. */
1452         for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1453                 if ((*ptr)->fd == fd) {
1454                         entry = *ptr;
1455                         *ptr = (*ptr)->next;
1456                         status = 0;
1457                         break;
1458                 }
1459         }
1460
1461         if (status < 0 || close(entry->fd) < 0)
1462                 return -1;
1463
1464         /*
1465          * As Samba is catching and eating child process
1466          * exits we don't really care about the child exit
1467          * code, a -1 with errno = ECHILD will do fine for us.
1468          */
1469
1470         do {
1471                 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1472         } while (wait_pid == -1 && errno == EINTR);
1473
1474         SAFE_FREE(entry);
1475
1476         if (wait_pid == -1)
1477                 return -1;
1478         return wstatus;
1479 }
1480
1481 /**************************************************************************
1482  Wrapper for Admin Logs.
1483 ****************************************************************************/
1484
1485  void sys_adminlog(int priority, const char *format_str, ...) 
1486 {
1487         va_list ap;
1488         int ret;
1489         char *msgbuf = NULL;
1490
1491         va_start( ap, format_str );
1492         ret = vasprintf( &msgbuf, format_str, ap );
1493         va_end( ap );
1494
1495         if (ret == -1)
1496                 return;
1497
1498 #if defined(HAVE_SYSLOG)
1499         syslog( priority, "%s", msgbuf );
1500 #else
1501         DEBUG(0,("%s", msgbuf ));
1502 #endif
1503         SAFE_FREE(msgbuf);
1504 }
1505
1506 /******** Solaris EA helper function prototypes ********/
1507 #ifdef HAVE_ATTROPEN
1508 #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
1509 static int solaris_write_xattr(int attrfd, const char *value, size_t size);
1510 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
1511 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
1512 static int solaris_unlinkat(int attrdirfd, const char *name);
1513 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
1514 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
1515 #endif
1516
1517 /**************************************************************************
1518  Wrappers for extented attribute calls. Based on the Linux package with
1519  support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
1520 ****************************************************************************/
1521
1522 ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size)
1523 {
1524 #if defined(HAVE_GETXATTR)
1525 #ifndef XATTR_ADD_OPT
1526         return getxattr(path, name, value, size);
1527 #else
1528         int options = 0;
1529         return getxattr(path, name, value, size, 0, options);
1530 #endif
1531 #elif defined(HAVE_GETEA)
1532         return getea(path, name, value, size);
1533 #elif defined(HAVE_EXTATTR_GET_FILE)
1534         char *s;
1535         ssize_t retval;
1536         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1537                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1538         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1539         /*
1540          * The BSD implementation has a nasty habit of silently truncating
1541          * the returned value to the size of the buffer, so we have to check
1542          * that the buffer is large enough to fit the returned value.
1543          */
1544         if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1545                 if(retval > size) {
1546                         errno = ERANGE;
1547                         return -1;
1548                 }
1549                 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
1550                         return retval;
1551         }
1552
1553         DEBUG(10,("sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno)));
1554         return -1;
1555 #elif defined(HAVE_ATTR_GET)
1556         int retval, flags = 0;
1557         int valuelength = (int)size;
1558         char *attrname = strchr(name,'.') + 1;
1559
1560         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1561
1562         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1563
1564         return retval ? retval : valuelength;
1565 #elif defined(HAVE_ATTROPEN)
1566         ssize_t ret = -1;
1567         int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
1568         if (attrfd >= 0) {
1569                 ret = solaris_read_xattr(attrfd, value, size);
1570                 close(attrfd);
1571         }
1572         return ret;
1573 #else
1574         errno = ENOSYS;
1575         return -1;
1576 #endif
1577 }
1578
1579 ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size)
1580 {
1581 #if defined(HAVE_LGETXATTR)
1582         return lgetxattr(path, name, value, size);
1583 #elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
1584         int options = XATTR_NOFOLLOW;
1585         return getxattr(path, name, value, size, 0, options);
1586 #elif defined(HAVE_LGETEA)
1587         return lgetea(path, name, value, size);
1588 #elif defined(HAVE_EXTATTR_GET_LINK)
1589         char *s;
1590         ssize_t retval;
1591         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1592                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1593         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1594
1595         if((retval=extattr_get_link(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1596                 if(retval > size) {
1597                         errno = ERANGE;
1598                         return -1;
1599                 }
1600                 if((retval=extattr_get_link(path, attrnamespace, attrname, value, size)) >= 0)
1601                         return retval;
1602         }
1603
1604         DEBUG(10,("sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno)));
1605         return -1;
1606 #elif defined(HAVE_ATTR_GET)
1607         int retval, flags = ATTR_DONTFOLLOW;
1608         int valuelength = (int)size;
1609         char *attrname = strchr(name,'.') + 1;
1610
1611         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1612
1613         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1614
1615         return retval ? retval : valuelength;
1616 #elif defined(HAVE_ATTROPEN)
1617         ssize_t ret = -1;
1618         int attrfd = solaris_attropen(path, name, O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1619         if (attrfd >= 0) {
1620                 ret = solaris_read_xattr(attrfd, value, size);
1621                 close(attrfd);
1622         }
1623         return ret;
1624 #else
1625         errno = ENOSYS;
1626         return -1;
1627 #endif
1628 }
1629
1630 ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size)
1631 {
1632 #if defined(HAVE_FGETXATTR)
1633 #ifndef XATTR_ADD_OPT
1634         return fgetxattr(filedes, name, value, size);
1635 #else
1636         int options = 0;
1637         return fgetxattr(filedes, name, value, size, 0, options);
1638 #endif
1639 #elif defined(HAVE_FGETEA)
1640         return fgetea(filedes, name, value, size);
1641 #elif defined(HAVE_EXTATTR_GET_FD)
1642         char *s;
1643         ssize_t retval;
1644         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1645                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1646         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1647
1648         if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
1649                 if(retval > size) {
1650                         errno = ERANGE;
1651                         return -1;
1652                 }
1653                 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
1654                         return retval;
1655         }
1656
1657         DEBUG(10,("sys_fgetxattr: extattr_get_fd() failed with: %s\n", strerror(errno)));
1658         return -1;
1659 #elif defined(HAVE_ATTR_GETF)
1660         int retval, flags = 0;
1661         int valuelength = (int)size;
1662         char *attrname = strchr(name,'.') + 1;
1663
1664         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1665
1666         retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
1667
1668         return retval ? retval : valuelength;
1669 #elif defined(HAVE_ATTROPEN)
1670         ssize_t ret = -1;
1671         int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
1672         if (attrfd >= 0) {
1673                 ret = solaris_read_xattr(attrfd, value, size);
1674                 close(attrfd);
1675         }
1676         return ret;
1677 #else
1678         errno = ENOSYS;
1679         return -1;
1680 #endif
1681 }
1682
1683 #if defined(HAVE_EXTATTR_LIST_FILE)
1684
1685 #define EXTATTR_PREFIX(s)       (s), (sizeof((s))-1)
1686
1687 static struct {
1688         int space;
1689         const char *name;
1690         size_t len;
1691
1692 extattr[] = {
1693         { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
1694         { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
1695 };
1696
1697 typedef union {
1698         const char *path;
1699         int filedes;
1700 } extattr_arg;
1701
1702 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
1703 {
1704         ssize_t list_size, total_size = 0;
1705         int i, t, len;
1706         char *buf;
1707         /* Iterate through extattr(2) namespaces */
1708         for(t = 0; t < (sizeof(extattr)/sizeof(extattr[0])); t++) {
1709                 switch(type) {
1710 #if defined(HAVE_EXTATTR_LIST_FILE)
1711                         case 0:
1712                                 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
1713                                 break;
1714 #endif
1715 #if defined(HAVE_EXTATTR_LIST_LINK)
1716                         case 1:
1717                                 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
1718                                 break;
1719 #endif
1720 #if defined(HAVE_EXTATTR_LIST_FD)
1721                         case 2:
1722                                 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
1723                                 break;
1724 #endif
1725                         default:
1726                                 errno = ENOSYS;
1727                                 return -1;
1728                 }
1729                 /* Some error happend. Errno should be set by the previous call */
1730                 if(list_size < 0)
1731                         return -1;
1732                 /* No attributes */
1733                 if(list_size == 0)
1734                         continue;
1735                 /* XXX: Call with an empty buffer may be used to calculate
1736                    necessary buffer size. Unfortunately, we can't say, how
1737                    many attributes were returned, so here is the potential
1738                    problem with the emulation.
1739                 */
1740                 if(list == NULL) {
1741                         /* Take the worse case of one char attribute names - 
1742                            two bytes per name plus one more for sanity.
1743                         */
1744                         total_size += list_size + (list_size/2 + 1)*extattr[t].len;
1745                         continue;
1746                 }
1747                 /* Count necessary offset to fit namespace prefixes */
1748                 len = 0;
1749                 for(i = 0; i < list_size; i += list[i] + 1)
1750                         len += extattr[t].len;
1751
1752                 total_size += list_size + len;
1753                 /* Buffer is too small to fit the results */
1754                 if(total_size > size) {
1755                         errno = ERANGE;
1756                         return -1;
1757                 }
1758                 /* Shift results back, so we can prepend prefixes */
1759                 buf = memmove(list + len, list, list_size);
1760
1761                 for(i = 0; i < list_size; i += len + 1) {
1762                         len = buf[i];
1763                         strncpy(list, extattr[t].name, extattr[t].len + 1);
1764                         list += extattr[t].len;
1765                         strncpy(list, buf + i + 1, len);
1766                         list[len] = '\0';
1767                         list += len + 1;
1768                 }
1769                 size -= total_size;
1770         }
1771         return total_size;
1772 }
1773
1774 #endif
1775
1776 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1777 static char attr_buffer[ATTR_MAX_VALUELEN];
1778
1779 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
1780 {
1781         int retval = 0, index;
1782         attrlist_cursor_t *cursor = 0;
1783         int total_size = 0;
1784         attrlist_t * al = (attrlist_t *)attr_buffer;
1785         attrlist_ent_t *ae;
1786         size_t ent_size, left = size;
1787         char *bp = list;
1788
1789         while (True) {
1790             if (filedes)
1791                 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1792             else
1793                 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1794             if (retval) break;
1795             for (index = 0; index < al->al_count; index++) {
1796                 ae = ATTR_ENTRY(attr_buffer, index);
1797                 ent_size = strlen(ae->a_name) + sizeof("user.");
1798                 if (left >= ent_size) {
1799                     strncpy(bp, "user.", sizeof("user."));
1800                     strncat(bp, ae->a_name, ent_size - sizeof("user."));
1801                     bp += ent_size;
1802                     left -= ent_size;
1803                 } else if (size) {
1804                     errno = ERANGE;
1805                     retval = -1;
1806                     break;
1807                 }
1808                 total_size += ent_size;
1809             }
1810             if (al->al_more == 0) break;
1811         }
1812         if (retval == 0) {
1813             flags |= ATTR_ROOT;
1814             cursor = 0;
1815             while (True) {
1816                 if (filedes)
1817                     retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1818                 else
1819                     retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1820                 if (retval) break;
1821                 for (index = 0; index < al->al_count; index++) {
1822                     ae = ATTR_ENTRY(attr_buffer, index);
1823                     ent_size = strlen(ae->a_name) + sizeof("system.");
1824                     if (left >= ent_size) {
1825                         strncpy(bp, "system.", sizeof("system."));
1826                         strncat(bp, ae->a_name, ent_size - sizeof("system."));
1827                         bp += ent_size;
1828                         left -= ent_size;
1829                     } else if (size) {
1830                         errno = ERANGE;
1831                         retval = -1;
1832                         break;
1833                     }
1834                     total_size += ent_size;
1835                 }
1836                 if (al->al_more == 0) break;
1837             }
1838         }
1839         return (ssize_t)(retval ? retval : total_size);
1840 }
1841
1842 #endif
1843
1844 ssize_t sys_listxattr (const char *path, char *list, size_t size)
1845 {
1846 #if defined(HAVE_LISTXATTR)
1847 #ifndef XATTR_ADD_OPT
1848         return listxattr(path, list, size);
1849 #else
1850         int options = 0;
1851         return listxattr(path, list, size, options);
1852 #endif
1853 #elif defined(HAVE_LISTEA)
1854         return listea(path, list, size);
1855 #elif defined(HAVE_EXTATTR_LIST_FILE)
1856         extattr_arg arg;
1857         arg.path = path;
1858         return bsd_attr_list(0, arg, list, size);
1859 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1860         return irix_attr_list(path, 0, list, size, 0);
1861 #elif defined(HAVE_ATTROPEN)
1862         ssize_t ret = -1;
1863         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
1864         if (attrdirfd >= 0) {
1865                 ret = solaris_list_xattr(attrdirfd, list, size);
1866                 close(attrdirfd);
1867         }
1868         return ret;
1869 #else
1870         errno = ENOSYS;
1871         return -1;
1872 #endif
1873 }
1874
1875 ssize_t sys_llistxattr (const char *path, char *list, size_t size)
1876 {
1877 #if defined(HAVE_LLISTXATTR)
1878         return llistxattr(path, list, size);
1879 #elif defined(HAVE_LISTXATTR) && defined(XATTR_ADD_OPT)
1880         int options = XATTR_NOFOLLOW;
1881         return listxattr(path, list, size, options);
1882 #elif defined(HAVE_LLISTEA)
1883         return llistea(path, list, size);
1884 #elif defined(HAVE_EXTATTR_LIST_LINK)
1885         extattr_arg arg;
1886         arg.path = path;
1887         return bsd_attr_list(1, arg, list, size);
1888 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1889         return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
1890 #elif defined(HAVE_ATTROPEN)
1891         ssize_t ret = -1;
1892         int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1893         if (attrdirfd >= 0) {
1894                 ret = solaris_list_xattr(attrdirfd, list, size);
1895                 close(attrdirfd);
1896         }
1897         return ret;
1898 #else
1899         errno = ENOSYS;
1900         return -1;
1901 #endif
1902 }
1903
1904 ssize_t sys_flistxattr (int filedes, char *list, size_t size)
1905 {
1906 #if defined(HAVE_FLISTXATTR)
1907 #ifndef XATTR_ADD_OPT
1908         return flistxattr(filedes, list, size);
1909 #else
1910         int options = 0;
1911         return flistxattr(filedes, list, size, options);
1912 #endif
1913 #elif defined(HAVE_FLISTEA)
1914         return flistea(filedes, list, size);
1915 #elif defined(HAVE_EXTATTR_LIST_FD)
1916         extattr_arg arg;
1917         arg.filedes = filedes;
1918         return bsd_attr_list(2, arg, list, size);
1919 #elif defined(HAVE_ATTR_LISTF)
1920         return irix_attr_list(NULL, filedes, list, size, 0);
1921 #elif defined(HAVE_ATTROPEN)
1922         ssize_t ret = -1;
1923         int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
1924         if (attrdirfd >= 0) {
1925                 ret = solaris_list_xattr(attrdirfd, list, size);
1926                 close(attrdirfd);
1927         }
1928         return ret;
1929 #else
1930         errno = ENOSYS;
1931         return -1;
1932 #endif
1933 }
1934
1935 int sys_removexattr (const char *path, const char *name)
1936 {
1937 #if defined(HAVE_REMOVEXATTR)
1938 #ifndef XATTR_ADD_OPT
1939         return removexattr(path, name);
1940 #else
1941         int options = 0;
1942         return removexattr(path, name, options);
1943 #endif
1944 #elif defined(HAVE_REMOVEEA)
1945         return removeea(path, name);
1946 #elif defined(HAVE_EXTATTR_DELETE_FILE)
1947         char *s;
1948         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1949                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1950         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1951
1952         return extattr_delete_file(path, attrnamespace, attrname);
1953 #elif defined(HAVE_ATTR_REMOVE)
1954         int flags = 0;
1955         char *attrname = strchr(name,'.') + 1;
1956
1957         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1958
1959         return attr_remove(path, attrname, flags);
1960 #elif defined(HAVE_ATTROPEN)
1961         int ret = -1;
1962         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
1963         if (attrdirfd >= 0) {
1964                 ret = solaris_unlinkat(attrdirfd, name);
1965                 close(attrdirfd);
1966         }
1967         return ret;
1968 #else
1969         errno = ENOSYS;
1970         return -1;
1971 #endif
1972 }
1973
1974 int sys_lremovexattr (const char *path, const char *name)
1975 {
1976 #if defined(HAVE_LREMOVEXATTR)
1977         return lremovexattr(path, name);
1978 #elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
1979         int options = XATTR_NOFOLLOW;
1980         return removexattr(path, name, options);
1981 #elif defined(HAVE_LREMOVEEA)
1982         return lremoveea(path, name);
1983 #elif defined(HAVE_EXTATTR_DELETE_LINK)
1984         char *s;
1985         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1986                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1987         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1988
1989         return extattr_delete_link(path, attrnamespace, attrname);
1990 #elif defined(HAVE_ATTR_REMOVE)
1991         int flags = ATTR_DONTFOLLOW;
1992         char *attrname = strchr(name,'.') + 1;
1993
1994         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1995
1996         return attr_remove(path, attrname, flags);
1997 #elif defined(HAVE_ATTROPEN)
1998         int ret = -1;
1999         int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
2000         if (attrdirfd >= 0) {
2001                 ret = solaris_unlinkat(attrdirfd, name);
2002                 close(attrdirfd);
2003         }
2004         return ret;
2005 #else
2006         errno = ENOSYS;
2007         return -1;
2008 #endif
2009 }
2010
2011 int sys_fremovexattr (int filedes, const char *name)
2012 {
2013 #if defined(HAVE_FREMOVEXATTR)
2014 #ifndef XATTR_ADD_OPT
2015         return fremovexattr(filedes, name);
2016 #else
2017         int options = 0;
2018         return fremovexattr(filedes, name, options);
2019 #endif
2020 #elif defined(HAVE_FREMOVEEA)
2021         return fremoveea(filedes, name);
2022 #elif defined(HAVE_EXTATTR_DELETE_FD)
2023         char *s;
2024         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2025                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2026         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2027
2028         return extattr_delete_fd(filedes, attrnamespace, attrname);
2029 #elif defined(HAVE_ATTR_REMOVEF)
2030         int flags = 0;
2031         char *attrname = strchr(name,'.') + 1;
2032
2033         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
2034
2035         return attr_removef(filedes, attrname, flags);
2036 #elif defined(HAVE_ATTROPEN)
2037         int ret = -1;
2038         int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
2039         if (attrdirfd >= 0) {
2040                 ret = solaris_unlinkat(attrdirfd, name);
2041                 close(attrdirfd);
2042         }
2043         return ret;
2044 #else
2045         errno = ENOSYS;
2046         return -1;
2047 #endif
2048 }
2049
2050 int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
2051 {
2052 #if defined(HAVE_SETXATTR)
2053 #ifndef XATTR_ADD_OPT
2054         return setxattr(path, name, value, size, flags);
2055 #else
2056         int options = 0;
2057         return setxattr(path, name, value, size, 0, options);
2058 #endif
2059 #elif defined(HAVE_SETEA)
2060         return setea(path, name, value, size, flags);
2061 #elif defined(HAVE_EXTATTR_SET_FILE)
2062         char *s;
2063         int retval = 0;
2064         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2065                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2066         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2067         if (flags) {
2068                 /* Check attribute existence */
2069                 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
2070                 if (retval < 0) {
2071                         /* REPLACE attribute, that doesn't exist */
2072                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
2073                                 errno = ENOATTR;
2074                                 return -1;
2075                         }
2076                         /* Ignore other errors */
2077                 }
2078                 else {
2079                         /* CREATE attribute, that already exists */
2080                         if (flags & XATTR_CREATE) {
2081                                 errno = EEXIST;
2082                                 return -1;
2083                         }
2084                 }
2085         }
2086         retval = extattr_set_file(path, attrnamespace, attrname, value, size);
2087         return (retval < 0) ? -1 : 0;
2088 #elif defined(HAVE_ATTR_SET)
2089         int myflags = 0;
2090         char *attrname = strchr(name,'.') + 1;
2091
2092         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2093         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2094         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2095
2096         return attr_set(path, attrname, (const char *)value, size, myflags);
2097 #elif defined(HAVE_ATTROPEN)
2098         int ret = -1;
2099         int myflags = O_RDWR;
2100         int attrfd;
2101         if (flags & XATTR_CREATE) myflags |= O_EXCL;
2102         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2103         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2104         if (attrfd >= 0) {
2105                 ret = solaris_write_xattr(attrfd, value, size);
2106                 close(attrfd);
2107         }
2108         return ret;
2109 #else
2110         errno = ENOSYS;
2111         return -1;
2112 #endif
2113 }
2114
2115 int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags)
2116 {
2117 #if defined(HAVE_LSETXATTR)
2118         return lsetxattr(path, name, value, size, flags);
2119 #elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
2120         int options = XATTR_NOFOLLOW;
2121         return setxattr(path, name, value, size, 0, options);
2122 #elif defined(LSETEA)
2123         return lsetea(path, name, value, size, flags);
2124 #elif defined(HAVE_EXTATTR_SET_LINK)
2125         char *s;
2126         int retval = 0;
2127         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2128                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2129         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2130         if (flags) {
2131                 /* Check attribute existence */
2132                 retval = extattr_get_link(path, attrnamespace, attrname, NULL, 0);
2133                 if (retval < 0) {
2134                         /* REPLACE attribute, that doesn't exist */
2135                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
2136                                 errno = ENOATTR;
2137                                 return -1;
2138                         }
2139                         /* Ignore other errors */
2140                 }
2141                 else {
2142                         /* CREATE attribute, that already exists */
2143                         if (flags & XATTR_CREATE) {
2144                                 errno = EEXIST;
2145                                 return -1;
2146                         }
2147                 }
2148         }
2149
2150         retval = extattr_set_link(path, attrnamespace, attrname, value, size);
2151         return (retval < 0) ? -1 : 0;
2152 #elif defined(HAVE_ATTR_SET)
2153         int myflags = ATTR_DONTFOLLOW;
2154         char *attrname = strchr(name,'.') + 1;
2155
2156         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2157         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2158         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2159
2160         return attr_set(path, attrname, (const char *)value, size, myflags);
2161 #elif defined(HAVE_ATTROPEN)
2162         int ret = -1;
2163         int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW;
2164         int attrfd;
2165         if (flags & XATTR_CREATE) myflags |= O_EXCL;
2166         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2167         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2168         if (attrfd >= 0) {
2169                 ret = solaris_write_xattr(attrfd, value, size);
2170                 close(attrfd);
2171         }
2172         return ret;
2173 #else
2174         errno = ENOSYS;
2175         return -1;
2176 #endif
2177 }
2178
2179 int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
2180 {
2181 #if defined(HAVE_FSETXATTR)
2182 #ifndef XATTR_ADD_OPT
2183         return fsetxattr(filedes, name, value, size, flags);
2184 #else
2185         int options = 0;
2186         return fsetxattr(filedes, name, value, size, 0, options);
2187 #endif
2188 #elif defined(HAVE_FSETEA)
2189         return fsetea(filedes, name, value, size, flags);
2190 #elif defined(HAVE_EXTATTR_SET_FD)
2191         char *s;
2192         int retval = 0;
2193         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2194                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2195         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2196         if (flags) {
2197                 /* Check attribute existence */
2198                 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
2199                 if (retval < 0) {
2200                         /* REPLACE attribute, that doesn't exist */
2201                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
2202                                 errno = ENOATTR;
2203                                 return -1;
2204                         }
2205                         /* Ignore other errors */
2206                 }
2207                 else {
2208                         /* CREATE attribute, that already exists */
2209                         if (flags & XATTR_CREATE) {
2210                                 errno = EEXIST;
2211                                 return -1;
2212                         }
2213                 }
2214         }
2215         retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
2216         return (retval < 0) ? -1 : 0;
2217 #elif defined(HAVE_ATTR_SETF)
2218         int myflags = 0;
2219         char *attrname = strchr(name,'.') + 1;
2220
2221         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2222         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2223         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2224
2225         return attr_setf(filedes, attrname, (const char *)value, size, myflags);
2226 #elif defined(HAVE_ATTROPEN)
2227         int ret = -1;
2228         int myflags = O_RDWR | O_XATTR;
2229         int attrfd;
2230         if (flags & XATTR_CREATE) myflags |= O_EXCL;
2231         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2232         attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2233         if (attrfd >= 0) {
2234                 ret = solaris_write_xattr(attrfd, value, size);
2235                 close(attrfd);
2236         }
2237         return ret;
2238 #else
2239         errno = ENOSYS;
2240         return -1;
2241 #endif
2242 }
2243
2244 /**************************************************************************
2245  helper functions for Solaris' EA support
2246 ****************************************************************************/
2247 #ifdef HAVE_ATTROPEN
2248 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
2249 {
2250         struct stat sbuf;
2251
2252         if (fstat(attrfd, &sbuf) == -1) {
2253                 errno = ENOATTR;
2254                 return -1;
2255         }
2256
2257         /* This is to return the current size of the named extended attribute */
2258         if (size == 0) {
2259                 return sbuf.st_size;
2260         }
2261
2262         /* check size and read xattr */
2263         if (sbuf.st_size > size) {
2264                 errno = ERANGE;
2265                 return -1;
2266         }
2267
2268         return read(attrfd, value, sbuf.st_size);
2269 }
2270
2271 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
2272 {
2273         ssize_t len = 0;
2274         DIR *dirp;
2275         struct dirent *de;
2276         int newfd = dup(attrdirfd);
2277         /* CAUTION: The originating file descriptor should not be
2278                     used again following the call to fdopendir().
2279                     For that reason we dup() the file descriptor
2280                     here to make things more clear. */
2281         dirp = fdopendir(newfd);
2282
2283         while ((de = readdir(dirp))) {
2284                 size_t listlen = strlen(de->d_name);
2285                 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
2286                         /* we don't want "." and ".." here: */
2287                         DEBUG(10,("skipped EA %s\n",de->d_name));
2288                         continue;
2289                 }
2290
2291                 if (size == 0) {
2292                         /* return the current size of the list of extended attribute names*/
2293                         len += listlen + 1;
2294                 } else {
2295                         /* check size and copy entrieŃ• + nul into list. */
2296                         if ((len + listlen + 1) > size) {
2297                                 errno = ERANGE;
2298                                 len = -1;
2299                                 break;
2300                         } else {
2301                                 safe_strcpy(list + len, de->d_name, listlen);
2302                                 len += listlen;
2303                                 list[len] = '\0';
2304                                 ++len;
2305                         }
2306                 }
2307         }
2308
2309         if (closedir(dirp) == -1) {
2310                 DEBUG(0,("closedir dirp failed: %s\n",strerror(errno)));
2311                 return -1;
2312         }
2313         return len;
2314 }
2315
2316 static int solaris_unlinkat(int attrdirfd, const char *name)
2317 {
2318         if (unlinkat(attrdirfd, name, 0) == -1) {
2319                 if (errno == ENOENT) {
2320                         errno = ENOATTR;
2321                 }
2322                 return -1;
2323         }
2324         return 0;
2325 }
2326
2327 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
2328 {
2329         int filedes = attropen(path, attrpath, oflag, mode);
2330         if (filedes == -1) {
2331                 DEBUG(10,("attropen FAILED: path: %s, name: %s, errno: %s\n",path,attrpath,strerror(errno)));
2332                 if (errno == EINVAL) {
2333                         errno = ENOTSUP;
2334                 } else {
2335                         errno = ENOATTR;
2336                 }
2337         }
2338         return filedes;
2339 }
2340
2341 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
2342 {
2343         int filedes = openat(fildes, path, oflag, mode);
2344         if (filedes == -1) {
2345                 DEBUG(10,("openat FAILED: fd: %d, path: %s, errno: %s\n",filedes,path,strerror(errno)));
2346                 if (errno == EINVAL) {
2347                         errno = ENOTSUP;
2348                 } else {
2349                         errno = ENOATTR;
2350                 }
2351         }
2352         return filedes;
2353 }
2354
2355 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
2356 {
2357         if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
2358                 return 0;
2359         } else {
2360                 DEBUG(10,("solaris_write_xattr FAILED!\n"));
2361                 return -1;
2362         }
2363 }
2364 #endif /*HAVE_ATTROPEN*/
2365
2366
2367 /****************************************************************************
2368  Return the major devicenumber for UNIX extensions.
2369 ****************************************************************************/
2370
2371 uint32 unix_dev_major(SMB_DEV_T dev)
2372 {
2373 #if defined(HAVE_DEVICE_MAJOR_FN)
2374         return (uint32)major(dev);
2375 #else
2376         return (uint32)(dev >> 8);
2377 #endif
2378 }
2379
2380 /****************************************************************************
2381  Return the minor devicenumber for UNIX extensions.
2382 ****************************************************************************/
2383
2384 uint32 unix_dev_minor(SMB_DEV_T dev)
2385 {
2386 #if defined(HAVE_DEVICE_MINOR_FN)
2387         return (uint32)minor(dev);
2388 #else
2389         return (uint32)(dev & 0xff);
2390 #endif
2391 }
2392
2393 #if defined(WITH_AIO)
2394
2395 /*******************************************************************
2396  An aio_read wrapper that will deal with 64-bit sizes.
2397 ********************************************************************/
2398
2399 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2400 {
2401 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_READ64)
2402         return aio_read64(aiocb);
2403 #elif defined(HAVE_AIO_READ)
2404         return aio_read(aiocb);
2405 #else
2406         errno = ENOSYS;
2407         return -1;
2408 #endif
2409 }
2410
2411 /*******************************************************************
2412  An aio_write wrapper that will deal with 64-bit sizes.
2413 ********************************************************************/
2414
2415 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2416 {
2417 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_WRITE64)
2418         return aio_write64(aiocb);
2419 #elif defined(HAVE_AIO_WRITE)
2420         return aio_write(aiocb);
2421 #else
2422         errno = ENOSYS;
2423         return -1;
2424 #endif
2425 }
2426
2427 /*******************************************************************
2428  An aio_return wrapper that will deal with 64-bit sizes.
2429 ********************************************************************/
2430
2431 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2432 {
2433 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_RETURN64)
2434         return aio_return64(aiocb);
2435 #elif defined(HAVE_AIO_RETURN)
2436         return aio_return(aiocb);
2437 #else
2438         errno = ENOSYS;
2439         return -1;
2440 #endif
2441 }
2442
2443 /*******************************************************************
2444  An aio_cancel wrapper that will deal with 64-bit sizes.
2445 ********************************************************************/
2446
2447 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2448 {
2449 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_CANCEL64)
2450         return aio_cancel64(fd, aiocb);
2451 #elif defined(HAVE_AIO_CANCEL)
2452         return aio_cancel(fd, aiocb);
2453 #else
2454         errno = ENOSYS;
2455         return -1;
2456 #endif
2457 }
2458
2459 /*******************************************************************
2460  An aio_error wrapper that will deal with 64-bit sizes.
2461 ********************************************************************/
2462
2463 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2464 {
2465 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_ERROR64)
2466         return aio_error64(aiocb);
2467 #elif defined(HAVE_AIO_ERROR)
2468         return aio_error(aiocb);
2469 #else
2470         errno = ENOSYS;
2471         return -1;
2472 #endif
2473 }
2474
2475 /*******************************************************************
2476  An aio_fsync wrapper that will deal with 64-bit sizes.
2477 ********************************************************************/
2478
2479 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2480 {
2481 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_FSYNC64)
2482         return aio_fsync64(op, aiocb);
2483 #elif defined(HAVE_AIO_FSYNC)
2484         return aio_fsync(op, aiocb);
2485 #else
2486         errno = ENOSYS;
2487         return -1;
2488 #endif
2489 }
2490
2491 /*******************************************************************
2492  An aio_fsync wrapper that will deal with 64-bit sizes.
2493 ********************************************************************/
2494
2495 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2496 {
2497 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_SUSPEND64)
2498         return aio_suspend64(cblist, n, timeout);
2499 #elif defined(HAVE_AIO_FSYNC)
2500         return aio_suspend(cblist, n, timeout);
2501 #else
2502         errno = ENOSYS;
2503         return -1;
2504 #endif
2505 }
2506 #else /* !WITH_AIO */
2507
2508 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2509 {
2510         errno = ENOSYS;
2511         return -1;
2512 }
2513
2514 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2515 {
2516         errno = ENOSYS;
2517         return -1;
2518 }
2519
2520 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2521 {
2522         errno = ENOSYS;
2523         return -1;
2524 }
2525
2526 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2527 {
2528         errno = ENOSYS;
2529         return -1;
2530 }
2531
2532 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2533 {
2534         errno = ENOSYS;
2535         return -1;
2536 }
2537
2538 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2539 {
2540         errno = ENOSYS;
2541         return -1;
2542 }
2543
2544 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2545 {
2546         errno = ENOSYS;
2547         return -1;
2548 }
2549 #endif /* WITH_AIO */
2550
2551 int sys_getpeereid( int s, uid_t *uid)
2552 {
2553 #if defined(HAVE_PEERCRED)
2554         struct ucred cred;
2555         socklen_t cred_len = sizeof(struct ucred);
2556         int ret;
2557
2558         ret = getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &cred_len);
2559         if (ret != 0) {
2560                 return -1;
2561         }
2562
2563         if (cred_len != sizeof(struct ucred)) {
2564                 errno = EINVAL;
2565                 return -1;
2566         }
2567
2568         *uid = cred.uid;
2569         return 0;
2570 #else
2571         errno = ENOSYS;
2572         return -1;
2573 #endif
2574 }
2575
2576 int sys_getnameinfo(const struct sockaddr *psa,
2577                         socklen_t salen,
2578                         char *host,
2579                         size_t hostlen,
2580                         char *service,
2581                         size_t servlen,
2582                         int flags)
2583 {
2584         /*
2585          * For Solaris we must make sure salen is the
2586          * correct length for the incoming sa_family.
2587          */
2588
2589         if (salen == sizeof(struct sockaddr_storage)) {
2590                 salen = sizeof(struct sockaddr_in);
2591 #if defined(HAVE_IPV6)
2592                 if (psa->sa_family == AF_INET6) {
2593                         salen = sizeof(struct sockaddr_in6);
2594                 }
2595 #endif
2596         }
2597         return getnameinfo(psa, salen, host, hostlen, service, servlen, flags);
2598 }
2599
2600 int sys_connect(int fd, const struct sockaddr * addr)
2601 {
2602         socklen_t salen = -1;
2603
2604         if (addr->sa_family == AF_INET) {
2605             salen = sizeof(struct sockaddr_in);
2606         } else if (addr->sa_family == AF_UNIX) {
2607             salen = sizeof(struct sockaddr_un);
2608         }
2609 #if defined(HAVE_IPV6)
2610         else if (addr->sa_family == AF_INET6) {
2611             salen = sizeof(struct sockaddr_in6);
2612         }
2613 #endif
2614
2615         return connect(fd, addr, salen);
2616 }