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