f453741fdd0eb0c472d2694e2460d8055d2435ba
[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 #ifdef NO_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(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<255;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
93 int sys_select(fd_set *fds,struct timeval *tval)
94 {
95   struct timeval t2;
96   int selrtn;
97
98   do {
99     if (tval) memcpy((void *)&t2,(void *)tval,sizeof(t2));
100     errno = 0;
101     selrtn = select(255,SELECT_CAST fds,NULL,NULL,tval?&t2:NULL);
102   } while (selrtn<0 && errno == EINTR);
103
104   return(selrtn);
105 }
106 #endif
107
108
109 /*******************************************************************
110 just a unlink wrapper
111 ********************************************************************/
112 int sys_unlink(char *fname)
113 {
114   return(unlink(dos_to_unix(fname,False)));
115 }
116
117
118 /*******************************************************************
119 a simple open() wrapper
120 ********************************************************************/
121 int sys_open(char *fname,int flags,int mode)
122 {
123   return(open(dos_to_unix(fname,False),flags,mode));
124 }
125
126
127 /*******************************************************************
128 a simple opendir() wrapper
129 ********************************************************************/
130 DIR *sys_opendir(char *dname)
131 {
132   return(opendir(dos_to_unix(dname,False)));
133 }
134
135
136 /*******************************************************************
137 and a stat() wrapper
138 ********************************************************************/
139 int sys_stat(char *fname,struct stat *sbuf)
140 {
141   return(stat(dos_to_unix(fname,False),sbuf));
142 }
143
144 /*******************************************************************
145 The wait() calls vary between systems
146 ********************************************************************/
147 int sys_waitpid(pid_t pid,int *status,int options)
148 {
149 #ifdef USE_WAITPID
150   return waitpid(pid,status,options);
151 #else /* USE_WAITPID */
152   return wait4(pid, status, options, NULL);
153 #endif /* USE_WAITPID */
154 }
155
156 /*******************************************************************
157 don't forget lstat()
158 ********************************************************************/
159 int sys_lstat(char *fname,struct stat *sbuf)
160 {
161   return(lstat(dos_to_unix(fname,False),sbuf));
162 }
163
164
165 /*******************************************************************
166 mkdir() gets a wrapper
167 ********************************************************************/
168 int sys_mkdir(char *dname,int mode)
169 {
170   return(mkdir(dos_to_unix(dname,False),mode));
171 }
172
173
174 /*******************************************************************
175 do does rmdir()
176 ********************************************************************/
177 int sys_rmdir(char *dname)
178 {
179   return(rmdir(dos_to_unix(dname,False)));
180 }
181
182
183 /*******************************************************************
184 I almost forgot chdir()
185 ********************************************************************/
186 int sys_chdir(char *dname)
187 {
188   return(chdir(dos_to_unix(dname,False)));
189 }
190
191
192 /*******************************************************************
193 now for utime()
194 ********************************************************************/
195 int sys_utime(char *fname,struct utimbuf *times)
196 {
197   /* if the modtime is 0 or -1 then ignore the call and
198      return success */
199   if (times->modtime == (time_t)0 || times->modtime == (time_t)-1)
200     return 0;
201   
202   /* if the access time is 0 or -1 then set it to the modtime */
203   if (times->actime == (time_t)0 || times->actime == (time_t)-1)
204     times->actime = times->modtime;
205    
206   return(utime(dos_to_unix(fname,False),times));
207 }
208
209 /*********************************************************
210 for rename across filesystems Patch from Warren Birnbaum 
211 <warrenb@hpcvscdp.cv.hp.com>
212 **********************************************************/
213
214 static int copy_reg(char *source, const char *dest)
215 {
216   struct stat source_stats;
217   int ifd;
218   int ofd;
219   char *buf;
220   int len;                      /* Number of bytes read into `buf'. */
221
222   lstat (source, &source_stats);
223   if (!S_ISREG (source_stats.st_mode))
224     {
225       return 1;
226     }
227
228   if (unlink (dest) && errno != ENOENT)
229     {
230       return 1;
231     }
232
233   if((ifd = open (source, O_RDONLY, 0)) < 0)
234     {
235       return 1;
236     }
237   if((ofd = open (dest, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0 )
238     {
239       close (ifd);
240       return 1;
241     }
242
243   if((buf = malloc( COPYBUF_SIZE )) == NULL)
244     {
245       close (ifd);  
246       close (ofd);  
247       unlink (dest);
248       return 1;
249     }
250
251   while ((len = read(ifd, buf, COPYBUF_SIZE)) > 0)
252     {
253       if (write_data(ofd, buf, len) < 0)
254         {
255           close (ifd);
256           close (ofd);
257           unlink (dest);
258           free(buf);
259           return 1;
260         }
261     }
262   free(buf);
263   if (len < 0)
264     {
265       close (ifd);
266       close (ofd);
267       unlink (dest);
268       return 1;
269     }
270
271   if (close (ifd) < 0)
272     {
273       close (ofd);
274       return 1;
275     }
276   if (close (ofd) < 0)
277     {
278       return 1;
279     }
280
281   /* chown turns off set[ug]id bits for non-root,
282      so do the chmod last.  */
283
284   /* Try to copy the old file's modtime and access time.  */
285   {
286     struct utimbuf tv;
287
288     tv.actime = source_stats.st_atime;
289     tv.modtime = source_stats.st_mtime;
290     if (utime (dest, &tv))
291       {
292         return 1;
293       }
294   }
295
296   /* Try to preserve ownership.  For non-root it might fail, but that's ok.
297      But root probably wants to know, e.g. if NFS disallows it.  */
298   if (chown (dest, source_stats.st_uid, source_stats.st_gid)
299       && (errno != EPERM))
300     {
301       return 1;
302     }
303
304   if (chmod (dest, source_stats.st_mode & 07777))
305     {
306       return 1;
307     }
308   unlink (source);
309   return 0;
310 }
311
312 /*******************************************************************
313 for rename()
314 ********************************************************************/
315 int sys_rename(char *from, char *to)
316 {
317     int rcode;  
318     pstring zfrom, zto;
319
320     pstrcpy (zfrom, dos_to_unix (from, False));
321     pstrcpy (zto, dos_to_unix (to, False));
322     rcode = rename (zfrom, zto);
323
324     if (errno == EXDEV) 
325       {
326         /* Rename across filesystems needed. */
327         rcode = copy_reg (zfrom, zto);        
328       }
329     return rcode;
330 }
331
332 /*******************************************************************
333 for chmod
334 ********************************************************************/
335 int sys_chmod(char *fname,int mode)
336 {
337   return(chmod(dos_to_unix(fname,False),mode));
338 }
339
340 /*******************************************************************
341 for getwd
342 ********************************************************************/
343 char *sys_getwd(char *s)
344 {
345   char *wd;
346 #ifdef USE_GETCWD
347   wd = (char *) getcwd (s, sizeof (pstring));
348 #else
349   wd = (char *) getwd (s);
350 #endif
351   if (wd)
352     unix_to_dos (wd, True);
353   return wd;
354 }
355
356 /*******************************************************************
357 chown isn't used much but OS/2 doesn't have it
358 ********************************************************************/
359 int sys_chown(char *fname,int uid,int gid)
360 {
361 #ifdef NO_CHOWN
362   DEBUG(1,("Warning - chown(%s,%d,%d) not done\n",fname,uid,gid));
363 #else
364   return(chown(fname,uid,gid));
365 #endif
366 }
367
368 /*******************************************************************
369 os/2 also doesn't have chroot
370 ********************************************************************/
371 int sys_chroot(char *dname)
372 {
373 #ifdef NO_CHROOT
374   DEBUG(1,("Warning - chroot(%s) not done\n",dname));
375 #else
376   return(chroot(dname));
377 #endif
378 }
379
380 /**************************************************************************
381 A wrapper for gethostbyname() that tries avoids looking up hostnames 
382 in the root domain, which can cause dial-on-demand links to come up for no
383 apparent reason.
384 ****************************************************************************/
385 struct hostent *sys_gethostbyname(char *name)
386 {
387 #ifdef REDUCE_ROOT_DNS_LOOKUPS
388   char query[256], hostname[256];
389   char *domain;
390
391   /* Does this name have any dots in it? If so, make no change */
392
393   if (strchr(name, '.'))
394     return(gethostbyname(name));
395
396   /* Get my hostname, which should have domain name 
397      attached. If not, just do the gethostname on the
398      original string. 
399   */
400
401   gethostname(hostname, sizeof(hostname) - 1);
402   hostname[sizeof(hostname) - 1] = 0;
403   if ((domain = strchr(hostname, '.')) == NULL)
404     return(gethostbyname(name));
405
406   /* Attach domain name to query and do modified query.
407      If names too large, just do gethostname on the
408      original string.
409   */
410
411   if((strlen(name) + strlen(domain)) >= sizeof(query))
412     return(gethostbyname(name));
413
414   slprintf(query, sizeof(query)-1, "%s%s", name, domain);
415   return(gethostbyname(query));
416 #else /* REDUCE_ROOT_DNS_LOOKUPS */
417   return(gethostbyname(name));
418 #endif /* REDUCE_ROOT_DNS_LOOKUPS */
419 }
420