16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <treefiles.h>
21 #define LINELEN 256 /**< Size of static buffer used to read the
22 authorization file (yuck) */
26 bool address_matches(const char* mask
, const struct sockaddr
* addr
, GError
** err
) {
27 struct addrinfo
*res
, *aitmp
, hints
;
29 char privmask
[strlen(mask
)+1];
31 int addrlen
= addr
->sa_family
== AF_INET
? 4 : 16;
33 assert(addr
->sa_family
== AF_INET
|| addr
->sa_family
== AF_INET6
);
35 strcpy(privmask
, mask
);
37 memset(&hints
, 0, sizeof(hints
));
38 hints
.ai_family
= AF_UNSPEC
;
39 hints
.ai_flags
= AI_NUMERICHOST
;
41 if((masksep
= strchr(privmask
, '/'))) {
43 masklen
= strtol(++masksep
, NULL
, 10);
45 masklen
= addrlen
* 8;
49 if((e
= getaddrinfo(privmask
, NULL
, &hints
, &res
))) {
50 g_set_error(err
, NBDS_ERR
, NBDS_ERR_GAI
, "could not parse netmask line: %s", gai_strerror(e
));
55 const uint8_t* byte_s
;
58 int len_left
= masklen
;
59 if(res
->ai_family
!= addr
->sa_family
) {
62 switch(addr
->sa_family
) {
64 byte_s
= (const uint8_t*)(&(((struct sockaddr_in
*)addr
)->sin_addr
));
65 byte_t
= (uint8_t*)(&(((struct sockaddr_in
*)(res
->ai_addr
))->sin_addr
));
68 byte_s
= (const uint8_t*)(&(((struct sockaddr_in6
*)addr
)->sin6_addr
));
69 byte_t
= (uint8_t*)(&(((struct sockaddr_in6
*)(res
->ai_addr
))->sin6_addr
));
72 while(len_left
>= 8) {
73 if(*byte_s
!= *byte_t
) {
80 mask
= getmaskbyte(len_left
);
81 if((*byte_s
& mask
) != (*byte_t
& mask
)) {
94 uint8_t getmaskbyte(int masklen
) {
99 for(int i
= 7; i
+ masklen
> 7; i
--) {
106 int authorized_client(CLIENT
*opts
) {
110 if (opts
->server
->authname
== NULL
) {
111 msg(LOG_INFO
, "No authorization file, granting access.");
115 if ((f
=fopen(opts
->server
->authname
,"r"))==NULL
) {
116 msg(LOG_INFO
, "Can't open authorization file %s (%s).",
117 opts
->server
->authname
, strerror(errno
));
121 while (fgets(line
,LINELEN
,f
)!=NULL
) {
124 if((pos
= strchr(line
, '#'))) {
127 /* Skip whitespace */
129 while((*pos
) && isspace(*pos
)) {
132 /* Skip content-free lines */
136 if(address_matches(line
, (struct sockaddr
*)&opts
->clientaddr
, NULL
)) {
147 * @param s the old server we want to duplicate
148 * @return new duplicated server
150 SERVER
* dup_serve(const SERVER
*const s
) {
151 SERVER
*serve
= NULL
;
153 serve
=g_new0(SERVER
, 1);
158 serve
->exportname
= g_strdup(s
->exportname
);
160 serve
->expected_size
= s
->expected_size
;
163 serve
->listenaddr
= g_strdup(s
->listenaddr
);
166 serve
->authname
= g_strdup(s
->authname
);
168 serve
->flags
= s
->flags
;
169 serve
->virtstyle
= s
->virtstyle
;
170 serve
->cidrlen
= s
->cidrlen
;
173 serve
->prerun
= g_strdup(s
->prerun
);
176 serve
->postrun
= g_strdup(s
->postrun
);
178 if(s
->transactionlog
)
179 serve
->transactionlog
= g_strdup(s
->transactionlog
);
182 serve
->servename
= g_strdup(s
->servename
);
185 serve
->cowdir
= g_strdup(s
->cowdir
);
187 serve
->max_connections
= s
->max_connections
;
192 uint64_t size_autodetect(int fhandle
) {
194 u64 bytes
__attribute__((unused
));
195 struct stat stat_buf
;
198 #ifdef HAVE_SYS_MOUNT_H
199 #ifdef HAVE_SYS_IOCTL_H
201 DEBUG("looking for export size with ioctl BLKGETSIZE64\n");
202 if (!ioctl(fhandle
, BLKGETSIZE64
, &bytes
) && bytes
) {
205 #endif /* BLKGETSIZE64 */
206 #endif /* HAVE_SYS_IOCTL_H */
207 #endif /* HAVE_SYS_MOUNT_H */
209 DEBUG("looking for fhandle size with fstat\n");
210 stat_buf
.st_size
= 0;
211 error
= fstat(fhandle
, &stat_buf
);
213 /* always believe stat if a regular file as it might really
215 if (S_ISREG(stat_buf
.st_mode
) || (stat_buf
.st_size
> 0))
216 return (uint64_t)stat_buf
.st_size
;
218 DEBUG("fstat failed: %s", strerror(errno
));
221 DEBUG("looking for fhandle size with lseek SEEK_END\n");
222 es
= lseek(fhandle
, (off_t
)0, SEEK_END
);
223 if (es
> ((off_t
)0)) {
226 DEBUG("lseek failed: %d", errno
==EBADF
?1:(errno
==ESPIPE
?2:(errno
==EINVAL
?3:4)));
229 DEBUG("Could not find size of exported block device: %s", strerror(errno
));
233 int exptrim(struct nbd_request
* req
, CLIENT
* client
) {
234 /* Don't trim when we're read only */
235 if(client
->server
->flags
& F_READONLY
) {
239 /* Don't trim beyond the size of the device, please */
240 if(req
->from
+ req
->len
> client
->exportsize
) {
244 /* For copy-on-write, we should trim on the diff file. Not yet
246 if(client
->server
->flags
& F_COPYONWRITE
) {
247 DEBUG("TRIM not supported yet on copy-on-write exports");
250 if (client
->server
->flags
& F_TREEFILES
) {
251 /* start address of first block to be trimmed */
252 off_t min
= ( ( req
->from
+ TREEPAGESIZE
- 1 ) / TREEPAGESIZE
) * TREEPAGESIZE
;
253 /* start address of first block NOT to be trimmed */
254 off_t max
= ( ( req
->from
+ req
->len
) / TREEPAGESIZE
) * TREEPAGESIZE
;
256 delete_treefile(client
->exportname
,client
->exportsize
,min
);
259 DEBUG("Performed TRIM request on TREE structure from %llu to %llu", (unsigned long long) req
->from
, (unsigned long long) req
->len
);
262 FILE_INFO cur
= g_array_index(client
->export
, FILE_INFO
, 0);
266 if(i
<client
->export
->len
) {
267 next
= g_array_index(client
->export
, FILE_INFO
, i
);
270 next
.startoff
= client
->exportsize
;
272 if(cur
.startoff
<= req
->from
&& next
.startoff
- cur
.startoff
>= req
->len
) {
273 off_t reqoff
= req
->from
- cur
.startoff
;
274 off_t curlen
= next
.startoff
- reqoff
;
275 off_t reqlen
= curlen
- reqoff
> req
->len
? req
->len
: curlen
- reqoff
;
276 punch_hole(cur
.fhandle
, reqoff
, reqlen
);
280 } while(i
< client
->export
->len
&& cur
.startoff
< (req
->from
+ req
->len
));
281 DEBUG("Performed TRIM request from %llu to %llu", (unsigned long long) req
->from
, (unsigned long long) req
->len
);
285 void myseek(int handle
,off_t a
) {
286 if (lseek(handle
, a
, SEEK_SET
) < 0) {
287 err("Can not seek locally!\n");