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