xref: /dflybsd-src/lib/libhammer/info.c (revision 0d5acd7467c4e95f792ef49fceb3ab8e917ce86b)
1 /*
2  * Copyright (c) 2011 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Antonio Huete <tuxillo@quantumachine.net>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include <dirent.h>
36 #include <err.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <sys/param.h>
43 #include <sys/stat.h>
44 #include <unistd.h>
45 
46 #include "libhammer.h"
47 
48 static u_int32_t count_snapshots(u_int32_t, char *, char *, int *);
49 
50 libhammer_volinfo_t
51 libhammer_get_volinfo(const char *path)
52 {
53 	struct hammer_ioc_pseudofs_rw pseudofs;
54 	struct hammer_pseudofs_data *pfs_od;
55 	struct hammer_ioc_info info;
56 	libhammer_pfsinfo_t pfstmp;
57 	libhammer_volinfo_t hvi;
58 	int pfs_id;
59 	int fd;
60 
61 	if ((fd = open(path, O_RDONLY)) < 0)
62 		return NULL;
63 
64 	hvi = _libhammer_malloc(sizeof(*hvi));
65 	TAILQ_INIT(&hvi->list_pseudo);
66 	if ((ioctl(fd, HAMMERIOC_GET_INFO, &info)) < 0) {
67 		libhammer_free_volinfo(hvi);
68 		close(fd);
69 		return NULL;
70 	}
71 
72 	/* Fill volume information */
73 	snprintf(hvi->vol_name, TXTLEN, "%s", info.vol_name);
74 	hvi->vol_fsid = info.vol_fsid;
75 	hvi->version = info.version;
76 	hvi->nvolumes = info.nvolumes;
77 	hvi->inodes = info.inodes;
78 	hvi->bigblocks = info.bigblocks;
79 	hvi->freebigblocks = info.freebigblocks;
80 	hvi->rsvbigblocks = info.rsvbigblocks;
81 
82 	pfs_od = _libhammer_malloc(sizeof(*pfs_od));
83 
84 	/*
85 	 * XXX - Iterate HAMMER_MAX_PFS (65536) PFS ids and rely on the ioctl(2)
86 	 * return code to determine whether the PFS actually exists or not.
87 	 * This is suboptimal. The correct way would be to extract the pseudofs
88 	 * information from the control records in the B-Tree, that's in kernel
89 	 * land.
90 	 */
91 	for(pfs_id = 0; pfs_id < HAMMER_MAX_PFS; pfs_id++) {
92 		bzero(&pseudofs, sizeof(pseudofs));
93 		bzero(pfs_od, sizeof(*pfs_od));
94 
95 		pseudofs.pfs_id = pfs_id;
96 		pseudofs.ondisk = pfs_od;
97 		pseudofs.bytes = sizeof(struct hammer_pseudofs_data);
98 		pseudofs.version = HAMMER_IOC_PSEUDOFS_VERSION;
99 		if (ioctl(fd, HAMMERIOC_GET_PSEUDOFS, &pseudofs) != -1) {
100 			/*
101 			 * XXX - In the case the path passed is on PFS#0 but it
102 			 * is not the mountpoint itself, it could produce a
103 			 * wrong type of PFS.
104 			 */
105 			pfstmp = _libhammer_malloc(sizeof(*pfstmp));
106 			pfstmp->ismaster =
107 			    (pfs_od->mirror_flags & HAMMER_PFSD_SLAVE) ? 0 : 1;
108 
109 			if (pfs_id == 0)
110 				pfstmp->mountedon = strdup(path);
111 			else
112 				pfstmp->mountedon =
113 				    libhammer_find_pfs_mount(pfs_id,
114 					hvi->vol_fsid, pfstmp->ismaster);
115 			/*
116 			 * Fill in structs used in the library. We don't rely on
117 			 * HAMMER own struct but we do fill our own.
118 			 */
119 			pfstmp->version = pseudofs.version;
120 			pfstmp->pfs_id = pseudofs.pfs_id;
121 			pfstmp->mirror_flags = pfs_od->mirror_flags;
122 			pfstmp->snapcount = count_snapshots(hvi->version,
123 			    pfstmp->snapshots, pfstmp->mountedon,
124 			    &pfstmp->head.error);
125 
126 			TAILQ_INSERT_TAIL(&hvi->list_pseudo, pfstmp, entries);
127 		}
128 	}
129 	free(pfs_od);
130 	close (fd);
131 
132 	return (hvi);
133 }
134 
135 void
136 libhammer_free_volinfo(libhammer_volinfo_t volinfo)
137 {
138 	struct libhammer_pfsinfo *pfstmp;
139 
140 	while(!TAILQ_EMPTY(&volinfo->list_pseudo)) {
141 		pfstmp = TAILQ_FIRST(&volinfo->list_pseudo);
142 		free(pfstmp->mountedon);
143 		TAILQ_REMOVE(&volinfo->list_pseudo, pfstmp, entries);
144 		free(pfstmp);
145 	}
146 	free(volinfo);
147 }
148 
149 static u_int32_t
150 count_snapshots(u_int32_t version, char *pfs_snapshots, char *mountedon,
151     int *errorp)
152 {
153 	struct hammer_ioc_snapshot snapinfo;
154 	char *snapshots_path, *fpath;
155 	struct dirent *den;
156 	struct stat st;
157 	DIR *dir;
158 	u_int32_t snapshot_count;
159 	int fd;
160 
161 	snapshot_count = 0;
162 
163 	bzero(&snapinfo, sizeof(struct hammer_ioc_snapshot));
164 
165 	fd = open(mountedon, O_RDONLY);
166 	if (fd < 0) {
167 		*errorp = errno;
168 		return 0;
169 	}
170 
171 	if (version < 3) {
172 		/*
173 		 * old style: count the number of softlinks in the snapshots dir
174 		 */
175 		if (pfs_snapshots[0])
176 			snapshots_path = pfs_snapshots;
177 		else
178 			asprintf(&snapshots_path, "%s/snapshots", mountedon);
179 		if ((dir = opendir(snapshots_path)) != NULL) {
180 			while ((den = readdir(dir)) != NULL) {
181 				if (den->d_name[0] == '.')
182 					continue;
183 				asprintf(&fpath, "%s/%s", snapshots_path,
184 				    den->d_name);
185 				if (lstat(fpath, &st) == 0 &&
186 				    S_ISLNK(st.st_mode))
187 					snapshot_count++;
188 				free(fpath);
189 			}
190 			closedir(dir);
191 		}
192 	} else {
193 		/*
194 		 * new style: file system meta-data
195 		 */
196 		do {
197 			if (ioctl(fd, HAMMERIOC_GET_SNAPSHOT, &snapinfo) < 0) {
198 				*errorp = errno;
199 				goto out;
200 			}
201 
202 			snapshot_count += snapinfo.count;
203 		} while (snapinfo.head.error == 0 && snapinfo.count);
204 	}
205 
206 out:
207 	if (!pfs_snapshots[0])
208 		free(snapshots_path);
209 	if (fd != -1)
210 		close(fd);
211 	return snapshot_count;
212 }
213