diff options
Diffstat (limited to 'nsvc.c')
| -rw-r--r-- | nsvc.c | 415 |
1 files changed, 415 insertions, 0 deletions
@@ -0,0 +1,415 @@ +#define SVC_PROGRAM +#include <fcntl.h> +#include <time.h> +#include <sys/file.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include "ninit.h" +#include "nsvc_buffer.h" + +extern int ioctl(); + +static char **Names_skip, **NamesX, *buf, *initroot, *nsvc_other, respmode; +static int NamesI, do_update, tty = -111; + +static void e(int n) { buffer_flush(buffer_1); _exit(n); } +static void die_xx(char *s) { errmsg_iam("nsvc"); err(2,s,0); _exit(1); } + +#include "get_services.h" +#include "findservice.h" +#include "open_inout.h" +#include "tryservice_nsvc.h" + +static char *get_name() { + char *x, *s, **skp; + again: + if (NamesI >= 0) { + x = (NamesI <= maxprocess) ? root_name(NamesI) : 0; + ++NamesI; + } else { + x = *NamesX; + ++NamesX; + } + if (x) + for (skp=Names_skip; (s=*skp); skp++) + if (!str_diff(s,x)) goto again; + return x; +} + +static void close_inout() { + close(infd); infd = -1; + close(outfd); outfd = -1; +} + +static int __findservice(char *service) { + int idx; + get_services(); + idx=findservice(service); +#ifdef CLEAN_SERVICE + if (idx<0) idx=findservice(cleanservice(service)); +#endif + return idx; +} + +void print_pid(char *service, pid_t pid) { + errmsg_iam("nsvc"); + carp(service,(pid < 0) ? ": no such service" : ": service not running"); +} + +/* return PID, -1 if service is not loaded */ +static pid_t __readpid(char *service, int verbose) { + pid_t idx=__findservice(service); + if (idx >= 0) idx = root[idx].pid; + if (verbose && idx<2) + print_pid(service, idx); + return idx; +} + +static char *fu_x(uint32t u, int len) { /* len must be max 10 !!! */ + char *x = fu(u); + int y = str_len(x); + while (y < len) { *--x = ' '; y++; } + return x; +} + +static void fs_x(const char *s, int len) { + int k = str_len(s); + outs(s); + if (k >= len) outc('\t'); + else while (k++ < len) outc(' '); +} + +static void fmt_time(unsigned long up) { + unsigned long u; + u = up % 60; up /= 60; + fmt_color(fu_x(u, 4),'6'," "); + if (up) { u = up % 60; up /= 60; fmt_color(fu_x(u, 2),'4'," "); } + if (up) { u = up % 24; up /= 24; fmt_color(fu_x(u, 2),'5'," "); } + if (up) fmt_color(fu_x(up,4),'2',""); +} + +static int fmt_service(int i, int flagtty) { + struct process *pr = root + i; + pid_t pid = pr->pid; + time_t cr, uptime; + static time_t now; + + if (tty==-111) { +#if defined(INIT_SYSTEM) + pid_t dummy; + tty = (ioctl(1, X_TIOCGPGRP, &dummy) == 0); +#else + tty=isatty(1); +#endif + } + + if (!now) now=time(0); + uptime = now - pr->startedat; + if (uptime<0) uptime=0; + + if (flagtty || tty) { + char *name=root_name(i); + if (flagtty<=4 && tty) { + char flags[8], *x, ch; + int len; + + if (errmsg_argv0) { outs(errmsg_argv0); outs(": "); } + fs_x(name, 16); + + switch (pid) { + case 0: x=" down"; ch='7'; break; + case 1: x="finish"; ch='2'; break; + default: + if (pr->pr_respawn) ch='1'; else ch='4'; + x=fu_x(pid,6); + } + fmt_color(x,ch," "); + + len=0; + if (pr->pr_respawn) flags[len++] = 'R'; + if (pr->cron) flags[len++] = 'C'; + if (pr->pr_end) flags[len++] = 'E'; + flags[len] = 0 ; + fs_x(flags, 3); + + fmt_time(uptime); + + if ((cr = pr->cron)) { + fmt_color("\tnext cron",'1',":"); + if (cr > now) fmt_time(cr-now); + else outs(" waititing"); + outc('\t'); + fmt_color(fu(cr), '8', ""); + } + outc('\n'); + } + else + msg(name); + } else { + errmsg_iam(0); + msg(fu(pid)," ",fu(uptime)); + } + + if (pid==0) return 2; else if (pid==1) return 3; else return 0; +} + +static void dumphistory() { + int j; + if (!maxhistory) { + carp("ninit compiled without history support"); + return; + } + errmsg_iam(0); + for (j=0; j<maxhistory; j++) + if (--history[j] <= maxprocess) { + fmt_service(history[j], 4+root[history[j]].pr_circular); + root[history[j]].pr_circular = 1; + } +} + +static void dumpdependencies(char* service, unsigned int skip) { + int i,idx; + idx=__findservice(service); + if (idx<0) { print_pid(service, -1); return; } + + errmsg_iam(0); + for (i=0; i<=maxprocess; ++i) { + if (root[i].father==idx && i!=idx) { + char *name = root_name(i); + int k=skip; + while (k-->0) outs(" "); + msg(name); + if (skip<16) dumpdependencies(name,skip+1); + else msg(buf," ...",name); + } + } +} + +static void wait_childs(int len) { + unsigned wtime; + pid_t i, pids[len]; + char *x; + + for (len=0; (x=get_name());) + if ((pids[len]=__readpid(x, 0)) > 1) ++len; + + close_inout(); + wtime = 4*atoulong(nsvc_other); + + while (1) { + for (i=len; i>0;) + if (kill(pids[--i],0) && errno != EPERM) + pids[i] = pids[--len]; + if (len==0) _exit(0); + if (wtime--==0) _exit(1); + nano_sleep(0,250000000); + } +} + +static int try_srv(char *s, char mode) { + int r; + char *save = nsvc_other; + if (mode == 'r') + nsvc_other = (respmode) ? "c" : 0; /* must be odd char !!! */ + r = tryservice(s, mode); + nsvc_other = save; + return r; +} + +static void get_timestamp() { + char *x = nsvc_other; + unsigned int now; + if (x[-1] == 'C') { + if (x[0] == '+') ++x; + else return; + } + if ((now = atoulong(x))) + nsvc_other = fu(time(0) + now); +} + +int main(int argc,char *argv[]) { + int i,idx,ret=0; + pid_t pid; + char *x, **skp; + + __b_1.x = alloca(BUFFER_1_LEN); + buf = alloca(BUFFER_TMP_LEN); + mem.a = INIT_ALLOC_BUFFER; + + x = env_get("NINIT_MEMORY"); + if (x) mem.a = atoulong(x); + mem.r=mem.a; + if (mem.a==0 || mem.a > 64000 || (mem.x=alloca(mem.a))==0) _exit(1); + + errmsg_iam("nsvc"); + infd = -1; outfd = -1; + INIT_ENV_GET_HOME(initroot,"NINIT_HOME","INIT_HOME"); + + Names_skip = alloca(argc * sizeof(char *)); + for (skp=Names_skip; (x=argv[1]); argv++) { + if (x[0] != '-' || x[1] != 'S') break; + *skp++ = x+2; + } + *skp = 0; + + { + int uid=getuid(), euid=geteuid(); + if (initroot && (uid != euid)) { ops: die_xx("\ago away!"); } + if (initroot==0) initroot=INITROOT; + + if (argv[1] == 0) { setuid(uid); goto REMOVE; } + open_inout(initroot); + + if (uid != euid) { + if (setuid(uid)) goto ops; + get_services(); + close_inout(); + } + } + + nsvc_other = argv[1] + 2; + + if (argv[2]==0) { + char *a1 = argv[1]; + get_services(); + close_inout(); + + if (a1[0] == '-') { + switch (a1[1]) { + case 'V': goto REMOVE; + case 'L': + errmsg_iam(0); + while (get_name()) fmt_service(NamesI-1, 1); + e(0); + case 'H': + dumphistory(); + e(0); + case 'D': + msg("memory usage: ",fu(mem.l + root_names_len)," = ", + fu(mem.l),"+",fu(root_names_len)," = services+names [", + fu(maxprocess+1),"]"); + e(0); + } + } + + i=__findservice(a1); + if (i==-1) { print_pid(a1, -1); e(1); } + ret=fmt_service(i,0); + + if (i >= 0 && tty && root[i].pid > 1) { + INIT_ARGS2(argv, "./sys/procfs", fu(root[i].pid)); + goto PROCFS; + } + } else { + char *x; + unsigned int sig=0; + + x = argv[2]; + + if (argv[1][0]=='-') { + char flagdown=1, try_flag='r'; + respmode = 0; + + switch (argv[1][1]) { + case 'P': + ret=try_srv(x, 'P'); + if (ret) carp("Could not set PID of service ",x); + break; + + case 'D': dumpdependencies(x,0); break; + case 'E': + case 'Z': + REMOVE: + argv[0] = "./sys/remove"; /* XXX: make sys as environ! */ + PROCFS: + close_inout(); + buffer_flush(buffer_1); + ret = chdir(initroot); + if (!ret) ret=execve(argv[0], argv, environ); + break; + default: + + if (argv[3] == 0 && !str_diff(argv[2], "ALL")) { + get_services(); + argc = maxprocess + 4; + } else { + NamesX = argv + 2; + NamesI--; + } + + switch (argv[1][1]) { + case 'W': + wait_childs(argc); + case 'g': + while ((x=get_name())) { + pid=__readpid(x,1); + if (pid > 1) { errmsg_iam(0); msg(fu(pid)); } + else ret = 1; + } + break; + case 'u': respmode=1; + case 'o': + try_flag='s'; + goto try_it; + + case 'C': try_flag='c'; /* cron */ + case 'R': respmode=1; + + try_it: + case 'r': flagdown=0; + case 'd': + get_timestamp(); + while ((x=get_name())) { + idx=try_srv(x, try_flag); + if (idx==0) { + if (try_flag=='s') idx=try_srv(x,'r'); + else if (flagdown) { + pid=__readpid(x,0); + if (pid>1 && 0==kill(pid,SIGTERM)) kill(pid,SIGCONT); + } + } + if (idx) { print_pid(x,-1); ret=1; } + } + break; + + default: +#ifdef NSVC_SIGNAL_CODED + { + unsigned char *S, *Sig = (unsigned char *)NSVC_SIGNAL_CODED; + for (S=Sig; *S; S += 2) + if (argv[1][1] == *S) { sig = S[1]; break; } + } +#else +#define kk(C,S) case C: sig=S; break + kk('t',SIGTERM); kk('a',SIGALRM); kk('p',SIGSTOP); kk('c',SIGCONT); + kk('h',SIGHUP); kk('i',SIGINT); kk('k',SIGKILL); +#endif + } /* inner switch */ + } /* outer switch */ + } + + if (sig) { + while ((x=get_name())) { + pid=__readpid(x,1); + if (pid < 2) + ret=1; + else if (kill(pid,sig)) { + char* s; + switch (errno) { + case EINVAL: s="invalid signal"; break; + case EPERM: s="permission denied"; break; + case ESRCH: s="no such pid"; break; + default: s="unknown error"; + } + carp(x,": could not send signal ",fu(sig)," to PID ",fu(pid),": ",s); + ret=1; + } + } + } + } + e(ret); + return 0; +} |
