16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <treefiles.h>
20 #ifdef HAVE_SYS_MOUNT_H
21 #include <sys/mount.h>
24 #define LINELEN 256 /**< Size of static buffer used to read the
25 authorization file (yuck) */
29 bool address_matches(const char* mask
, const struct sockaddr
* addr
, GError
** err
) {
30 struct addrinfo
*res
, *aitmp
, hints
;
32 char privmask
[strlen(mask
)+1];
34 int addrlen
= addr
->sa_family
== AF_INET
? 4 : 16;
36 strcpy(privmask
, mask
);
38 memset(&hints
, 0, sizeof(hints
));
39 hints
.ai_family
= AF_UNSPEC
;
40 hints
.ai_flags
= AI_NUMERICHOST
;
42 if((masksep
= strchr(privmask
, '/'))) {
44 masklen
= strtol(++masksep
, NULL
, 10);
46 masklen
= addrlen
* 8;
50 if((e
= getaddrinfo(privmask
, NULL
, &hints
, &res
))) {
51 g_set_error(err
, NBDS_ERR
, NBDS_ERR_GAI
, "could not parse netmask line: %s", gai_strerror(e
));
56 assert(addr
->sa_family
== AF_INET
|| addr
->sa_family
== AF_INET6
);
57 const uint8_t* byte_s
;
60 int len_left
= masklen
;
61 if(res
->ai_family
!= addr
->sa_family
) {
62 msg(LOG_DEBUG
, "client address does not match %d/%d: address family mismatch (IPv4 vs IPv6?)",
63 (int)res
->ai_family
, (int)addr
->sa_family
);
66 switch(addr
->sa_family
) {
68 byte_s
= (const uint8_t*)(&(((struct sockaddr_in
*)addr
)->sin_addr
));
69 byte_t
= (uint8_t*)(&(((struct sockaddr_in
*)(res
->ai_addr
))->sin_addr
));
72 byte_s
= (const uint8_t*)(&(((struct sockaddr_in6
*)addr
)->sin6_addr
));
73 byte_t
= (uint8_t*)(&(((struct sockaddr_in6
*)(res
->ai_addr
))->sin6_addr
));
76 while(len_left
>= 8) {
77 if(*byte_s
!= *byte_t
) {
84 mask
= getmaskbyte(len_left
);
85 if((*byte_s
& mask
) != (*byte_t
& mask
)) {
98 uint8_t getmaskbyte(int masklen
) {
103 for(int i
= 7; i
+ masklen
> 7; i
--) {
110 int authorized_client(CLIENT
*opts
) {
114 if (opts
->server
->authname
== NULL
) {
115 msg(LOG_INFO
, "No authorization file, granting access.");
119 if ((f
=fopen(opts
->server
->authname
,"r"))==NULL
) {
120 msg(LOG_INFO
, "Can't open authorization file %s (%s).",
121 opts
->server
->authname
, strerror(errno
));
125 while (fgets(line
,LINELEN
,f
)!=NULL
) {
128 if((pos
= strchr(line
, '#'))) {
131 /* Skip whitespace */
133 while((*pos
) && isspace(*pos
)) {
136 /* Skip content-free lines */
140 if(address_matches(line
, (struct sockaddr
*)&opts
->clientaddr
, NULL
)) {
151 * @param s the old server we want to duplicate
152 * @return new duplicated server
154 SERVER
* dup_serve(const SERVER
*const s
) {
155 SERVER
*serve
= NULL
;
157 serve
=g_new0(SERVER
, 1);
162 serve
->exportname
= g_strdup(s
->exportname
);
164 serve
->expected_size
= s
->expected_size
;
167 serve
->listenaddr
= g_strdup(s
->listenaddr
);
170 serve
->authname
= g_strdup(s
->authname
);
172 serve
->flags
= s
->flags
;
173 serve
->virtstyle
= s
->virtstyle
;
174 serve
->cidrlen
= s
->cidrlen
;
177 serve
->prerun
= g_strdup(s
->prerun
);
180 serve
->postrun
= g_strdup(s
->postrun
);
182 if(s
->transactionlog
)
183 serve
->transactionlog
= g_strdup(s
->transactionlog
);
186 serve
->servename
= g_strdup(s
->servename
);
189 serve
->cowdir
= g_strdup(s
->cowdir
);
191 serve
->max_connections
= s
->max_connections
;
196 uint64_t size_autodetect(int fhandle
) {
198 u64 bytes
__attribute__((unused
));
199 struct stat stat_buf
;
202 #ifdef HAVE_SYS_MOUNT_H
203 #ifdef HAVE_SYS_IOCTL_H
205 DEBUG("looking for export size with ioctl BLKGETSIZE64\n");
206 if (!ioctl(fhandle
, BLKGETSIZE64
, &bytes
) && bytes
) {
209 #endif /* BLKGETSIZE64 */
210 #endif /* HAVE_SYS_IOCTL_H */
211 #endif /* HAVE_SYS_MOUNT_H */
213 DEBUG("looking for fhandle size with fstat\n");
214 stat_buf
.st_size
= 0;
215 error
= fstat(fhandle
, &stat_buf
);
217 /* always believe stat if a regular file as it might really
219 if (S_ISREG(stat_buf
.st_mode
) || (stat_buf
.st_size
> 0))
220 return (uint64_t)stat_buf
.st_size
;
222 DEBUG("fstat failed: %s", strerror(errno
));
225 DEBUG("looking for fhandle size with lseek SEEK_END\n");
226 es
= lseek(fhandle
, (off_t
)0, SEEK_END
);
227 if (es
> ((off_t
)0)) {
230 DEBUG("lseek failed: %d", errno
==EBADF
?1:(errno
==ESPIPE
?2:(errno
==EINVAL
?3:4)));
233 DEBUG("Could not find size of exported block device: %s", strerror(errno
));
237 int exptrim(struct nbd_request
* req
, CLIENT
* client
) {
238 /* Caller did range checking */
239 assert(!(client
->server
->flags
& F_READONLY
));
240 assert(req
->from
+ req
->len
<= client
->exportsize
);
241 /* For copy-on-write, we should trim on the diff file. Not yet
243 if(client
->server
->flags
& F_COPYONWRITE
) {
244 DEBUG("TRIM not supported yet on copy-on-write exports");
247 if (client
->server
->flags
& F_TREEFILES
) {
248 /* start address of first block to be trimmed */
249 off_t min
= ( ( req
->from
+ TREEPAGESIZE
- 1 ) / TREEPAGESIZE
) * TREEPAGESIZE
;
250 /* start address of first block NOT to be trimmed */
251 off_t max
= ( ( req
->from
+ req
->len
) / TREEPAGESIZE
) * TREEPAGESIZE
;
253 delete_treefile(client
->exportname
,client
->exportsize
,min
);
256 DEBUG("Performed TRIM request on TREE structure from %llu to %llu", (unsigned long long) req
->from
, (unsigned long long) req
->len
);
259 FILE_INFO cur
= g_array_index(client
->export
, FILE_INFO
, 0);
263 if(i
<client
->export
->len
) {
264 next
= g_array_index(client
->export
, FILE_INFO
, i
);
267 next
.startoff
= client
->exportsize
;
269 if(cur
.startoff
<= req
->from
&& next
.startoff
- cur
.startoff
>= req
->len
) {
270 off_t reqoff
= req
->from
- cur
.startoff
;
271 off_t curlen
= next
.startoff
- reqoff
;
272 off_t reqlen
= curlen
- reqoff
> req
->len
? req
->len
: curlen
- reqoff
;
273 punch_hole(cur
.fhandle
, reqoff
, reqlen
);
277 } while(i
< client
->export
->len
&& cur
.startoff
< (req
->from
+ req
->len
));
278 DEBUG("Performed TRIM request from %llu to %llu", (unsigned long long) req
->from
, (unsigned long long) req
->len
);