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