(__hurd_path_lookup_retry): For REAUTH or NORMAL with empty retryname,
[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   err = 0;
81   
82   while (1)
83     {
84       if (dealloc_dir)
85         __mach_port_deallocate (__mach_task_self (), startdir);
86       if (err)
87         return pathtrans_error (err);
88
89       switch (doretry)
90         {
91         case FS_RETRY_REAUTH:
92           err = __io_reauthenticate (*result, _hurd_pid);
93           if (! err)
94             err = __USEPORT (AUTH, __auth_user_authenticate (port, *result,
95                                                              _hurd_pid,
96                                                              &newpt));
97           __mach_port_deallocate (__mach_task_self (), *result);
98           if (err)
99             return err;
100           *result = newpt;
101           /* Fall through.  */
102
103         case FS_RETRY_NORMAL:
104 #ifdef SYMLOOP_MAX
105           if (nloops++ >= SYMLOOP_MAX)
106             return ELOOP;
107 #endif
108
109           /* An empty RETRYNAME indicates we have the final port.  */
110           if (retryname[0] == '\0')
111             {
112             case FS_RETRY_NONE: /* XXX going away XXX */
113               /* We got a successful translation.  Now apply any open-time
114                  action flags we were passed.  */
115               if (flags & O_EXLOCK)
116                 ;               /* XXX */
117               if (!err && (flags & O_SHLOCK))
118                 ;               /* XXX */
119               if (!err && (flags & O_TRUNC))
120                 err = __file_truncate (*result, 0);
121
122               if (err)
123                 __mach_port_deallocate (__mach_task_self (), *result);
124               return err;
125             }
126
127           startdir = *result;
128           dealloc_dir = 1;
129           path = retryname;
130           break;
131
132         case FS_RETRY_MAGICAL:
133           switch (retryname[0])
134             {
135             case '/':
136               startdir = crdir;
137               dealloc_dir = 0;
138               if (*result != MACH_PORT_NULL)
139                 __mach_port_deallocate (__mach_task_self (), *result);
140               path = &retryname[1];
141               break;
142
143             case 'f':
144               if (retryname[1] == 'd' && retryname[2] == '/')
145                 {
146                   int fd;
147                   char *end;
148                   int save = errno;
149                   errno = 0;
150                   fd = (int) strtol (retryname, &end, 10);
151                   if (end == NULL || errno || /* Malformed number.  */
152                       /* Check for excess text after the number.  A slash is
153                          valid; it ends the component.  Any other character
154                          before the null is a violation of the protocol by
155                          the server.  */
156                       (*end != '/' && *end != '\0'))
157                     {
158                       errno = save;
159                       goto bad_magic;
160                     }
161                   *result = __getdport (fd);
162                   if (*result == MACH_PORT_NULL)
163                     {
164                       error_t err = errno;
165                       errno = save;
166                       return err;
167                     }
168                   errno = save;
169                   if (*end == '\0')
170                     return 0;
171                   else
172                     {
173                       /* Do a normal retry on the remaining components.  */
174                       startdir = *result;
175                       dealloc_dir = 1;
176                       path = end + 1; /* Skip the slash.  */
177                       break;
178                     }
179                 }
180               else
181                 goto bad_magic;
182               break;
183
184             case 'm':
185               if (retryname[1] == 'a' && retryname[2] == 'c' &&
186                   retryname[3] == 'h' && retryname[4] == 't' &&
187                   retryname[5] == 'y' && retryname[6] == 'p' &&
188                   retryname[7] == 'e')
189                 {
190                   error_t err;
191                   struct host_basic_info hostinfo;
192                   unsigned int hostinfocnt = HOST_BASIC_INFO_COUNT;
193                   char *p;
194                   if (err = __host_info (__mach_host_self (), HOST_BASIC_INFO,
195                                          (int *) &hostinfo, &hostinfocnt))
196                     return err;
197                   if (hostinfocnt != HOST_BASIC_INFO_COUNT)
198                     return EGRATUITOUS;
199                   p = _itoa (hostinfo.cpu_subtype, &retryname[8], 10, 0);
200                   *--p = '/';
201                   p = _itoa (hostinfo.cpu_type, &retryname[8], 10, 0);
202                   if (p < retryname)
203                     abort ();   /* XXX write this right if this ever happens */
204                   if (p > retryname)
205                     strcpy (retryname, p);
206                   startdir = *result;
207                   dealloc_dir = 1;
208                 }
209               else
210                 goto bad_magic;
211               break;
212
213             case 't':
214               if (retryname[1] == 't' && retryname[2] == 'y')
215                 switch (retryname[3])
216                   {
217                     error_t opentty (file_t *result)
218                       {
219                         error_t err;
220                         file_t unauth;
221                         err = __USEPORT (CTTYID,
222                                          __termctty_open_terminal (port,
223                                                                    flags,
224                                                                    &unauth));
225                         if (! err)
226                           {
227                             err = __io_reauthenticate (unauth, _hurd_pid);
228                             if (! err)
229                               err == __USEPORT
230                                 (AUTH, __auth_user_authenticate (port,
231                                                                  unauth,
232                                                                  _hurd_pid,
233                                                                  result));
234                             __mach_port_deallocate (__mach_task_self (),
235                                                     unauth);
236                           }
237                         return err;
238                       }
239
240                   case '\0':
241                     return opentty (result);
242                   case '/':
243                     if (err = opentty (&startdir))
244                       return err;
245                     dealloc_dir = 1;
246                     strcpy (retryname, &retryname[4]);
247                     break;
248                   default:
249                     goto bad_magic;
250                   }
251               else
252                 goto bad_magic;
253               break;
254
255             default:
256             bad_magic:
257               return EGRATUITOUS;
258             }
259
260         default:
261           return EGRATUITOUS;
262         }
263
264       err = __dir_pathtrans (startdir, path, flags, mode,
265                              &doretry, retryname, result);
266     }
267 }
268
269 error_t
270 __hurd_path_split (file_t crdir, file_t cwdir,
271                    const char *path,
272                    file_t *dir, char **name)
273 {
274   const char *lastslash;
275   error_t err;
276   
277   /* Skip leading slashes in the pathname.  */
278   if (*path == '/')
279     {
280       while (*path == '/')
281         ++path;
282       --path;                   /* Leave on one slash.  */
283     }
284   
285   lastslash = strrchr (path, '/');
286   
287   if (lastslash != NULL)
288     {
289       if (lastslash == path)
290         {
291           /* "/foobar" => crdir + "foobar".  */
292           *name = (char *) path + 1;
293           if (err = __mach_port_mod_refs (__mach_task_self (), 
294                                           crdir, MACH_PORT_RIGHT_SEND, +1))
295             return err;
296           *dir = crdir;
297           return 0;
298         }
299       else
300         {
301           /* "/dir1/dir2/.../file".  */
302           char dirname[lastslash - path + 1];
303           memcpy (dirname, path, lastslash - path);
304           dirname[lastslash - path] = '\0';
305           *name = (char *) lastslash + 1;
306           return __hurd_path_lookup (crdir, cwdir, dirname, 0, 0, dir);
307         }
308     }
309   else
310     {
311       /* "foobar" => cwdir + "foobar".  */
312       *name = (char *) path;
313       if (err = __mach_port_mod_refs (__mach_task_self (),
314                                       cwdir, MACH_PORT_RIGHT_SEND, +1))
315         return err;
316       *dir = cwdir;
317       return 0;
318     }
319 }
320 \f
321 file_t
322 __path_lookup (const char *path, int flags, mode_t mode)
323 {
324   error_t err;
325   file_t result, crdir, cwdir;
326   struct hurd_userlink crdir_ulink, cwdir_ulink;
327
328   crdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink);
329   cwdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink);
330
331   err = __hurd_path_lookup (crdir, cwdir, path, flags, mode, &result);
332
333   _hurd_port_free (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink, crdir);
334   _hurd_port_free (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink, cwdir);
335
336   if (err)
337     {
338       errno = err;
339       return MACH_PORT_NULL;
340     }
341   else
342     return result;
343 }
344
345 file_t
346 __path_split (const char *path, char **name)
347 {
348   error_t err;
349   file_t dir, crdir, cwdir;
350   struct hurd_userlink crdir_ulink, cwdir_ulink;
351
352   crdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink);
353   cwdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink);
354
355   err = __hurd_path_split (crdir, cwdir, path, &dir, name);
356
357   _hurd_port_free (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink, crdir);
358   _hurd_port_free (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink, cwdir);
359
360   if (err)
361     {
362       errno = err;
363       return MACH_PORT_NULL;
364     }
365   else
366     return dir;
367 }