From da5e07c057abbee8cc4d2beef03952c7a44fd9eb Mon Sep 17 00:00:00 2001 From: Wouter Verhelst Date: Tue, 6 Aug 2024 19:01:02 +0200 Subject: [PATCH] Reimplement daemonize() without using daemon() The daemon() helper function is widely implemented, but is not really standardized and is actually somewhat buggy on some platforms. Implementing the desired functionality is also not all that complicated. So, do it ourselves. Closes: gh-161 --- gznbd/.gitignore | 1 - gznbd/Makefile.am | 6 -- gznbd/gznbd.c | 242 ---------------------------------------------- nbd-server.c | 45 ++++++--- 4 files changed, 34 insertions(+), 260 deletions(-) delete mode 100644 gznbd/.gitignore delete mode 100644 gznbd/Makefile.am delete mode 100644 gznbd/gznbd.c diff --git a/gznbd/.gitignore b/gznbd/.gitignore deleted file mode 100644 index e550a6a4..00000000 --- a/gznbd/.gitignore +++ /dev/null @@ -1 +0,0 @@ -gznbd diff --git a/gznbd/Makefile.am b/gznbd/Makefile.am deleted file mode 100644 index d7940bba..00000000 --- a/gznbd/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -if GZNBD -bin_PROGRAMS = gznbd -gznbd_SOURCES = gznbd.c -gznbd_CFLAGS = -DTRACE -Wall -gznbd_LDADD = -lz ../libcliserv.la -endif diff --git a/gznbd/gznbd.c b/gznbd/gznbd.c deleted file mode 100644 index 47c74c78..00000000 --- a/gznbd/gznbd.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - (c) Marc Welz 2000, released under GPL, tested under Linux 2.2.17 - - Most of the stuff cribbed from the nbd package written by Pavel Machek - - Unfortunately quite slow since zlib has to decompress all the stuff between - seeks, so only suited to smaller files - - Could be a neat way to do userland encryption/steganography if you have - a crypto library which has a stdiolike interface to replace zlib - - Usage - - dd if=/dev/zero of=/tmp/image bs=1024 count=1024 - mke2fs -f /tmp/image - mount -o loop /tmp/image /mnt/ - cp /bin/ls /mnt/ - umount /mnt - sync - gzip -9 /tmp/image - gznbd /dev/nbd0 /tmp/image.gz - - gznbd does not background, from another terminal type - - mount -o ro,nocheck /dev/nbd0 /mnt/ - cd /mnt - ls - df - - ro is important, since writes will fail horribly and nochecks - speeds the mount up nicely - - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -/* asm/types defines __u??, at least on my system */ -#include - -#define MY_NAME "gznbd" - -/* these headers take care of endianness */ -#include "../config.h" -#include "../cliserv.h" - -#define BLOCK 1024 - -/* don't ask me why this value, I only copied it */ -#define CHUNK BLOCK*20 - - -int main(int argc, char **argv) -{ - int pr[2]; - int sk; - int nbd; - gzFile gz; - int gzerr; - - char chunk[CHUNK]; - struct nbd_request request; - struct nbd_reply reply; - - u64 size; - u64 from; - u32 len; - - if(argc<3){ - printf("Usage: %s nbdevice gzfile [size]\n",argv[0]); - exit(1); - } - - gz=gzopen(argv[2], "rb"); - if(gz==NULL){ - fprintf(stderr,"%s: unable open compressed file %s\n",argv[0],argv[2]); - exit(1); - } - - if(argc>3){ - size=atoll(argv[3]); - if((size==0)||(size%BLOCK)){ - fprintf(stderr,"%s: %s does not appear to be a valid size\n",argv[0],argv[3]); - exit(1); - } - printf("%s: file=%s, size=%"PRId64"\n",argv[0],argv[2],size); - } else { - char buffer[BLOCK]; - int result; - - size=0; - printf("%s: file=%s, seeking, ",argv[0],argv[2]); - fflush(stdout); - - /* expensive seek to get file size */ - while(BLOCK==(result=gzread(gz,buffer,BLOCK))){ - size+=BLOCK; - } - - if(result==0){ - printf("size=%"PRId64"\n",size); - } else { - printf("failed\n"); - if(result<0){ - fprintf(stderr,"%s: read failed: %s\n",argv[0],gzerror(gz,&gzerr)); - } else { - fprintf(stderr,"%s: incomplete last read, file has to be a multiple of %d\n",argv[0],BLOCK); - } - exit(1); - } - - if(gzrewind(gz)!=0){ - fprintf(stderr,"%s: unable to rewind gzfile\n",argv[0]); - exit(1); - } - - } - - if(socketpair(AF_UNIX, SOCK_STREAM, 0, pr)){ - fprintf(stderr,"%s: unable to create socketpair: %s\n",argv[0],strerror(errno)); - exit(1); - } - - switch(fork()){ - case -1 : - fprintf(stderr,"%s: unable to fork: %s\n",argv[0],strerror(errno)); - exit(1); - break; - case 0 : /* child */ - gzclose(gz); - - close(pr[0]); - - sk=pr[1]; - - nbd=open(argv[1], O_RDWR); - if(nbd<0){ - fprintf(stderr,"%s: unable to open %s: %s\n",argv[0],argv[1],strerror(errno)); - exit(1); - } - - if(ioctl(nbd,NBD_SET_SIZE,size)<0){ - fprintf(stderr,"%s: failed to set size for %s: %s\n",argv[0],argv[1],strerror(errno)); - exit(1); - } - - ioctl(nbd, NBD_CLEAR_SOCK); - - if(ioctl(nbd,NBD_SET_SOCK,sk)<0){ - fprintf(stderr,"%s: failed to set socket for %s: %s\n",argv[0],argv[1],strerror(errno)); - exit(1); - } - - if(ioctl(nbd,NBD_DO_IT)<0){ - fprintf(stderr,"%s: block device %s terminated: %s\n",argv[0],argv[1],strerror(errno)); - } - - ioctl(nbd, NBD_CLEAR_QUE); - ioctl(nbd, NBD_CLEAR_SOCK); - - exit(0); - - break; - } - - /* only parent here, child always exits */ - - close(pr[1]); - sk=pr[0]; - - reply.magic=htonl(NBD_REPLY_MAGIC); - reply.error=htonl(0); - - while(1){ - - if(read(sk,&request,sizeof(request))!=sizeof(request)){ - fprintf(stderr,"%s: incomplete request\n",argv[0]); - } - - memcpy(reply.handle,request.handle,sizeof(reply.handle)); - - len=ntohl(request.len); - from=ntohll(request.from); - -#ifdef TRACE -fprintf(stderr,"%s: len=%d, from=%"PRId64"\n",argv[0],len,from); -#endif - - if(request.magic!=htonl(NBD_REQUEST_MAGIC)){ - fprintf(stderr,"%s: bad magic\n",argv[0]); - reply.error=htonl(EIO); /* is that the right way of doing things ? */ - } - - if(ntohl(request.type)){ - fprintf(stderr,"%s: unsupported write request\n",argv[0]); - reply.error=htonl(EROFS); - } - - if(len+sizeof(struct nbd_reply)>CHUNK){ - fprintf(stderr,"%s: request too long\n",argv[0]); - reply.error=htonl(EIO); - } - - if(len+from>size){ - fprintf(stderr,"%s: request outside range\n",argv[0]); - reply.error=htonl(EIO); - } - - if(reply.error==htonl(0)){ - gzseek(gz,from,0); - if(gzread(gz,chunk+sizeof(struct nbd_reply),len)!=len){ - fprintf(stderr,"%s: unable to read\n",argv[0]); - reply.error=htonl(EIO); - len=0; - } - } else { - len=0; - } - - memcpy(chunk,&reply,sizeof(struct nbd_reply)); - if(write(sk,chunk,len+sizeof(struct nbd_reply))!=(len+sizeof(struct nbd_reply))){ - fprintf(stderr,"%s: write failed: %s\n",argv[0],strerror(errno)); - } - } - - gzclose(gz); - - return 0; -} diff --git a/nbd-server.c b/nbd-server.c index 60fc5a59..2818f2fe 100644 --- a/nbd-server.c +++ b/nbd-server.c @@ -3779,22 +3779,45 @@ void setup_servers(GArray *const servers, const gchar *const modernaddr, /** * Go daemon (unless we specified at compile time that we didn't want this) - * @param serve the first server of our configuration. If its port is zero, - * then do not daemonize, because we're doing inetd then. This parameter - * is only used to create a PID file of the form - * /var/run/nbd-server.<port>.pid; it's not modified in any way. **/ #if !defined(NODAEMON) void daemonize() { - FILE*pidf; - - if(daemon(0,0)<0) { - err("daemon"); - } + pid_t child=fork(); + if(child < 0) { + err("fork"); + } else if(child > 0) { + exit(EXIT_SUCCESS); + } else { + if(setsid() < 0) { + err("setsid"); + } + } + if(chdir("/")<0) { + err("chdir"); + } if(!*pidfname) { strncpy(pidfname, "/var/run/nbd-server.pid", 255); } - pidf=fopen(pidfname, "w"); + int newfd; + if((newfd = open("/dev/null", O_RDWR)) < 0) { + err("open"); + } + if(dup2(0, newfd) < 0) { + err("dup2 stdin"); + } + if(dup2(1, newfd) < 0) { + err("dup2 stdout"); + } + if(dup2(2, newfd) < 0) { + err("dup2 stderr"); + } + child=fork(); + if(child < 0) { + err("fork"); + } else if(child > 0) { + exit(EXIT_SUCCESS); + } + FILE*pidf=fopen(pidfname, "w"); if(pidf) { fprintf(pidf,"%d\n", (int)getpid()); fclose(pidf); @@ -3804,7 +3827,7 @@ void daemonize() { } } #else -#define daemonize(serve) +#define daemonize() #endif /* !defined(NODAEMON) */ /*