static char * get_mountinfo (int proc_fd, const char *mountpoint) { char *line_mountpoint, *line_mountpoint_end; cleanup_free char *mountinfo = NULL; cleanup_free char *free_me = NULL; char *line, *line_start; char *res = NULL; int i; if (mountpoint[0] != '/') { cleanup_free char *cwd = getcwd (NULL, 0); if (cwd == NULL) die_oom (); mountpoint = free_me = strconcat3 (cwd, "/", mountpoint); } mountinfo = load_file_at (proc_fd, "self/mountinfo"); if (mountinfo == NULL) return NULL; line = mountinfo; while (*line != 0) { cleanup_free char *unescaped = NULL; line_start = line; for (i = 0; i < 4; i++) line = skip_token (line, TRUE); line_mountpoint = line; line = skip_token (line, FALSE); line_mountpoint_end = line; line = skip_line (line); unescaped = unescape_mountpoint (line_mountpoint, line_mountpoint_end - line_mountpoint); if (strcmp (mountpoint, unescaped) == 0) { res = line_start; line[-1] = 0; break; } } if (res) return xstrdup (res); return NULL; }
static MountTab parse_mountinfo (int proc_fd, const char *root_mount) { cleanup_free char *mountinfo = NULL; cleanup_free MountInfoLine *lines = NULL; cleanup_free MountInfoLine **by_id = NULL; cleanup_mount_tab MountTab mount_tab = NULL; MountInfo *end_tab; int n_mounts; char *line; int i; int max_id; unsigned int n_lines; int root; mountinfo = load_file_at (proc_fd, "self/mountinfo"); if (mountinfo == NULL) die_with_error ("Can't open /proc/self/mountinfo"); n_lines = count_lines (mountinfo); lines = xcalloc (n_lines * sizeof (MountInfoLine)); max_id = 0; line = mountinfo; i = 0; root = -1; while (*line != 0) { int rc, consumed = 0; unsigned int maj, min; char *end; char *rest; char *mountpoint; char *mountpoint_end; char *options; char *options_end; char *next_line; assert (i < n_lines); end = strchr (line, '\n'); if (end != NULL) { *end = 0; next_line = end + 1; } else next_line = line + strlen (line); rc = sscanf (line, "%d %d %u:%u %n", &lines[i].id, &lines[i].parent_id, &maj, &min, &consumed); if (rc != 4) die ("Can't parse mountinfo line"); rest = line + consumed; rest = skip_token (rest, TRUE); /* mountroot */ mountpoint = rest; rest = skip_token (rest, FALSE); /* mountpoint */ mountpoint_end = rest++; options = rest; rest = skip_token (rest, FALSE); /* vfs options */ options_end = rest; *mountpoint_end = 0; lines[i].mountpoint = unescape_inline (mountpoint); *options_end = 0; lines[i].options = options; if (lines[i].id > max_id) max_id = lines[i].id; if (lines[i].parent_id > max_id) max_id = lines[i].parent_id; if (path_equal (lines[i].mountpoint, root_mount)) root = i; i++; line = next_line; } assert (i == n_lines); if (root == -1) { mount_tab = xcalloc (sizeof (MountInfo) * (1)); return steal_pointer (&mount_tab); } by_id = xcalloc ((max_id + 1) * sizeof (MountInfoLine*)); for (i = 0; i < n_lines; i++) by_id[lines[i].id] = &lines[i]; for (i = 0; i < n_lines; i++) { MountInfoLine *this = &lines[i]; MountInfoLine *parent = by_id[this->parent_id]; MountInfoLine **to_sibling; MountInfoLine *sibling; bool covered = FALSE; if (!has_path_prefix (this->mountpoint, root_mount)) continue; if (parent == NULL) continue; if (strcmp (parent->mountpoint, this->mountpoint) == 0) parent->covered = TRUE; to_sibling = &parent->first_child; sibling = parent->first_child; while (sibling != NULL) { /* If this mountpoint is a path prefix of the sibling, * say this->mp=/foo/bar and sibling->mp=/foo, then it is * covered by the sibling, and we drop it. */ if (has_path_prefix (this->mountpoint, sibling->mountpoint)) { covered = TRUE; break; } /* If the sibling is a path prefix of this mount point, * say this->mp=/foo and sibling->mp=/foo/bar, then the sibling * is covered, and we drop it. */ if (has_path_prefix (sibling->mountpoint, this->mountpoint)) *to_sibling = sibling->next_sibling; else to_sibling = &sibling->next_sibling; sibling = sibling->next_sibling; } if (covered) continue; *to_sibling = this; } n_mounts = count_mounts (&lines[root]); mount_tab = xcalloc (sizeof (MountInfo) * (n_mounts + 1)); end_tab = collect_mounts (&mount_tab[0], &lines[root]); assert (end_tab == &mount_tab[n_mounts]); return steal_pointer (&mount_tab); }