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

Last change on this file was 871, checked in by Silvan Scherrer, 11 years ago

samba server 3.6: update vendor to 3.6.24

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