2 (c) Marc Welz 2000, released under GPL, tested under Linux 2.2.17
4 Most of the stuff cribbed from the nbd package written by Pavel Machek
6 Unfortunately quite slow since zlib has to decompress all the stuff between
7 seeks, so only suited to smaller files
9 Could be a neat way to do userland encryption/steganography if you have
10 a crypto library which has a stdiolike interface to replace zlib
14 dd if=/dev/zero of=/tmp/image bs=1024 count=1024
16 mount -o loop /tmp/image /mnt/
21 gznbd /dev/nbd0 /tmp/image.gz
23 gznbd does not background, from another terminal type
25 mount -o ro,nocheck /dev/nbd0 /mnt/
30 ro is important, since writes will fail horribly and nochecks
31 speeds the mount up nicely
45 #include <sys/ioctl.h>
46 #include <sys/types.h>
47 #include <sys/socket.h>
49 #include <netinet/in.h>
51 /* asm/types defines __u??, at least on my system */
52 #include <asm/types.h>
54 #define MY_NAME "gznbd"
56 /* these headers take care of endianness */
57 #include "../config.h"
58 #include "../cliserv.h"
62 /* don't ask me why this value, I only copied it */
63 #define CHUNK BLOCK*20
66 int main(int argc
, char **argv
)
75 struct nbd_request request
;
76 struct nbd_reply reply
;
83 printf("Usage: %s nbdevice gzfile [size]\n",argv
[0]);
87 gz
=gzopen(argv
[2], "rb");
89 fprintf(stderr
,"%s: unable open compressed file %s\n",argv
[0],argv
[2]);
95 if((size
==0)||(size
%BLOCK
)){
96 fprintf(stderr
,"%s: %s does not appear to be a valid size\n",argv
[0],argv
[3]);
99 printf("%s: file=%s, size=%"PRId64
"\n",argv
[0],argv
[2],size
);
105 printf("%s: file=%s, seeking, ",argv
[0],argv
[2]);
108 /* expensive seek to get file size */
109 while(BLOCK
==(result
=gzread(gz
,buffer
,BLOCK
))){
114 printf("size=%"PRId64
"\n",size
);
118 fprintf(stderr
,"%s: read failed: %s\n",argv
[0],gzerror(gz
,&gzerr
));
120 fprintf(stderr
,"%s: incomplete last read, file has to be a multiple of %d\n",argv
[0],BLOCK
);
126 fprintf(stderr
,"%s: unable to rewind gzfile\n",argv
[0]);
132 if(socketpair(AF_UNIX
, SOCK_STREAM
, 0, pr
)){
133 fprintf(stderr
,"%s: unable to create socketpair: %s\n",argv
[0],strerror(errno
));
139 fprintf(stderr
,"%s: unable to fork: %s\n",argv
[0],strerror(errno
));
149 nbd
=open(argv
[1], O_RDWR
);
151 fprintf(stderr
,"%s: unable to open %s: %s\n",argv
[0],argv
[1],strerror(errno
));
155 if(ioctl(nbd
,NBD_SET_SIZE
,size
)<0){
156 fprintf(stderr
,"%s: failed to set size for %s: %s\n",argv
[0],argv
[1],strerror(errno
));
160 ioctl(nbd
, NBD_CLEAR_SOCK
);
162 if(ioctl(nbd
,NBD_SET_SOCK
,sk
)<0){
163 fprintf(stderr
,"%s: failed to set socket for %s: %s\n",argv
[0],argv
[1],strerror(errno
));
167 if(ioctl(nbd
,NBD_DO_IT
)<0){
168 fprintf(stderr
,"%s: block device %s terminated: %s\n",argv
[0],argv
[1],strerror(errno
));
171 ioctl(nbd
, NBD_CLEAR_QUE
);
172 ioctl(nbd
, NBD_CLEAR_SOCK
);
179 /* only parent here, child always exits */
184 reply
.magic
=htonl(NBD_REPLY_MAGIC
);
185 reply
.error
=htonl(0);
189 if(read(sk
,&request
,sizeof(request
))!=sizeof(request
)){
190 fprintf(stderr
,"%s: incomplete request\n",argv
[0]);
193 memcpy(reply
.handle
,request
.handle
,sizeof(reply
.handle
));
195 len
=ntohl(request
.len
);
196 from
=ntohll(request
.from
);
199 fprintf(stderr
,"%s: len=%d, from=%"PRId64
"\n",argv
[0],len
,from
);
202 if(request
.magic
!=htonl(NBD_REQUEST_MAGIC
)){
203 fprintf(stderr
,"%s: bad magic\n",argv
[0]);
204 reply
.error
=htonl(EIO
); /* is that the right way of doing things ? */
207 if(ntohl(request
.type
)){
208 fprintf(stderr
,"%s: unsupported write request\n",argv
[0]);
209 reply
.error
=htonl(EROFS
);
212 if(len
+sizeof(struct nbd_reply
)>CHUNK
){
213 fprintf(stderr
,"%s: request too long\n",argv
[0]);
214 reply
.error
=htonl(EIO
);
218 fprintf(stderr
,"%s: request outside range\n",argv
[0]);
219 reply
.error
=htonl(EIO
);
222 if(reply
.error
==htonl(0)){
224 if(gzread(gz
,chunk
+sizeof(struct nbd_reply
),len
)!=len
){
225 fprintf(stderr
,"%s: unable to read\n",argv
[0]);
226 reply
.error
=htonl(EIO
);
233 memcpy(chunk
,&reply
,sizeof(struct nbd_reply
));
234 if(write(sk
,chunk
,len
+sizeof(struct nbd_reply
))!=(len
+sizeof(struct nbd_reply
))){
235 fprintf(stderr
,"%s: write failed: %s\n",argv
[0],strerror(errno
));