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