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