1 /*
2 * Copyright (C) 2018 Jakub Kruszona-Zawadzki, Core Technology Sp. z o.o.
3 *
4 * This file is part of MooseFS.
5 *
6 * MooseFS is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, version 2 (only).
9 *
10 * MooseFS is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with MooseFS; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA
18 * or visit http://www.gnu.org/licenses/gpl-2.0.html
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <stddef.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <netinet/in.h>
31 #include <sys/socket.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <sys/stat.h>
35 #include <sys/ioctl.h>
36 #include <fcntl.h>
37 #include <syslog.h>
38 #include <signal.h>
39 #include <errno.h>
40 #include <inttypes.h>
41 #include <pthread.h>
42
43 #ifdef HAVE_LINUX_NBD_H
44 #include <linux/nbd.h>
45 #else
46 #define NBD_REQUEST_MAGIC 0x25609513
47 #define NBD_REPLY_MAGIC 0x67446698
48 enum {
49 NBD_CMD_READ = 0,
50 NBD_CMD_WRITE = 1,
51 NBD_CMD_DISC = 2,
52 NBD_CMD_FLUSH = 3,
53 NBD_CMD_TRIM = 4
54 };
55 #define NBD_SET_SOCK _IO( 0xab, 0 )
56 #define NBD_SET_BLKSIZE _IO( 0xab, 1 )
57 #define NBD_SET_SIZE _IO( 0xab, 2 )
58 #define NBD_DO_IT _IO( 0xab, 3 )
59 #define NBD_CLEAR_SOCK _IO( 0xab, 4 )
60 #define NBD_CLEAR_QUE _IO( 0xab, 5 )
61 #define NBD_PRINT_DEBUG _IO( 0xab, 6 )
62 #define NBD_SET_SIZE_BLOCKS _IO( 0xab, 7 )
63 #define NBD_DISCONNECT _IO( 0xab, 8 )
64 #define NBD_SET_TIMEOUT _IO( 0xab, 9 )
65 #define NBD_SET_FLAGS _IO( 0xab, 10)
66 #endif
67
68 #ifdef HAVE_LINUX_FS_H
69 #include <linux/fs.h>
70 #else
71 #define BLKGETSIZE64 _IOR(0x12,114,size_t)
72 #endif
73
74 #include "mfsio.h"
75 #include "lwthread.h"
76 #include "datapack.h"
77 #include "portable.h"
78 #include "squeue.h"
79 #include "workers.h"
80 #include "strerr.h"
81 #include "massert.h"
82 #include "sizestr.h"
83 #include "sockets.h"
84 #include "processname.h"
85 #include "idstr.h"
86
87 #define READ_TOMS 1000
88 #define WRITE_TOMS 1000
89
90 enum {
91 MFSNBD_NOP,
92 MFSNBD_STOP,
93 MFSNBD_ADD,
94 MFSNBD_REMOVE,
95 MFSNBD_LIST,
96 MFSNBD_RESIZE
97 };
98
99 enum {
100 MFSNBD_OK,
101 MFSNBD_ERROR
102 };
103
104 #define NBD_LINK_PREFIX "/dev/mfs/"
105 #define NBD_LINK_PREFIX_LENG 9
106
107 #define NBD_ERR_SIZE 200
108
109 /*
110
111 NAME:
112 leng:8 data:8*leng
113 PATH:
114 leng:16 data:8*leng
115
116 MFSNBD_STOP:
117 -> -
118 <- status:8
119
120 MFSNBD_ADD:
121 -> mfspath:PATH device:NAME linkname:NAME size:64
122 <- status:8 answer:NAME
123
124 MFSNBD_REMOVE:
125 -> mfspath:PATH device:NAME linkname:NAME
126 <- status:8 answer:NAME
127
128 MFSNBD_LIST:
129 -> -
130 <- devices:8 devices * [ mfspath:PATH device:NAME linkname:NAME size:64 ]
131
132 MFSNBD_RESIZE:
133 -> mfspath:PATH device:NAME linkname:NAME size:64
134 <- status:8
135
136 */
137
138 #define FLAG_READONLY 1
139
140 typedef struct nbdcommon {
141 char *linkname;
142 char *nbddevice;
143 char *mfsfile;
144 uint64_t fsize;
145 uint32_t flags;
146 int sp[2];
147 int mfsfd;
148 int nbdfd;
149 pthread_t ctrl_thread;
150 pthread_t recv_thread;
151 pthread_t send_thread;
152 void *aqueue; // per bdev answer queues
153 } nbdcommon;
154
155 typedef struct nbdrequest {
156 nbdcommon *nbdcp;
157 uint8_t handle[8];
158 uint64_t offset;
159 uint32_t length;
160 uint16_t cmd;
161 uint16_t cmdflags;
162 uint32_t status;
163 uint8_t data[1];
164 } nbdrequest;
165
166 typedef struct _bdlist {
167 nbdcommon *nbdcp;
168 struct _bdlist *next;
169 } bdlist;
170
171 static void *workers_set;
172
173 static bdlist *bdhead;
174
175 static mfscfg mcfg;
176
177 #ifdef NBD_DEBUG
nbd_cmd_str(uint32_t cmd)178 static const char* nbd_cmd_str(uint32_t cmd) {
179 switch (cmd) {
180 case NBD_CMD_READ:
181 return "READ";
182 case NBD_CMD_WRITE:
183 return "WRITE";
184 case NBD_CMD_DISC:
185 return "DISC";
186 case NBD_CMD_FLUSH:
187 return "FLUSH";
188 case NBD_CMD_TRIM:
189 return "TRIM";
190 }
191 return "???";
192 }
193 #endif
194
writeall(int sock,uint8_t * buff,uint32_t leng)195 int32_t writeall(int sock,uint8_t *buff,uint32_t leng) {
196 uint32_t bsent;
197 int res;
198 bsent = 0;
199 while (bsent<leng) {
200 res = write(sock,buff+bsent,leng-bsent);
201 if (res<0) {
202 return -1;
203 }
204 bsent += res;
205 }
206 return bsent;
207 }
208
readall(int sock,uint8_t * buf,uint32_t leng)209 int32_t readall(int sock,uint8_t *buf,uint32_t leng) {
210 uint32_t brecv;
211 int res;
212 brecv = 0;
213 while (brecv<leng) {
214 res = read(sock,buf+brecv,leng-brecv);
215 if (res<=0) {
216 return -1;
217 }
218 brecv += res;
219 }
220 return brecv;
221 }
222
skipall(int sock,uint32_t leng)223 int32_t skipall(int sock,uint32_t leng) {
224 static uint8_t skipbuff[16384];
225 uint32_t brecv;
226 int res;
227 brecv = 0;
228 while (brecv<leng) {
229 if (leng-brecv>16384) {
230 res = read(sock,skipbuff,16384);
231 } else {
232 res = read(sock,skipbuff,leng-brecv);
233 }
234 if (res<=0) {
235 return -1;
236 }
237 brecv += res;
238 }
239 return brecv;
240 }
241
nbd_worker_fn(void * data,uint32_t workerscnt)242 void nbd_worker_fn(void *data,uint32_t workerscnt) {
243 nbdrequest *r = (nbdrequest*)data;
244 nbdcommon *nbdcp = r->nbdcp;
245
246 // syslog(LOG_NOTICE,"worker function for %s got request (cmd:%s)",nbdcp->nbddevice,nbd_cmd_str(r->cmd));
247 (void)workerscnt;
248 switch (r->cmd) {
249 case NBD_CMD_READ:
250 if (r->offset + r->length > nbdcp->fsize) {
251 r->status = EOVERFLOW;
252 } else {
253 if (mfs_pread(nbdcp->mfsfd,r->data,r->length,r->offset)<0) {
254 r->status = errno;
255 } else {
256 r->status = errno;
257 }
258 }
259 break;
260 case NBD_CMD_WRITE:
261 if (nbdcp->flags & FLAG_READONLY) {
262 r->status = EROFS;
263 } else if (r->offset + r->length > nbdcp->fsize) {
264 r->status = EOVERFLOW;
265 } else {
266 if (mfs_pwrite(nbdcp->mfsfd,r->data,r->length,r->offset)<0) {
267 r->status = errno;
268 } else {
269 r->status = 0;
270 }
271 }
272 break;
273 case NBD_CMD_DISC:
274 mfs_fsync(nbdcp->mfsfd);
275 r->status = 0;
276 break;
277 #ifdef NBD_CMD_FLUSH
278 case NBD_CMD_FLUSH:
279 if (nbdcp->flags & FLAG_READONLY) {
280 r->status = EROFS;
281 } else if (mfs_fsync(nbdcp->mfsfd)<0) {
282 r->status = errno;
283 } else {
284 r->status = 0;
285 }
286 #endif
287 default:
288 // ignore other commands
289 r->status = 0;
290 }
291 // syslog(LOG_NOTICE,"worker function for %s enqueue status %u (cmd:%s)",nbdcp->nbddevice,r->status,nbd_cmd_str(r->cmd));
292 squeue_put(nbdcp->aqueue,r);
293 }
294
receive_thread(void * arg)295 void* receive_thread(void *arg) {
296 uint8_t commbuff[28];
297 const uint8_t *rptr;
298 const uint8_t *handleptr;
299 uint8_t *wptr;
300 uint32_t bytesread;
301 uint32_t magic;
302 uint16_t cmdflags;
303 uint32_t cmd;
304 uint64_t offset;
305 uint32_t length;
306 int res;
307 nbdrequest *r;
308 nbdcommon *nbdcp = (nbdcommon*)arg;
309
310 // syslog(LOG_NOTICE,"receive thread for %s started",nbdcp->nbddevice);
311 bytesread = 0;
312 for (;;) {
313 res = read(nbdcp->sp[0],commbuff+bytesread,28-bytesread);
314 if (res<=0) {
315 // disconnect - simulate NBD_CMD_DISC
316 wptr = commbuff;
317 put32bit(&wptr,NBD_REQUEST_MAGIC);
318 put32bit(&wptr,NBD_CMD_DISC);
319 memset(wptr,0,20);
320 bytesread = 28;
321 } else {
322 bytesread += res;
323 }
324 if (bytesread<28) {
325 continue;
326 }
327 bytesread = 0;
328 rptr = commbuff;
329 magic = get32bit(&rptr);
330 cmdflags = get16bit(&rptr);
331 cmd = get16bit(&rptr);
332 handleptr = rptr;
333 rptr += 8; // skip handle
334 offset = get64bit(&rptr);
335 length = get32bit(&rptr);
336 if (magic!=NBD_REQUEST_MAGIC) { // desync - simulate NBD_CMD_DISC
337 cmd = NBD_CMD_DISC;
338 }
339 // syslog(LOG_NOTICE,"receive thread for %s got request (cmd:%s)",nbdcp->nbddevice,nbd_cmd_str(cmd));
340 if (cmd==NBD_CMD_WRITE || cmd==NBD_CMD_READ) {
341 r = (nbdrequest*)malloc(offsetof(nbdrequest,data)+length);
342 } else {
343 r = (nbdrequest*)malloc(offsetof(nbdrequest,data));
344 }
345 passert(r);
346 r->nbdcp = nbdcp;
347 memcpy(r->handle,handleptr,8);
348 r->offset = offset;
349 r->length = length;
350 r->cmd = cmd;
351 r->cmdflags = cmdflags;
352 if (cmd==NBD_CMD_WRITE) {
353 readall(nbdcp->sp[0],r->data,length);
354 }
355 // nbd_worker_fn(r,0);
356 workers_newjob(workers_set,r);
357 if (cmd==NBD_CMD_DISC) {
358 return NULL;
359 }
360 }
361 }
362
send_thread(void * arg)363 void* send_thread(void *arg) {
364 uint8_t commbuff[16];
365 uint8_t *wptr;
366 nbdrequest *r;
367 void *data;
368 nbdcommon *nbdcp = (nbdcommon*)arg;
369
370 // syslog(LOG_NOTICE,"send thread for %s started",nbdcp->nbddevice);
371 wptr = commbuff;
372 put32bit(&wptr,NBD_REPLY_MAGIC);
373 for (;;) {
374 squeue_get(nbdcp->aqueue,&data);
375 if (data==NULL) {
376 syslog(LOG_NOTICE,"send thread for %s ending (data==NULL)",nbdcp->nbddevice);
377 return NULL;
378 }
379 r = (nbdrequest*)data;
380 // syslog(LOG_NOTICE,"send thread for %s got status %u for request (cmd:%s)",nbdcp->nbddevice,r->status,nbd_cmd_str(r->cmd));
381 wptr = commbuff+4;
382 put32bit(&wptr,r->status);
383 memcpy(wptr,r->handle,8);
384 writeall(nbdcp->sp[0],commbuff,16);
385 if (r->cmd==NBD_CMD_READ && r->status==0) {
386 writeall(nbdcp->sp[0],r->data,r->length);
387 }
388 if (r->cmd==NBD_CMD_DISC) {
389 syslog(LOG_NOTICE,"send thread for %s ending (cmd:DISC)",nbdcp->nbddevice);
390 return NULL;
391 }
392 free(r);
393 }
394 }
395
nbd_controller_thread(void * arg)396 void* nbd_controller_thread(void *arg) {
397 nbdcommon *nbdcp = ((nbdcommon*)(arg));
398 int err;
399
400 err = ioctl(nbdcp->nbdfd, NBD_SET_SOCK, nbdcp->sp[1]);
401 if (err<0) {
402 ioctl(nbdcp->nbdfd, NBD_CLEAR_QUE);
403 ioctl(nbdcp->nbdfd, NBD_CLEAR_SOCK);
404 // exit(1);
405 return NULL;
406 }
407 #if defined NBD_SET_FLAGS && defined NBD_FLAG_SEND_FLUSH && defined NBD_CMD_FLUSH
408 err = ioctl(nbdcp->nbdfd, NBD_SET_FLAGS, NBD_FLAG_SEND_FLUSH);
409 if (err<0) {
410 ioctl(nbdcp->nbdfd, NBD_CLEAR_QUE);
411 ioctl(nbdcp->nbdfd, NBD_CLEAR_SOCK);
412 // exit(1);
413 return NULL;
414 }
415 #endif
416 // syslog(LOG_NOTICE,"controller thread for %s performs DO_IT ioctl",nbdcp->nbddevice);
417 // fprintf(stderr,"waiting for peer to finish ...\n");
418 ioctl(nbdcp->nbdfd, NBD_DO_IT); // this will wait
419 syslog(LOG_NOTICE,"controller thread for %s finished",nbdcp->nbddevice);
420 // fprintf(stderr,"... finished\n");
421 ioctl(nbdcp->nbdfd, NBD_CLEAR_QUE);
422 ioctl(nbdcp->nbdfd, NBD_CLEAR_SOCK);
423 return NULL;
424 }
425
426 static uint8_t term;
427
termhandle(int signo)428 void termhandle(int signo) {
429 term = 1;
430 (void)signo;
431 }
432
set_signals(void)433 void set_signals(void) {
434 struct sigaction sa;
435
436 #ifdef SA_RESTART
437 sa.sa_flags = SA_RESTART;
438 #else
439 sa.sa_flags = 0;
440 #endif
441 sigemptyset(&sa.sa_mask);
442 sa.sa_handler = termhandle;
443 sigaction(SIGTERM,&sa,(struct sigaction *)0);
444 sigaction(SIGINT,&sa,(struct sigaction *)0);
445 sa.sa_handler = SIG_IGN;
446 sigaction(SIGPIPE,&sa,(struct sigaction *)0);
447 }
448
make_daemon(void)449 void make_daemon(void) {
450 int f;
451 int pipefd[2];
452
453 fflush(stdout);
454 fflush(stderr);
455
456 if (pipe(pipefd)<0) {
457 syslog(LOG_ERR,"daemonize, pipe error: %s",strerror(errno));
458 exit(1);
459 }
460
461 f = fork();
462 if (f<0) {
463 syslog(LOG_ERR,"daemonize, first fork error: %s",strerror(errno));
464 exit(1);
465 }
466 if (f>0) {
467 int status;
468 char buf;
469 close(pipefd[1]); // close unused write end
470 while (read(pipefd[0], &buf, 1) > 0) {
471 status = write(STDOUT_FILENO, &buf, 1); // ignore status
472 }
473 waitpid(f,&status,0);
474 exit(0);
475 }
476 if (chdir("/")<0) {
477 syslog(LOG_NOTICE,"can't change working directory to '/': %s",strerror(errno));
478 }
479 setsid();
480 setpgid(0,getpid());
481 f = fork();
482 if (f<0) {
483 syslog(LOG_ERR,"daemonize, second fork error: %s",strerror(errno));
484 exit(1);
485 }
486 if (f>0) {
487 close(pipefd[0]);
488 close(pipefd[1]);
489 exit(0);
490 }
491
492 set_signals();
493 close(pipefd[0]);
494
495 f = open("/dev/null", O_RDWR, 0);
496 close(STDIN_FILENO);
497 sassert(dup(f)==STDIN_FILENO);
498 close(STDOUT_FILENO);
499 sassert(dup(f)==STDOUT_FILENO);
500 close(STDERR_FILENO);
501 sassert(dup(pipefd[1])==STDERR_FILENO);
502 close(f);
503 close(pipefd[1]);
504 }
505
charconv(char c)506 static inline char charconv(char c) {
507 if ((c>='0' && c<='9') || (c>='A' && c<='Z') || (c>='a' && c<='z') || (c=='.') || (c=='-')) {
508 return c;
509 } else {
510 return '_';
511 }
512 }
513
linkname_generate(char * linkname,const char * masterhost,const char * masterport,const char * filename)514 char* linkname_generate(char *linkname,const char *masterhost,const char *masterport,const char *filename) {
515 uint32_t mhl,mpl,fnl,l,i;
516 char *ln;
517
518 if (linkname!=NULL) {
519 fnl = strlen(linkname);
520
521 ln = malloc(fnl+NBD_LINK_PREFIX_LENG+1);
522 passert(ln);
523
524 memcpy(ln,NBD_LINK_PREFIX,NBD_LINK_PREFIX_LENG);
525 l = 9;
526 for (i=0 ; i<fnl ; i++) {
527 ln[l++] = charconv(linkname[i]);
528 }
529 free(linkname);
530 } else {
531 mhl = strlen(masterhost);
532 mpl = strlen(masterport);
533 fnl = strlen(filename);
534
535 ln = malloc(mhl+mpl+fnl+3+1+NBD_LINK_PREFIX_LENG);
536 passert(ln);
537
538 memcpy(ln,NBD_LINK_PREFIX,NBD_LINK_PREFIX_LENG);
539 l=9;
540 for (i=0 ; i<mhl ; i++) {
541 ln[l++] = charconv(masterhost[i]);
542 }
543 ln[l++] = '_';
544 for (i=0 ; i<mpl ; i++) {
545 ln[l++] = charconv(masterport[i]);
546 }
547 ln[l++] = '_';
548 for (i=0 ; i<fnl ; i++) {
549 ln[l++] = charconv(filename[i]);
550 }
551 }
552 ln[l++] = '\0';
553 if (l>256+NBD_LINK_PREFIX_LENG) { // we don't want names longer than 255 chars
554 ln[256+NBD_LINK_PREFIX_LENG]='\0';
555 }
556 return ln;
557 }
558
find_free_nbddevice(void)559 char* find_free_nbddevice(void) {
560 int nbdfd;
561 char devicename[50];
562 uint64_t size;
563 uint32_t i;
564 int err;
565
566 for (i=0;;i++) {
567 snprintf(devicename,50,"/dev/nbd%u",i);
568 devicename[49] = 0;
569 nbdfd = open(devicename,O_RDWR);
570 if (nbdfd<0) {
571 if (errno==ENOENT) {
572 return NULL;
573 }
574 } else {
575 err = ioctl(nbdfd,BLKGETSIZE64,&size);
576 close(nbdfd);
577 if (err<0) {
578 return NULL;
579 }
580 if (size==0) {
581 return strdup(devicename);
582 }
583 }
584 }
585 return NULL;
586 }
587
nbd_linktest(nbdcommon * nbdcp)588 int nbd_linktest(nbdcommon *nbdcp) {
589 uint64_t size;
590 int err,fd;
591
592 fd = open(nbdcp->linkname,O_RDWR);
593 if (fd>=0) {
594 err = ioctl(fd,BLKGETSIZE64,&size);
595 close(fd);
596 if (err>=0 && size>0) {
597 return -1;
598 }
599 }
600 return 0;
601 }
602
nbd_packet_to_str(const uint8_t * pstr,uint32_t pleng)603 char* nbd_packet_to_str(const uint8_t *pstr,uint32_t pleng) {
604 char *r;
605 if (pleng==0) {
606 return NULL;
607 }
608 r = malloc(pleng+1);
609 passert(r);
610 memcpy(r,pstr,pleng);
611 r[pleng]=0;
612 return r;
613 }
614
nbd_start(nbdcommon * nbdcp,char errmsg[NBD_ERR_SIZE])615 int nbd_start(nbdcommon *nbdcp,char errmsg[NBD_ERR_SIZE]) {
616 uint64_t size;
617 int omode,lmode;
618 int err,status;
619 struct stat stbuf;
620
621 #define nbd_start_err_msg(format, ...) {\
622 syslog(LOG_ERR,(format), __VA_ARGS__); \
623 snprintf(errmsg,NBD_ERR_SIZE,(format), __VA_ARGS__); \
624 }
625
626 errmsg[0] = 0;
627 err = socketpair(AF_UNIX, SOCK_STREAM, 0, nbdcp->sp);
628
629 if (err<0) {
630 nbd_start_err_msg("can't create socket pair: %s",strerror(errno));
631 goto err1;
632 }
633
634 if (nbdcp->nbddevice==NULL) {
635 nbdcp->nbddevice = find_free_nbddevice();
636 }
637
638 if (nbdcp->nbddevice==NULL) {
639 nbd_start_err_msg("%s","can't find free NBD device");
640 goto err2;
641 }
642
643 nbdcp->nbdfd = open(nbdcp->nbddevice,O_RDWR);
644 if (nbdcp->nbdfd<0) {
645 nbd_start_err_msg("error opening %s: %s",nbdcp->nbddevice,strerror(errno));
646 goto err2;
647 }
648
649 err = ioctl(nbdcp->nbdfd,BLKGETSIZE64,&size);
650 if (err<0) {
651 nbd_start_err_msg("can't obtain size of block device (%s): %s",nbdcp->nbddevice,strerror(errno));
652 goto err3;
653 }
654 if (size>0) {
655 nbd_start_err_msg("it seems that block device (%s) is already mapped",nbdcp->nbddevice);
656 goto err3;
657 }
658
659 if (nbdcp->flags & FLAG_READONLY) {
660 omode = O_RDONLY;
661 lmode = LOCK_SH;
662 } else {
663 omode = O_RDWR;
664 lmode = LOCK_EX;
665 }
666 if (nbdcp->fsize!=0) {
667 omode |= O_CREAT;
668 }
669 nbdcp->mfsfd = mfs_open(nbdcp->mfsfile,omode,0666);
670 if (nbdcp->mfsfd<0) {
671 nbd_start_err_msg("error opening MFS file %s: %s",nbdcp->mfsfile,strerror(errno));
672 goto err3;
673 }
674
675 if (mfs_flock(nbdcp->mfsfd,lmode|LOCK_NB)<0) {
676 nbd_start_err_msg("MFS file %s is locked (likely mapped elsewhere)",nbdcp->mfsfile);
677 goto err4;
678 }
679
680 if (nbdcp->fsize==0) {
681 if (mfs_fstat(nbdcp->mfsfd,&stbuf)<0) {
682 nbd_start_err_msg("can't stat MFS file '%s': %s",nbdcp->mfsfile,strerror(errno));
683 goto err5;
684 }
685 nbdcp->fsize = stbuf.st_size;
686 }
687
688 nbdcp->fsize = 4096 * (nbdcp->fsize/4096);
689
690 if (nbdcp->fsize==0) {
691 nbd_start_err_msg("%s","file size too low (less than one 4k block)");
692 goto err5;
693 }
694
695 // use size
696 #if 0
697 err = ioctl(nbdcp->nbdfd, NBD_SET_SIZE, nbdcp->fsize);
698 if (err<0) {
699 syslog(LOG_ERR,"error setting block device size (%s): %s",nbdcp->nbddevice,strerror(errno));
700 goto err5;
701 }
702 #endif
703 // use blocks
704 err = ioctl(nbdcp->nbdfd, NBD_SET_BLKSIZE, 4096);
705 if (err<0) {
706 nbd_start_err_msg("error setting block device block size (%s): %s",nbdcp->nbddevice,strerror(errno));
707 goto err5;
708 }
709 err = ioctl(nbdcp->nbdfd, NBD_SET_SIZE_BLOCKS, nbdcp->fsize / 4096);
710 if (err<0) {
711 nbd_start_err_msg("error setting block device number of blocks (%s): %s",nbdcp->nbddevice,strerror(errno));
712 goto err5;
713 }
714
715 err = ioctl(nbdcp->nbdfd, NBD_CLEAR_SOCK);
716 if (err<0) {
717 nbd_start_err_msg("error clearing socket for NBD device (%s): %s",nbdcp->nbddevice,strerror(errno));
718 goto err5;
719 }
720
721 err = ioctl(nbdcp->nbdfd, NBD_SET_TIMEOUT, 1800);
722 if (err<0) {
723 syslog(LOG_NOTICE,"error setting timeout for NBD device (%s): %s",nbdcp->nbddevice,strerror(errno));
724 }
725
726 nbdcp->aqueue = squeue_new(0);
727 if (nbdcp->aqueue==NULL) {
728 nbd_start_err_msg("%s","can't create queue");
729 goto err5;
730 }
731
732 err = lwt_minthread_create(&(nbdcp->ctrl_thread),0,nbd_controller_thread,nbdcp);
733 if (err<0) {
734 nbd_start_err_msg("can't create controller thread: %s",strerror(errno));
735 goto err6;
736 }
737
738 err = lwt_minthread_create(&(nbdcp->send_thread),0,send_thread,nbdcp);
739 if (err<0) {
740 nbd_start_err_msg("can't create send thread: %s",strerror(errno));
741 goto err7;
742 }
743
744 err = lwt_minthread_create(&(nbdcp->recv_thread),0,receive_thread,nbdcp);
745 if (err<0) {
746 nbd_start_err_msg("can't create receive thread: %s",strerror(errno));
747 goto err8;
748 }
749
750 err = fork(); // reread partition tables - needs to be done in separate process
751 if (err<0) {
752 syslog(LOG_NOTICE,"fork error: %s",strerror(errno)); // ignore this
753 } else {
754 if (err==0) { // child
755 err = open(nbdcp->nbddevice,O_RDONLY);
756 if (err<0) {
757 syslog(LOG_ERR,"error opening %s: %s",nbdcp->nbddevice,strerror(errno));
758 } else {
759 close(err);
760 }
761 exit(0);
762 } else {
763 waitpid(err,&status,0);
764 }
765 }
766
767 err = mkdir(NBD_LINK_PREFIX,0777); // ignore status
768 err = unlink(nbdcp->linkname); // ignore status
769 err = symlink(nbdcp->nbddevice,nbdcp->linkname);
770 if (err<0) {
771 syslog(LOG_NOTICE,"can't create nbd device symlink %s->%s: %s",nbdcp->linkname,nbdcp->nbddevice,strerror(errno));
772 }
773 return 0;
774
775 err8:
776 squeue_close(nbdcp->aqueue);
777 pthread_join(nbdcp->send_thread,NULL);
778 err7:
779 ioctl(nbdcp->nbdfd, NBD_CLEAR_QUE);
780 ioctl(nbdcp->nbdfd, NBD_DISCONNECT);
781 ioctl(nbdcp->nbdfd, NBD_CLEAR_SOCK);
782 pthread_join(nbdcp->ctrl_thread,NULL);
783 err6:
784 squeue_delete(nbdcp->aqueue);
785 err5:
786 mfs_flock(nbdcp->mfsfd,LOCK_UN); // just in case
787 err4:
788 mfs_close(nbdcp->mfsfd);
789 err3:
790 close(nbdcp->nbdfd);
791 err2:
792 close(nbdcp->sp[0]);
793 close(nbdcp->sp[1]);
794 err1:
795 return -1;
796 }
797
nbd_stop(nbdcommon * nbdcp)798 void nbd_stop(nbdcommon *nbdcp) {
799 int err;
800
801 err = ioctl(nbdcp->nbdfd, NBD_CLEAR_QUE);
802 if (err<0) {
803 syslog(LOG_ERR,"%s: ioctl (NBD_CLEAR_QUE) failed: %s",nbdcp->nbddevice,strerror(errno));
804 }
805 err = ioctl(nbdcp->nbdfd, NBD_DISCONNECT);
806 if (err<0) {
807 syslog(LOG_ERR,"%s: ioctl (NBD_DISCONNECT) failed: %s",nbdcp->nbddevice,strerror(errno));
808 }
809 err = ioctl(nbdcp->nbdfd, NBD_CLEAR_SOCK);
810 if (err<0) {
811 syslog(LOG_ERR,"%s: ioctl (NBD_CLEAR_SOCK) failed: %s",nbdcp->nbddevice,strerror(errno));
812 }
813
814 pthread_join(nbdcp->recv_thread,NULL);
815 pthread_join(nbdcp->send_thread,NULL);
816 pthread_join(nbdcp->ctrl_thread,NULL);
817
818 squeue_delete(nbdcp->aqueue);
819
820 mfs_flock(nbdcp->mfsfd,LOCK_UN); // just in case
821 mfs_close(nbdcp->mfsfd);
822
823 err = unlink(nbdcp->linkname);
824 if (err<0) {
825 syslog(LOG_NOTICE,"can't remove nbd device symlink %s->%s: %s",nbdcp->linkname,nbdcp->nbddevice,strerror(errno));
826 }
827 }
828
nbd_free(nbdcommon * nbdcp)829 void nbd_free(nbdcommon *nbdcp) {
830 if (nbdcp->linkname) {
831 free(nbdcp->linkname);
832 }
833 if (nbdcp->nbddevice) {
834 free(nbdcp->nbddevice);
835 }
836 if (nbdcp->mfsfile) {
837 free(nbdcp->mfsfile);
838 }
839 free(nbdcp);
840 }
841
nbd_match(nbdcommon * nbdcp,uint32_t pleng,const uint8_t * path,uint32_t dleng,const uint8_t * device,uint32_t nleng,const uint8_t * name)842 static uint8_t nbd_match(nbdcommon *nbdcp,uint32_t pleng,const uint8_t *path,uint32_t dleng,const uint8_t *device,uint32_t nleng,const uint8_t *name) {
843 if (pleng>0 && (pleng!=strlen(nbdcp->mfsfile) || memcmp(nbdcp->mfsfile,path,pleng))) {
844 return 0;
845 } else if (dleng>0 && (dleng!=strlen(nbdcp->nbddevice) || memcmp(nbdcp->nbddevice,device,dleng))) {
846 return 0;
847 } else if (nleng>0 && (nleng!=strlen(nbdcp->linkname+NBD_LINK_PREFIX_LENG) || memcmp(nbdcp->linkname+NBD_LINK_PREFIX_LENG,name,nleng))) {
848 return 0;
849 }
850 return 1;
851 }
852
853 /* cli <-> daemon communication */
854
855 /* daemon handlers */
856
nbd_handle_nop(int sock,const uint8_t * buff,uint32_t leng)857 void nbd_handle_nop(int sock,const uint8_t *buff,uint32_t leng) {
858 uint8_t ans[8],*wptr;
859
860 (void)buff;
861 (void)leng;
862 wptr = ans;
863 put32bit(&wptr,MFSNBD_NOP);
864 put32bit(&wptr,0);
865 unixtowrite(sock,ans,8,1000); // ignore status
866 }
867
nbd_handle_stop_daemon(int sock,const uint8_t * buff,uint32_t leng)868 void nbd_handle_stop_daemon(int sock,const uint8_t *buff,uint32_t leng) {
869 uint8_t ans[9],*wptr;
870
871 (void)buff;
872 (void)leng;
873 term = 1;
874 wptr = ans;
875 put32bit(&wptr,MFSNBD_STOP);
876 put32bit(&wptr,1);
877 put8bit(&wptr,(leng==0)?MFSNBD_OK:MFSNBD_ERROR);
878 unixtowrite(sock,ans,9,1000); // ignore status
879 }
880
nbd_handle_add_device(int sock,const uint8_t * buff,uint32_t leng)881 void nbd_handle_add_device(int sock,const uint8_t *buff,uint32_t leng) {
882 const uint8_t *rptr;
883 uint8_t ans[10+NBD_ERR_SIZE],*wptr;
884 uint32_t msglen;
885 uint8_t status;
886 const uint8_t *path,*device,*name;
887 uint16_t pleng;
888 uint8_t dleng,nleng;
889 uint64_t size;
890 uint32_t flags;
891 static bdlist *bdl;
892
893 wptr = ans;
894 put32bit(&wptr,MFSNBD_ADD);
895 put32bit(&wptr,0);
896 rptr = buff;
897 if (leng<16U) {
898 unixtowrite(sock,ans,8,1000);
899 return;
900 }
901 pleng = get16bit(&rptr);
902 path = rptr;
903 rptr += pleng;
904 if (leng<16U+pleng) {
905 unixtowrite(sock,ans,8,1000);
906 return;
907 }
908 dleng = get8bit(&rptr);
909 device = rptr;
910 rptr += dleng;
911 if (leng<16U+pleng+dleng) {
912 unixtowrite(sock,ans,8,1000);
913 return;
914 }
915 nleng = get8bit(&rptr);
916 name = rptr;
917 rptr += nleng;
918 if (leng!=16U+pleng+dleng+nleng) {
919 unixtowrite(sock,ans,8,1000);
920 return;
921 }
922 size = get64bit(&rptr);
923 flags = get32bit(&rptr);
924 if (pleng==0) {
925 msglen = snprintf((char*)(ans+10),NBD_ERR_SIZE,"empty filename");
926 status = MFSNBD_ERROR;
927 } else {
928 bdl = malloc(sizeof(bdlist));
929 passert(bdl);
930 bdl->nbdcp = malloc(sizeof(nbdcommon));
931 passert(bdl->nbdcp);
932 bdl->nbdcp->mfsfile = nbd_packet_to_str(path,pleng);
933 bdl->nbdcp->nbddevice = nbd_packet_to_str(device,dleng);
934 bdl->nbdcp->linkname = nbd_packet_to_str(name,nleng);
935 bdl->nbdcp->fsize = size;
936 bdl->nbdcp->flags = flags;
937 bdl->nbdcp->linkname = linkname_generate(bdl->nbdcp->linkname,mcfg.masterhost,mcfg.masterport,bdl->nbdcp->mfsfile);
938 if (nbd_linktest(bdl->nbdcp)<0) {
939 msglen = snprintf((char*)(ans+10),NBD_ERR_SIZE,"link exists");
940 status = MFSNBD_ERROR;
941 nbd_free(bdl->nbdcp);
942 free(bdl);
943 } else {
944 if (nbd_start(bdl->nbdcp,(char*)(ans+10))<0) {
945 ans[9+NBD_ERR_SIZE]=0;
946 msglen = strlen((char*)(ans+10));
947 status = MFSNBD_ERROR;
948 nbd_free(bdl->nbdcp);
949 free(bdl);
950 } else {
951 msglen = snprintf((char*)(ans+10),NBD_ERR_SIZE,"started block device: (%s->%s : MFS:/%s : %.3lfGiB)",bdl->nbdcp->linkname,bdl->nbdcp->nbddevice,bdl->nbdcp->mfsfile,bdl->nbdcp->fsize/(1024.0*1024.0*1024.0));
952 status = MFSNBD_OK;
953 bdl->next = bdhead;
954 bdhead = bdl;
955 }
956 }
957 }
958 wptr = ans+4;
959 if (msglen>NBD_ERR_SIZE) {
960 msglen=NBD_ERR_SIZE;
961 }
962 put32bit(&wptr,msglen+2);
963 put8bit(&wptr,status);
964 put8bit(&wptr,msglen);
965 unixtowrite(sock,ans,10+msglen,1000);
966 return;
967 }
968
nbd_handle_remove_device(int sock,const uint8_t * buff,uint32_t leng)969 void nbd_handle_remove_device(int sock,const uint8_t *buff,uint32_t leng) {
970 const uint8_t *rptr;
971 uint8_t ans[10+NBD_ERR_SIZE],*wptr;
972 uint32_t msglen;
973 const uint8_t *path,*device,*name;
974 uint16_t pleng;
975 uint8_t dleng,nleng;
976 static bdlist *bdl,**bdlp;
977 uint8_t found;
978
979 wptr = ans;
980 put32bit(&wptr,MFSNBD_REMOVE);
981 put32bit(&wptr,0);
982 rptr = buff;
983 if (leng<4U) {
984 unixtowrite(sock,ans,8,1000);
985 return;
986 }
987 pleng = get16bit(&rptr);
988 path = rptr;
989 rptr += pleng;
990 if (leng<4U+pleng) {
991 unixtowrite(sock,ans,8,1000);
992 return;
993 }
994 dleng = get8bit(&rptr);
995 device = rptr;
996 rptr += dleng;
997 if (leng<4U+pleng+dleng) {
998 unixtowrite(sock,ans,8,1000);
999 return;
1000 }
1001 nleng = get8bit(&rptr);
1002 name = rptr;
1003 rptr += nleng;
1004 if (leng!=4U+pleng+dleng+nleng) {
1005 unixtowrite(sock,ans,8,1000);
1006 return;
1007 }
1008 found = 0;
1009 msglen = 0;
1010 bdlp = &bdhead;
1011 while (found==0 && (bdl=*bdlp)!=NULL) {
1012 if (nbd_match(bdl->nbdcp,pleng,path,dleng,device,nleng,name)) {
1013 msglen = snprintf((char*)(ans+10),NBD_ERR_SIZE,"stop block device: (%s->%s : MFS:/%s : %.3lfGiB)",bdl->nbdcp->linkname,bdl->nbdcp->nbddevice,bdl->nbdcp->mfsfile,bdl->nbdcp->fsize/(1024.0*1024.0*1024.0));
1014 nbd_stop(bdl->nbdcp);
1015 nbd_free(bdl->nbdcp);
1016 *bdlp = bdl->next;
1017 free(bdl);
1018 found = 1;
1019 } else {
1020 bdlp = &(bdl->next);
1021 }
1022 }
1023 if (found==0) {
1024 msglen = snprintf((char*)(ans+10),NBD_ERR_SIZE,"device not found");
1025 }
1026 wptr = ans+4;
1027 if (msglen>NBD_ERR_SIZE) {
1028 msglen=NBD_ERR_SIZE;
1029 }
1030 put32bit(&wptr,msglen+2);
1031 put8bit(&wptr,(found)?MFSNBD_OK:MFSNBD_ERROR);
1032 put8bit(&wptr,msglen);
1033 unixtowrite(sock,ans,10+msglen,1000);
1034 return;
1035 }
1036
nbd_handle_list_devices(int sock,const uint8_t * buff,uint32_t leng)1037 void nbd_handle_list_devices(int sock,const uint8_t *buff,uint32_t leng) {
1038 uint8_t dcnt;
1039 uint32_t dsize;
1040 uint32_t pleng,dleng,nleng;
1041 static bdlist *bdl;
1042 uint8_t *ans,*wptr;
1043
1044 (void)buff;
1045 if (leng!=0) {
1046 ans = malloc(8);
1047 passert(ans);
1048 wptr = ans;
1049 put32bit(&wptr,MFSNBD_LIST);
1050 put32bit(&wptr,0);
1051 unixtowrite(sock,ans,8,1000);
1052 free(ans);
1053 return;
1054 }
1055 dcnt = 0;
1056 dsize = 1;
1057 for (bdl=bdhead ; bdl!=NULL ; bdl=bdl->next) {
1058 pleng = strlen(bdl->nbdcp->mfsfile);
1059 dleng = strlen(bdl->nbdcp->nbddevice);
1060 nleng = strlen(bdl->nbdcp->linkname+NBD_LINK_PREFIX_LENG);
1061 if (pleng>65535) {
1062 pleng = 65535;
1063 }
1064 if (dleng>255) {
1065 dleng = 255;
1066 }
1067 if (nleng>255) {
1068 nleng = 255;
1069 }
1070 dsize += pleng + dleng + nleng + 16;
1071 dcnt++;
1072 }
1073 ans = malloc(8+dsize);
1074 passert(ans);
1075 wptr = ans;
1076 put32bit(&wptr,MFSNBD_LIST);
1077 put32bit(&wptr,dsize);
1078 put8bit(&wptr,dcnt);
1079 for (bdl=bdhead ; bdl!=NULL ; bdl=bdl->next) {
1080 pleng = strlen(bdl->nbdcp->mfsfile);
1081 dleng = strlen(bdl->nbdcp->nbddevice);
1082 nleng = strlen(bdl->nbdcp->linkname+NBD_LINK_PREFIX_LENG);
1083 if (pleng>65535) {
1084 pleng = 65535;
1085 }
1086 if (dleng>255) {
1087 dleng = 255;
1088 }
1089 if (nleng>255) {
1090 nleng = 255;
1091 }
1092 put16bit(&wptr,pleng);
1093 memcpy(wptr,bdl->nbdcp->mfsfile,pleng);
1094 wptr+=pleng;
1095 put8bit(&wptr,dleng);
1096 memcpy(wptr,bdl->nbdcp->nbddevice,dleng);
1097 wptr+=dleng;
1098 put8bit(&wptr,nleng);
1099 memcpy(wptr,bdl->nbdcp->linkname+NBD_LINK_PREFIX_LENG,nleng);
1100 wptr+=nleng;
1101 put64bit(&wptr,bdl->nbdcp->fsize);
1102 put32bit(&wptr,bdl->nbdcp->flags);
1103 }
1104 unixtowrite(sock,ans,8+dsize,1000);
1105 free(ans);
1106 return;
1107 }
1108
nbd_handle_resize_device(int sock,const uint8_t * buff,uint32_t leng)1109 void nbd_handle_resize_device(int sock,const uint8_t *buff,uint32_t leng) {
1110 const uint8_t *rptr;
1111 uint8_t ans[10+NBD_ERR_SIZE],*wptr;
1112 uint32_t msglen;
1113 const uint8_t *path,*device,*name;
1114 uint16_t pleng;
1115 uint8_t dleng,nleng;
1116 uint64_t size,tsize;
1117 static bdlist *bdl;
1118 uint8_t found;
1119
1120 wptr = ans;
1121 put32bit(&wptr,MFSNBD_RESIZE);
1122 put32bit(&wptr,0);
1123 rptr = buff;
1124 if (leng<12U) {
1125 unixtowrite(sock,ans,8,1000);
1126 return;
1127 }
1128 pleng = get16bit(&rptr);
1129 path = rptr;
1130 rptr += pleng;
1131 if (leng<12U+pleng) {
1132 unixtowrite(sock,ans,8,1000);
1133 return;
1134 }
1135 dleng = get8bit(&rptr);
1136 device = rptr;
1137 rptr += dleng;
1138 if (leng<12U+pleng+dleng) {
1139 unixtowrite(sock,ans,8,1000);
1140 return;
1141 }
1142 nleng = get8bit(&rptr);
1143 name = rptr;
1144 rptr += nleng;
1145 if (leng!=12U+pleng+dleng+nleng) {
1146 unixtowrite(sock,ans,8,1000);
1147 return;
1148 }
1149 size = get64bit(&rptr);
1150 found = 0;
1151 msglen = 0;
1152 for (bdl=bdhead ; found==0 && bdl!=NULL ; bdl=bdl->next) {
1153 if (nbd_match(bdl->nbdcp,pleng,path,dleng,device,nleng,name)) {
1154 if (size==0) {
1155 struct stat stbuf;
1156 if (mfs_fstat(bdl->nbdcp->mfsfd,&stbuf)<0) {
1157 msglen = snprintf((char*)(ans+10),NBD_ERR_SIZE,"can't stat MFS file '%s': %s",bdl->nbdcp->mfsfile,strerror(errno));
1158 } else {
1159 size = stbuf.st_size;
1160 }
1161 }
1162 if (size>0) {
1163 size = 4096 * (size/4096);
1164 if (size==0) {
1165 msglen = snprintf((char*)(ans+10),NBD_ERR_SIZE,"file size too low (less than one 4k block)");
1166 }
1167 }
1168 if (size>0) {
1169 if (ioctl(bdl->nbdcp->nbdfd, NBD_SET_SIZE_BLOCKS, size / 4096)<0) {
1170 msglen = snprintf((char*)(ans+10),NBD_ERR_SIZE,"error setting block device number of blocks (%s): %s",bdl->nbdcp->nbddevice,strerror(errno));
1171 } else {
1172 if (ioctl(bdl->nbdcp->nbdfd,BLKGETSIZE64,&tsize)<0) {
1173 msglen = snprintf((char*)(ans+10),NBD_ERR_SIZE,"error testing block device size (%s): %s",bdl->nbdcp->nbddevice,strerror(errno));
1174 } else {
1175 if (tsize != size) {
1176 msglen = snprintf((char*)(ans+10),NBD_ERR_SIZE,"can't resize block device - kernel 4.18+ is needed");
1177 } else {
1178 msglen = snprintf((char*)(ans+10),NBD_ERR_SIZE,"change size of block device: (%s->%s : MFS:/%s : %.3lfGiB) -> %.3lfGiB",bdl->nbdcp->linkname,bdl->nbdcp->nbddevice,bdl->nbdcp->mfsfile,bdl->nbdcp->fsize/(1024.0*1024.0*1024.0),size/(1024.0*1024.0*1024.0));
1179 bdl->nbdcp->fsize = size;
1180 }
1181 }
1182 }
1183 }
1184 found = 1;
1185 }
1186 }
1187 if (found==0) {
1188 msglen = snprintf((char*)(ans+10),NBD_ERR_SIZE,"device not found");
1189 }
1190 wptr = ans+4;
1191 if (msglen>NBD_ERR_SIZE) {
1192 msglen=NBD_ERR_SIZE;
1193 }
1194 put32bit(&wptr,msglen+2);
1195 put8bit(&wptr,(found)?MFSNBD_OK:MFSNBD_ERROR);
1196 put8bit(&wptr,msglen);
1197 unixtowrite(sock,ans,10+msglen,1000);
1198 return;
1199 }
1200
nbd_handle_request(int sock)1201 void nbd_handle_request(int sock) {
1202 uint32_t cmd,leng;
1203 uint8_t hdr[8];
1204 uint8_t *buff;
1205 const uint8_t *rptr;
1206
1207 buff = NULL;
1208 if (unixtoread(sock,hdr,8,READ_TOMS)!=8) {
1209 goto err;
1210 }
1211 rptr = hdr;
1212 cmd = get32bit(&rptr);
1213 leng = get32bit(&rptr);
1214 if (leng>100000) {
1215 goto err;
1216 }
1217 if (leng>0) {
1218 buff = malloc(leng);
1219 if (buff==NULL) {
1220 goto err;
1221 }
1222 } else {
1223 buff = NULL;
1224 }
1225 if (unixtoread(sock,buff,leng,READ_TOMS)!=(int32_t)leng) {
1226 goto err;
1227 }
1228 switch (cmd) {
1229 case MFSNBD_NOP:
1230 nbd_handle_nop(sock,buff,leng);
1231 break;
1232 case MFSNBD_STOP:
1233 nbd_handle_stop_daemon(sock,buff,leng);
1234 break;
1235 case MFSNBD_ADD:
1236 nbd_handle_add_device(sock,buff,leng);
1237 break;
1238 case MFSNBD_REMOVE:
1239 nbd_handle_remove_device(sock,buff,leng);
1240 break;
1241 case MFSNBD_LIST:
1242 nbd_handle_list_devices(sock,buff,leng);
1243 break;
1244 case MFSNBD_RESIZE:
1245 nbd_handle_resize_device(sock,buff,leng);
1246 break;
1247 }
1248 err:
1249 if (buff!=NULL) {
1250 free(buff);
1251 }
1252 return;
1253 }
1254
1255
1256 /* daemon main loop */
1257
1258
nbd_stop_all_devices(void)1259 void nbd_stop_all_devices(void) {
1260 static bdlist *bdl,**bdlp;
1261 bdlp = &bdhead;
1262 while ((bdl=*bdlp)!=NULL) {
1263 nbd_stop(bdl->nbdcp);
1264 nbd_free(bdl->nbdcp);
1265 *bdlp = bdl->next;
1266 free(bdl);
1267 }
1268 }
1269
password_read(const char * filename)1270 char* password_read(const char *filename) {
1271 FILE *fd;
1272 char passwordbuff[1024];
1273 char *ret;
1274 int i;
1275
1276 fd = fopen(filename,"r");
1277 if (fd==NULL) {
1278 fprintf(stderr,"error opening password file: %s\n",filename);
1279 return NULL;
1280 }
1281 if (fgets(passwordbuff,1024,fd)==NULL) {
1282 fprintf(stderr,"password file (%s) is empty\n",filename);
1283 fclose(fd);
1284 return NULL;
1285 }
1286 fclose(fd);
1287 passwordbuff[1023]=0;
1288 i = strlen(passwordbuff);
1289 while (i>0) {
1290 i--;
1291 if (passwordbuff[i]=='\n' || passwordbuff[i]=='\r') {
1292 passwordbuff[i]=0;
1293 } else {
1294 break;
1295 }
1296 }
1297 if (i==0) {
1298 fprintf(stderr,"first line in password file (%s) is empty\n",filename);
1299 return NULL;
1300 }
1301 ret = malloc(i+1);
1302 passert(ret);
1303 memcpy(ret,passwordbuff,i);
1304 memset(passwordbuff,0,1024);
1305 ret[i] = 0;
1306 return ret;
1307 }
1308
usage(const char * appname)1309 void usage(const char *appname) {
1310 fprintf(stderr,"usage:\n");
1311 fprintf(stderr,"\tstart daemon: %s start [ -H masterhost ] [ -P masterport ] [ -p masterpassword | -x passwordfile ] [ -l link_socket_name ]\n",appname);
1312 fprintf(stderr,"\tstop daemon: %s stop [ -l link_socket_name ]\n",appname);
1313 fprintf(stderr,"\tadd mapping: %s map [ -l link_socket_name ] -f mfsfile [ -d /dev/nbdX ] [ -n linkname ] [ -s bdevsize ]\n",appname);
1314 fprintf(stderr,"\tdelete mapping: %s unmap [ -l link_socket_name ] [ -f mfsfile ] [ -d /dev/nbdX ] [ -n linkname ]\n",appname);
1315 fprintf(stderr,"\tlist mappings: %s list [ -l link_socket_name ] [ -t m|u ]\n",appname);
1316 fprintf(stderr,"\tchange size: %s resize [ -l link_socket_name ] ( -f mfsfile | -d /dev/nbdX ) [ -s bdevsize ]\n",appname);
1317 // exit(1);
1318 }
1319
nbd_start_daemon(const char * appname,int argc,char * argv[])1320 int nbd_start_daemon(const char *appname,int argc,char *argv[]) {
1321 char *passfile;
1322 char *lsockname;
1323 int fg,ch;
1324 int lsock;
1325
1326 int argc_back;
1327 char **argv_back;
1328
1329 argc_back = argc;
1330 argv_back = argv;
1331
1332 argc--;
1333 argv++;
1334
1335 memset(&mcfg,0,sizeof(mcfg));
1336 passfile = NULL;
1337 lsockname = NULL;
1338 fg = 0;
1339 bdhead = NULL;
1340
1341 while ((ch = getopt(argc, argv, "H:P:S:p:x:l:Fh?")) != -1) {
1342 switch (ch) {
1343 case 'H':
1344 if (mcfg.masterhost!=NULL) {
1345 free(mcfg.masterhost);
1346 }
1347 mcfg.masterhost = strdup(optarg);
1348 break;
1349 case 'P':
1350 if (mcfg.masterport!=NULL) {
1351 free(mcfg.masterport);
1352 }
1353 mcfg.masterport = strdup(optarg);
1354 break;
1355 case 'S':
1356 if (mcfg.masterpath!=NULL) {
1357 free(mcfg.masterpath);
1358 }
1359 mcfg.masterpath = strdup(optarg);
1360 break;
1361 case 'p':
1362 if (mcfg.masterpassword!=NULL) {
1363 free(mcfg.masterpassword);
1364 }
1365 mcfg.masterpassword = strdup(optarg);
1366 break;
1367 case 'x':
1368 if (passfile!=NULL) {
1369 free(passfile);
1370 }
1371 passfile = strdup(optarg);
1372 break;
1373 case 'l':
1374 if (lsockname!=NULL) {
1375 free(lsockname);
1376 }
1377 lsockname = strdup(optarg);
1378 break;
1379 case 'F':
1380 fg = 1;
1381 break;
1382 case 'h':
1383 default:
1384 usage(appname);
1385 return 0;
1386 }
1387 }
1388
1389 if (passfile!=NULL) {
1390 if (mcfg.masterpassword!=NULL) {
1391 fprintf(stderr,"options '-p' and '-x' are mutually exclusive\n");
1392 return 1;
1393 }
1394 mcfg.masterpassword = password_read(passfile);
1395 if (mcfg.masterpassword==NULL) {
1396 return 1;
1397 }
1398 }
1399
1400 processname_init(argc_back,argv_back); // prepare everything for 'processname_set'
1401
1402 openlog("mfsblockdev", LOG_PID | LOG_NDELAY, LOG_USER);
1403
1404 if (mcfg.masterhost==NULL) {
1405 mcfg.masterhost = strdup("mfsmaster");
1406 }
1407 if (mcfg.masterport==NULL) {
1408 mcfg.masterport = strdup("9421");
1409 }
1410 mcfg.mountpoint = strdup("[NBD]");
1411 if (mcfg.masterpath==NULL) {
1412 mcfg.masterpath = strdup("/");
1413 }
1414 mcfg.read_cache_mb = 128;
1415 mcfg.write_cache_mb = 128;
1416 mcfg.error_on_lost_chunk = 0;
1417 mcfg.error_on_no_space = 0;
1418 mcfg.io_try_cnt = 30;
1419
1420 if (lsockname==NULL) {
1421 lsockname = strdup(NBD_LINK_PREFIX "nbdsock");
1422 mkdir(NBD_LINK_PREFIX,0777);
1423 }
1424
1425 lsock = unixsocket();
1426 if (unixlisten(lsock,lsockname,5)<0) {
1427 if (errno==EADDRINUSE) {
1428 int csock;
1429 csock = unixsocket();
1430 if (unixconnect(csock,lsockname)<0) {
1431 if (errno==ECONNREFUSED) {
1432 unlink(lsockname);
1433 }
1434 } else {
1435 unixclose(csock);
1436 }
1437 }
1438 if (unixlisten(lsock,lsockname,5)<0) {
1439 syslog(LOG_ERR,"error creating unix socket '%s': %s",lsockname,strerror(errno));
1440 fprintf(stderr,"error creating unix socket '%s': %s\n",lsockname,strerror(errno));
1441 free(lsockname);
1442 return 1;
1443 }
1444 }
1445
1446 if (mfs_init(&mcfg,1)<0) {
1447 syslog(LOG_ERR,"can't connect to master");
1448 fprintf(stderr,"can't connect to master\n");
1449 unixclose(lsock);
1450 unlink(lsockname);
1451 return 1;
1452 }
1453
1454 term = 0;
1455 if (fg==0) {
1456 make_daemon();
1457 } else {
1458 set_signals();
1459 }
1460
1461 if (mfs_init(&mcfg,2)<0) {
1462 syslog(LOG_ERR,"can't initialize MFS");
1463 fprintf(stderr,"can't initialize MFS\n");
1464 unixclose(lsock);
1465 unlink(lsockname);
1466 free(lsockname);
1467 return 1;
1468 }
1469
1470 workers_set = workers_init(150,30,0,"nbd",nbd_worker_fn);
1471
1472 if (fg==0) {
1473 int f;
1474 f = open("/dev/null", O_RDWR, 0);
1475 if (dup2(f,STDERR_FILENO)<0) {
1476 syslog(LOG_ERR,"dup2 error: %s",strerror(errno));
1477 term = 1;
1478 }
1479 close(f);
1480 }
1481
1482 if (term==0) {
1483 char pname[256];
1484 syslog(LOG_NOTICE,"main loop start");
1485 snprintf(pname,256,"mfsbdev (daemon cmdlink:%s)",lsockname);
1486 pname[255] = 0;
1487 processname_set(pname); // removes password from 'ps'
1488 }
1489
1490 while (term==0) {
1491 int csock;
1492 csock = unixtoaccept(lsock,100);
1493 if (csock>=0) {
1494 nbd_handle_request(csock);
1495 unixclose(csock);
1496 } else {
1497 if (errno!=ETIMEDOUT) {
1498 syslog(LOG_NOTICE,"accept returned: %s",strerror(errno));
1499 }
1500 }
1501 }
1502
1503 syslog(LOG_NOTICE,"got term signal - closing nbd devices");
1504
1505 nbd_stop_all_devices();
1506 massert(bdhead==NULL,"structures not cleared properly");
1507
1508 workers_term(workers_set);
1509 mfs_term();
1510
1511 unixclose(lsock);
1512 syslog(LOG_NOTICE,"removing socket file '%s'",lsockname);
1513 if (unlink(lsockname)<0) {
1514 syslog(LOG_ERR,"can't unlink socket '%s': %s",lsockname,strerror(errno));
1515 }
1516 syslog(LOG_NOTICE,"socket file '%s' removed",lsockname);
1517 free(lsockname);
1518
1519 return 0;
1520 }
1521
1522
1523 /* cli dispatchers */
1524
1525
nbd_stop_daemon(const char * appname,int argc,char * argv[])1526 int nbd_stop_daemon(const char *appname,int argc,char *argv[]) {
1527 uint8_t buff[8];
1528 uint8_t *wptr;
1529 const uint8_t *rptr;
1530 char *lsockname;
1531 int ch;
1532 int csock;
1533 uint32_t cmd,leng;
1534 int res;
1535 int cnt;
1536 struct stat st;
1537
1538 csock = -1;
1539 lsockname = NULL;
1540 res = 1;
1541
1542 while ((ch = getopt(argc, argv, "l:?")) != -1) {
1543 switch (ch) {
1544 case 'l':
1545 if (lsockname!=NULL) {
1546 free(lsockname);
1547 }
1548 lsockname = strdup(optarg);
1549 break;
1550 case 'h':
1551 default:
1552 usage(appname);
1553 return 0;
1554 }
1555 }
1556
1557 if (lsockname==NULL) {
1558 lsockname = strdup(NBD_LINK_PREFIX "nbdsock");
1559 }
1560
1561 csock = unixsocket();
1562 if (unixtoconnect(csock,lsockname,1000)<0) {
1563 fprintf(stderr,"can't connect to socket '%s': %s\n",lsockname,strerror(errno));
1564 goto err;
1565 }
1566
1567 wptr = buff;
1568 put32bit(&wptr,MFSNBD_STOP);
1569 put32bit(&wptr,0);
1570 if (unixtowrite(csock,buff,8,1000)!=8) {
1571 fprintf(stderr,"unable to send data to '%s': %s\n",lsockname,strerror(errno));
1572 goto err;
1573 }
1574
1575 memset(buff,0,8);
1576
1577 if (unixtoread(csock,buff,8,5000)!=8) {
1578 fprintf(stderr,"error receiving data from '%s': %s\n",lsockname,strerror(errno));
1579 goto err;
1580 }
1581
1582 rptr = buff;
1583 cmd = get32bit(&rptr);
1584 leng = get32bit(&rptr);
1585
1586 if (cmd!=MFSNBD_STOP) {
1587 fprintf(stderr,"got wrong answer from '%s': Bad Command\n",lsockname);
1588 goto err;
1589 }
1590
1591 if (leng!=1) {
1592 fprintf(stderr,"got wrong answer from '%s': Wrong Size\n",lsockname);
1593 goto err;
1594 }
1595
1596 if (unixtoread(csock,buff,1,1000)!=1) {
1597 fprintf(stderr,"error receiving data from '%s': %s\n",lsockname,strerror(errno));
1598 goto err;
1599 }
1600 unixclose(csock);
1601 csock = -1;
1602
1603 if (buff[0]!=MFSNBD_OK) {
1604 fprintf(stderr,"error stopping daemon on '%s'\n",lsockname);
1605 goto err;
1606 }
1607
1608 printf("daemon received STOP command\n");
1609 printf("waiting for daemon ...");
1610 fflush(stdout);
1611 cnt=0;
1612 while (stat(lsockname,&st)==0) {
1613 usleep(10000);
1614 cnt++;
1615 if ((cnt%100)==0) {
1616 printf(".");
1617 fflush(stdout);
1618 }
1619 if (cnt>1000) {
1620 printf(" giving up\n");
1621 goto err;
1622 }
1623 }
1624 printf(" ok\n");
1625
1626 res = 0;
1627 err:
1628 if (csock>=0) {
1629 unixclose(csock);
1630 }
1631 if (lsockname!=NULL) {
1632 free(lsockname);
1633 }
1634 return res;
1635 }
1636
nbd_add_mapping(const char * appname,int argc,char * argv[])1637 int nbd_add_mapping(const char *appname,int argc,char *argv[]) {
1638 uint8_t *buff;
1639 uint8_t *wptr;
1640 const uint8_t *rptr;
1641 char *filename,*device,*linkname;
1642 uint64_t size;
1643 uint32_t flags;
1644 uint32_t dsize,pleng,dleng,nleng;
1645 uint8_t aleng,status;
1646 char *answer;
1647 char *lsockname;
1648 int ch;
1649 int csock;
1650 int res;
1651 uint32_t cmd,leng;
1652
1653 csock = -1;
1654 buff = NULL;
1655 lsockname = NULL;
1656 filename = NULL;
1657 device = NULL;
1658 linkname = NULL;
1659 answer = NULL;
1660 size = 0;
1661 flags = 0;
1662 res = 1;
1663
1664 while ((ch = getopt(argc, argv, "l:f:d:n:s:r?")) != -1) {
1665 switch (ch) {
1666 case 'l':
1667 if (lsockname!=NULL) {
1668 free(lsockname);
1669 }
1670 lsockname = strdup(optarg);
1671 break;
1672 case 'f':
1673 if (filename!=NULL) {
1674 free(filename);
1675 }
1676 filename = strdup(optarg);
1677 break;
1678 case 'd':
1679 if (device!=NULL) {
1680 free(device);
1681 }
1682 device = strdup(optarg);
1683 break;
1684 case 'n':
1685 if (linkname!=NULL) {
1686 free(linkname);
1687 }
1688 if (strlen(optarg)>NBD_LINK_PREFIX_LENG && memcmp(optarg,NBD_LINK_PREFIX,NBD_LINK_PREFIX_LENG)==0) {
1689 linkname = strdup(optarg+NBD_LINK_PREFIX_LENG);
1690 } else {
1691 linkname = strdup(optarg);
1692 }
1693 break;
1694 case 's':
1695 size = sizestrtod(optarg,NULL);
1696 break;
1697 case 'r':
1698 flags |= FLAG_READONLY;
1699 break;
1700 case 'h':
1701 default:
1702 usage(appname);
1703 return 0;
1704 }
1705 }
1706
1707 if (filename==NULL) {
1708 fprintf(stderr,"MFS file name (option -f) not specified\n");
1709 goto err;
1710 }
1711 if (lsockname==NULL) {
1712 lsockname = strdup(NBD_LINK_PREFIX "nbdsock");
1713 }
1714
1715 csock = unixsocket();
1716 if (unixtoconnect(csock,lsockname,1000)<0) {
1717 fprintf(stderr,"can't connect to socket '%s': %s\n",lsockname,strerror(errno));
1718 goto err;
1719 }
1720
1721 pleng = strlen(filename);
1722 if (pleng>65535) {
1723 fprintf(stderr,"MFS file name too long\n");
1724 goto err;
1725 }
1726 if (device!=NULL) {
1727 dleng = strlen(device);
1728 if (dleng>255) {
1729 fprintf(stderr,"device name too long\n");
1730 goto err;
1731 }
1732 } else {
1733 dleng = 0;
1734 }
1735 if (linkname!=NULL) {
1736 nleng = strlen(linkname);
1737 if (nleng>255) {
1738 fprintf(stderr,"link name too long\n");
1739 goto err;
1740 }
1741 } else {
1742 nleng = 0;
1743 }
1744 dsize = 16 + pleng + dleng + nleng;
1745
1746 buff = malloc(8+dsize);
1747 passert(buff);
1748 wptr = buff;
1749 put32bit(&wptr,MFSNBD_ADD);
1750 put32bit(&wptr,dsize);
1751
1752 put16bit(&wptr,pleng);
1753 memcpy(wptr,filename,pleng);
1754 wptr+=pleng;
1755 put8bit(&wptr,dleng);
1756 if (dleng>0) {
1757 memcpy(wptr,device,dleng);
1758 wptr+=dleng;
1759 }
1760 put8bit(&wptr,nleng);
1761 if (nleng>0) {
1762 memcpy(wptr,linkname,nleng);
1763 wptr+=nleng;
1764 }
1765 put64bit(&wptr,size);
1766 put32bit(&wptr,flags);
1767
1768 if (unixtowrite(csock,buff,8+dsize,1000)!=(ssize_t)(8+dsize)) {
1769 fprintf(stderr,"unable to send data to '%s': %s\n",lsockname,strerror(errno));
1770 goto err;
1771 }
1772
1773 memset(buff,0,8);
1774
1775 if (unixtoread(csock,buff,8,5000)!=8) {
1776 fprintf(stderr,"error receiving data from '%s': %s\n",lsockname,strerror(errno));
1777 goto err;
1778 }
1779
1780 rptr = buff;
1781 cmd = get32bit(&rptr);
1782 leng = get32bit(&rptr);
1783
1784 if (cmd!=MFSNBD_ADD) {
1785 fprintf(stderr,"got wrong answer from '%s': Bad Command\n",lsockname);
1786 goto err;
1787 }
1788
1789 if (leng<2 || leng>2+NBD_ERR_SIZE) {
1790 fprintf(stderr,"got wrong answer from '%s': Wrong Size\n",lsockname);
1791 goto err;
1792 }
1793
1794 free(buff);
1795 buff = malloc(leng);
1796 passert(buff);
1797
1798 if (unixtoread(csock,buff,leng,1000)!=(ssize_t)leng) {
1799 fprintf(stderr,"error receiving data from '%s': %s\n",lsockname,strerror(errno));
1800 goto err;
1801 }
1802 unixclose(csock);
1803 csock = -1;
1804
1805 rptr = buff;
1806 status = get8bit(&rptr);
1807 aleng = get8bit(&rptr);
1808 answer = nbd_packet_to_str(rptr,aleng);
1809
1810 if (answer!=NULL) {
1811 if (status==MFSNBD_OK) {
1812 printf("%s\n",answer);
1813 } else {
1814 fprintf(stderr,"%s\n",answer);
1815 goto err;
1816 }
1817 }
1818
1819 res = 0;
1820 err:
1821 if (csock>=0) {
1822 unixclose(csock);
1823 }
1824 if (lsockname!=NULL) {
1825 free(lsockname);
1826 }
1827 if (filename!=NULL) {
1828 free(filename);
1829 }
1830 if (device!=NULL) {
1831 free(device);
1832 }
1833 if (linkname!=NULL) {
1834 free(linkname);
1835 }
1836 if (answer!=NULL) {
1837 free(answer);
1838 }
1839 if (buff!=NULL) {
1840 free(buff);
1841 }
1842 return res;
1843 }
1844
nbd_remove_mapping(const char * appname,int argc,char * argv[])1845 int nbd_remove_mapping(const char *appname,int argc,char *argv[]) {
1846 uint8_t *buff;
1847 uint8_t *wptr;
1848 const uint8_t *rptr;
1849 char *filename,*device,*linkname;
1850 uint32_t dsize,pleng,dleng,nleng;
1851 uint8_t aleng,status;
1852 char *answer;
1853 char *lsockname;
1854 int ch;
1855 int csock;
1856 int res;
1857 uint32_t cmd,leng;
1858
1859 csock = -1;
1860 buff = NULL;
1861 lsockname = NULL;
1862 filename = NULL;
1863 device = NULL;
1864 linkname = NULL;
1865 answer = NULL;
1866 res = 1;
1867
1868 while ((ch = getopt(argc, argv, "l:f:d:n:?")) != -1) {
1869 switch (ch) {
1870 case 'l':
1871 if (lsockname!=NULL) {
1872 free(lsockname);
1873 }
1874 lsockname = strdup(optarg);
1875 break;
1876 case 'f':
1877 if (filename!=NULL) {
1878 free(filename);
1879 }
1880 filename = strdup(optarg);
1881 break;
1882 case 'd':
1883 if (device!=NULL) {
1884 free(device);
1885 }
1886 device = strdup(optarg);
1887 break;
1888 case 'n':
1889 if (linkname!=NULL) {
1890 free(linkname);
1891 }
1892 if (strlen(optarg)>NBD_LINK_PREFIX_LENG && memcmp(optarg,NBD_LINK_PREFIX,NBD_LINK_PREFIX_LENG)==0) {
1893 linkname = strdup(optarg+NBD_LINK_PREFIX_LENG);
1894 } else {
1895 linkname = strdup(optarg);
1896 }
1897 break;
1898 case 'h':
1899 default:
1900 usage(appname);
1901 return 0;
1902 }
1903 }
1904
1905 if (filename==NULL && device==NULL && linkname==NULL) {
1906 fprintf(stderr,"device not specified\n");
1907 goto err;
1908 }
1909 if (lsockname==NULL) {
1910 lsockname = strdup(NBD_LINK_PREFIX "nbdsock");
1911 }
1912
1913 csock = unixsocket();
1914 if (unixtoconnect(csock,lsockname,1000)<0) {
1915 fprintf(stderr,"can't connect to socket '%s': %s\n",lsockname,strerror(errno));
1916 goto err;
1917 }
1918
1919 if (filename!=NULL) {
1920 pleng = strlen(filename);
1921 if (pleng>65535) {
1922 fprintf(stderr,"MFS file name too long\n");
1923 goto err;
1924 }
1925 } else {
1926 pleng = 0;
1927 }
1928 if (device!=NULL) {
1929 dleng = strlen(device);
1930 if (dleng>255) {
1931 fprintf(stderr,"device name too long\n");
1932 goto err;
1933 }
1934 } else {
1935 dleng = 0;
1936 }
1937 if (linkname!=NULL) {
1938 nleng = strlen(linkname);
1939 if (nleng>255) {
1940 fprintf(stderr,"link name too long\n");
1941 goto err;
1942 }
1943 } else {
1944 nleng = 0;
1945 }
1946 dsize = 4 + pleng + dleng + nleng;
1947
1948 buff = malloc(8+dsize);
1949 passert(buff);
1950 wptr = buff;
1951 put32bit(&wptr,MFSNBD_REMOVE);
1952 put32bit(&wptr,dsize);
1953
1954 put16bit(&wptr,pleng);
1955 if (pleng>0) {
1956 memcpy(wptr,filename,pleng);
1957 wptr+=pleng;
1958 }
1959 put8bit(&wptr,dleng);
1960 if (dleng>0) {
1961 memcpy(wptr,device,dleng);
1962 wptr+=dleng;
1963 }
1964 put8bit(&wptr,nleng);
1965 if (nleng>0) {
1966 memcpy(wptr,linkname,nleng);
1967 wptr+=nleng;
1968 }
1969
1970 if (unixtowrite(csock,buff,8+dsize,1000)!=(ssize_t)(8+dsize)) {
1971 fprintf(stderr,"unable to send data to '%s': %s\n",lsockname,strerror(errno));
1972 goto err;
1973 }
1974
1975 memset(buff,0,8);
1976
1977 if (unixtoread(csock,buff,8,5000)!=8) {
1978 fprintf(stderr,"error receiving data from '%s': %s\n",lsockname,strerror(errno));
1979 goto err;
1980 }
1981
1982 rptr = buff;
1983 cmd = get32bit(&rptr);
1984 leng = get32bit(&rptr);
1985
1986 if (cmd!=MFSNBD_REMOVE) {
1987 fprintf(stderr,"got wrong answer from '%s': Bad Command\n",lsockname);
1988 goto err;
1989 }
1990
1991 if (leng<2 || leng>2+NBD_ERR_SIZE) {
1992 fprintf(stderr,"got wrong answer from '%s': Wrong Size\n",lsockname);
1993 goto err;
1994 }
1995
1996 free(buff);
1997 buff = malloc(leng);
1998 passert(buff);
1999
2000 if (unixtoread(csock,buff,leng,1000)!=(ssize_t)leng) {
2001 fprintf(stderr,"error receiving data from '%s': %s\n",lsockname,strerror(errno));
2002 goto err;
2003 }
2004 unixclose(csock);
2005 csock = -1;
2006
2007 rptr = buff;
2008 status = get8bit(&rptr);
2009 aleng = get8bit(&rptr);
2010 answer = nbd_packet_to_str(rptr,aleng);
2011
2012 if (answer!=NULL) {
2013 if (status==MFSNBD_OK) {
2014 printf("%s\n",answer);
2015 } else {
2016 fprintf(stderr,"%s\n",answer);
2017 goto err;
2018 }
2019 }
2020
2021 res = 0;
2022 err:
2023 if (csock>=0) {
2024 unixclose(csock);
2025 }
2026 if (lsockname!=NULL) {
2027 free(lsockname);
2028 }
2029 if (filename!=NULL) {
2030 free(filename);
2031 }
2032 if (device!=NULL) {
2033 free(device);
2034 }
2035 if (linkname!=NULL) {
2036 free(linkname);
2037 }
2038 if (answer!=NULL) {
2039 free(answer);
2040 }
2041 if (buff!=NULL) {
2042 free(buff);
2043 }
2044 return res;
2045 }
2046
nbd_resize_bdev(const char * appname,int argc,char * argv[])2047 int nbd_resize_bdev(const char *appname,int argc,char *argv[]) {
2048 uint8_t *buff;
2049 uint8_t *wptr;
2050 const uint8_t *rptr;
2051 char *filename,*device,*linkname;
2052 uint64_t size;
2053 uint32_t dsize,pleng,dleng,nleng;
2054 uint8_t aleng,status;
2055 char *answer;
2056 char *lsockname;
2057 int ch;
2058 int csock;
2059 int res;
2060 uint32_t cmd,leng;
2061
2062 csock = -1;
2063 buff = NULL;
2064 lsockname = NULL;
2065 filename = NULL;
2066 device = NULL;
2067 linkname = NULL;
2068 answer = NULL;
2069 size = 0;
2070 res = 1;
2071
2072 while ((ch = getopt(argc, argv, "l:f:d:n:s:?")) != -1) {
2073 switch (ch) {
2074 case 'l':
2075 if (lsockname!=NULL) {
2076 free(lsockname);
2077 }
2078 lsockname = strdup(optarg);
2079 break;
2080 case 'f':
2081 if (filename!=NULL) {
2082 free(filename);
2083 }
2084 filename = strdup(optarg);
2085 break;
2086 case 'd':
2087 if (device!=NULL) {
2088 free(device);
2089 }
2090 device = strdup(optarg);
2091 break;
2092 case 'n':
2093 if (linkname!=NULL) {
2094 free(linkname);
2095 }
2096 if (strlen(optarg)>NBD_LINK_PREFIX_LENG && memcmp(optarg,NBD_LINK_PREFIX,NBD_LINK_PREFIX_LENG)==0) {
2097 linkname = strdup(optarg+NBD_LINK_PREFIX_LENG);
2098 } else {
2099 linkname = strdup(optarg);
2100 }
2101 break;
2102 case 's':
2103 size = sizestrtod(optarg,NULL);
2104 break;
2105 case 'h':
2106 default:
2107 usage(appname);
2108 return 0;
2109 }
2110 }
2111
2112 if (filename==NULL && device==NULL && linkname==NULL) {
2113 fprintf(stderr,"device not specified\n");
2114 goto err;
2115 }
2116 if (lsockname==NULL) {
2117 lsockname = strdup(NBD_LINK_PREFIX "nbdsock");
2118 }
2119
2120 csock = unixsocket();
2121 if (unixtoconnect(csock,lsockname,1000)<0) {
2122 fprintf(stderr,"can't connect to socket '%s': %s\n",lsockname,strerror(errno));
2123 goto err;
2124 }
2125
2126 if (filename!=NULL) {
2127 pleng = strlen(filename);
2128 if (pleng>65535) {
2129 fprintf(stderr,"MFS file name too long\n");
2130 goto err;
2131 }
2132 } else {
2133 pleng = 0;
2134 }
2135 if (device!=NULL) {
2136 dleng = strlen(device);
2137 if (dleng>255) {
2138 fprintf(stderr,"device name too long\n");
2139 goto err;
2140 }
2141 } else {
2142 dleng = 0;
2143 }
2144 if (linkname!=NULL) {
2145 nleng = strlen(linkname);
2146 if (nleng>255) {
2147 fprintf(stderr,"link name too long\n");
2148 goto err;
2149 }
2150 } else {
2151 nleng = 0;
2152 }
2153 dsize = 12 + pleng + dleng + nleng;
2154
2155 buff = malloc(8+dsize);
2156 passert(buff);
2157 wptr = buff;
2158 put32bit(&wptr,MFSNBD_RESIZE);
2159 put32bit(&wptr,dsize);
2160
2161 put16bit(&wptr,pleng);
2162 if (pleng>0) {
2163 memcpy(wptr,filename,pleng);
2164 wptr+=pleng;
2165 }
2166 put8bit(&wptr,dleng);
2167 if (dleng>0) {
2168 memcpy(wptr,device,dleng);
2169 wptr+=dleng;
2170 }
2171 put8bit(&wptr,nleng);
2172 if (nleng>0) {
2173 memcpy(wptr,linkname,nleng);
2174 wptr+=nleng;
2175 }
2176 put64bit(&wptr,size);
2177
2178 if (unixtowrite(csock,buff,8+dsize,1000)!=(ssize_t)(8+dsize)) {
2179 fprintf(stderr,"unable to send data to '%s': %s\n",lsockname,strerror(errno));
2180 goto err;
2181 }
2182
2183 memset(buff,0,8);
2184
2185 if (unixtoread(csock,buff,8,5000)!=8) {
2186 fprintf(stderr,"error receiving data from '%s': %s\n",lsockname,strerror(errno));
2187 goto err;
2188 }
2189
2190 rptr = buff;
2191 cmd = get32bit(&rptr);
2192 leng = get32bit(&rptr);
2193
2194 if (cmd!=MFSNBD_RESIZE) {
2195 fprintf(stderr,"got wrong answer from '%s': Bad Command\n",lsockname);
2196 goto err;
2197 }
2198
2199 if (leng<2 || leng>2+NBD_ERR_SIZE) {
2200 fprintf(stderr,"got wrong answer from '%s': Wrong Size\n",lsockname);
2201 goto err;
2202 }
2203
2204 free(buff);
2205 buff = malloc(leng);
2206 passert(buff);
2207
2208 if (unixtoread(csock,buff,leng,1000)!=(ssize_t)leng) {
2209 fprintf(stderr,"error receiving data from '%s': %s\n",lsockname,strerror(errno));
2210 goto err;
2211 }
2212 unixclose(csock);
2213 csock = -1;
2214
2215 rptr = buff;
2216 status = get8bit(&rptr);
2217 aleng = get8bit(&rptr);
2218 answer = nbd_packet_to_str(rptr,aleng);
2219
2220 if (answer!=NULL) {
2221 if (status==MFSNBD_OK) {
2222 printf("%s\n",answer);
2223 } else {
2224 fprintf(stderr,"%s\n",answer);
2225 goto err;
2226 }
2227 }
2228
2229 res = 0;
2230 err:
2231 if (csock>=0) {
2232 unixclose(csock);
2233 }
2234 if (lsockname!=NULL) {
2235 free(lsockname);
2236 }
2237 if (filename!=NULL) {
2238 free(filename);
2239 }
2240 if (device!=NULL) {
2241 free(device);
2242 }
2243 if (linkname!=NULL) {
2244 free(linkname);
2245 }
2246 if (answer!=NULL) {
2247 free(answer);
2248 }
2249 if (buff!=NULL) {
2250 free(buff);
2251 }
2252 return res;
2253 }
2254
nbd_list_mappings(const char * appname,int argc,char * argv[])2255 int nbd_list_mappings(const char *appname,int argc,char *argv[]) {
2256 uint8_t cbuff[8],*buff;
2257 uint8_t *wptr;
2258 const uint8_t *rptr;
2259 uint8_t dcnt;
2260 uint16_t pleng;
2261 uint8_t dleng,nleng;
2262 uint64_t size;
2263 uint32_t flags;
2264 uint8_t displaymode;
2265 char *path,*device,*linkname;
2266 char *lsockname;
2267 uint8_t lsockcustom;
2268 int ch;
2269 int csock;
2270 uint32_t cmd,leng;
2271 int res;
2272
2273 csock = -1;
2274 lsockname = NULL;
2275 lsockcustom = 0;
2276 displaymode = 0;
2277 buff = NULL;
2278 res = 1;
2279
2280 while ((ch = getopt(argc, argv, "l:t:?")) != -1) {
2281 switch (ch) {
2282 case 'l':
2283 if (lsockname!=NULL) {
2284 free(lsockname);
2285 }
2286 lsockname = strdup(optarg);
2287 lsockcustom = 1;
2288 break;
2289 case 't':
2290 if (optarg[0]=='A' || optarg[0]=='a' || optarg[0]=='M' || optarg[0]=='m') {
2291 displaymode = 1;
2292 } else if (optarg[0]=='R' || optarg[0]=='r' || optarg[0]=='D' || optarg[0]=='d' || optarg[0]=='U' || optarg[0]=='u') {
2293 displaymode = 2;
2294 } else {
2295 fprintf(stderr,"unknown display mode: %s\n",optarg);
2296 usage(appname);
2297 return 0;
2298 }
2299 break;
2300 case 'h':
2301 default:
2302 usage(appname);
2303 return 0;
2304 }
2305 }
2306
2307 if (lsockname==NULL) {
2308 lsockname = strdup(NBD_LINK_PREFIX "nbdsock");
2309 }
2310
2311 csock = unixsocket();
2312 if (unixtoconnect(csock,lsockname,1000)<0) {
2313 fprintf(stderr,"can't connect to socket '%s': %s\n",lsockname,strerror(errno));
2314 goto err;
2315 }
2316
2317 wptr = cbuff;
2318 put32bit(&wptr,MFSNBD_LIST);
2319 put32bit(&wptr,0);
2320 if (unixtowrite(csock,cbuff,8,1000)!=8) {
2321 fprintf(stderr,"unable to send data to '%s': %s\n",lsockname,strerror(errno));
2322 goto err;
2323 }
2324
2325 memset(cbuff,0,8);
2326
2327 if (unixtoread(csock,cbuff,8,5000)!=8) {
2328 fprintf(stderr,"error receiving data from '%s': %s\n",lsockname,strerror(errno));
2329 goto err;
2330 }
2331
2332 rptr = cbuff;
2333 cmd = get32bit(&rptr);
2334 leng = get32bit(&rptr);
2335
2336 if (cmd!=MFSNBD_LIST) {
2337 fprintf(stderr,"got wrong answer from '%s': Bad Command\n",lsockname);
2338 goto err;
2339 }
2340
2341 buff = malloc(leng);
2342 passert(buff);
2343
2344 if (unixtoread(csock,buff,leng,1000)!=(ssize_t)leng) {
2345 fprintf(stderr,"error receiving data from '%s': %s\n",lsockname,strerror(errno));
2346 goto err;
2347 }
2348
2349 unixclose(csock);
2350 csock = -1;
2351
2352 rptr = buff;
2353 dcnt = get8bit(&rptr);
2354 while (dcnt>0) {
2355 pleng = get16bit(&rptr);
2356 path = nbd_packet_to_str(rptr,pleng);
2357 rptr += pleng;
2358 dleng = get8bit(&rptr);
2359 device = nbd_packet_to_str(rptr,dleng);
2360 rptr += dleng;
2361 nleng = get8bit(&rptr);
2362 linkname = nbd_packet_to_str(rptr,nleng);
2363 rptr += nleng;
2364 size = get64bit(&rptr);
2365 flags = get32bit(&rptr);
2366 if (displaymode!=0) {
2367 if (displaymode==1) {
2368 printf("%s map",appname);
2369 } else {
2370 printf("%s unmap",appname);
2371 }
2372 if (lsockcustom) {
2373 printf(" -l '%s'",lsockname);
2374 }
2375 if (path!=NULL) {
2376 printf(" -f '%s'",path);
2377 }
2378 if (device!=NULL) {
2379 printf(" -d '%s'",device);
2380 }
2381 if (linkname!=NULL) {
2382 printf(" -n '%s'",linkname);
2383 }
2384 if (displaymode==1) {
2385 printf(" -s %"PRIu64,size);
2386 if (flags & FLAG_READONLY) {
2387 printf(" -r");
2388 }
2389 }
2390 printf("\n");
2391 } else {
2392 printf("file: %s ; device: %s ; link: %s ; size: %"PRIu64" (%.3lfGiB) ; rwmode: %s\n",(path==NULL)?"":path,(device==NULL)?"":device,(linkname==NULL)?"":linkname,size,size/(1024.0*1024.0*1024.0),(flags & FLAG_READONLY)?"ro":"rw");
2393 }
2394 if (path!=NULL) {
2395 free(path);
2396 }
2397 if (device!=NULL) {
2398 free(device);
2399 }
2400 if (linkname!=NULL) {
2401 free(linkname);
2402 }
2403 dcnt--;
2404 }
2405
2406 res = 0;
2407 err:
2408 if (csock>=0) {
2409 unixclose(csock);
2410 }
2411 if (lsockname!=NULL) {
2412 free(lsockname);
2413 }
2414 if (buff!=NULL) {
2415 free(buff);
2416 }
2417 return res;
2418 }
2419
main(int argc,char * argv[])2420 int main(int argc,char *argv[]) {
2421 char *appname;
2422 int res;
2423
2424 appname = strdup(argv[0]);
2425
2426 strerr_init();
2427
2428 if (argc<2) {
2429 usage(appname);
2430 res = 1;
2431 } else if (strcmp(argv[1],"start")==0) {
2432 res = nbd_start_daemon(appname,argc,argv);
2433 } else if (strcmp(argv[1],"stop")==0) {
2434 res = nbd_stop_daemon(appname,argc-1,argv+1);
2435 } else if (strcmp(argv[1],"map")==0 || strcmp(argv[1],"add")==0) {
2436 res = nbd_add_mapping(appname,argc-1,argv+1);
2437 } else if (strcmp(argv[1],"unmap")==0 || strcmp(argv[1],"remove")==0 || strcmp(argv[1],"delete")==0 || strcmp(argv[1],"del")==0 || strcmp(argv[1],"rm")==0) {
2438 res = nbd_remove_mapping(appname,argc-1,argv+1);
2439 } else if (strcmp(argv[1],"resize")==0) {
2440 res = nbd_resize_bdev(appname,argc-1,argv+1);
2441 } else if (strcmp(argv[1],"list")==0) {
2442 res = nbd_list_mappings(appname,argc-1,argv+1);
2443 } else {
2444 usage(appname);
2445 res = 1;
2446 }
2447 free(appname);
2448 return res;
2449 }
2450