(__hurd_path_lookup_retry): Grok magic "tty".
[kopensolaris-gnu/glibc.git] / hurd / hurdlookup.c
1 /* Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB.  If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA.  */
18
19 #include <hurd.h>
20 #include <string.h>
21 #include <limits.h>
22 #include <fcntl.h>
23 #include "stdio/_itoa.h"
24
25 /* Translate the error from dir_pathtrans into the error the user sees.  */
26 static inline error_t
27 pathtrans_error (error_t error)
28 {
29   switch (error)
30     {
31     case EOPNOTSUPP:
32     case MIG_BAD_ID:
33       /* These indicate that the server does not understand dir_pathtrans
34          at all.  If it were a directory, it would, by definition.  */
35       return ENOTDIR;
36     default:
37       return error;
38     }
39 }
40
41 error_t
42 __hurd_path_lookup (file_t crdir, file_t cwdir,
43                     const char *path, int flags, mode_t mode,
44                     file_t *result)
45 {
46   error_t err;
47   enum retry_type doretry;
48   char retryname[1024];         /* XXX string_t LOSES! */
49   file_t startdir;
50
51   startdir = path[0] == '/' ? crdir : cwdir;
52
53   while (path[0] == '/')
54     path++;
55
56   if (err = __dir_pathtrans (startdir, path, flags, mode,
57                              &doretry, retryname, result))
58     return pathtrans_error (err);
59
60   return __hurd_path_lookup_retry (crdir, doretry, retryname, flags, mode,
61                                    result);
62 }
63
64 error_t
65 __hurd_path_lookup_retry (file_t crdir,
66                           enum retry_type doretry,
67                           char retryname[1024],
68                           int flags, mode_t mode,
69                           file_t *result)
70 {
71   error_t err;
72   file_t startdir;
73   file_t newpt;
74   char *path;
75   int dealloc_dir;
76   int nloops;
77
78   dealloc_dir = 0;
79   nloops = 0;
80   
81   while (1)
82     {
83       if (dealloc_dir)
84         __mach_port_deallocate (__mach_task_self (), startdir);
85       if (err)
86         return pathtrans_error (err);
87
88       switch (doretry)
89         {
90         case FS_RETRY_NONE:
91           /* We got a successful translation.  Now apply any
92              open-time action flags we were passed.  */
93           if (flags & O_EXLOCK)
94             ;                   /* XXX */
95           if (!err && (flags & O_SHLOCK))
96             ;                   /* XXX */
97           if (!err && (flags & O_TRUNC))
98             err = __file_truncate (*result, 0);
99
100           if (err)
101             __mach_port_deallocate (__mach_task_self (), *result);
102           return err;
103           
104         case FS_RETRY_REAUTH:
105           err = __io_reauthenticate (*result, _hurd_pid);
106           if (! err)
107             err = __USEPORT (AUTH, __auth_user_authenticate (port, *result,
108                                                              _hurd_pid,
109                                                              &newpt));
110           __mach_port_deallocate (__mach_task_self (), *result);
111           if (err)
112             return err;
113           *result = newpt;
114           /* Fall through.  */
115
116         case FS_RETRY_NORMAL:
117 #ifdef SYMLOOP_MAX
118           if (nloops++ >= SYMLOOP_MAX)
119             return ELOOP;
120 #endif
121
122           startdir = *result;
123           dealloc_dir = 1;
124           path = retryname;
125           break;
126
127         case FS_RETRY_MAGICAL:
128           switch (retryname[0])
129             {
130             case '/':
131               startdir = crdir;
132               dealloc_dir = 0;
133               if (*result != MACH_PORT_NULL)
134                 __mach_port_deallocate (__mach_task_self (), *result);
135               path = &retryname[1];
136               break;
137
138             case 'f':
139               if (retryname[1] == 'd' && retryname[2] == '/')
140                 {
141                   int fd;
142                   char *end;
143                   int save = errno;
144                   errno = 0;
145                   fd = (int) strtol (retryname, &end, 10);
146                   if (end == NULL || errno || /* Malformed number.  */
147                       /* Check for excess text after the number.  A slash is
148                          valid; it ends the component.  Any other character
149                          before the null is a violation of the protocol by
150                          the server.  */
151                       (*end != '/' && *end != '\0'))
152                     {
153                       errno = save;
154                       goto bad_magic;
155                     }
156                   *result = __getdport (fd);
157                   if (*result == MACH_PORT_NULL)
158                     {
159                       error_t err = errno;
160                       errno = save;
161                       return err;
162                     }
163                   errno = save;
164                   if (*end == '\0')
165                     return 0;
166                   else
167                     {
168                       /* Do a normal retry on the remaining components.  */
169                       startdir = *result;
170                       dealloc_dir = 1;
171                       path = end + 1; /* Skip the slash.  */
172                       break;
173                     }
174                 }
175               else
176                 goto bad_magic;
177               break;
178
179             case 'm':
180               if (retryname[1] == 'a' && retryname[2] == 'c' &&
181                   retryname[3] == 'h' && retryname[4] == 't' &&
182                   retryname[5] == 'y' && retryname[6] == 'p' &&
183                   retryname[7] == 'e')
184                 {
185                   error_t err;
186                   struct host_basic_info hostinfo;
187                   unsigned int hostinfocnt = HOST_BASIC_INFO_COUNT;
188                   char *p;
189                   if (err = __host_info (__mach_host_self (), HOST_BASIC_INFO,
190                                          (int *) &hostinfo, &hostinfocnt))
191                     return err;
192                   if (hostinfocnt != HOST_BASIC_INFO_COUNT)
193                     return EGRATUITOUS;
194                   p = _itoa (hostinfo.cpu_subtype, &retryname[8], 10, 0);
195                   *--p = '/';
196                   p = _itoa (hostinfo.cpu_type, &retryname[8], 10, 0);
197                   if (p < retryname)
198                     abort ();   /* XXX write this right if this ever happens */
199                   if (p > retryname)
200                     strcpy (retryname, p);
201                   startdir = *result;
202                   dealloc_dir = 1;
203                 }
204               else
205                 goto bad_magic;
206               break;
207
208             case 't':
209               if (retryname[1] == 't' && retryname[2] == 'y')
210                 switch (retryname[3])
211                   {
212                   case '\0':
213                     return _hurd_ports_get (INIT_PORT_CTTYID, result);
214                   case '/':
215                     if (err = _hurd_ports_get (INIT_PORT_CTTYID, &startdir))
216                       return err;
217                     dealloc_dir = 1;
218                     strcpy (retryname, &retryname[4]);
219                     break;
220                   default:
221                     goto bad_magic;
222                   }
223               else
224                 goto bad_magic;
225               break;
226
227             default:
228             bad_magic:
229               return EGRATUITOUS;
230             }
231
232         default:
233           return EGRATUITOUS;
234         }
235
236       err = __dir_pathtrans (startdir, path, flags, mode,
237                              &doretry, retryname, result);
238     }
239 }
240
241 error_t
242 __hurd_path_split (file_t crdir, file_t cwdir,
243                    const char *path,
244                    file_t *dir, char **name)
245 {
246   const char *lastslash;
247   error_t err;
248   
249   /* Skip leading slashes in the pathname.  */
250   if (*path == '/')
251     {
252       while (*path == '/')
253         ++path;
254       --path;                   /* Leave on one slash.  */
255     }
256   
257   lastslash = strrchr (path, '/');
258   
259   if (lastslash != NULL)
260     {
261       if (lastslash == path)
262         {
263           /* "/foobar" => crdir + "foobar".  */
264           *name = (char *) path + 1;
265           if (err = __mach_port_mod_refs (__mach_task_self (), 
266                                           crdir, MACH_PORT_RIGHT_SEND, +1))
267             return err;
268           *dir = crdir;
269           return 0;
270         }
271       else
272         {
273           /* "/dir1/dir2/.../file".  */
274           char dirname[lastslash - path + 1];
275           memcpy (dirname, path, lastslash - path);
276           dirname[lastslash - path] = '\0';
277           *name = (char *) lastslash + 1;
278           return __hurd_path_lookup (crdir, cwdir, dirname, 0, 0, dir);
279         }
280     }
281   else
282     {
283       /* "foobar" => cwdir + "foobar".  */
284       *name = (char *) path;
285       if (err = __mach_port_mod_refs (__mach_task_self (),
286                                       cwdir, MACH_PORT_RIGHT_SEND, +1))
287         return err;
288       *dir = cwdir;
289       return 0;
290     }
291 }
292 \f
293 file_t
294 __path_lookup (const char *path, int flags, mode_t mode)
295 {
296   error_t err;
297   file_t result, crdir, cwdir;
298   struct hurd_userlink crdir_ulink, cwdir_ulink;
299
300   crdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink);
301   cwdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink);
302
303   err = __hurd_path_lookup (crdir, cwdir, path, flags, mode, &result);
304
305   _hurd_port_free (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink, crdir);
306   _hurd_port_free (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink, cwdir);
307
308   if (err)
309     {
310       errno = err;
311       return MACH_PORT_NULL;
312     }
313   else
314     return result;
315 }
316
317 file_t
318 __path_split (const char *path, char **name)
319 {
320   error_t err;
321   file_t dir, crdir, cwdir;
322   struct hurd_userlink crdir_ulink, cwdir_ulink;
323
324   crdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink);
325   cwdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink);
326
327   err = __hurd_path_split (crdir, cwdir, path, &dir, name);
328
329   _hurd_port_free (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink, crdir);
330   _hurd_port_free (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink, cwdir);
331
332   if (err)
333     {
334       errno = err;
335       return MACH_PORT_NULL;
336     }
337   else
338     return dir;
339 }