17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <treefiles.h>
21 #ifdef HAVE_SYS_IOCTL_H
22 #include <sys/ioctl.h>
24 #ifdef HAVE_SYS_MOUNT_H
25 #include <sys/mount.h>
28 #define LINELEN 256 /**< Size of static buffer used to read the
29 authorization file (yuck) */
32 bool address_matches(const char* mask
, const struct sockaddr
* addr
, GError
** err
) {
33 struct addrinfo
*res
, *aitmp
, hints
;
35 char privmask
[strlen(mask
)+1];
37 int addrlen
= addr
->sa_family
== AF_INET
? 4 : 16;
39 strcpy(privmask
, mask
);
41 memset(&hints
, 0, sizeof(hints
));
42 hints
.ai_family
= AF_UNSPEC
;
43 hints
.ai_flags
= AI_NUMERICHOST
;
45 if((masksep
= strchr(privmask
, '/'))) {
47 masklen
= strtol(++masksep
, NULL
, 10);
49 masklen
= addrlen
* 8;
53 if((e
= getaddrinfo(privmask
, NULL
, &hints
, &res
))) {
54 g_set_error(err
, NBDS_ERR
, NBDS_ERR_GAI
, "could not parse netmask line: %s", gai_strerror(e
));
59 assert(addr
->sa_family
== AF_INET
|| addr
->sa_family
== AF_INET6
);
60 const uint8_t* byte_s
;
63 int len_left
= masklen
;
64 if(res
->ai_family
!= addr
->sa_family
) {
65 msg(LOG_DEBUG
, "client address does not match %d/%d: address family mismatch (IPv4 vs IPv6?)",
66 (int)res
->ai_family
, (int)addr
->sa_family
);
69 switch(addr
->sa_family
) {
71 byte_s
= (const uint8_t*)(&(((struct sockaddr_in
*)addr
)->sin_addr
));
72 byte_t
= (uint8_t*)(&(((struct sockaddr_in
*)(res
->ai_addr
))->sin_addr
));
75 byte_s
= (const uint8_t*)(&(((struct sockaddr_in6
*)addr
)->sin6_addr
));
76 byte_t
= (uint8_t*)(&(((struct sockaddr_in6
*)(res
->ai_addr
))->sin6_addr
));
79 while(len_left
>= 8) {
80 if(*byte_s
!= *byte_t
) {
87 mask
= getmaskbyte(len_left
);
88 if((*byte_s
& mask
) != (*byte_t
& mask
)) {
101 uint8_t getmaskbyte(int masklen
) {
106 for(int i
= 7; i
+ masklen
> 7; i
--) {
113 int authorized_client(CLIENT
*opts
) {
117 if (opts
->server
->authname
== NULL
) {
118 msg(LOG_INFO
, "No authorization file, granting access.");
122 if ((f
=fopen(opts
->server
->authname
,"r"))==NULL
) {
123 msg(LOG_INFO
, "Can't open authorization file %s (%s).",
124 opts
->server
->authname
, strerror(errno
));
128 while (fgets(line
,LINELEN
,f
)!=NULL
) {
131 if((pos
= strchr(line
, '#'))) {
134 /* Skip whitespace */
136 while((*pos
) && isspace(*pos
)) {
139 /* Skip content-free lines */
143 if(address_matches(line
, (struct sockaddr
*)&opts
->clientaddr
, NULL
)) {
154 * @param s the old server we want to duplicate
155 * @return new duplicated server
157 SERVER
* dup_serve(const SERVER
*const s
) {
158 SERVER
*serve
= NULL
;
160 serve
=g_new0(SERVER
, 1);
165 serve
->exportname
= g_strdup(s
->exportname
);
167 serve
->expected_size
= s
->expected_size
;
170 serve
->listenaddr
= g_strdup(s
->listenaddr
);
173 serve
->authname
= g_strdup(s
->authname
);
175 serve
->flags
= s
->flags
;
176 serve
->virtstyle
= s
->virtstyle
;
177 serve
->cidrlen
= s
->cidrlen
;
180 serve
->prerun
= g_strdup(s
->prerun
);
183 serve
->postrun
= g_strdup(s
->postrun
);
185 if(s
->transactionlog
)
186 serve
->transactionlog
= g_strdup(s
->transactionlog
);
189 serve
->servename
= g_strdup(s
->servename
);
192 serve
->cowdir
= g_strdup(s
->cowdir
);
194 serve
->max_connections
= s
->max_connections
;
199 uint64_t size_autodetect(int fhandle
) {
201 u64 bytes
__attribute__((unused
));
202 struct stat stat_buf
;
205 #ifdef HAVE_SYS_MOUNT_H
206 #ifdef HAVE_SYS_IOCTL_H
208 DEBUG("looking for export size with ioctl BLKGETSIZE64\n");
209 if (!ioctl(fhandle
, BLKGETSIZE64
, &bytes
) && bytes
) {
212 #endif /* BLKGETSIZE64 */
213 #endif /* HAVE_SYS_IOCTL_H */
214 #endif /* HAVE_SYS_MOUNT_H */
216 DEBUG("looking for fhandle size with fstat\n");
217 stat_buf
.st_size
= 0;
218 error
= fstat(fhandle
, &stat_buf
);
220 /* always believe stat if a regular file as it might really
222 if (S_ISREG(stat_buf
.st_mode
) || (stat_buf
.st_size
> 0))
223 return (uint64_t)stat_buf
.st_size
;
225 DEBUG("fstat failed: %s", strerror(errno
));
228 DEBUG("looking for fhandle size with lseek SEEK_END\n");
229 es
= lseek(fhandle
, (off_t
)0, SEEK_END
);
230 if (es
> ((off_t
)0)) {
233 DEBUG("lseek failed: %d", errno
==EBADF
?1:(errno
==ESPIPE
?2:(errno
==EINVAL
?3:4)));
236 DEBUG("Could not find size of exported block device: %s", strerror(errno
));
240 int exptrim(struct nbd_request
* req
, CLIENT
* client
) {
241 /* Caller did range checking */
242 assert(!(client
->server
->flags
& F_READONLY
));
243 assert(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 pthread_mutex_t cntmutex
= PTHREAD_MUTEX_INITIALIZER
;
287 SERVER
* serve_inc_ref(SERVER
*s
) {
288 pthread_mutex_lock(&cntmutex
);
290 pthread_mutex_unlock(&cntmutex
);
294 SERVER
* serve_dec_ref(SERVER
*s
) {
295 pthread_mutex_lock(&cntmutex
);
296 if(--(s
->refcnt
) == 0) {
300 pthread_mutex_unlock(&cntmutex
);