do_mounts_devfs.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #include <linux/kernel.h>
  2. #include <linux/dirent.h>
  3. #include <linux/string.h>
  4. #include "do_mounts.h"
  5. void __init mount_devfs(void)
  6. {
  7. sys_mount("devfs", "/dev", "devfs", 0, NULL);
  8. }
  9. void __init umount_devfs(char *path)
  10. {
  11. sys_umount(path, 0);
  12. }
  13. /*
  14. * If the dir will fit in *buf, return its length. If it won't fit, return
  15. * zero. Return -ve on error.
  16. */
  17. static int __init do_read_dir(int fd, void *buf, int len)
  18. {
  19. long bytes, n;
  20. char *p = buf;
  21. sys_lseek(fd, 0, 0);
  22. for (bytes = 0; bytes < len; bytes += n) {
  23. n = sys_getdents64(fd, (struct linux_dirent64 *)(p + bytes),
  24. len - bytes);
  25. if (n < 0)
  26. return n;
  27. if (n == 0)
  28. return bytes;
  29. }
  30. return 0;
  31. }
  32. /*
  33. * Try to read all of a directory. Returns the contents at *p, which
  34. * is kmalloced memory. Returns the number of bytes read at *len. Returns
  35. * NULL on error.
  36. */
  37. static void * __init read_dir(char *path, int *len)
  38. {
  39. int size;
  40. int fd = sys_open(path, 0, 0);
  41. *len = 0;
  42. if (fd < 0)
  43. return NULL;
  44. for (size = 1 << 9; size <= (PAGE_SIZE << MAX_ORDER); size <<= 1) {
  45. void *p = kmalloc(size, GFP_KERNEL);
  46. int n;
  47. if (!p)
  48. break;
  49. n = do_read_dir(fd, p, size);
  50. if (n > 0) {
  51. sys_close(fd);
  52. *len = n;
  53. return p;
  54. }
  55. kfree(p);
  56. if (n == -EINVAL)
  57. continue; /* Try a larger buffer */
  58. if (n < 0)
  59. break;
  60. }
  61. sys_close(fd);
  62. return NULL;
  63. }
  64. /*
  65. * recursively scan <path>, looking for a device node of type <dev>
  66. */
  67. static int __init find_in_devfs(char *path, unsigned dev)
  68. {
  69. char *end = path + strlen(path);
  70. int rest = path + 64 - end;
  71. int size;
  72. char *p = read_dir(path, &size);
  73. char *s;
  74. if (!p)
  75. return -1;
  76. for (s = p; s < p + size; s += ((struct linux_dirent64 *)s)->d_reclen) {
  77. struct linux_dirent64 *d = (struct linux_dirent64 *)s;
  78. if (strlen(d->d_name) + 2 > rest)
  79. continue;
  80. switch (d->d_type) {
  81. case DT_BLK:
  82. sprintf(end, "/%s", d->d_name);
  83. if (bstat(path) != dev)
  84. break;
  85. kfree(p);
  86. return 0;
  87. case DT_DIR:
  88. if (strcmp(d->d_name, ".") == 0)
  89. break;
  90. if (strcmp(d->d_name, "..") == 0)
  91. break;
  92. sprintf(end, "/%s", d->d_name);
  93. if (find_in_devfs(path, dev) < 0)
  94. break;
  95. kfree(p);
  96. return 0;
  97. }
  98. }
  99. kfree(p);
  100. return -1;
  101. }
  102. /*
  103. * create a device node called <name> which points to
  104. * <devfs_name> if possible, otherwise find a device node
  105. * which matches <dev> and make <name> a symlink pointing to it.
  106. */
  107. int __init create_dev(char *name, dev_t dev, char *devfs_name)
  108. {
  109. char path[64];
  110. sys_unlink(name);
  111. if (devfs_name && devfs_name[0]) {
  112. if (strncmp(devfs_name, "/dev/", 5) == 0)
  113. devfs_name += 5;
  114. sprintf(path, "/dev/%s", devfs_name);
  115. if (sys_access(path, 0) == 0)
  116. return sys_symlink(devfs_name, name);
  117. }
  118. if (!dev)
  119. return -1;
  120. strcpy(path, "/dev");
  121. if (find_in_devfs(path, new_encode_dev(dev)) < 0)
  122. return -1;
  123. return sys_symlink(path + 5, name);
  124. }