source: vendor/3.5.0/source3/lib/system.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

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