/[hurd]/hurd/trans/magic.c
ViewVC logotype

Diff of /hurd/trans/magic.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.16 by roland, Sat Jun 15 22:37:16 2002 UTC revision 1.17 by roland, Thu Mar 6 02:24:53 2003 UTC
# Line 1  Line 1 
1  /* A translator for returning FS_RETRY_MAGIC strings.  /* A translator for returning FS_RETRY_MAGIC strings.
2    
3     Copyright (C) 1999,2001,02 Free Software Foundation, Inc.     Copyright (C) 1999,2001,02, 03 Free Software Foundation, Inc.
4    
5     This program is free software; you can redistribute it and/or     This program is free software; you can redistribute it and/or
6     modify it under the terms of the GNU General Public License as     modify it under the terms of the GNU General Public License as
# Line 19  Line 19 
19  #include <hurd.h>  #include <hurd.h>
20  #include <hurd/ports.h>  #include <hurd/ports.h>
21  #include <hurd/trivfs.h>  #include <hurd/trivfs.h>
22    #include <hurd/fshelp.h>
23  #include <hurd/fsys.h>  #include <hurd/fsys.h>
24  #include <version.h>  #include <version.h>
25    
# Line 36  Line 37 
37  #include <assert.h>  #include <assert.h>
38    
39  const char *argp_program_version = STANDARD_HURD_VERSION (magic);  const char *argp_program_version = STANDARD_HURD_VERSION (magic);
40  static char args_doc[] = "MAGIC";  
41  static char doc[] = "A translator that returns the magic retry result MAGIC.";  /* This structure has all the state about one filesystem.
42  static const struct argp_option options[] =     It hangs off trivfs_control->hook.  */
43    struct magic
44  {  {
45    {"directory", 'd', 0,         0, "Provide virtual (empty) directory node"},    /* We chain all filesystems together so we can tell easily when they are
46    {0}       all unused.  */
47  };    struct trivfs_control *next;
48    
49      /* The magic string we return for lookups.  */
50      char *magic;
51    
52  /* The magic string we return for lookups.  */    int directory;                /* --directory flag */
 static char *magic;  
53    
54  static int directory;           /* --directory flag */    /* Pre-fab contents of dummy directory for dir_readdir.
55         Set up only under --directory.  */
56      void *dirbuf;
57      size_t dirbufsize;
58    
59  /* Pre-fab contents of dummy directory for dir_readdir.    unsigned int nusers;          /* Count of users, only with --directory.  */
60     Set up only under --directory.  */  };
61  static void *dirbuf;  
62  static size_t dirbufsize;  static inline void
63    free_magic (struct magic *m)
64    {
65      free (m->magic);
66      if (m->dirbuf)
67        munmap (m->dirbuf, m->dirbufsize);
68      free (m);
69    }
70    
71    static struct trivfs_control *all_fsys;
72    
73  /* Trivfs hooks  */  /* Trivfs hooks  */
74    
# Line 68  int trivfs_allow_open = O_READ; Line 84  int trivfs_allow_open = O_READ;
84  void  void
85  trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)  trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
86  {  {
87    st->st_size = dirbufsize;    struct magic *const m = cred->po->cntl->hook;
88    
89      st->st_size = m->dirbufsize;
90    st->st_blocks = getpagesize () / S_BLKSIZE;    st->st_blocks = getpagesize () / S_BLKSIZE;
91    
92    st->st_mode = ((st->st_mode & ~S_IFMT & ~ALLPERMS)    st->st_mode = ((st->st_mode & ~S_IFMT & ~ALLPERMS)
# Line 79  trivfs_modify_stat (struct trivfs_protid Line 97  trivfs_modify_stat (struct trivfs_protid
97  error_t  error_t
98  trivfs_goaway (struct trivfs_control *fsys, int flags)  trivfs_goaway (struct trivfs_control *fsys, int flags)
99  {  {
100    exit (0);    struct magic *const m = fsys->hook;
101    
102      /* We are single-threaded, so no fancy stuff is needed here.  */
103    
104      if (m->nusers > 0 && !(flags & FSYS_GOAWAY_FORCE))
105        return EBUSY;
106    
107      /* No more communication with the parent filesystem.
108         This running RPC should now be the only ref keeping FSYS alive.  */
109      ports_destroy_right (fsys);
110      return 0;
111  }  }
112    
113    
114    /* Clean pointers in a struct trivfs_control when its last reference
115       vanishes before it's freed.  This overrides the libtrivfs version
116       so we can clean up our hook data.  */
117    void
118    trivfs_clean_cntl (void *arg)
119    {
120      struct trivfs_control *cntl = arg;
121      struct magic *const m = cntl->hook;
122    
123      /* Remove us from the list of all filesystems.  */
124      struct trivfs_control **lastp = &all_fsys;
125      while (*lastp != cntl)
126        lastp = &((struct magic *) (*lastp)->hook)->next;
127      *lastp = m->next;
128    
129      if (all_fsys == 0)
130        /* Nothing more to do in this life.  */
131        exit (0);
132    
133      mach_port_destroy (mach_task_self (), cntl->filesys_id);
134      mach_port_destroy (mach_task_self (), cntl->file_id);
135      mach_port_deallocate (mach_task_self (), cntl->underlying);
136    
137      free_magic (m);
138    }
139    
140  /* This hook is used when running without --directory;  /* This hook is used when running without --directory;
141     it circumvents basically all the trivfs machinery.  */     it circumvents basically all the trivfs machinery.  */
# Line 96  magic_getroot (struct trivfs_control *cn Line 150  magic_getroot (struct trivfs_control *cn
150                 retry_type *do_retry, char *retry_name,                 retry_type *do_retry, char *retry_name,
151                 mach_port_t *node, mach_msg_type_name_t *node_type)                 mach_port_t *node, mach_msg_type_name_t *node_type)
152  {  {
153    strcpy (retry_name, magic);    struct magic *const m = cntl->hook;
154    
155      if (m->directory)
156        return EAGAIN;              /* Do normal trivfs getroot processing.  */
157    
158      strcpy (retry_name, m->magic);
159    *do_retry = FS_RETRY_MAGICAL;    *do_retry = FS_RETRY_MAGICAL;
160    *node = MACH_PORT_NULL;    *node = MACH_PORT_NULL;
161    *node_type = MACH_MSG_TYPE_COPY_SEND;    *node_type = MACH_MSG_TYPE_COPY_SEND;
# Line 125  magic_open  (struct trivfs_control *cntl Line 184  magic_open  (struct trivfs_control *cntl
184        assert_perror (err);        assert_perror (err);
185        err = mach_port_deallocate (mach_task_self (), dotdot);        err = mach_port_deallocate (mach_task_self (), dotdot);
186        assert_perror (err);        assert_perror (err);
187          struct magic *const m = cntl->hook;
188          m->nusers++;
189      }      }
190    return err;    return err;
191  }  }
192    
193    /* We have this hook only for simple tracking of the live user ports.  */
194    static void
195    magic_protid_destroy (struct trivfs_protid *cred)
196    {
197      struct magic *const m = cred->po->cntl->hook;
198      m->nusers--;
199    }
200    
201    
202  /* Do a directory lookup.  */  /* Do a directory lookup.  */
203    
# Line 154  trivfs_S_dir_lookup (struct trivfs_proti Line 223  trivfs_S_dir_lookup (struct trivfs_proti
223    
224    if (name[0] != '\0')    if (name[0] != '\0')
225      {      {
226        if (!directory)        struct magic *const m = cred->po->cntl->hook;
227    
228          if (!m->directory)
229          return ENOTDIR;          return ENOTDIR;
       else  
         {  
           /* We have a real lookup in the dummy directory.  
              Handle `.' and `..' specially, and anything else  
              gets redirected to the magical retry.  */  
230    
231          /* We have a real lookup in the dummy directory.
232             Handle `.' and `..' specially, and anything else
233             gets redirected to the magical retry.  */
234    
235          while (*name == '/')
236            ++name;
237          while (!strncmp (name, "./", 2))
238            {
239              name += 2;
240            while (*name == '/')            while (*name == '/')
241              ++name;              ++name;
242            while (!strncmp (name, "./", 2))          }
             {  
               name += 2;  
               while (*name == '/')  
                 ++name;  
             }  
243    
244            if (!strcmp (name, "..") || !strncmp (name, "../", 3))        if (!strcmp (name, "..") || !strncmp (name, "../", 3))
245              {          {
246                name += 2;            name += 2;
247                while (*name == '/')            while (*name == '/')
248                  ++name;              ++name;
249                strcpy (retry_name, name);            strcpy (retry_name, name);
250                *retry_type = FS_RETRY_REAUTH;            *retry_type = FS_RETRY_REAUTH;
251                *retrypt = (mach_port_t) cred->po->hook;            *retrypt = (mach_port_t) cred->po->hook;
252                *retrypt_type = MACH_MSG_TYPE_COPY_SEND;            *retrypt_type = MACH_MSG_TYPE_COPY_SEND;
253                return 0;            return 0;
254              }          }
255            else if (name[0] != '\0' && strcmp (name, "."))        else if (name[0] != '\0' && strcmp (name, "."))
256            {
257              if (m->magic == 0)
258                strcpy (retry_name, name);
259              else
260              {              {
261                char *p = stpcpy (retry_name, magic);                char *p = stpcpy (retry_name, m->magic);
262                *p++ = '/';                *p++ = '/';
263                strcpy (p, name);                strcpy (p, name);
               *retry_type = FS_RETRY_MAGICAL;  
               *retrypt = MACH_PORT_NULL;  
               *retrypt_type = MACH_MSG_TYPE_COPY_SEND;  
               return 0;  
264              }              }
265              *retry_type = FS_RETRY_MAGICAL;
266              *retrypt = MACH_PORT_NULL;
267              *retrypt_type = MACH_MSG_TYPE_COPY_SEND;
268              return 0;
269          }          }
270      }      }
271    
# Line 253  trivfs_S_dir_readdir (struct trivfs_prot Line 327  trivfs_S_dir_readdir (struct trivfs_prot
327    if (!cred)    if (!cred)
328      return EOPNOTSUPP;      return EOPNOTSUPP;
329    
330      struct magic *const m = cred->po->cntl->hook;
331    
332    if (entry > 0)    if (entry > 0)
333      {      {
334        void *p;        void *p;
335        int i;        int i;
336        i = 0;        i = 0;
337        for (p = dirbuf; p < dirbuf + dirbufsize;        for (p = m->dirbuf; p < m->dirbuf + m->dirbufsize;
338             p += ((struct dirent *) p)->d_reclen)             p += ((struct dirent *) p)->d_reclen)
339          if (i++ == entry)          if (i++ == entry)
340            break;            break;
341        *data = p;        *data = p;
342        *datalen = dirbuf + dirbufsize - p;        *datalen = m->dirbuf + m->dirbufsize - p;
343        *amount = 2 - entry;        *amount = 2 - entry;
344      }      }
345    else    else
346      {      {
347        *data = dirbuf;        *data = m->dirbuf;
348        *datalen = dirbufsize;        *datalen = m->dirbufsize;
349        *amount = 2;        *amount = 2;
350      }      }
351    
# Line 278  trivfs_S_dir_readdir (struct trivfs_prot Line 354  trivfs_S_dir_readdir (struct trivfs_prot
354  }  }
355    
356    
357    #include <hurd/paths.h>
358    #define _SERVERS_MAGIC _SERVERS "magic"
359    
360    /* To whom should we try to delegate on startup?  */
361    static const char *delegate = _SERVERS_MAGIC;
362    
363    static const struct argp_option options[] =
364    {
365      {"directory", 'd', 0,         0, "Provide virtual (empty) directory node"},
366      {"use-server", 'U', "NAME",   0,
367       "Delegate to server NAME instead of " _SERVERS_MAGIC},
368      {0}
369    };
370    
371  static error_t  static error_t
372  parse_opt (int opt, char *arg, struct argp_state *state)  parse_opt (int opt, char *arg, struct argp_state *state)
373  {  {
374      struct magic *const m = state->input;
375    
376    switch (opt)    switch (opt)
377      {      {
378      case 'd':      case 'U':
379        directory = 1;        /* This is only valid for the startup options, not delegates.  */
380          if (all_fsys != 0)
381            return EINVAL;
382          delegate = arg;
383        return 0;        return 0;
384    
385        case 'd':
386      case ARGP_KEY_NO_ARGS:      case ARGP_KEY_NO_ARGS:
387        argp_usage (state);        m->directory = 1;
388        return EINVAL;        return 0;
389    
390      case ARGP_KEY_ARGS:      case ARGP_KEY_ARG:
391        if (state->next != state->argc - 1)        if (m->magic != 0)
392          {          {
393            argp_usage (state);            argp_usage (state);
394            return EINVAL;            return EINVAL;
395          }          }
396        else        m->magic = strdup (arg);
397          return m->magic == 0 ? ENOMEM : 0;
398    
399        case ARGP_KEY_SUCCESS:
400          if (m->directory)
401          {          {
402            magic = state->argv[state->next];            inline struct dirent *add (struct dirent *d, const char *name)
403            return 0;              {
404                  d->d_fileno = 2;  /* random */
405                  d->d_type = DT_DIR;
406                  d->d_namlen = strlen (name);
407                  strcpy (d->d_name, name);
408                  d->d_name[d->d_namlen] = '\0';
409                  d->d_reclen = &d->d_name[d->d_namlen + 1] - (char *) d;
410                  d->d_reclen = ((d->d_reclen + __alignof (struct dirent) - 1)
411                                 & ~(__alignof (struct dirent) - 1));
412                  return (struct dirent *) ((char *) d + d->d_reclen);
413                }
414              struct dirent *d;
415              m->dirbuf = mmap (0, getpagesize (), PROT_READ|PROT_WRITE,
416                                MAP_ANON, 0, 0);
417              d = add (m->dirbuf, ".");
418              d = add (d, "..");
419              m->dirbufsize = (char *) d - (char *) m->dirbuf;
420          }          }
421        break;        return 0;
422      }      }
423    
424    return ARGP_ERR_UNKNOWN;    return ARGP_ERR_UNKNOWN;
# Line 313  error_t Line 428  error_t
428  trivfs_append_args (struct trivfs_control *fsys,  trivfs_append_args (struct trivfs_control *fsys,
429                      char **argz, size_t *argz_len)                      char **argz, size_t *argz_len)
430  {  {
431    return ((directory ? argz_add (argz, argz_len, "--directory") : 0)    struct magic *const m = fsys->hook;
432            ?: argz_add (argz, argz_len, magic));    return ((m->directory ? argz_add (argz, argz_len, "--directory") : 0)
433              ?: (m->magic ? argz_add (argz, argz_len, m->magic) : 0));
434  }  }
435    
436    static struct argp argp =
437      {
438        options, parse_opt, "MAGIC",
439        "A translator that returns the magic retry result MAGIC."
440      };
441    
442  int  int
443  main (int argc, char **argv)  main (int argc, char **argv)
# Line 323  main (int argc, char **argv) Line 445  main (int argc, char **argv)
445    error_t err;    error_t err;
446    mach_port_t bootstrap;    mach_port_t bootstrap;
447    struct trivfs_control *fsys;    struct trivfs_control *fsys;
448    struct argp argp = { options, parse_opt, args_doc, doc };    struct magic *m = calloc (1, sizeof *m);
449    
450    argp_parse (&argp, argc, argv, 0, 0, 0);    argp_parse (&argp, argc, argv, 0, 0, m);
451    
452    task_get_bootstrap_port (mach_task_self (), &bootstrap);    task_get_bootstrap_port (mach_task_self (), &bootstrap);
453    if (bootstrap == MACH_PORT_NULL)    if (bootstrap == MACH_PORT_NULL)
454      error (1, 0, "Must be started as a translator");      error (1, 0, "Must be started as a translator");
455    
456      if (delegate != 0)
457        {
458          /* First, try to have the canonical server sitting on /servers/magic
459             take over for us.  */
460          err = fshelp_delegate_translation (delegate, bootstrap, argv);
461          if (err == 0)
462            return 0;
463        }
464    
465      /* Nope, we are doing it ourselves.  */
466    
467      trivfs_getroot_hook = &magic_getroot;
468      trivfs_open_hook = &magic_open;
469      trivfs_protid_destroy_hook = &magic_protid_destroy;
470    
471    /* Reply to our parent */    /* Reply to our parent */
472    err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);    err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
473    mach_port_deallocate (mach_task_self (), bootstrap);    mach_port_deallocate (mach_task_self (), bootstrap);
474    if (err)    if (err)
475      error (3, err, "Contacting parent");      error (3, err, "Contacting parent");
476      fsys->hook = m;
477      all_fsys = fsys;
478    
479    if (directory)    /* Launch. */
480      while (1)
481      {      {
482        inline struct dirent *add (struct dirent *d, const char *name)        ports_manage_port_operations_one_thread (fsys->pi.bucket, trivfs_demuxer,
483                                                   10 * 60 * 1000);
484    
485          /* That returns when 10 minutes pass without an RPC.  Try shutting down
486             as if sent fsys_goaway; if we have any users who need us to stay
487             around, this returns EBUSY and we loop to service more RPCs.  */
488    
489          struct trivfs_control *fs = all_fsys;
490          do
491          {          {
492            d->d_fileno = 2;      /* random */            struct magic *const m = fs->hook;
493            d->d_type = DT_DIR;            struct trivfs_control *const next = m->next;
494            d->d_namlen = strlen (name);            trivfs_goaway (fs, 0);
495            strcpy (d->d_name, name);            fs = next;
496            d->d_name[d->d_namlen] = '\0';          } while (fs != 0);
497            d->d_reclen = &d->d_name[d->d_namlen + 1] - (char *) d;      }
498            d->d_reclen = ((d->d_reclen + __alignof (struct dirent) - 1)  
499                           & ~(__alignof (struct dirent) - 1));    return 0;
500            return (struct dirent *) ((char *) d + d->d_reclen);  }
501          }  
502        struct dirent *d;  
503        dirbuf = mmap (0, getpagesize (), PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);  /* Handle delegated filesystems.  */
504        d = add (dirbuf, ".");  error_t
505        d = add (d, "..");  trivfs_S_fsys_forward (mach_port_t server,
506        dirbufsize = (char *) d - (char *) dirbuf;                         mach_port_t reply,
507                           mach_msg_type_name_t replytype,
508                           mach_port_t requestor,
509                           char *argz, size_t argz_len)
510    {
511      struct trivfs_protid *cred
512        = ports_lookup_port (all_fsys->pi.bucket, server,
513                             trivfs_protid_portclasses[0]);
514      if (!cred)
515        return EOPNOTSUPP;
516      ports_port_deref (cred);
517    
518        trivfs_open_hook = &magic_open;    /* Allocate a new structure for parameters, and parse the arguments
519         to fill it in.  */
520      struct magic *m = calloc (1, sizeof *m);
521      if (!m)
522        return ENOMEM;
523    
524      int argc = argz_count (argz, argz_len);
525      char *argv[argc + 1];
526      argz_extract (argz, argz_len, argv);
527      error_t err = argp_parse (&argp, argc, argv,
528                                ARGP_NO_ERRS | ARGP_NO_HELP, 0, m);
529      if (err)
530        {
531          free_magic (m);
532          return err;
533      }      }
   else  
     trivfs_getroot_hook = &magic_getroot;  
534    
535    /* Launch. */    /* Now we are ready to start up the filesystem.  Contact the parent.  */
536    ports_manage_port_operations_one_thread (fsys->pi.bucket, trivfs_demuxer,    struct trivfs_control *fsys;
537                                             2 * 60 * 1000);    err = trivfs_startup (requestor, 0,
538                            trivfs_cntl_portclasses[0], all_fsys->pi.bucket,
539                            trivfs_protid_portclasses[0], all_fsys->pi.bucket,
540                            &fsys);
541      if (err)
542        {
543          free_magic (m);
544          return err;
545        }
546      mach_port_deallocate (mach_task_self (), requestor);
547    
548      /* The new filesystem is all hooked up.
549         Put it on the list of all filesystems we are serving.  */
550      m->next = all_fsys;
551      fsys->hook = m;
552      all_fsys = fsys;
553    
554    return 0;    return 0;
555  }  }

Legend:
Removed from v.1.16  
changed lines
  Added in v.1.17

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26