More abstraction of file system data types, to move to a 64
[ira/wip.git] / source3 / lib / system.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Samba system utilities
5    Copyright (C) Andrew Tridgell 1992-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 extern int DEBUGLEVEL;
25
26 /*
27    The idea is that this file will eventually have wrappers around all
28    important system calls in samba. The aims are:
29
30    - to enable easier porting by putting OS dependent stuff in here
31
32    - to allow for hooks into other "pseudo-filesystems"
33
34    - to allow easier integration of things like the japanese extensions
35
36    - to support the philosophy of Samba to expose the features of
37      the OS within the SMB model. In general whatever file/printer/variable
38      expansions/etc make sense to the OS should be acceptable to Samba.
39 */
40
41
42 /*******************************************************************
43 this replaces the normal select() system call
44 return if some data has arrived on one of the file descriptors
45 return -1 means error
46 ********************************************************************/
47 #ifndef HAVE_SELECT
48 static int pollfd(int fd)
49 {
50   int     r=0;
51
52 #ifdef HAS_RDCHK
53   r = rdchk(fd);
54 #elif defined(TCRDCHK)
55   (void)ioctl(fd, TCRDCHK, &r);
56 #else
57   (void)ioctl(fd, FIONREAD, &r);
58 #endif
59
60   return(r);
61 }
62
63 int sys_select(int maxfd, fd_set *fds,struct timeval *tval)
64 {
65   fd_set fds2;
66   int counter=0;
67   int found=0;
68
69   FD_ZERO(&fds2);
70
71   while (1) 
72   {
73     int i;
74     for (i=0;i<maxfd;i++) {
75       if (FD_ISSET(i,fds) && pollfd(i)>0) {
76         found++;
77         FD_SET(i,&fds2);
78       }
79     }
80
81     if (found) {
82       memcpy((void *)fds,(void *)&fds2,sizeof(fds2));
83       return(found);
84     }
85       
86     if (tval && tval->tv_sec < counter) return(0);
87       sleep(1);
88       counter++;
89   }
90 }
91
92 #else /* !NO_SELECT */
93 int sys_select(int maxfd, fd_set *fds,struct timeval *tval)
94 {
95 #ifdef USE_POLL
96   struct pollfd pfd[256];
97   int i;
98   int maxpoll;
99   int timeout;
100   int pollrtn;
101
102   maxpoll = 0;
103   for( i = 0; i < maxfd; i++) {
104     if(FD_ISSET(i,fds)) {
105       struct pollfd *pfdp = &pfd[maxpoll++];
106       pfdp->fd = i;
107       pfdp->events = POLLIN;
108       pfdp->revents = 0;
109     }
110   }
111
112   timeout = (tval != NULL) ? (tval->tv_sec * 1000) + (tval->tv_usec/1000) :
113                 -1;
114   errno = 0;
115   do {
116     pollrtn = poll( &pfd[0], maxpoll, timeout);
117   } while (pollrtn<0 && errno == EINTR);
118
119   FD_ZERO(fds);
120
121   for( i = 0; i < maxpoll; i++)
122     if( pfd[i].revents & POLLIN )
123       FD_SET(pfd[i].fd,fds);
124
125   return pollrtn;
126 #else /* USE_POLL */
127
128   struct timeval t2;
129   int selrtn;
130
131   do {
132     if (tval) memcpy((void *)&t2,(void *)tval,sizeof(t2));
133     errno = 0;
134     selrtn = select(maxfd,SELECT_CAST fds,NULL,NULL,tval?&t2:NULL);
135   } while (selrtn<0 && errno == EINTR);
136
137   return(selrtn);
138 }
139 #endif /* USE_POLL */
140 #endif /* NO_SELECT */
141
142
143 /*******************************************************************
144 just a unlink wrapper that calls dos_to_unix.
145 ********************************************************************/
146 int dos_unlink(char *fname)
147 {
148   return(unlink(dos_to_unix(fname,False)));
149 }
150
151
152 /*******************************************************************
153 a simple open() wrapper that calls dos_to_unix.
154 ********************************************************************/
155 int dos_open(char *fname,int flags,int mode)
156 {
157   return(open(dos_to_unix(fname,False),flags,mode));
158 }
159
160
161 /*******************************************************************
162 a simple opendir() wrapper that calls dos_to_unix
163 ********************************************************************/
164 DIR *dos_opendir(char *dname)
165 {
166         return(opendir(dos_to_unix(dname,False)));
167 }
168
169
170 /*******************************************************************
171 and a stat() wrapper that calls dos_to_unix.
172 ********************************************************************/
173 int dos_stat(char *fname,SMB_STRUCT_STAT *sbuf)
174 {
175   return(stat(dos_to_unix(fname,False),sbuf));
176 }
177
178 /*******************************************************************
179 The wait() calls vary between systems
180 ********************************************************************/
181 int sys_waitpid(pid_t pid,int *status,int options)
182 {
183 #ifdef HAVE_WAITPID
184   return waitpid(pid,status,options);
185 #else /* HAVE_WAITPID */
186   return wait4(pid, status, options, NULL);
187 #endif /* HAVE_WAITPID */
188 }
189
190 /*******************************************************************
191 don't forget lstat() that calls dos_to_unix.
192 ********************************************************************/
193 int dos_lstat(char *fname,struct stat *sbuf)
194 {
195   return(lstat(dos_to_unix(fname,False),sbuf));
196 }
197
198
199 /*******************************************************************
200 mkdir() gets a wrapper that calls dos_to_unix.
201 ********************************************************************/
202 int dos_mkdir(char *dname,int mode)
203 {
204   return(mkdir(dos_to_unix(dname,False),mode));
205 }
206
207
208 /*******************************************************************
209 do does rmdir() - call dos_to_unix
210 ********************************************************************/
211 int dos_rmdir(char *dname)
212 {
213   return(rmdir(dos_to_unix(dname,False)));
214 }
215
216
217 /*******************************************************************
218 I almost forgot chdir() - call dos_to_unix.
219 ********************************************************************/
220 int dos_chdir(char *dname)
221 {
222   return(chdir(dos_to_unix(dname,False)));
223 }
224
225
226 /*******************************************************************
227 now for utime() - call dos_to_unix.
228 ********************************************************************/
229 int dos_utime(char *fname,struct utimbuf *times)
230 {
231   /* if the modtime is 0 or -1 then ignore the call and
232      return success */
233   if (times->modtime == (time_t)0 || times->modtime == (time_t)-1)
234     return 0;
235   
236   /* if the access time is 0 or -1 then set it to the modtime */
237   if (times->actime == (time_t)0 || times->actime == (time_t)-1)
238     times->actime = times->modtime;
239    
240   return(utime(dos_to_unix(fname,False),times));
241 }
242
243 /*********************************************************
244 for rename across filesystems Patch from Warren Birnbaum 
245 <warrenb@hpcvscdp.cv.hp.com>
246 **********************************************************/
247
248 static int copy_reg(char *source, const char *dest)
249 {
250   struct stat source_stats;
251   int ifd;
252   int ofd;
253   char *buf;
254   int len;                      /* Number of bytes read into `buf'. */
255
256   lstat (source, &source_stats);
257   if (!S_ISREG (source_stats.st_mode))
258     {
259       return 1;
260     }
261
262   if (unlink (dest) && errno != ENOENT)
263     {
264       return 1;
265     }
266
267   if((ifd = open (source, O_RDONLY, 0)) < 0)
268     {
269       return 1;
270     }
271   if((ofd = open (dest, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0 )
272     {
273       close (ifd);
274       return 1;
275     }
276
277   if((buf = malloc( COPYBUF_SIZE )) == NULL)
278     {
279       close (ifd);  
280       close (ofd);  
281       unlink (dest);
282       return 1;
283     }
284
285   while ((len = read(ifd, buf, COPYBUF_SIZE)) > 0)
286     {
287       if (write_data(ofd, buf, len) < 0)
288         {
289           close (ifd);
290           close (ofd);
291           unlink (dest);
292           free(buf);
293           return 1;
294         }
295     }
296   free(buf);
297   if (len < 0)
298     {
299       close (ifd);
300       close (ofd);
301       unlink (dest);
302       return 1;
303     }
304
305   if (close (ifd) < 0)
306     {
307       close (ofd);
308       return 1;
309     }
310   if (close (ofd) < 0)
311     {
312       return 1;
313     }
314
315   /* chown turns off set[ug]id bits for non-root,
316      so do the chmod last.  */
317
318   /* Try to copy the old file's modtime and access time.  */
319   {
320     struct utimbuf tv;
321
322     tv.actime = source_stats.st_atime;
323     tv.modtime = source_stats.st_mtime;
324     if (utime (dest, &tv))
325       {
326         return 1;
327       }
328   }
329
330   /* Try to preserve ownership.  For non-root it might fail, but that's ok.
331      But root probably wants to know, e.g. if NFS disallows it.  */
332   if (chown (dest, source_stats.st_uid, source_stats.st_gid)
333       && (errno != EPERM))
334     {
335       return 1;
336     }
337
338   if (chmod (dest, source_stats.st_mode & 07777))
339     {
340       return 1;
341     }
342   unlink (source);
343   return 0;
344 }
345
346 /*******************************************************************
347 for rename() - call dos_to_unix.
348 ********************************************************************/
349 int dos_rename(char *from, char *to)
350 {
351     int rcode;  
352     pstring zfrom, zto;
353
354     pstrcpy (zfrom, dos_to_unix (from, False));
355     pstrcpy (zto, dos_to_unix (to, False));
356     rcode = rename (zfrom, zto);
357
358     if (errno == EXDEV) 
359       {
360         /* Rename across filesystems needed. */
361         rcode = copy_reg (zfrom, zto);        
362       }
363     return rcode;
364 }
365
366 /*******************************************************************
367 for chmod - call dos_to_unix.
368 ********************************************************************/
369 int dos_chmod(char *fname,int mode)
370 {
371   return(chmod(dos_to_unix(fname,False),mode));
372 }
373
374 /*******************************************************************
375 for getwd
376 ********************************************************************/
377 char *sys_getwd(char *s)
378 {
379         char *wd;
380 #ifdef HAVE_GETCWD
381         wd = (char *)getcwd(s, sizeof (pstring));
382 #else
383         wd = (char *)getwd(s);
384 #endif
385         if (wd)
386                 unix_to_dos(wd, True);
387         return wd;
388 }
389
390 /*******************************************************************
391 chown isn't used much but OS/2 doesn't have it
392 ********************************************************************/
393 int sys_chown(char *fname,int uid,int gid)
394 {
395 #ifndef HAVE_CHOWN
396         static int done;
397         if (!done) {
398                 DEBUG(1,("WARNING: no chown!\n"));
399                 done=1;
400         }
401 #else
402         return(chown(fname,uid,gid));
403 #endif
404 }
405
406 /*******************************************************************
407 os/2 also doesn't have chroot
408 ********************************************************************/
409 int sys_chroot(char *dname)
410 {
411 #ifndef HAVE_CHROOT
412         static int done;
413         if (!done) {
414                 DEBUG(1,("WARNING: no chroot!\n"));
415                 done=1;
416         }
417 #else
418         return(chroot(dname));
419 #endif
420 }
421
422 /**************************************************************************
423 A wrapper for gethostbyname() that tries avoids looking up hostnames 
424 in the root domain, which can cause dial-on-demand links to come up for no
425 apparent reason.
426 ****************************************************************************/
427 struct hostent *sys_gethostbyname(char *name)
428 {
429 #ifdef REDUCE_ROOT_DNS_LOOKUPS
430   char query[256], hostname[256];
431   char *domain;
432
433   /* Does this name have any dots in it? If so, make no change */
434
435   if (strchr(name, '.'))
436     return(gethostbyname(name));
437
438   /* Get my hostname, which should have domain name 
439      attached. If not, just do the gethostname on the
440      original string. 
441   */
442
443   gethostname(hostname, sizeof(hostname) - 1);
444   hostname[sizeof(hostname) - 1] = 0;
445   if ((domain = strchr(hostname, '.')) == NULL)
446     return(gethostbyname(name));
447
448   /* Attach domain name to query and do modified query.
449      If names too large, just do gethostname on the
450      original string.
451   */
452
453   if((strlen(name) + strlen(domain)) >= sizeof(query))
454     return(gethostbyname(name));
455
456   slprintf(query, sizeof(query)-1, "%s%s", name, domain);
457   return(gethostbyname(query));
458 #else /* REDUCE_ROOT_DNS_LOOKUPS */
459   return(gethostbyname(name));
460 #endif /* REDUCE_ROOT_DNS_LOOKUPS */
461 }
462