~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
cvs/emstar/fusd/fusdd/fusdd.c


  1 /*
  2  *
  3  * Copyright (c) 2003 The Regents of the University of California.  All 
  4  * rights reserved.
  5  *
  6  * Redistribution and use in source and binary forms, with or without
  7  * modification, are permitted provided that the following conditions
  8  * are met:
  9  *
 10  * - Redistributions of source code must retain the above copyright
 11  *   notice, this list of conditions and the following disclaimer.
 12  *
 13  * - Neither the name of the University nor the names of its
 14  *   contributors may be used to endorse or promote products derived
 15  *   from this software without specific prior written permission.
 16  *
 17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
 18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 19  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 20  * PARTICULAR  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
 21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 25  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28  *
 29  */
 30  
 31 /*
 32  *  FUSDd
 33  *
 34  *  The user-space component of FUSD for non-DevFS Linux 2.4 systems
 35  *
 36  */
 37 
 38 #include <sys/stat.h>
 39 #include <unistd.h>
 40 #include <stdlib.h>
 41 #include <sys/types.h>
 42 #include <errno.h>
 43 #include <fcntl.h>  
 44 #include <string.h>
 45 #include <stdio.h>
 46 #include <sys/ioctl.h>
 47 
 48 #include "fusd.h"
 49 #include "fusdd_i.h"
 50 #include <fusd_msg.h>
 51 
 52 #define FUSD_MAX_DEVS  20000
 53 #define F_PATH_MAX       (FUSD_MAX_NAME_LENGTH + 10)
 54 
 55 extern int unlink_dirs;
 56 
 57 struct dev {
 58   char *name;
 59   uint16_t major;  
 60   uint16_t minor;
 61   int mark:1;
 62   int del:1;
 63 };
 64 
 65 struct dev *dev_lookup(char *name);
 66 void dev_insert(struct dev *add);
 67 void dev_compress();
 68 void dev_dump();
 69 
 70 /* current active devices */
 71 struct dev *active_devs=NULL;
 72 int dev_count=0;
 73 int dev_alloc=0;
 74 int verbose=0;
 75 
 76 #define DEV_TO_NUM(x) (makedev((x)->major, (x)->minor))
 77 #define DEV_EQ(x,y) (((x)->major == (y)->major) && ((x)->minor == (y)->minor))
 78 #define DEV_ZERO(x) (((x)->major == 0) && ((x)->minor == 0))
 79 
 80 /*
 81  *  debug function
 82  */
 83 
 84 void dev_dump()
 85 {
 86   int i;
 87   printf("%d devs, %d alloc\n", dev_count, dev_alloc);
 88   for (i=0; i<dev_count; i++) {
 89     printf("%s %d\n", active_devs[i].name, active_devs[i].del);
 90   }
 91   printf("\n");
 92 }
 93 
 94 
 95 void dev_test()
 96 {
 97   struct dev d = {};
 98 
 99 #define TESTI(s)  d.name = strdup(s); dev_insert(&d); dev_dump();
100 #define TESTD(s)  dev_lookup(s)->del = 1; dev_dump();
101 
102   TESTI("b");
103   TESTI("d");
104   TESTI("f");
105   TESTI("a");
106   TESTI("aa");
107   TESTI("g");
108 
109   TESTD("d");
110   TESTD("a");
111   TESTD("g");
112   dev_compress(); dev_dump();
113 
114   TESTD("f");
115   dev_compress(); dev_dump();
116 }
117 
118 /*
119  *  device list manipulation
120  */
121 
122 int dev_cmp(const void *x, const void *y)
123 {
124   struct dev *xd = (struct dev *)x;
125   struct dev *yd = (struct dev *)y;
126   return strcmp(xd->name, yd->name);
127 }
128 
129 struct dev *dev_lookup(char *name)
130 {
131   struct dev key = {
132     name: name
133   };
134   if (active_devs == NULL) return NULL;
135   return bsearch(&key, active_devs, dev_count, sizeof(struct dev), dev_cmp);
136 }
137 
138 void dev_insert(struct dev *add)
139 {
140   int i;
141 
142   dev_count++;
143 
144   /* need to expand? */
145   if (dev_alloc < dev_count) {
146     dev_alloc *= 2;
147     if (dev_alloc == 0) dev_alloc = 64;
148     active_devs = realloc(active_devs, sizeof(struct dev)*dev_alloc);
149   }
150 
151   /* locate position */
152   for (i=dev_count-1; i>0; i--) {
153     if (strcmp(add->name, active_devs[i-1].name) > 0) { 
154       goto found;
155     }
156     active_devs[i] = active_devs[i-1];
157   }
158   
159  found:
160   /* store */
161   active_devs[i] = *add;
162 }
163 
164 
165 void dev_compress()
166 {
167   int i;
168   int shift=0;
169 
170   for (i=0; i<dev_count; i++) {
171     if (active_devs[i].del) {
172       free(active_devs[i].name);
173       shift++;
174       continue;
175     }
176     if (shift) active_devs[i-shift] = active_devs[i];
177   }
178   dev_count -= shift;
179 }
180 
181 
182 /*
183  *  Prepend /dev.. careful.. static allocation!
184  */
185 
186 char *dev_path(char *name)
187 {
188   static char path[F_PATH_MAX+1];
189 
190   /* prepend /dev */
191   strcpy(path, DEFAULT_DEV_ROOT);
192   strcat(path, name);
193 
194   return path;
195 }
196 
197 
198 /*
199  * mkdir_with_parents: given a pathname, create a directory with that
200  * name and possibly any parents of that directory, if necessary.
201  *
202  * Returns:
203  *   0 if the directory was created successfully (or already existed)
204  *  -1 with errno set appropriately if there was an error creating the
205  *     directory or any of its parents
206  */
207 
208 int f_mkdir_with_parents(char *path_orig)
209 {
210   char path[F_PATH_MAX+1];
211   char *parent_end;
212   
213   strcpy(path, path_orig);
214 
215   /* skip over any leading slashes, then find the first slash after
216    * that */
217   parent_end = index(path + strspn(path, "/"), '/');
218 
219   /* now, for each component of the path, create the dir */
220   while (parent_end != NULL) {
221     *parent_end = '\0';
222 
223     if (mkdir(path, 0755) < 0 && errno != EEXIST) {
224       return -1;
225     }
226 
227     *parent_end = '/';
228     parent_end = index(parent_end+1, '/');
229   }
230 
231   return 0;
232 }
233 
234 
235 
236 int clear_marks(void *data) 
237 {
238   int i;
239   if (verbose) fprintf(stderr, "Clearing Marks\n");
240   /* clear the marks first */
241   for (i=0; i<dev_count; i++)
242     active_devs[i].mark=0;
243   return 0;
244 }
245 
246 
247 void dev_remove(struct dev *dev)
248 {
249   if (dev->name) {
250     if (verbose)
251       fprintf(stderr, "Unlinking unused device %s\n", dev->name);
252     unlink(dev_path(dev->name));
253     
254     if (unlink_dirs) {
255       /* rmdir the enclosing directory */
256       char *tmp = strdup(dev->name);
257       char *slash;
258       
259       while ((slash = strrchr(tmp, '/'))) {
260         *slash = 0;
261         
262         if (verbose) 
263           fprintf(stderr, "Removing dir %s\n", dev_path(tmp));
264         
265         if (rmdir(dev_path(tmp)) < 0) {
266           if (verbose) 
267             fprintf(stderr, "Unable to remove dir %s: %m\n", tmp);
268           break;
269         }
270       }
271       
272       free(tmp);
273     }
274   }
275   dev->del = 1;
276 }
277 
278 
279 int unlink_unmarked(void *data)
280 {
281   int i;
282   if (verbose) fprintf(stderr, "Unlinking unmarked\n");
283   /* unlink any unmarked devices */
284   for (i=0; i<dev_count; i++) {
285     if (active_devs[i].mark == 0)
286       dev_remove(&active_devs[i]);
287   }
288   dev_compress();
289   return 0;
290 }
291 
292 
293 int process(fusd_status_t *fs, int count, void *data)
294 {
295   int i;
296 
297   for (i=0; i<count; i++, fs++) {
298     struct stat s;
299     int fd;
300     struct dev *ptr = dev_lookup(fs->name);
301     char *path;
302 
303     /* if zombie, remove if present */
304     if (fs->zombie) {
305       if (verbose)
306         fprintf(stderr, "ignoring zombie %s\n", fs->name);
307       continue;
308     }
309   
310     /* if null device, remove if present */
311     if (DEV_ZERO(fs)) {
312       if (verbose)
313         fprintf(stderr, "ignoring non-device %s\n", fs->name);
314       continue;
315     }
316 
317     /* if present, verify the device setting */
318     if (ptr) {
319       /* we're done if it matches out current state */
320       if (DEV_EQ(ptr,fs))
321         goto mark;
322       /* otherwise it will be updated after we succeed */
323     }
324 
325     /* 
326      * OK, now we have an entry that might need to be added
327      */
328 
329     path = dev_path(fs->name);
330     
331     if (verbose)
332       fprintf(stderr, "checking '%s' -> %d,%d [%x]\n",
333               path, fs->major, fs->minor, (uint32_t)DEV_TO_NUM(fs));
334     
335     /* Stat the device file. */
336     if (stat(path, &s) < 0) {
337       if (errno == ENOENT) {
338         
339         /* create any subdirectories */
340         if (f_mkdir_with_parents(path) < 0) {
341           fprintf(stderr, "Unable to create directory components for device %s\n", path);
342           continue;
343         }
344         
345         /* do the mknod */
346         goto create;
347       }
348       
349       fprintf(stderr, "Stat of %s failed: %m\n", path);
350       continue;
351     }
352     
353     /* Check the stat, see if it matches */
354     
355     /* if this is a regular file, delete it! */
356     if (S_ISREG(s.st_mode)) {
357       fprintf(stderr, "Deleting existing regular file: %s\n", path);
358       if (unlink(path) < 0) {
359         fprintf(stderr, "Unable to unlink existing regular file %s\n", path);
360         goto remove;
361       }
362       goto create;
363     }
364     
365     /* if this is not a chrdev, ignore it -- (this may hang the client) 
366      * this might be a directory!!
367      *  $$$ figure out a better thing to do here?? */
368     if (!S_ISCHR(s.st_mode)) {
369       
370       if (S_ISDIR(s.st_mode)) 
371         fprintf(stderr, "Device overloading a directory!! NOT deleting: %s\n", path);
372       else
373         fprintf(stderr, "Device overloading a non-regular file.. NOT deleting: %s\n", path);
374       
375       /* don't goto remove here because we don't want to delete this file! */
376       if (ptr) ptr->del = 1;
377       continue;
378     }
379 
380     /* otherwise, if it's a chrdev, check the bits */
381     if (s.st_rdev != DEV_TO_NUM(fs)) {
382       /* delete it if they don't match */
383       if (unlink(path) < 0) {
384         fprintf(stderr, "Unable to unlink existing device file %s\n", path);
385         goto remove;
386       }
387     }
388     
389     /* the existing inode is correct. */
390     else {
391       /* if it's marked unmade then do the open to set it 'made' */
392       if (fs->unmade)
393         goto do_open;
394       
395       /* otherwise just mark it as OK */
396       goto mark;
397     }
398     
399   create:
400     /* OK, now do the mknod! */
401     if (mknod(path, S_IFCHR | 0777, DEV_TO_NUM(fs)) < 0) {
402       fprintf(stderr, " *** Unable to mknod device %d.%d to %s\n", 
403               fs->major, fs->minor, path);
404       goto remove;
405     }
406     
407     if (verbose)
408       fprintf(stderr, " *** mknod'd device %d,%d (%x) dev %s\n", 
409               fs->major, fs->minor, (uint32_t)DEV_TO_NUM(fs), path);
410     
411   do_open:
412     /* open it to activate it! */
413     fd = open(path, O_RDONLY);
414     if (fd >= 0) {
415       fprintf(stderr, " *** What?? our open succeeded??\n");
416       close(fd);
417     }
418     
419     else {
420       switch (errno) {
421 
422       case ENOENT:
423         /* this happens if the device has already been deleted in the kernel */
424         /* if ptr is valid, we just don't mark it, it will be removed later  */
425         if (ptr == NULL)
426           unlink(path);
427         goto remove;
428 
429       case EXDEV:
430         /* this means we succeeded */
431         if (verbose)
432           fprintf(stderr, " *** Open should have 'made' dev %s\n", path);
433         break;
434 
435       default:
436         fprintf(stderr, " *** Oops.. unexpected error opening dev %s: %m\n", path);
437       }
438     }
439     
440   mark:
441     if (ptr) {
442       /* if key is already there, update the state */
443       ptr->major = fs->major;
444       ptr->minor = fs->minor;
445       ptr->mark = 1;    
446     }
447       
448     else {
449       struct dev key = {
450         name: strdup(fs->name),
451         major: fs->major,
452         minor: fs->minor,
453         mark: 1
454       };
455 
456       dev_insert(&key);
457     }
458     continue;
459 
460   remove:
461     if (ptr) dev_remove(ptr);
462   }
463 
464   /* finalize deletions */
465   dev_compress();
466 
467   return STATUS_OK;
468 }
469 
470 
471 void start_fusdd(int set_verbose)
472 {
473   int fd;
474   int status;
475   verbose = set_verbose;
476 
477   fprintf(stderr, "fusdd: FUSDd Starting...%s\n", verbose ? " (Verbose Mode)" : "");
478   umask(0);
479   
480   /* check UID */
481   if (geteuid()) {
482     fprintf(stderr, "fusdd: Sorry, I must run as root!\n");
483     exit(1);
484   }
485 
486   /* modprobe kfusd */
487   status = system("/sbin/modprobe kfusd");
488   if (status < 0) {
489     fprintf(stderr, "fusdd: modprobe failed: %m\n");
490   }
491   else if (status) {
492     fprintf(stderr, "fusdd: modprobe returned '%d', can't find fusd?  Continuing...\n", 
493             status);
494   }
495 
496   /* mknod the FUSD control channel etc */
497   f_mkdir_with_parents(FUSD_CONTROL_DEVNAME);
498   if (mknod(FUSD_CONTROL_DEVNAME, S_IFCHR | 0777, 
499             makedev(FUSD_DEV_MAJOR, FUSD_CONTROL_MINOR)) < 0)
500     if (errno != EEXIST)
501       fprintf(stderr, "Unable to mknod FUSD control device: %m\n");
502   if (mknod(FUSD_STATUS_DEVNAME, S_IFCHR | 0777, 
503             makedev(FUSD_DEV_MAJOR, FUSD_STATUS_MINOR)) < 0)
504     if (errno != EEXIST)
505       fprintf(stderr, "Unable to mknod FUSD status device: %m\n");
506   
507   /* open the FUSD status device */
508   fd = open(FUSD_STATUS_DEVNAME, O_RDONLY);
509   if (fd < 0) {
510     fprintf(stderr, "fusdd: Can't open %s.. Make sure FUSD module is inserted: %m\n", 
511             FUSD_STATUS_DEVNAME);
512     goto delete;
513   }
514 
515   /* turn on binary mode */
516   if (ioctl(fd, FUSD_STATUS_USE_BINARY, NULL) < 0) {
517     fprintf(stderr, "fusd: BINARY_MODE ioctl() failed: %m\n");
518     exit(1);    
519   }
520   
521   /* daemonize? */
522   if (!verbose) {
523     int status = fork();
524 
525     if (status < 0) {
526       fprintf(stderr, "fusdd: Unable to fork!\n");
527       exit(1);
528     }
529 
530     if (status)
531       return;
532 
533     /* child: daemonize */
534     setpgrp();
535     chdir("/");
536     close(0);
537     close(1);
538   }
539 
540   /* Tell FUSD who we are */
541   if (ioctl(fd, FUSD_STATUS_I_AM_FUSDD, NULL) < 0) {
542     if (errno == 524) {
543       fprintf(stderr, "fusdd: This FUSD uses DevFS: daemon exiting.\n");
544       return;
545     }
546     fprintf(stderr, "fusd: I_AM_FUSDD ioctl() failed: %m\n");
547     goto delete;
548   }
549 
550   if (!verbose)
551     close(2);
552 
553   {
554     fusd_status_context_t fsctx = {
555       fd: fd,
556       new_data_cb: process,
557       begin_full_cb: clear_marks,
558       end_full_cb: unlink_unmarked,
559     };
560 
561     /* Now we read! */
562     while (1) {
563       int status;
564 
565       /* process it */
566       status = fusd_status_process(&fsctx);
567 
568       switch (status) {
569       case STATUS_ERR:
570         fprintf(stderr, "fusd: Read failed: %m\n");
571         exit(1);
572       case STATUS_DONE:
573         if (fusd_status_wait(&fsctx) < 0) {
574           fprintf(stderr, "fusd: Poll failed: %m\n");
575           exit(1);
576         }
577       }
578     }
579   }
580 
581  delete:
582   unlink(FUSD_CONTROL_DEVNAME);
583   unlink(FUSD_STATUS_DEVNAME);
584   exit(1);
585 }
586 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.