minit

A small yet feature-complete init (http://fefe.de/minit/)
Log | Files | Refs | README | LICENSE

commit df48be20758eca03667a8d9268e5812e3f2b0229
parent 85d8345b2606a7670d65f133d9fe4e677d8c8b76
Author: leitner <leitner>
Date:   Tue, 24 May 2022 09:47:06 +0000

modernize codebase a bit, fix bug when params didn't end in newline

Diffstat:
MMakefile | 4++--
Mftrigger.c | 8+++++---
Mminit-update.c | 3---
Mminit.c | 65++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mopendevconsole.c | 11++++++++---
Mopenreadclose.c | 15++++++++++-----
Mshutdown.c | 14+++++++++-----
Msplit.c | 20+++++++++++++++++++-
8 files changed, 103 insertions(+), 37 deletions(-)

diff --git a/Makefile b/Makefile @@ -7,7 +7,7 @@ PIE= CFLAGS=-Wall -W -pipe -fomit-frame-pointer -Os $(PIE) CROSS= #CROSS=arm-linux- -LDFLAGS=-s +LDFLAGS=-s $(PIE) MANDIR=/usr/man path = $(subst :, ,$(PATH)) @@ -50,7 +50,7 @@ endif minit: minit.o split.o openreadclose.o opendevconsole.o msvc: msvc.o ftrigger: ftrigger.o -minit-update: minit-update.o split.o openreadclose.o +minit-update: minit-update.o serdo: serdo.o waitinterface: waitinterface.o waitport: waitport.o diff --git a/ftrigger.c b/ftrigger.c @@ -112,7 +112,10 @@ again: continue; case 1: break; }; - read(in,buf,sizeof(buf)); + if (read(in,buf,sizeof(buf)) < (ssize_t)sizeof(*ie)) { + buffer_putmflush(buffer_2,"error reading inotify notification: ",strerror(errno),"\n"); + exit(111); + } #if 0 buffer_puts(buffer_1,"got event for wd "); @@ -212,8 +215,7 @@ goodevent: if (v) buffer_putmflush(buffer_1,"file \"",root[i].filename,"\" changed, running command \"",root[i].command,"\"\n"); if (vfork()==0) { - system(root[i].command); - exit(0); + exit(system(root[i].command)); } } } diff --git a/minit-update.c b/minit-update.c @@ -25,9 +25,6 @@ static char buf[BUFLEN+1]; static unsigned int verbose; static int do_update; -int openreadclose(char *fn, char **buf, unsigned long *len); -char **split(char *buf,int c,int *len,int plus,int ofs); - void feed_struct_to_minit(struct process *data); ssize_t read_outfd(void *buf, size_t count); diff --git a/minit.c b/minit.c @@ -18,6 +18,7 @@ #include <stdlib.h> #include <alloca.h> #include <sys/reboot.h> +#include <write12.h> #include <libowfat/fmt.h> #include <libowfat/str.h> @@ -80,8 +81,8 @@ static int doupdate; static int i_am_init; -extern int openreadclose(char *fn, char **buf, unsigned long *len); -extern char **split(char *buf,int c,int *len,int plus,int ofs); +extern int openreadclose(char *fn, char **buf, size_t *len); +extern char **split(char *buf,int c,size_t* len,size_t plus,size_t ofs); extern char **environ; @@ -223,10 +224,10 @@ pid_t forkandexec(int pause,int service) { int count=0; pid_t p; int fd; - unsigned long len; + size_t len; int islink; char *s=0; - int argc; + size_t argc; char *argv0=0; again: switch (p=fork()) { @@ -239,10 +240,26 @@ again: if (i_am_init) { ioctl(0, TIOCNOTTY, 0); - setsid(); + if (setsid() == -1) { + __write2("setsid failed unexpectedly.\n"); + // This should never fail. init is run as root. + // If it does fail, don't exit for fear of bricking the system + } opendevconsole(); /* ioctl(0, TIOCSCTTY, 1); */ - tcsetpgrp(0, getpgrp()); + int r = tcsetpgrp(0, getpgrp()); + if (r == -1 && errno!=ENOTTY) { // will get this error for log services + __write2("tcsetpgrp failed unexpectedly: "); + switch (errno) { + case EBADF: __write2("EBADF\n"); break; + case EINVAL: __write2("EINVAL\n"); break; +// case ENOTTY: __write2("ENOTTY\n"); break; + case EPERM: __write2("EPERM\n"); break; + default: __write2("unhandled\n"); + } + // This should never fail. init is run as root. + // If it does fail, don't exit for fear of bricking the system + } } if (pause) { @@ -252,12 +269,19 @@ again: nanosleep(&req,0); } if ((fd=open("in",O_RDONLY))!=-1) { - dup2(fd,0); + if (dup2(fd,0) != 0) { + __write2("dup2 failed unexpectedly.\n"); + // This should never fail. init is run as root. + // If it does fail, don't exit for fear of bricking the system + } fcntl(0,F_SETFD,0); } if ((fd=open("out",O_WRONLY))!=-1) { - dup2(fd,1); - dup2(fd,2); + if (dup2(fd,1) != 1 || dup2(fd,2) != 2) { + __write2("dup2 failed unexpectedly.\n"); + // This should never fail. init is run as root. + // If it does fail, don't exit for fear of bricking the system + } fcntl(1,F_SETFD,0); fcntl(2,F_SETFD,0); } @@ -271,7 +295,8 @@ again: } if (!openreadclose("params",&s,&len)) { argv=split(s,'\n',&argc,2,1); - if (argv[argc-1]) argv[argc-1]=0; else argv[argc]=0; + if (argc && argv[argc-1][0]==0) --argc; // if params ended on newline, don't pass empty last arg + argv[argc]=0; } else { argv=(char**)alloca(2*sizeof(char*)); argv[1]=0; @@ -314,12 +339,19 @@ again: argv0=c; } if (root[service].__stdin != 0) { - dup2(root[service].__stdin,0); + if (dup2(root[service].__stdin,0) != 0) { + __write2("dup2 failed unexpectedly.\n"); + // This should never fail. init is run as root. + // If it does fail, don't exit for fear of bricking the system + } fcntl(0,F_SETFD,0); } if (root[service].__stdout != 1) { - dup2(root[service].__stdout,1); - dup2(root[service].__stdout,2); + if (dup2(root[service].__stdout,1) != 1 || dup2(root[service].__stdout,2) != 2) { + __write2("dup2 failed unexpectedly.\n"); + // This should never fail. init is run as root. + // If it does fail, don't exit for fear of bricking the system + } fcntl(1,F_SETFD,0); fcntl(2,F_SETFD,0); } @@ -380,7 +412,7 @@ int startservice(int service,int pause,int father) { // Need to free(s) independent of openreadclose return value if (!openreadclose("depends",&s,&len)) { char **deps=0; - int depc,i; + size_t depc,i; deps=split(s,'\n',&depc,0,0); for (i=0; i<depc; i++) { int Service,blacklisted,j; @@ -605,7 +637,10 @@ error: write(outfd,"1",1); if (1==poll(&pfd,nfds,5000)) { struct process tmp; - read(infd,&tmp,sizeof tmp); + if (read(infd,&tmp,sizeof tmp) != sizeof(tmp)) { + __write2("update failed, struct size mismatch.\n"); + goto ok; + } tmp.name=strdup(buf+1); addprocess(&tmp); } diff --git a/opendevconsole.c b/opendevconsole.c @@ -1,12 +1,17 @@ #include <fcntl.h> #include <unistd.h> +#include <write12.h> +#include <stdlib.h> void opendevconsole() { int fd; if ((fd=open("/dev/console",O_RDWR|O_NOCTTY))>=0) { - dup2(fd,0); - dup2(fd,1); - dup2(fd,2); + if (dup2(fd,0) != 0 || + dup2(fd,1) != 1 || + dup2(fd,2) != 2) { + __write2("dup2 failed unexpectedly.\n"); + exit(111); + } if (fd>2) close(fd); } } diff --git a/openreadclose.c b/openreadclose.c @@ -1,23 +1,28 @@ #ifndef EMBEDDED +#define _FILE_OFFSET_BITS 64 #include <unistd.h> #include <fcntl.h> #include <stdlib.h> #endif -int openreadclose(char *fn, char **buf, unsigned long *len) { +int openreadclose(char *fn, char **buf, size_t *len) { int fd=open(fn,O_RDONLY); if (fd<0) return -1; if (!*buf) { - *len=lseek(fd,0,SEEK_END); - lseek(fd,0,SEEK_SET); + off_t o = lseek(fd, 0, SEEK_END); + if (o < 0 || o > 0x7fffffff) goto error; // impose sanity limits + *len = o; *buf=(char*)malloc(*len+1); if (!*buf) { +error: close(fd); return -1; } } - *len=read(fd,*buf,*len); - if (*len != (unsigned long)-1) + *len=pread(fd,*buf,*len,0); + if (*len == (unsigned long)-1) + (*buf)[0]=0; + else (*buf)[*len]=0; return close(fd); } diff --git a/shutdown.c b/shutdown.c @@ -48,8 +48,8 @@ static inline int __write2(const char*s) { return write(2,s,str_len(s)); } extern void opendevconsole(); extern char **environ; -extern int openreadclose(char *fn, char **buf, unsigned long *len); -extern char **split(char *buf,int c,int *len,int plus,int ofs); +extern int openreadclose(char *fn, char **buf, size_t *len); +extern char **split(char *buf,int c,size_t* len,size_t plus,size_t ofs); extern char *optarg; void wall(char *buf) { @@ -93,7 +93,7 @@ int minit_serviceDown(char *service) { if (!openreadclose("depends", &s, &len)) { char **deps; - int depc, i; + size_t depc, i; deps=split(s, '\n', &depc, 0, 0); for (i=0; i<depc; i++) { if (deps[i][0] == '#') continue; @@ -118,7 +118,8 @@ int minit_serviceDown(char *service) { strncpy(buf+1, service, 1400); buf[1400]=0; write(infd, buf, str_len(buf)); - read(outfd, buf, 1500); + if (read(outfd, buf, 1500) < 1) + __write2("\t(status read failed)"); i=kill(pid, SIGTERM); if (i == 0) __write2("\t\tdone\n"); else __write2("\t\tfailed\n"); @@ -168,7 +169,10 @@ int main(int argc, char *const argv[]) { int cfg_sulogin = 0; #ifdef ALLOW_SUID - setuid(geteuid()); + if (setuid(geteuid()) == -1) { + __write2("setuid(geteuid()) failed.\n"); + return 111; + } #endif if (getuid() != 0) { __write2("you are not root, go away!\n"); diff --git a/split.c b/split.c @@ -2,7 +2,7 @@ /* split buf into n strings that are separated by c. return n as *len. * Allocate plus more slots and leave the first ofs of them alone. */ -char **split(char *buf,int c,int *len,int plus,int ofs) { +char **split(char *buf,int c,size_t* len,size_t plus,size_t ofs) { int n=1; char **v=0; char **w; @@ -25,3 +25,21 @@ char **split(char *buf,int c,int *len,int plus,int ofs) { *len=w-v; return v; } + +#ifdef UNITTEST +#include <assert.h> +#include <string.h> +#include <stdio.h> + +int main() { + char inp[]="foo\nbar\nbaz"; + size_t len; + char** x=split(inp, '\n', &len, 2, 1); + assert(len==4 && !strcmp(x[1],"foo") && !strcmp(x[2],"bar") && !strcmp(x[3],"baz") && x[4]==NULL); + free(x); + char inp2[]="fnord"; + x=split(inp2, '\n', &len, 2, 1); + assert(len==2 && !strcmp(x[1],"fnord") && x[2]==NULL); + return 0; +} +#endif