partname.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. #include "common.h"
  3. #define BUFLEN 64
  4. struct devpath {
  5. char prefix[5];
  6. char device[11];
  7. };
  8. struct partname_volume {
  9. struct volume v;
  10. union {
  11. char devpathstr[16];
  12. struct devpath devpath;
  13. } dev;
  14. union {
  15. char devpathstr[16];
  16. struct devpath devpath;
  17. } parent_dev;
  18. };
  19. static struct driver partname_driver;
  20. static int partname_volume_identify(struct volume *v)
  21. {
  22. struct partname_volume *p = container_of(v, struct partname_volume, v);
  23. int ret = FS_NONE;
  24. FILE *f;
  25. f = fopen(p->dev.devpathstr, "r");
  26. if (!f)
  27. return ret;
  28. ret = block_file_identify(f, 0);
  29. fclose(f);
  30. return ret;
  31. }
  32. static int partname_volume_init(struct volume *v)
  33. {
  34. struct partname_volume *p = container_of(v, struct partname_volume, v);
  35. char voldir[BUFLEN];
  36. unsigned int volsize;
  37. snprintf(voldir, sizeof(voldir), "%s/%s", block_dir_name, p->dev.devpath.device);
  38. if (read_uint_from_file(voldir, "size", &volsize))
  39. return -1;
  40. v->type = BLOCKDEV;
  41. v->size = volsize << 9; /* size is returned in sectors of 512 bytes */
  42. v->blk = p->dev.devpathstr;
  43. return block_volume_format(v, 0, p->parent_dev.devpathstr);
  44. }
  45. /* adapted from procd/utils.c -> should go to libubox */
  46. static char* get_var_from_file(const char* filename, const char* name, char* out, int len)
  47. {
  48. char line[1024], *c, *sptr;
  49. int fd = open(filename, O_RDONLY);
  50. if (fd == -1)
  51. return NULL;
  52. ssize_t r = read(fd, line, sizeof(line) - 1);
  53. close(fd);
  54. if (r <= 0)
  55. return NULL;
  56. line[r] = 0;
  57. for (c = strtok_r(line, " \t\n", &sptr); c;
  58. c = strtok_r(NULL, " \t\n", &sptr)) {
  59. char *sep = strchr(c, '=');
  60. if (sep == NULL)
  61. continue;
  62. ssize_t klen = sep - c;
  63. if (strncmp(name, c, klen) || name[klen] != 0)
  64. continue;
  65. strncpy(out, &sep[1], len);
  66. out[len-1] = '\0';
  67. return out;
  68. }
  69. return NULL;
  70. }
  71. static char *rootdevname(char *devpath) {
  72. int l;
  73. l = strlen(devpath) - 1;
  74. /* strip partition suffix from root=/dev/... string */
  75. while (l > 0 && (devpath[l] >= '0' && devpath[l] <= '9'))
  76. --l;
  77. if (devpath[l] != 'p')
  78. ++l;
  79. devpath[l] = '\0';
  80. return basename(devpath);
  81. }
  82. static struct volume *partname_volume_find(char *name)
  83. {
  84. struct partname_volume *p;
  85. char ueventgstr[BUFLEN];
  86. char namebuf[BUFLEN];
  87. char rootparam[BUFLEN];
  88. char *rootdev = NULL, *devname, *tmp;
  89. int j;
  90. bool found = false;
  91. bool allow_fallback = false;
  92. bool has_root = false;
  93. glob_t gl;
  94. if (get_var_from_file("/proc/cmdline", "fstools_ignore_partname", rootparam, sizeof(rootparam))) {
  95. if (!strcmp("1", rootparam))
  96. return NULL;
  97. }
  98. /*
  99. * Some device may contains a GPT partition named rootfs_data that may not be suitable.
  100. * To save from regression with old implementation that doesn't use fstools_ignore_partname to
  101. * explicitly say that that partname scan should be ignored, make explicit that scanning each
  102. * partition should be done by providing fstools_partname_fallback_scan=1 and skip partname scan
  103. * in every other case.
  104. */
  105. if (get_var_from_file("/proc/cmdline", "fstools_partname_fallback_scan", rootparam, sizeof(rootparam))) {
  106. if (!strcmp("1", rootparam))
  107. allow_fallback = true;
  108. }
  109. if (get_var_from_file("/proc/cmdline", "root", rootparam, sizeof(rootparam)))
  110. has_root = true;
  111. if (has_root && rootparam[0] == '/') {
  112. rootdev = rootdevname(rootparam);
  113. /* find partition on same device as rootfs */
  114. snprintf(ueventgstr, sizeof(ueventgstr), "%s/%s/*/uevent", block_dir_name, rootdev);
  115. } else {
  116. /* For compatibility, devices with root= params must explicitly opt into this fallback. */
  117. if (has_root && !allow_fallback)
  118. return NULL;
  119. /* no useful 'root=' kernel cmdline parameter, find on any block device */
  120. snprintf(ueventgstr, sizeof(ueventgstr), "%s/*/uevent", block_dir_name);
  121. }
  122. if (!glob(ueventgstr, GLOB_NOESCAPE, NULL, &gl))
  123. for (j = 0; j < gl.gl_pathc; j++) {
  124. if (!get_var_from_file(gl.gl_pathv[j], "PARTNAME", namebuf, sizeof(namebuf)))
  125. continue;
  126. if (!strncmp(namebuf, name, sizeof(namebuf))) {
  127. found = 1;
  128. break;
  129. }
  130. }
  131. if (!found)
  132. return NULL;
  133. devname = gl.gl_pathv[j];
  134. tmp = strrchr(devname, '/');
  135. if (!tmp)
  136. return NULL;
  137. *tmp = '\0';
  138. devname = strrchr(devname, '/') + 1;
  139. p = calloc(1, sizeof(*p));
  140. memcpy(p->dev.devpath.prefix, "/dev/", sizeof(p->dev.devpath.prefix));
  141. strncpy(p->dev.devpath.device, devname, sizeof(p->dev.devpath.device) - 1);
  142. p->dev.devpath.device[sizeof(p->dev.devpath.device)-1] = '\0';
  143. memcpy(p->parent_dev.devpath.prefix, "/dev/", sizeof(p->parent_dev.devpath.prefix));
  144. if (rootdev)
  145. strncpy(p->parent_dev.devpath.device, rootdev, sizeof(p->parent_dev.devpath.device) - 1);
  146. else
  147. strncpy(p->parent_dev.devpath.device, rootdevname(devname), sizeof(p->parent_dev.devpath.device) - 1);
  148. p->parent_dev.devpath.device[sizeof(p->parent_dev.devpath.device)-1] = '\0';
  149. p->v.drv = &partname_driver;
  150. p->v.blk = p->dev.devpathstr;
  151. p->v.name = name;
  152. return &p->v;
  153. }
  154. static struct driver partname_driver = {
  155. .name = "partname",
  156. .priority = 25,
  157. .find = partname_volume_find,
  158. .init = partname_volume_init,
  159. .identify = partname_volume_identify,
  160. };
  161. DRIVER(partname_driver);