r14600: Refactor capability interface from being IRIX-specific to using only
[jra/samba/.git] / source3 / lib / system.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Samba system utilities
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Jeremy Allison  1998-2005
6    Copyright (C) Timur Bakeyev        2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 /*
26    The idea is that this file will eventually have wrappers around all
27    important system calls in samba. The aims are:
28
29    - to enable easier porting by putting OS dependent stuff in here
30
31    - to allow for hooks into other "pseudo-filesystems"
32
33    - to allow easier integration of things like the japanese extensions
34
35    - to support the philosophy of Samba to expose the features of
36      the OS within the SMB model. In general whatever file/printer/variable
37      expansions/etc make sense to the OS should be acceptable to Samba.
38 */
39
40
41
42 /*******************************************************************
43  A wrapper for usleep in case we don't have one.
44 ********************************************************************/
45
46 int sys_usleep(long usecs)
47 {
48 #ifndef HAVE_USLEEP
49         struct timeval tval;
50 #endif
51
52         /*
53          * We need this braindamage as the glibc usleep
54          * is not SPEC1170 complient... grumble... JRA.
55          */
56
57         if(usecs < 0 || usecs > 1000000) {
58                 errno = EINVAL;
59                 return -1;
60         }
61
62 #if HAVE_USLEEP
63         usleep(usecs);
64         return 0;
65 #else /* HAVE_USLEEP */
66         /*
67          * Fake it with select...
68          */
69         tval.tv_sec = 0;
70         tval.tv_usec = usecs/1000;
71         select(0,NULL,NULL,NULL,&tval);
72         return 0;
73 #endif /* HAVE_USLEEP */
74 }
75
76 /*******************************************************************
77 A read wrapper that will deal with EINTR.
78 ********************************************************************/
79
80 ssize_t sys_read(int fd, void *buf, size_t count)
81 {
82         ssize_t ret;
83
84         do {
85                 ret = read(fd, buf, count);
86         } while (ret == -1 && errno == EINTR);
87         return ret;
88 }
89
90 /*******************************************************************
91 A write wrapper that will deal with EINTR.
92 ********************************************************************/
93
94 ssize_t sys_write(int fd, const void *buf, size_t count)
95 {
96         ssize_t ret;
97
98         do {
99                 ret = write(fd, buf, count);
100         } while (ret == -1 && errno == EINTR);
101         return ret;
102 }
103
104
105 /*******************************************************************
106 A pread wrapper that will deal with EINTR and 64-bit file offsets.
107 ********************************************************************/
108
109 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
110 ssize_t sys_pread(int fd, void *buf, size_t count, SMB_OFF_T off)
111 {
112         ssize_t ret;
113
114         do {
115 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_PREAD64)
116                 ret = pread64(fd, buf, count, off);
117 #else
118                 ret = pread(fd, buf, count, off);
119 #endif
120         } while (ret == -1 && errno == EINTR);
121         return ret;
122 }
123 #endif
124
125 /*******************************************************************
126 A write wrapper that will deal with EINTR and 64-bit file offsets.
127 ********************************************************************/
128
129 #if defined(HAVE_PWRITE) || defined(HAVE_PWRITE64)
130 ssize_t sys_pwrite(int fd, const void *buf, size_t count, SMB_OFF_T off)
131 {
132         ssize_t ret;
133
134         do {
135 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_PWRITE64)
136                 ret = pwrite64(fd, buf, count, off);
137 #else
138                 ret = pwrite(fd, buf, count, off);
139 #endif
140         } while (ret == -1 && errno == EINTR);
141         return ret;
142 }
143 #endif
144
145 /*******************************************************************
146 A send wrapper that will deal with EINTR.
147 ********************************************************************/
148
149 ssize_t sys_send(int s, const void *msg, size_t len, int flags)
150 {
151         ssize_t ret;
152
153         do {
154                 ret = send(s, msg, len, flags);
155         } while (ret == -1 && errno == EINTR);
156         return ret;
157 }
158
159 /*******************************************************************
160 A sendto wrapper that will deal with EINTR.
161 ********************************************************************/
162
163 ssize_t sys_sendto(int s,  const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
164 {
165         ssize_t ret;
166
167         do {
168                 ret = sendto(s, msg, len, flags, to, tolen);
169         } while (ret == -1 && errno == EINTR);
170         return ret;
171 }
172
173 /*******************************************************************
174 A recvfrom wrapper that will deal with EINTR.
175 ********************************************************************/
176
177 ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
178 {
179         ssize_t ret;
180
181         do {
182                 ret = recvfrom(s, buf, len, flags, from, fromlen);
183         } while (ret == -1 && errno == EINTR);
184         return ret;
185 }
186
187 /*******************************************************************
188 A fcntl wrapper that will deal with EINTR.
189 ********************************************************************/
190
191 int sys_fcntl_ptr(int fd, int cmd, void *arg)
192 {
193         int ret;
194
195         do {
196                 ret = fcntl(fd, cmd, arg);
197         } while (ret == -1 && errno == EINTR);
198         return ret;
199 }
200
201 /*******************************************************************
202 A fcntl wrapper that will deal with EINTR.
203 ********************************************************************/
204
205 int sys_fcntl_long(int fd, int cmd, long arg)
206 {
207         int ret;
208
209         do {
210                 ret = fcntl(fd, cmd, arg);
211         } while (ret == -1 && errno == EINTR);
212         return ret;
213 }
214
215 /*******************************************************************
216 A stat() wrapper that will deal with 64 bit filesizes.
217 ********************************************************************/
218
219 int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf)
220 {
221         int ret;
222 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
223         ret = stat64(fname, sbuf);
224 #else
225         ret = stat(fname, sbuf);
226 #endif
227         /* we always want directories to appear zero size */
228         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
229         return ret;
230 }
231
232 /*******************************************************************
233  An fstat() wrapper that will deal with 64 bit filesizes.
234 ********************************************************************/
235
236 int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf)
237 {
238         int ret;
239 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
240         ret = fstat64(fd, sbuf);
241 #else
242         ret = fstat(fd, sbuf);
243 #endif
244         /* we always want directories to appear zero size */
245         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
246         return ret;
247 }
248
249 /*******************************************************************
250  An lstat() wrapper that will deal with 64 bit filesizes.
251 ********************************************************************/
252
253 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf)
254 {
255         int ret;
256 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
257         ret = lstat64(fname, sbuf);
258 #else
259         ret = lstat(fname, sbuf);
260 #endif
261         /* we always want directories to appear zero size */
262         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
263         return ret;
264 }
265
266 /*******************************************************************
267  An ftruncate() wrapper that will deal with 64 bit filesizes.
268 ********************************************************************/
269
270 int sys_ftruncate(int fd, SMB_OFF_T offset)
271 {
272 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
273         return ftruncate64(fd, offset);
274 #else
275         return ftruncate(fd, offset);
276 #endif
277 }
278
279 /*******************************************************************
280  An lseek() wrapper that will deal with 64 bit filesizes.
281 ********************************************************************/
282
283 SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
284 {
285 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
286         return lseek64(fd, offset, whence);
287 #else
288         return lseek(fd, offset, whence);
289 #endif
290 }
291
292 /*******************************************************************
293  An fseek() wrapper that will deal with 64 bit filesizes.
294 ********************************************************************/
295
296 int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence)
297 {
298 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64)
299         return fseek64(fp, offset, whence);
300 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEKO64)
301         return fseeko64(fp, offset, whence);
302 #else
303         return fseek(fp, offset, whence);
304 #endif
305 }
306
307 /*******************************************************************
308  An ftell() wrapper that will deal with 64 bit filesizes.
309 ********************************************************************/
310
311 SMB_OFF_T sys_ftell(FILE *fp)
312 {
313 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64)
314         return (SMB_OFF_T)ftell64(fp);
315 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELLO64)
316         return (SMB_OFF_T)ftello64(fp);
317 #else
318         return (SMB_OFF_T)ftell(fp);
319 #endif
320 }
321
322 /*******************************************************************
323  A creat() wrapper that will deal with 64 bit filesizes.
324 ********************************************************************/
325
326 int sys_creat(const char *path, mode_t mode)
327 {
328 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CREAT64)
329         return creat64(path, mode);
330 #else
331         /*
332          * If creat64 isn't defined then ensure we call a potential open64.
333          * JRA.
334          */
335         return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
336 #endif
337 }
338
339 /*******************************************************************
340  An open() wrapper that will deal with 64 bit filesizes.
341 ********************************************************************/
342
343 int sys_open(const char *path, int oflag, mode_t mode)
344 {
345 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPEN64)
346         return open64(path, oflag, mode);
347 #else
348         return open(path, oflag, mode);
349 #endif
350 }
351
352 /*******************************************************************
353  An fopen() wrapper that will deal with 64 bit filesizes.
354 ********************************************************************/
355
356 FILE *sys_fopen(const char *path, const char *type)
357 {
358 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_FOPEN64)
359         return fopen64(path, type);
360 #else
361         return fopen(path, type);
362 #endif
363 }
364
365 /*******************************************************************
366  An opendir wrapper that will deal with 64 bit filesizes.
367 ********************************************************************/
368
369 SMB_STRUCT_DIR *sys_opendir(const char *name)
370 {
371 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPENDIR64)
372         return opendir64(name);
373 #else
374         return opendir(name);
375 #endif
376 }
377
378 /*******************************************************************
379  A readdir wrapper that will deal with 64 bit filesizes.
380 ********************************************************************/
381
382 SMB_STRUCT_DIRENT *sys_readdir(SMB_STRUCT_DIR *dirp)
383 {
384 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
385         return readdir64(dirp);
386 #else
387         return readdir(dirp);
388 #endif
389 }
390
391 /*******************************************************************
392  A seekdir wrapper that will deal with 64 bit filesizes.
393 ********************************************************************/
394
395 void sys_seekdir(SMB_STRUCT_DIR *dirp, long offset)
396 {
397 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_SEEKDIR64)
398         seekdir64(dirp, offset);
399 #else
400         seekdir(dirp, offset);
401 #endif
402 }
403
404 /*******************************************************************
405  A telldir wrapper that will deal with 64 bit filesizes.
406 ********************************************************************/
407
408 long sys_telldir(SMB_STRUCT_DIR *dirp)
409 {
410 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_TELLDIR64)
411         return (long)telldir64(dirp);
412 #else
413         return (long)telldir(dirp);
414 #endif
415 }
416
417 /*******************************************************************
418  A rewinddir wrapper that will deal with 64 bit filesizes.
419 ********************************************************************/
420
421 void sys_rewinddir(SMB_STRUCT_DIR *dirp)
422 {
423 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_REWINDDIR64)
424         rewinddir64(dirp);
425 #else
426         rewinddir(dirp);
427 #endif
428 }
429
430 /*******************************************************************
431  A close wrapper that will deal with 64 bit filesizes.
432 ********************************************************************/
433
434 int sys_closedir(SMB_STRUCT_DIR *dirp)
435 {
436 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CLOSEDIR64)
437         return closedir64(dirp);
438 #else
439         return closedir(dirp);
440 #endif
441 }
442
443 /*******************************************************************
444  An mknod() wrapper that will deal with 64 bit filesizes.
445 ********************************************************************/
446
447 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
448 {
449 #if defined(HAVE_MKNOD) || defined(HAVE_MKNOD64)
450 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_MKNOD64) && defined(HAVE_DEV64_T)
451         return mknod64(path, mode, dev);
452 #else
453         return mknod(path, mode, dev);
454 #endif
455 #else
456         /* No mknod system call. */
457         errno = ENOSYS;
458         return -1;
459 #endif
460 }
461
462 /*******************************************************************
463  Wrapper for realpath.
464 ********************************************************************/
465
466 char *sys_realpath(const char *path, char *resolved_path)
467 {
468 #if defined(HAVE_REALPATH)
469         return realpath(path, resolved_path);
470 #else
471         /* As realpath is not a system call we can't return ENOSYS. */
472         errno = EINVAL;
473         return NULL;
474 #endif
475 }
476
477 /*******************************************************************
478 The wait() calls vary between systems
479 ********************************************************************/
480
481 int sys_waitpid(pid_t pid,int *status,int options)
482 {
483 #ifdef HAVE_WAITPID
484         return waitpid(pid,status,options);
485 #else /* HAVE_WAITPID */
486         return wait4(pid, status, options, NULL);
487 #endif /* HAVE_WAITPID */
488 }
489
490 /*******************************************************************
491  System wrapper for getwd
492 ********************************************************************/
493
494 char *sys_getwd(char *s)
495 {
496         char *wd;
497 #ifdef HAVE_GETCWD
498         wd = (char *)getcwd(s, sizeof (pstring));
499 #else
500         wd = (char *)getwd(s);
501 #endif
502         return wd;
503 }
504
505 /*******************************************************************
506 system wrapper for symlink
507 ********************************************************************/
508
509 int sys_symlink(const char *oldpath, const char *newpath)
510 {
511 #ifndef HAVE_SYMLINK
512         errno = ENOSYS;
513         return -1;
514 #else
515         return symlink(oldpath, newpath);
516 #endif
517 }
518
519 /*******************************************************************
520 system wrapper for readlink
521 ********************************************************************/
522
523 int sys_readlink(const char *path, char *buf, size_t bufsiz)
524 {
525 #ifndef HAVE_READLINK
526         errno = ENOSYS;
527         return -1;
528 #else
529         return readlink(path, buf, bufsiz);
530 #endif
531 }
532
533 /*******************************************************************
534 system wrapper for link
535 ********************************************************************/
536
537 int sys_link(const char *oldpath, const char *newpath)
538 {
539 #ifndef HAVE_LINK
540         errno = ENOSYS;
541         return -1;
542 #else
543         return link(oldpath, newpath);
544 #endif
545 }
546
547 /*******************************************************************
548 chown isn't used much but OS/2 doesn't have it
549 ********************************************************************/
550
551 int sys_chown(const char *fname,uid_t uid,gid_t gid)
552 {
553 #ifndef HAVE_CHOWN
554         static int done;
555         if (!done) {
556                 DEBUG(1,("WARNING: no chown!\n"));
557                 done=1;
558         }
559         errno = ENOSYS;
560         return -1;
561 #else
562         return(chown(fname,uid,gid));
563 #endif
564 }
565
566 /*******************************************************************
567 os/2 also doesn't have chroot
568 ********************************************************************/
569 int sys_chroot(const char *dname)
570 {
571 #ifndef HAVE_CHROOT
572         static int done;
573         if (!done) {
574                 DEBUG(1,("WARNING: no chroot!\n"));
575                 done=1;
576         }
577         errno = ENOSYS;
578         return -1;
579 #else
580         return(chroot(dname));
581 #endif
582 }
583
584 /**************************************************************************
585 A wrapper for gethostbyname() that tries avoids looking up hostnames 
586 in the root domain, which can cause dial-on-demand links to come up for no
587 apparent reason.
588 ****************************************************************************/
589
590 struct hostent *sys_gethostbyname(const char *name)
591 {
592 #ifdef REDUCE_ROOT_DNS_LOOKUPS
593         char query[256], hostname[256];
594         char *domain;
595
596         /* Does this name have any dots in it? If so, make no change */
597
598         if (strchr_m(name, '.'))
599                 return(gethostbyname(name));
600
601         /* Get my hostname, which should have domain name 
602                 attached. If not, just do the gethostname on the
603                 original string. 
604         */
605
606         gethostname(hostname, sizeof(hostname) - 1);
607         hostname[sizeof(hostname) - 1] = 0;
608         if ((domain = strchr_m(hostname, '.')) == NULL)
609                 return(gethostbyname(name));
610
611         /* Attach domain name to query and do modified query.
612                 If names too large, just do gethostname on the
613                 original string.
614         */
615
616         if((strlen(name) + strlen(domain)) >= sizeof(query))
617                 return(gethostbyname(name));
618
619         slprintf(query, sizeof(query)-1, "%s%s", name, domain);
620         return(gethostbyname(query));
621 #else /* REDUCE_ROOT_DNS_LOOKUPS */
622         return(gethostbyname(name));
623 #endif /* REDUCE_ROOT_DNS_LOOKUPS */
624 }
625
626
627 #if defined(HAVE_POSIX_CAPABILITIES)
628
629 #ifdef HAVE_SYS_CAPABILITY_H
630
631 #if defined(BROKEN_REDHAT_7_SYSTEM_HEADERS) && !defined(_I386_STATFS_H) && !defined(_PPC_STATFS_H)
632 #define _I386_STATFS_H
633 #define _PPC_STATFS_H
634 #define BROKEN_REDHAT_7_STATFS_WORKAROUND
635 #endif
636
637 #include <sys/capability.h>
638
639 #ifdef BROKEN_REDHAT_7_STATFS_WORKAROUND
640 #undef _I386_STATFS_H
641 #undef _PPC_STATFS_H
642 #undef BROKEN_REDHAT_7_STATFS_WORKAROUND
643 #endif
644
645 #endif /* HAVE_SYS_CAPABILITY_H */
646
647 /**************************************************************************
648  Try and abstract process capabilities (for systems that have them).
649 ****************************************************************************/
650
651 /* Set the POSIX capabilities needed for the given purpose into the effective
652  * capability set of the current process. Make sure they are always removed
653  * from the inheritable set, because there is no circumstance in which our
654  * children should inherit our elevated privileges.
655  */
656 static BOOL set_process_capability(enum smbd_capability capability,
657                                    BOOL enable)
658 {
659         cap_value_t cap_vals[2] = {0};
660         int num_cap_vals = 0;
661
662         cap_t cap;
663
664         cap = cap_get_proc();
665         if (cap == NULL) {
666                 DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
667                         strerror(errno)));
668                 return False;
669         }
670
671         switch (capability) {
672                 case KERNEL_OPLOCK_CAPABILITY:
673 #ifdef CAP_NETWORK_MGT
674                         /* IRIX has CAP_NETWORK_MGT for oplocks. */
675                         cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
676 #endif
677                         break;
678         }
679
680         SMB_ASSERT(num_cap_vals <= ARRAY_SIZE(cap_vals));
681
682         if (num_cap_vals == 0) {
683                 cap_free(cap);
684                 return True;
685         }
686
687         cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
688                 enable ? CAP_SET : CAP_CLEAR);
689         cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
690
691         if (cap_set_proc(cap) == -1) {
692                 DEBUG(0, ("set_process_capability: cap_set_proc failed: %s\n",
693                         strerror(errno)));
694                 cap_free(cap);
695                 return False;
696         }
697
698         cap_free(cap);
699         return True;
700 }
701
702 #endif /* HAVE_POSIX_CAPABILITIES */
703
704 /****************************************************************************
705  Gain the oplock capability from the kernel if possible.
706 ****************************************************************************/
707
708 void set_effective_capability(enum smbd_capability capability)
709 {
710 #if defined(HAVE_POSIX_CAPABILITIES)
711         set_process_capability(capability, True);
712 #endif /* HAVE_POSIX_CAPABILITIES */
713 }
714
715 void drop_effective_capability(enum smbd_capability capability)
716 {
717 #if defined(HAVE_POSIX_CAPABILITIES)
718         set_process_capability(capability, False);
719 #endif /* HAVE_POSIX_CAPABILITIES */
720 }
721
722 /**************************************************************************
723  Wrapper for random().
724 ****************************************************************************/
725
726 long sys_random(void)
727 {
728 #if defined(HAVE_RANDOM)
729         return (long)random();
730 #elif defined(HAVE_RAND)
731         return (long)rand();
732 #else
733         DEBUG(0,("Error - no random function available !\n"));
734         exit(1);
735 #endif
736 }
737
738 /**************************************************************************
739  Wrapper for srandom().
740 ****************************************************************************/
741
742 void sys_srandom(unsigned int seed)
743 {
744 #if defined(HAVE_SRANDOM)
745         srandom(seed);
746 #elif defined(HAVE_SRAND)
747         srand(seed);
748 #else
749         DEBUG(0,("Error - no srandom function available !\n"));
750         exit(1);
751 #endif
752 }
753
754 /**************************************************************************
755  Returns equivalent to NGROUPS_MAX - using sysconf if needed.
756 ****************************************************************************/
757
758 int groups_max(void)
759 {
760 #if defined(SYSCONF_SC_NGROUPS_MAX)
761         int ret = sysconf(_SC_NGROUPS_MAX);
762         return (ret == -1) ? NGROUPS_MAX : ret;
763 #else
764         return NGROUPS_MAX;
765 #endif
766 }
767
768 /**************************************************************************
769  Wrapper for getgroups. Deals with broken (int) case.
770 ****************************************************************************/
771
772 int sys_getgroups(int setlen, gid_t *gidset)
773 {
774 #if !defined(HAVE_BROKEN_GETGROUPS)
775         return getgroups(setlen, gidset);
776 #else
777
778         GID_T gid;
779         GID_T *group_list;
780         int i, ngroups;
781
782         if(setlen == 0) {
783                 return getgroups(setlen, &gid);
784         }
785
786         /*
787          * Broken case. We need to allocate a
788          * GID_T array of size setlen.
789          */
790
791         if(setlen < 0) {
792                 errno = EINVAL; 
793                 return -1;
794         } 
795
796         if (setlen == 0)
797                 setlen = groups_max();
798
799         if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
800                 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
801                 return -1;
802         }
803
804         if((ngroups = getgroups(setlen, group_list)) < 0) {
805                 int saved_errno = errno;
806                 SAFE_FREE(group_list);
807                 errno = saved_errno;
808                 return -1;
809         }
810
811         for(i = 0; i < ngroups; i++)
812                 gidset[i] = (gid_t)group_list[i];
813
814         SAFE_FREE(group_list);
815         return ngroups;
816 #endif /* HAVE_BROKEN_GETGROUPS */
817 }
818
819
820 /**************************************************************************
821  Wrapper for setgroups. Deals with broken (int) case. Automatically used
822  if we have broken getgroups.
823 ****************************************************************************/
824
825 int sys_setgroups(int setlen, gid_t *gidset)
826 {
827 #if !defined(HAVE_SETGROUPS)
828         errno = ENOSYS;
829         return -1;
830 #endif /* HAVE_SETGROUPS */
831
832 #if !defined(HAVE_BROKEN_GETGROUPS)
833         return setgroups(setlen, gidset);
834 #else
835
836         GID_T *group_list;
837         int i ; 
838
839         if (setlen == 0)
840                 return 0 ;
841
842         if (setlen < 0 || setlen > groups_max()) {
843                 errno = EINVAL; 
844                 return -1;   
845         }
846
847         /*
848          * Broken case. We need to allocate a
849          * GID_T array of size setlen.
850          */
851
852         if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
853                 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
854                 return -1;    
855         }
856  
857         for(i = 0; i < setlen; i++) 
858                 group_list[i] = (GID_T) gidset[i]; 
859
860         if(setgroups(setlen, group_list) != 0) {
861                 int saved_errno = errno;
862                 SAFE_FREE(group_list);
863                 errno = saved_errno;
864                 return -1;
865         }
866  
867         SAFE_FREE(group_list);
868         return 0 ;
869 #endif /* HAVE_BROKEN_GETGROUPS */
870 }
871
872 /**************************************************************************
873  Wrappers for setpwent(), getpwent() and endpwent()
874 ****************************************************************************/
875
876 void sys_setpwent(void)
877 {
878         setpwent();
879 }
880
881 struct passwd *sys_getpwent(void)
882 {
883         return getpwent();
884 }
885
886 void sys_endpwent(void)
887 {
888         endpwent();
889 }
890
891 /**************************************************************************
892  Wrappers for getpwnam(), getpwuid(), getgrnam(), getgrgid()
893 ****************************************************************************/
894
895 struct passwd *sys_getpwnam(const char *name)
896 {
897         return getpwnam(name);
898 }
899
900 struct passwd *sys_getpwuid(uid_t uid)
901 {
902         return getpwuid(uid);
903 }
904
905 struct group *sys_getgrnam(const char *name)
906 {
907         return getgrnam(name);
908 }
909
910 struct group *sys_getgrgid(gid_t gid)
911 {
912         return getgrgid(gid);
913 }
914
915 #if 0 /* NOT CURRENTLY USED - JRA */
916 /**************************************************************************
917  The following are the UNICODE versions of *all* system interface functions
918  called within Samba. Ok, ok, the exceptions are the gethostbyXX calls,
919  which currently are left as ascii as they are not used other than in name
920  resolution.
921 ****************************************************************************/
922
923 /**************************************************************************
924  Wide stat. Just narrow and call sys_xxx.
925 ****************************************************************************/
926
927 int wsys_stat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
928 {
929         pstring fname;
930         return sys_stat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
931 }
932
933 /**************************************************************************
934  Wide lstat. Just narrow and call sys_xxx.
935 ****************************************************************************/
936
937 int wsys_lstat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
938 {
939         pstring fname;
940         return sys_lstat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
941 }
942
943 /**************************************************************************
944  Wide creat. Just narrow and call sys_xxx.
945 ****************************************************************************/
946
947 int wsys_creat(const smb_ucs2_t *wfname, mode_t mode)
948 {
949         pstring fname;
950         return sys_creat(unicode_to_unix(fname,wfname,sizeof(fname)), mode);
951 }
952
953 /**************************************************************************
954  Wide open. Just narrow and call sys_xxx.
955 ****************************************************************************/
956
957 int wsys_open(const smb_ucs2_t *wfname, int oflag, mode_t mode)
958 {
959         pstring fname;
960         return sys_open(unicode_to_unix(fname,wfname,sizeof(fname)), oflag, mode);
961 }
962
963 /**************************************************************************
964  Wide fopen. Just narrow and call sys_xxx.
965 ****************************************************************************/
966
967 FILE *wsys_fopen(const smb_ucs2_t *wfname, const char *type)
968 {
969         pstring fname;
970         return sys_fopen(unicode_to_unix(fname,wfname,sizeof(fname)), type);
971 }
972
973 /**************************************************************************
974  Wide opendir. Just narrow and call sys_xxx.
975 ****************************************************************************/
976
977 SMB_STRUCT_DIR *wsys_opendir(const smb_ucs2_t *wfname)
978 {
979         pstring fname;
980         return opendir(unicode_to_unix(fname,wfname,sizeof(fname)));
981 }
982
983 /**************************************************************************
984  Wide readdir. Return a structure pointer containing a wide filename.
985 ****************************************************************************/
986
987 SMB_STRUCT_WDIRENT *wsys_readdir(SMB_STRUCT_DIR *dirp)
988 {
989         static SMB_STRUCT_WDIRENT retval;
990         SMB_STRUCT_DIRENT *dirval = sys_readdir(dirp);
991
992         if(!dirval)
993                 return NULL;
994
995         /*
996          * The only POSIX defined member of this struct is d_name.
997          */
998
999         unix_to_unicode(retval.d_name,dirval->d_name,sizeof(retval.d_name));
1000
1001         return &retval;
1002 }
1003
1004 /**************************************************************************
1005  Wide getwd. Call sys_xxx and widen. Assumes s points to a wpstring.
1006 ****************************************************************************/
1007
1008 smb_ucs2_t *wsys_getwd(smb_ucs2_t *s)
1009 {
1010         pstring fname;
1011         char *p = sys_getwd(fname);
1012
1013         if(!p)
1014                 return NULL;
1015
1016         return unix_to_unicode(s, p, sizeof(wpstring));
1017 }
1018
1019 /**************************************************************************
1020  Wide chown. Just narrow and call sys_xxx.
1021 ****************************************************************************/
1022
1023 int wsys_chown(const smb_ucs2_t *wfname, uid_t uid, gid_t gid)
1024 {
1025         pstring fname;
1026         return chown(unicode_to_unix(fname,wfname,sizeof(fname)), uid, gid);
1027 }
1028
1029 /**************************************************************************
1030  Wide chroot. Just narrow and call sys_xxx.
1031 ****************************************************************************/
1032
1033 int wsys_chroot(const smb_ucs2_t *wfname)
1034 {
1035         pstring fname;
1036         return chroot(unicode_to_unix(fname,wfname,sizeof(fname)));
1037 }
1038
1039 /**************************************************************************
1040  Wide getpwnam. Return a structure pointer containing wide names.
1041 ****************************************************************************/
1042
1043 SMB_STRUCT_WPASSWD *wsys_getpwnam(const smb_ucs2_t *wname)
1044 {
1045         static SMB_STRUCT_WPASSWD retval;
1046         fstring name;
1047         struct passwd *pwret = sys_getpwnam(unicode_to_unix(name,wname,sizeof(name)));
1048
1049         if(!pwret)
1050                 return NULL;
1051
1052         unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
1053         retval.pw_passwd = pwret->pw_passwd;
1054         retval.pw_uid = pwret->pw_uid;
1055         retval.pw_gid = pwret->pw_gid;
1056         unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
1057         unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
1058         unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
1059
1060         return &retval;
1061 }
1062
1063 /**************************************************************************
1064  Wide getpwuid. Return a structure pointer containing wide names.
1065 ****************************************************************************/
1066
1067 SMB_STRUCT_WPASSWD *wsys_getpwuid(uid_t uid)
1068 {
1069         static SMB_STRUCT_WPASSWD retval;
1070         struct passwd *pwret = sys_getpwuid(uid);
1071
1072         if(!pwret)
1073                 return NULL;
1074
1075         unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
1076         retval.pw_passwd = pwret->pw_passwd;
1077         retval.pw_uid = pwret->pw_uid;
1078         retval.pw_gid = pwret->pw_gid;
1079         unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
1080         unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
1081         unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
1082
1083         return &retval;
1084 }
1085 #endif /* NOT CURRENTLY USED - JRA */
1086
1087 /**************************************************************************
1088  Extract a command into an arg list. Uses a static pstring for storage.
1089  Caller frees returned arg list (which contains pointers into the static pstring).
1090 ****************************************************************************/
1091
1092 static char **extract_args(const char *command)
1093 {
1094         static pstring trunc_cmd;
1095         char *ptr;
1096         int argcl;
1097         char **argl = NULL;
1098         int i;
1099
1100         pstrcpy(trunc_cmd, command);
1101
1102         if(!(ptr = strtok(trunc_cmd, " \t"))) {
1103                 errno = EINVAL;
1104                 return NULL;
1105         }
1106
1107         /*
1108          * Count the args.
1109          */
1110
1111         for( argcl = 1; ptr; ptr = strtok(NULL, " \t"))
1112                 argcl++;
1113
1114         if((argl = (char **)SMB_MALLOC((argcl + 1) * sizeof(char *))) == NULL)
1115                 return NULL;
1116
1117         /*
1118          * Now do the extraction.
1119          */
1120
1121         pstrcpy(trunc_cmd, command);
1122
1123         ptr = strtok(trunc_cmd, " \t");
1124         i = 0;
1125         argl[i++] = ptr;
1126
1127         while((ptr = strtok(NULL, " \t")) != NULL)
1128                 argl[i++] = ptr;
1129
1130         argl[i++] = NULL;
1131         return argl;
1132 }
1133
1134 /**************************************************************************
1135  Wrapper for fork. Ensures that mypid is reset. Used so we can write
1136  a sys_getpid() that only does a system call *once*.
1137 ****************************************************************************/
1138
1139 static pid_t mypid = (pid_t)-1;
1140
1141 pid_t sys_fork(void)
1142 {
1143         pid_t forkret = fork();
1144
1145         if (forkret == (pid_t)0) /* Child - reset mypid so sys_getpid does a system call. */
1146                 mypid = (pid_t) -1;
1147
1148         return forkret;
1149 }
1150
1151 /**************************************************************************
1152  Wrapper for getpid. Ensures we only do a system call *once*.
1153 ****************************************************************************/
1154
1155 pid_t sys_getpid(void)
1156 {
1157         if (mypid == (pid_t)-1)
1158                 mypid = getpid();
1159
1160         return mypid;
1161 }
1162
1163 /**************************************************************************
1164  Wrapper for popen. Safer as it doesn't search a path.
1165  Modified from the glibc sources.
1166  modified by tridge to return a file descriptor. We must kick our FILE* habit
1167 ****************************************************************************/
1168
1169 typedef struct _popen_list
1170 {
1171         int fd;
1172         pid_t child_pid;
1173         struct _popen_list *next;
1174 } popen_list;
1175
1176 static popen_list *popen_chain;
1177
1178 int sys_popen(const char *command)
1179 {
1180         int parent_end, child_end;
1181         int pipe_fds[2];
1182         popen_list *entry = NULL;
1183         char **argl = NULL;
1184
1185         if (pipe(pipe_fds) < 0)
1186                 return -1;
1187
1188         parent_end = pipe_fds[0];
1189         child_end = pipe_fds[1];
1190
1191         if (!*command) {
1192                 errno = EINVAL;
1193                 goto err_exit;
1194         }
1195
1196         if((entry = SMB_MALLOC_P(popen_list)) == NULL)
1197                 goto err_exit;
1198
1199         ZERO_STRUCTP(entry);
1200
1201         /*
1202          * Extract the command and args into a NULL terminated array.
1203          */
1204
1205         if(!(argl = extract_args(command)))
1206                 goto err_exit;
1207
1208         entry->child_pid = sys_fork();
1209
1210         if (entry->child_pid == -1) {
1211                 goto err_exit;
1212         }
1213
1214         if (entry->child_pid == 0) {
1215
1216                 /*
1217                  * Child !
1218                  */
1219
1220                 int child_std_end = STDOUT_FILENO;
1221                 popen_list *p;
1222
1223                 close(parent_end);
1224                 if (child_end != child_std_end) {
1225                         dup2 (child_end, child_std_end);
1226                         close (child_end);
1227                 }
1228
1229                 /*
1230                  * POSIX.2:  "popen() shall ensure that any streams from previous
1231                  * popen() calls that remain open in the parent process are closed
1232                  * in the new child process."
1233                  */
1234
1235                 for (p = popen_chain; p; p = p->next)
1236                         close(p->fd);
1237
1238                 execv(argl[0], argl);
1239                 _exit (127);
1240         }
1241
1242         /*
1243          * Parent.
1244          */
1245
1246         close (child_end);
1247         SAFE_FREE(argl);
1248
1249         /* Link into popen_chain. */
1250         entry->next = popen_chain;
1251         popen_chain = entry;
1252         entry->fd = parent_end;
1253
1254         return entry->fd;
1255
1256 err_exit:
1257
1258         SAFE_FREE(entry);
1259         SAFE_FREE(argl);
1260         close(pipe_fds[0]);
1261         close(pipe_fds[1]);
1262         return -1;
1263 }
1264
1265 /**************************************************************************
1266  Wrapper for pclose. Modified from the glibc sources.
1267 ****************************************************************************/
1268
1269 int sys_pclose(int fd)
1270 {
1271         int wstatus;
1272         popen_list **ptr = &popen_chain;
1273         popen_list *entry = NULL;
1274         pid_t wait_pid;
1275         int status = -1;
1276
1277         /* Unlink from popen_chain. */
1278         for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1279                 if ((*ptr)->fd == fd) {
1280                         entry = *ptr;
1281                         *ptr = (*ptr)->next;
1282                         status = 0;
1283                         break;
1284                 }
1285         }
1286
1287         if (status < 0 || close(entry->fd) < 0)
1288                 return -1;
1289
1290         /*
1291          * As Samba is catching and eating child process
1292          * exits we don't really care about the child exit
1293          * code, a -1 with errno = ECHILD will do fine for us.
1294          */
1295
1296         do {
1297                 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1298         } while (wait_pid == -1 && errno == EINTR);
1299
1300         SAFE_FREE(entry);
1301
1302         if (wait_pid == -1)
1303                 return -1;
1304         return wstatus;
1305 }
1306
1307 /**************************************************************************
1308  Wrappers for dlopen, dlsym, dlclose.
1309 ****************************************************************************/
1310
1311 void *sys_dlopen(const char *name, int flags)
1312 {
1313 #if defined(HAVE_DLOPEN)
1314         return dlopen(name, flags);
1315 #else
1316         return NULL;
1317 #endif
1318 }
1319
1320 void *sys_dlsym(void *handle, const char *symbol)
1321 {
1322 #if defined(HAVE_DLSYM)
1323     return dlsym(handle, symbol);
1324 #else
1325     return NULL;
1326 #endif
1327 }
1328
1329 int sys_dlclose (void *handle)
1330 {
1331 #if defined(HAVE_DLCLOSE)
1332         return dlclose(handle);
1333 #else
1334         return 0;
1335 #endif
1336 }
1337
1338 const char *sys_dlerror(void)
1339 {
1340 #if defined(HAVE_DLERROR)
1341         return dlerror();
1342 #else
1343         return NULL;
1344 #endif
1345 }
1346
1347 int sys_dup2(int oldfd, int newfd) 
1348 {
1349 #if defined(HAVE_DUP2)
1350         return dup2(oldfd, newfd);
1351 #else
1352         errno = ENOSYS;
1353         return -1;
1354 #endif
1355 }
1356
1357 /**************************************************************************
1358  Wrapper for Admin Logs.
1359 ****************************************************************************/
1360
1361  void sys_adminlog(int priority, const char *format_str, ...) 
1362 {
1363         va_list ap;
1364         int ret;
1365         char *msgbuf = NULL;
1366
1367         va_start( ap, format_str );
1368         ret = vasprintf( &msgbuf, format_str, ap );
1369         va_end( ap );
1370
1371         if (ret == -1)
1372                 return;
1373
1374 #if defined(HAVE_SYSLOG)
1375         syslog( priority, "%s", msgbuf );
1376 #else
1377         DEBUG(0,("%s", msgbuf ));
1378 #endif
1379         SAFE_FREE(msgbuf);
1380 }
1381
1382 /**************************************************************************
1383  Wrappers for extented attribute calls. Based on the Linux package with
1384  support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
1385 ****************************************************************************/
1386
1387 ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size)
1388 {
1389 #if defined(HAVE_GETXATTR)
1390         return getxattr(path, name, value, size);
1391 #elif defined(HAVE_GETEA)
1392         return getea(path, name, value, size);
1393 #elif defined(HAVE_EXTATTR_GET_FILE)
1394         char *s;
1395         ssize_t retval;
1396         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1397                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1398         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1399         /*
1400          * The BSD implementation has a nasty habit of silently truncating
1401          * the returned value to the size of the buffer, so we have to check
1402          * that the buffer is large enough to fit the returned value.
1403          */
1404         if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1405                 if(retval > size) {
1406                         errno = ERANGE;
1407                         return -1;
1408                 }
1409                 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
1410                         return retval;
1411         }
1412
1413         DEBUG(10,("sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno)));
1414         return -1;
1415 #elif defined(HAVE_ATTR_GET)
1416         int retval, flags = 0;
1417         int valuelength = (int)size;
1418         char *attrname = strchr(name,'.') + 1;
1419         
1420         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1421
1422         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1423
1424         return retval ? retval : valuelength;
1425 #else
1426         errno = ENOSYS;
1427         return -1;
1428 #endif
1429 }
1430
1431 ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size)
1432 {
1433 #if defined(HAVE_LGETXATTR)
1434         return lgetxattr(path, name, value, size);
1435 #elif defined(HAVE_LGETEA)
1436         return lgetea(path, name, value, size);
1437 #elif defined(HAVE_EXTATTR_GET_LINK)
1438         char *s;
1439         ssize_t retval;
1440         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1441                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1442         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1443
1444         if((retval=extattr_get_link(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1445                 if(retval > size) {
1446                         errno = ERANGE;
1447                         return -1;
1448                 }
1449                 if((retval=extattr_get_link(path, attrnamespace, attrname, value, size)) >= 0)
1450                         return retval;
1451         }
1452         
1453         DEBUG(10,("sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno)));
1454         return -1;
1455 #elif defined(HAVE_ATTR_GET)
1456         int retval, flags = ATTR_DONTFOLLOW;
1457         int valuelength = (int)size;
1458         char *attrname = strchr(name,'.') + 1;
1459         
1460         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1461
1462         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1463
1464         return retval ? retval : valuelength;
1465 #else
1466         errno = ENOSYS;
1467         return -1;
1468 #endif
1469 }
1470
1471 ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size)
1472 {
1473 #if defined(HAVE_FGETXATTR)
1474         return fgetxattr(filedes, name, value, size);
1475 #elif defined(HAVE_FGETEA)
1476         return fgetea(filedes, name, value, size);
1477 #elif defined(HAVE_EXTATTR_GET_FD)
1478         char *s;
1479         ssize_t retval;
1480         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1481                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1482         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1483
1484         if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
1485                 if(retval > size) {
1486                         errno = ERANGE;
1487                         return -1;
1488                 }
1489                 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
1490                         return retval;
1491         }
1492         
1493         DEBUG(10,("sys_fgetxattr: extattr_get_fd() failed with: %s\n", strerror(errno)));
1494         return -1;
1495 #elif defined(HAVE_ATTR_GETF)
1496         int retval, flags = 0;
1497         int valuelength = (int)size;
1498         char *attrname = strchr(name,'.') + 1;
1499         
1500         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1501
1502         retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
1503
1504         return retval ? retval : valuelength;
1505 #else
1506         errno = ENOSYS;
1507         return -1;
1508 #endif
1509 }
1510
1511 #if defined(HAVE_EXTATTR_LIST_FILE)
1512
1513 #define EXTATTR_PREFIX(s)       (s), (sizeof((s))-1)
1514
1515 static struct {
1516         int space;
1517         const char *name;
1518         size_t len;
1519
1520 extattr[] = {
1521         { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
1522         { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
1523 };
1524
1525 typedef union {
1526         const char *path;
1527         int filedes;
1528 } extattr_arg;
1529
1530 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
1531 {
1532         ssize_t list_size, total_size = 0;
1533         int i, t, len;
1534         char *buf;
1535         /* Iterate through extattr(2) namespaces */
1536         for(t = 0; t < (sizeof(extattr)/sizeof(extattr[0])); t++) {
1537                 switch(type) {
1538 #if defined(HAVE_EXTATTR_LIST_FILE)
1539                         case 0:
1540                                 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
1541                                 break;
1542 #endif
1543 #if defined(HAVE_EXTATTR_LIST_LINK)
1544                         case 1:
1545                                 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
1546                                 break;
1547 #endif
1548 #if defined(HAVE_EXTATTR_LIST_FD)
1549                         case 2:
1550                                 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
1551                                 break;
1552 #endif
1553                         default:
1554                                 errno = ENOSYS;
1555                                 return -1;
1556                 }
1557                 /* Some error happend. Errno should be set by the previous call */
1558                 if(list_size < 0)
1559                         return -1;
1560                 /* No attributes */
1561                 if(list_size == 0)
1562                         continue;
1563                 /* XXX: Call with an empty buffer may be used to calculate
1564                    necessary buffer size. Unfortunately, we can't say, how
1565                    many attributes were returned, so here is the potential
1566                    problem with the emulation.
1567                 */
1568                 if(list == NULL) {
1569                         /* Take the worse case of one char attribute names - 
1570                            two bytes per name plus one more for sanity.
1571                         */
1572                         total_size += list_size + (list_size/2 + 1)*extattr[t].len;
1573                         continue;
1574                 }
1575                 /* Count necessary offset to fit namespace prefixes */
1576                 len = 0;
1577                 for(i = 0; i < list_size; i += list[i] + 1)
1578                         len += extattr[t].len;
1579
1580                 total_size += list_size + len;
1581                 /* Buffer is too small to fit the results */
1582                 if(total_size > size) {
1583                         errno = ERANGE;
1584                         return -1;
1585                 }
1586                 /* Shift results back, so we can prepend prefixes */
1587                 buf = memmove(list + len, list, list_size);
1588
1589                 for(i = 0; i < list_size; i += len + 1) {
1590                         len = buf[i];
1591                         strncpy(list, extattr[t].name, extattr[t].len + 1);
1592                         list += extattr[t].len;
1593                         strncpy(list, buf + i + 1, len);
1594                         list[len] = '\0';
1595                         list += len + 1;
1596                 }
1597                 size -= total_size;
1598         }
1599         return total_size;
1600 }
1601
1602 #endif
1603
1604 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1605 static char attr_buffer[ATTR_MAX_VALUELEN];
1606
1607 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
1608 {
1609         int retval = 0, index;
1610         attrlist_cursor_t *cursor = 0;
1611         int total_size = 0;
1612         attrlist_t * al = (attrlist_t *)attr_buffer;
1613         attrlist_ent_t *ae;
1614         size_t ent_size, left = size;
1615         char *bp = list;
1616
1617         while (True) {
1618             if (filedes)
1619                 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1620             else
1621                 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1622             if (retval) break;
1623             for (index = 0; index < al->al_count; index++) {
1624                 ae = ATTR_ENTRY(attr_buffer, index);
1625                 ent_size = strlen(ae->a_name) + sizeof("user.");
1626                 if (left >= ent_size) {
1627                     strncpy(bp, "user.", sizeof("user."));
1628                     strncat(bp, ae->a_name, ent_size - sizeof("user."));
1629                     bp += ent_size;
1630                     left -= ent_size;
1631                 } else if (size) {
1632                     errno = ERANGE;
1633                     retval = -1;
1634                     break;
1635                 }
1636                 total_size += ent_size;
1637             }
1638             if (al->al_more == 0) break;
1639         }
1640         if (retval == 0) {
1641             flags |= ATTR_ROOT;
1642             cursor = 0;
1643             while (True) {
1644                 if (filedes)
1645                     retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1646                 else
1647                     retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1648                 if (retval) break;
1649                 for (index = 0; index < al->al_count; index++) {
1650                     ae = ATTR_ENTRY(attr_buffer, index);
1651                     ent_size = strlen(ae->a_name) + sizeof("system.");
1652                     if (left >= ent_size) {
1653                         strncpy(bp, "system.", sizeof("system."));
1654                         strncat(bp, ae->a_name, ent_size - sizeof("system."));
1655                         bp += ent_size;
1656                         left -= ent_size;
1657                     } else if (size) {
1658                         errno = ERANGE;
1659                         retval = -1;
1660                         break;
1661                     }
1662                     total_size += ent_size;
1663                 }
1664                 if (al->al_more == 0) break;
1665             }
1666         }
1667         return (ssize_t)(retval ? retval : total_size);
1668 }
1669
1670 #endif
1671
1672 ssize_t sys_listxattr (const char *path, char *list, size_t size)
1673 {
1674 #if defined(HAVE_LISTXATTR)
1675         return listxattr(path, list, size);
1676 #elif defined(HAVE_LISTEA)
1677         return listea(path, list, size);
1678 #elif defined(HAVE_EXTATTR_LIST_FILE)
1679         extattr_arg arg;
1680         arg.path = path;
1681         return bsd_attr_list(0, arg, list, size);
1682 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1683         return irix_attr_list(path, 0, list, size, 0);
1684 #else
1685         errno = ENOSYS;
1686         return -1;
1687 #endif
1688 }
1689
1690 ssize_t sys_llistxattr (const char *path, char *list, size_t size)
1691 {
1692 #if defined(HAVE_LLISTXATTR)
1693         return llistxattr(path, list, size);
1694 #elif defined(HAVE_LLISTEA)
1695         return llistea(path, list, size);
1696 #elif defined(HAVE_EXTATTR_LIST_LINK)
1697         extattr_arg arg;
1698         arg.path = path;
1699         return bsd_attr_list(1, arg, list, size);
1700 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1701         return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
1702 #else
1703         errno = ENOSYS;
1704         return -1;
1705 #endif
1706 }
1707
1708 ssize_t sys_flistxattr (int filedes, char *list, size_t size)
1709 {
1710 #if defined(HAVE_FLISTXATTR)
1711         return flistxattr(filedes, list, size);
1712 #elif defined(HAVE_FLISTEA)
1713         return flistea(filedes, list, size);
1714 #elif defined(HAVE_EXTATTR_LIST_FD)
1715         extattr_arg arg;
1716         arg.filedes = filedes;
1717         return bsd_attr_list(2, arg, list, size);
1718 #elif defined(HAVE_ATTR_LISTF)
1719         return irix_attr_list(NULL, filedes, list, size, 0);
1720 #else
1721         errno = ENOSYS;
1722         return -1;
1723 #endif
1724 }
1725
1726 int sys_removexattr (const char *path, const char *name)
1727 {
1728 #if defined(HAVE_REMOVEXATTR)
1729         return removexattr(path, name);
1730 #elif defined(HAVE_REMOVEEA)
1731         return removeea(path, name);
1732 #elif defined(HAVE_EXTATTR_DELETE_FILE)
1733         char *s;
1734         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1735                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1736         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1737
1738         return extattr_delete_file(path, attrnamespace, attrname);
1739 #elif defined(HAVE_ATTR_REMOVE)
1740         int flags = 0;
1741         char *attrname = strchr(name,'.') + 1;
1742         
1743         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1744
1745         return attr_remove(path, attrname, flags);
1746 #else
1747         errno = ENOSYS;
1748         return -1;
1749 #endif
1750 }
1751
1752 int sys_lremovexattr (const char *path, const char *name)
1753 {
1754 #if defined(HAVE_LREMOVEXATTR)
1755         return lremovexattr(path, name);
1756 #elif defined(HAVE_LREMOVEEA)
1757         return lremoveea(path, name);
1758 #elif defined(HAVE_EXTATTR_DELETE_LINK)
1759         char *s;
1760         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1761                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1762         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1763
1764         return extattr_delete_link(path, attrnamespace, attrname);
1765 #elif defined(HAVE_ATTR_REMOVE)
1766         int flags = ATTR_DONTFOLLOW;
1767         char *attrname = strchr(name,'.') + 1;
1768         
1769         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1770
1771         return attr_remove(path, attrname, flags);
1772 #else
1773         errno = ENOSYS;
1774         return -1;
1775 #endif
1776 }
1777
1778 int sys_fremovexattr (int filedes, const char *name)
1779 {
1780 #if defined(HAVE_FREMOVEXATTR)
1781         return fremovexattr(filedes, name);
1782 #elif defined(HAVE_FREMOVEEA)
1783         return fremoveea(filedes, name);
1784 #elif defined(HAVE_EXTATTR_DELETE_FD)
1785         char *s;
1786         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1787                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1788         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1789
1790         return extattr_delete_fd(filedes, attrnamespace, attrname);
1791 #elif defined(HAVE_ATTR_REMOVEF)
1792         int flags = 0;
1793         char *attrname = strchr(name,'.') + 1;
1794         
1795         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1796
1797         return attr_removef(filedes, attrname, flags);
1798 #else
1799         errno = ENOSYS;
1800         return -1;
1801 #endif
1802 }
1803
1804 #if !defined(HAVE_SETXATTR)
1805 #define XATTR_CREATE  0x1       /* set value, fail if attr already exists */
1806 #define XATTR_REPLACE 0x2       /* set value, fail if attr does not exist */
1807 #endif
1808
1809 int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
1810 {
1811 #if defined(HAVE_SETXATTR)
1812         return setxattr(path, name, value, size, flags);
1813 #elif defined(HAVE_SETEA)
1814         return setea(path, name, value, size, flags);
1815 #elif defined(HAVE_EXTATTR_SET_FILE)
1816         char *s;
1817         int retval = 0;
1818         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1819                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1820         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1821         if (flags) {
1822                 /* Check attribute existence */
1823                 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
1824                 if (retval < 0) {
1825                         /* REPLACE attribute, that doesn't exist */
1826                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
1827                                 errno = ENOATTR;
1828                                 return -1;
1829                         }
1830                         /* Ignore other errors */
1831                 }
1832                 else {
1833                         /* CREATE attribute, that already exists */
1834                         if (flags & XATTR_CREATE) {
1835                                 errno = EEXIST;
1836                                 return -1;
1837                         }
1838                 }
1839         }
1840         retval = extattr_set_file(path, attrnamespace, attrname, value, size);
1841         return (retval < 0) ? -1 : 0;
1842 #elif defined(HAVE_ATTR_SET)
1843         int myflags = 0;
1844         char *attrname = strchr(name,'.') + 1;
1845         
1846         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
1847         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
1848         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
1849
1850         return attr_set(path, attrname, (const char *)value, size, myflags);
1851 #else
1852         errno = ENOSYS;
1853         return -1;
1854 #endif
1855 }
1856
1857 int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags)
1858 {
1859 #if defined(HAVE_LSETXATTR)
1860         return lsetxattr(path, name, value, size, flags);
1861 #elif defined(LSETEA)
1862         return lsetea(path, name, value, size, flags);
1863 #elif defined(HAVE_EXTATTR_SET_LINK)
1864         char *s;
1865         int retval = 0;
1866         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1867                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1868         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1869         if (flags) {
1870                 /* Check attribute existence */
1871                 retval = extattr_get_link(path, attrnamespace, attrname, NULL, 0);
1872                 if (retval < 0) {
1873                         /* REPLACE attribute, that doesn't exist */
1874                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
1875                                 errno = ENOATTR;
1876                                 return -1;
1877                         }
1878                         /* Ignore other errors */
1879                 }
1880                 else {
1881                         /* CREATE attribute, that already exists */
1882                         if (flags & XATTR_CREATE) {
1883                                 errno = EEXIST;
1884                                 return -1;
1885                         }
1886                 }
1887         }
1888
1889         retval = extattr_set_link(path, attrnamespace, attrname, value, size);
1890         return (retval < 0) ? -1 : 0;
1891 #elif defined(HAVE_ATTR_SET)
1892         int myflags = ATTR_DONTFOLLOW;
1893         char *attrname = strchr(name,'.') + 1;
1894         
1895         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
1896         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
1897         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
1898
1899         return attr_set(path, attrname, (const char *)value, size, myflags);
1900 #else
1901         errno = ENOSYS;
1902         return -1;
1903 #endif
1904 }
1905
1906 int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
1907 {
1908 #if defined(HAVE_FSETXATTR)
1909         return fsetxattr(filedes, name, value, size, flags);
1910 #elif defined(HAVE_FSETEA)
1911         return fsetea(filedes, name, value, size, flags);
1912 #elif defined(HAVE_EXTATTR_SET_FD)
1913         char *s;
1914         int retval = 0;
1915         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1916                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1917         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1918         if (flags) {
1919                 /* Check attribute existence */
1920                 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
1921                 if (retval < 0) {
1922                         /* REPLACE attribute, that doesn't exist */
1923                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
1924                                 errno = ENOATTR;
1925                                 return -1;
1926                         }
1927                         /* Ignore other errors */
1928                 }
1929                 else {
1930                         /* CREATE attribute, that already exists */
1931                         if (flags & XATTR_CREATE) {
1932                                 errno = EEXIST;
1933                                 return -1;
1934                         }
1935                 }
1936         }
1937         retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
1938         return (retval < 0) ? -1 : 0;
1939 #elif defined(HAVE_ATTR_SETF)
1940         int myflags = 0;
1941         char *attrname = strchr(name,'.') + 1;
1942         
1943         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
1944         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
1945         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
1946
1947         return attr_setf(filedes, attrname, (const char *)value, size, myflags);
1948 #else
1949         errno = ENOSYS;
1950         return -1;
1951 #endif
1952 }
1953
1954 /****************************************************************************
1955  Return the major devicenumber for UNIX extensions.
1956 ****************************************************************************/
1957                                                                                                                 
1958 uint32 unix_dev_major(SMB_DEV_T dev)
1959 {
1960 #if defined(HAVE_DEVICE_MAJOR_FN)
1961         return (uint32)major(dev);
1962 #else
1963         return (uint32)(dev >> 8);
1964 #endif
1965 }
1966                                                                                                                 
1967 /****************************************************************************
1968  Return the minor devicenumber for UNIX extensions.
1969 ****************************************************************************/
1970                                                                                                                 
1971 uint32 unix_dev_minor(SMB_DEV_T dev)
1972 {
1973 #if defined(HAVE_DEVICE_MINOR_FN)
1974         return (uint32)minor(dev);
1975 #else
1976         return (uint32)(dev & 0xff);
1977 #endif
1978 }
1979
1980 #if defined(WITH_AIO)
1981
1982 /*******************************************************************
1983  An aio_read wrapper that will deal with 64-bit sizes.
1984 ********************************************************************/
1985                                                                                                                                            
1986 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
1987 {
1988 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_READ64)
1989         return aio_read64(aiocb);
1990 #elif defined(HAVE_AIO_READ)
1991         return aio_read(aiocb);
1992 #else
1993         errno = ENOSYS;
1994         return -1;
1995 #endif
1996 }
1997
1998 /*******************************************************************
1999  An aio_write wrapper that will deal with 64-bit sizes.
2000 ********************************************************************/
2001                                                                                                                                            
2002 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2003 {
2004 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_WRITE64)
2005         return aio_write64(aiocb);
2006 #elif defined(HAVE_AIO_WRITE)
2007         return aio_write(aiocb);
2008 #else
2009         errno = ENOSYS;
2010         return -1;
2011 #endif
2012 }
2013
2014 /*******************************************************************
2015  An aio_return wrapper that will deal with 64-bit sizes.
2016 ********************************************************************/
2017                                                                                                                                            
2018 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2019 {
2020 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_RETURN64)
2021         return aio_return64(aiocb);
2022 #elif defined(HAVE_AIO_RETURN)
2023         return aio_return(aiocb);
2024 #else
2025         errno = ENOSYS;
2026         return -1;
2027 #endif
2028 }
2029
2030 /*******************************************************************
2031  An aio_cancel wrapper that will deal with 64-bit sizes.
2032 ********************************************************************/
2033
2034 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2035 {
2036 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_CANCEL64)
2037         return aio_cancel64(fd, aiocb);
2038 #elif defined(HAVE_AIO_CANCEL)
2039         return aio_cancel(fd, aiocb);
2040 #else
2041         errno = ENOSYS;
2042         return -1;
2043 #endif
2044 }
2045
2046 /*******************************************************************
2047  An aio_error wrapper that will deal with 64-bit sizes.
2048 ********************************************************************/
2049
2050 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2051 {
2052 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_ERROR64)
2053         return aio_error64(aiocb);
2054 #elif defined(HAVE_AIO_ERROR)
2055         return aio_error(aiocb);
2056 #else
2057         errno = ENOSYS;
2058         return -1;
2059 #endif
2060 }
2061
2062 /*******************************************************************
2063  An aio_fsync wrapper that will deal with 64-bit sizes.
2064 ********************************************************************/
2065
2066 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2067 {
2068 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_FSYNC64)
2069         return aio_fsync64(op, aiocb);
2070 #elif defined(HAVE_AIO_FSYNC)
2071         return aio_fsync(op, aiocb);
2072 #else
2073         errno = ENOSYS;
2074         return -1;
2075 #endif
2076 }
2077
2078 /*******************************************************************
2079  An aio_fsync wrapper that will deal with 64-bit sizes.
2080 ********************************************************************/
2081
2082 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2083 {
2084 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_SUSPEND64)
2085         return aio_suspend64(cblist, n, timeout);
2086 #elif defined(HAVE_AIO_FSYNC)
2087         return aio_suspend(cblist, n, timeout);
2088 #else
2089         errno = ENOSYS;
2090         return -1;
2091 #endif
2092 }
2093 #else /* !WITH_AIO */
2094
2095 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2096 {
2097         errno = ENOSYS;
2098         return -1;
2099 }
2100
2101 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2102 {
2103         errno = ENOSYS;
2104         return -1;
2105 }
2106
2107 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2108 {
2109         errno = ENOSYS;
2110         return -1;
2111 }
2112
2113 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2114 {
2115         errno = ENOSYS;
2116         return -1;
2117 }
2118
2119 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2120 {
2121         errno = ENOSYS;
2122         return -1;
2123 }
2124
2125 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2126 {
2127         errno = ENOSYS;
2128         return -1;
2129 }
2130
2131 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2132 {
2133         errno = ENOSYS;
2134         return -1;
2135 }
2136 #endif /* WITH_AIO */