9 #include <netinet/in.h>
11 #include <sys/types.h>
20 #include <sys/resource.h>
23 #include <sys/socket.h>
30 const int safesigs[]={SIGQUIT,SIGINT,SIGTERM,SIGIOT,SIGALRM,-1}; //SIGCHLD->childsignal anyway
32 const char *upsc_sshpath="/usr/bin/ssh"; /* upsetupconn()... */
33 const char *upsc_dstport=DS_PORT;
35 void chk(const void *p)
39 FATAL(CRIT,"NULL-check failure, memory exhausted? FATAL: %m");
43 static void *vbchecknull=NULL;
44 static struct varbuf *vbcheckhead=(struct varbuf *)&vbchecknull;
45 static unsigned vbchecknum;
46 #ifdef FATALSIG_INSANE
47 static char vbcheckno;
51 pthread_mutex_t vbcheckmx=PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
53 static void vbchecklock (void)
54 { if (pthread_mutex_lock (&vbcheckmx)) FATAL(CRIT,"Mutex ""lock on vbcheck mx"); }
55 static void vbcheckunlock(void)
56 { if (pthread_mutex_unlock(&vbcheckmx)) FATAL(CRIT,"Mutex unlock on vbcheck mx"); }
58 static char vbchecklist(struct varbuf *vb)
66 for (vbs=vbcheckhead;vbs;vbs=vbs->checknext,tot++)
72 assert(vb->checknext);
73 while (tot++,(vbs=vbs->checknext)!=vbchecknull) assert(vb!=vbs);
74 assert(tot==vbchecknum+1);
79 void vbcheck(struct varbuf *vb)
81 struct varbufnode *vbn;
85 if (vbcheckno) return; vbchecklock();
86 assert(vbchecklist(vb));
87 if (vb->done) assert(!!vb->f);
88 if (vb->free) assert(!!vb->l);
89 assert((!vb->f)==(!vb->f));
90 for (vbn=vb->f;vbn;vbn=vbn->next) {
91 if (vbn==vb->f) assert(vb->done<=vbn->size);
92 if (vbn==vb->l) assert(vb->free<=vbn->size);
93 for (s=vbn->buf;s<vbn->buf+vbn->size;s++) touch=*s;
102 if (vbcheckno) return; vbchecklock();
103 assert(!vbchecknull);
104 for (vb=vbcheckhead;vb!=(struct varbuf *)&vbchecknull;vb=vb->checknext) vbcheck(vb);
110 void vbdebug(struct varbuf *vb,const char *msg)
112 struct varbufnode *vbn;
113 fprintf(stderr,"vbdebug(%s): vb=%p",msg,vb);
116 fprintf(stderr,"\n");
119 fprintf(stderr,", first=%p, last=%p, done=%u, free=%u\n",vb->f,vb->l,vb->done,vb->free);
120 for (vbn=vb->f;vbn;vbn=vbn->next) {
122 fprintf(stderr," *VBN: %p: size=%u, buf:",vbn,vbn->size);
123 for (i=0;i<vbn->size;i++) {
125 if (isprint(c)) fprintf(stderr," '%c'",c);
126 else fprintf(stderr," %02x",(unsigned char)c);
128 fprintf(stderr,"\n");
130 fprintf(stderr,"vbdebug(%s): finishing...\n",msg);
134 struct varbufnode *vbnnew(size_t sugsize)
136 struct varbufnode *r;
137 if (!vbnexact && sugsize<VB_DEFSIZE) sugsize=VB_DEFSIZE;
138 chk(r=malloc(sizeof(*r)+sugsize));
144 void vbgrow(struct varbuf *vb,size_t sugsize)
146 struct varbufnode *vbn;
147 vbdebug(vb,"vbgrow");
150 if (vb->l && vb->l->size>sugsize) sugsize=vb->l->size;
151 if (sugsize*2<=VB_MAXSIZE) sugsize*=2;
152 else if (sugsize<VB_MAXSIZE) sugsize=VB_MAXSIZE;
155 if (vb->l) vb->l->next=vbn;
161 void vbinit(struct varbuf *vb)
164 if (!vbcheckno) assert(!vbchecklist(vb));
166 bzero(vb,sizeof(*vb));
169 vb->checknext=vbcheckhead;
177 struct varbufnode *vbremone(struct varbuf *vb)
179 struct varbufnode *r;
180 vbdebug(vb,"vbremone");
192 void vbclear(struct varbuf *vb)
194 vbdebug(vb,"vbclear");
195 while (vb->f) vbremone(vb);
198 void vbrem(struct varbuf *vb)
208 assert(vbchecknum>0);
209 for (vbp=&vbcheckhead;*vbp;vbp=&(*vbp)->checknext)
213 bzero(vb,sizeof(*vb));
218 size_t vbsize(struct varbuf *vb,size_t maxsize)
221 struct varbufnode *vbn=vb->f;
223 vbdebug(vb,"vbsize");
224 while (vbn && (!maxsize || size<maxsize)) {
225 size+=VBNSIZE(vb,vbn);
231 #define GENVARBUFC(argmid) \
232 void vbput##argmid(struct varbuf *vb,const argmid arg) \
233 { vbwrite(vb,&arg,sizeof(arg)); } \
234 char vbget##argmid(struct varbuf *vb,argmid *argp) \
235 { if (sizeof(*argp)>1 && !VBCHKSIZE(vb,sizeof(*argp))) return(0); \
236 return(vbread(vb,argp,sizeof(*argp))); }
238 #ifndef INLINE_PUTGETCHAR
246 void vbwrite(struct varbuf *vb,const void *buf,size_t count)
250 vbdebug(vb,"vbwrite");
254 memcpy(vb->l->buf+VBNSIZEL(vb,vb->l),buf,(now=min(vb->free,count)));
261 assert(vb->free>=count);
262 assert(vb->l&&vb->l->size==vb->free);
263 memcpy(vb->l->buf,buf,count);
268 extern size_t vbputstring(struct varbuf *vb,const char *s)
275 ssize_t vbwritefd(struct varbuf *vb,int fd)
279 vbdebug(vb,"vbwritefd");
281 if (!vb->free) vbgrow(vb,0);
282 now=read(fd,vb->l->buf+vb->l->size-vb->free,vb->free);
283 dbg("vbwritefd: now=%d\n",now);
285 if (errno==EAGAIN) break;
298 size_t vbpeek(struct varbuf *vb,ssize_t offs,void *buf,size_t count)
300 size_t got=0,now,size;
302 struct varbufnode *vbn=vb->f;
304 vbdebug(vb,"vbpeek");
305 if ((doread=(offs==-1))) offs=0;
307 while (vbn && count) {
308 size=VBNSIZEL(vb,vbn);
310 memcpy(buf,vbn->buf+offs,(now=min(count,size-offs)));
321 if (!VBNSIZE(vb,vb->f)) {
331 ssize_t vbchrn(struct varbuf *vb,ssize_t offs,char c,char dir)
335 struct varbufnode *vbn;
337 struct varbufnode *vbn;
338 ssize_t distoffs=0,size=vbsize(vb,0);
341 if (offs==-1 || offs>=size) {
342 if (dir>0) return(-1);
345 if (offs<0) return(-1);
349 while (vbn && offs>=vbn->size) {
351 chk(vbl2=alloca(sizeof(*vbl2)));
361 if (dir<0) for (;;) {
362 if (vbn && offs<VBNSIZEL(vb,vbn)) {
363 ssize_t start=VBNSTART(vb,vbn); // FIXME: not really - GCC bug! (size_t crashes)
364 dbg("seeking back... start=%u,offs=%d,vbn->size=%u\n",start,offs,vbn->size);
365 while (offs>=start&&vbn->buf[offs]!=c) offs--;
366 if (offs>=start) return(distoffs+offs);
375 if (dir>0) while (vbn) {
376 size_t size=VBNSIZEL(vb,vbn);
378 dbg("vbn=%p,offs=%d,size=%d\n",vbn,offs,size);
380 if ((s=memchr(vbn->buf+offs,c,size-offs)))
381 return(distoffs+(s-vbn->buf));
389 ssize_t vbreadfd(struct varbuf *vb,int fd)
393 vbdebug(vb,"vbreadfd");
394 dbg("entering vbreadfd(fd=%d)\n",fd);
396 size_t size=VBNSIZE(vb,vb->f);
397 now=write(fd,vb->f->buf+vb->done,size);
398 dbg("vbreadfd: now=%d\n",now);
399 if (now<0 && errno!=EAGAIN) return(now);
400 if (now<=0) return(got);
402 assert(vb->done<=size);
404 if (!VBNSIZE(vb,vb->f))
412 static void fixupnulls(char *s,size_t len,const char *fname)
417 for (d=s;(d=memchr(d,'\0',s+len-d));) { *d++=' '; tot++; }
418 if (tot) logmsg((quiet_null?MYLOG_DEBUG:MYLOG_ERR),
419 "%s() replaced %u '\\0's by ' ' in: %.*s",fname,tot,(int)len,s);
422 char *vbgetline(struct varbuf *vb,char term)
427 if (!(len=vbchrn(vb,0,term,1)+1)) return(NULL);
430 r=vbread(vb,s,len); assert(r==len);
431 assert(s[len-1]==term);
433 fixupnulls(s,len-1,"vbgetline");
437 size_t chkvsprintf(char **sp,const char *fmt,va_list ap)
439 size_t bufsize=VB_DEFSIZE;
443 chk(*sp=realloc(*sp,bufsize));
444 i=vsnprintf(*sp,bufsize,fmt,ap);
445 dbg("chkvsprintf: bufsize=%u,i=%d,fmt:%s\n",bufsize,i,fmt);
446 if (i>=0&&i<bufsize) break;
453 size_t vbvprintf(struct varbuf *vb,const char *fmt,va_list ap,char remlf)
458 len=chkvsprintf(&buf,fmt,ap);
461 for (s=buf;(c=*s);s++) {
462 if (c<0 || (c>=' '&&c!='\\')) {
468 case '\n' : vbputchar(vb,'n'); break;
469 case '\r' : vbputchar(vb,'r'); break;
470 case 1 ... 9: //FALLTHRU
471 case 11 ... 12: //FALLTHRU
472 case 14 ... 31: vbprintf(vb,"x%02X",c); break;
473 case '\\' : vbputchar(vb,'\\'); break;
478 else vbwrite(vb,buf,len);
483 size_t vbprintf(struct varbuf *vb,const char *fmt,...) //stub
489 r=vbvprintf(vb,fmt,ap,0);
495 #define PSTR_MAX 65535
496 #define PSTR_TYPE short
499 #define PSTR_TYPE char
502 #define PSTR_PUTLEN2(vb,len,type) vbput##type((vb),(type)(len))
503 #define PSTR_PUTLEN1(vb,len,type) PSTR_PUTLEN2(vb,len,type)
504 #define PSTR_PUTLEN(vb,len) PSTR_PUTLEN1((vb),(len),PSTR_TYPE)
506 void vbpstrputstring(struct varbuf *vb,const char *s)
508 size_t len=strlen(s);
510 LOG(CRIT,"String longer (%u) than PSTRing max (%u)",len,PSTR_MAX);
512 dbg("vbpstrputstring-longer than MAX: \"%s\"\n",s);
518 size_t vbpstrcopy(struct varbuf *vbd,struct varbuf *vbs,ssize_t len)
521 if (len==-1) len=vbsize(vbs,0);
522 else if ((size=vbsize(vbs,len))<len) len=size;
525 LOG(CRIT,"String longer (%u) than PSTRing max (%u)",len,PSTR_MAX);
527 vbdebug(vbs,"vbpstrputstring-longer than MAX");
529 PSTR_PUTLEN(vbd,len);
531 if (was!=len) vbdrop(vbs,was-len);
535 void vbpstrprintf(struct varbuf *vb,const char *fmt,...)
538 char buf[PSTR_MAX+1];
542 i=vsnprintf(buf,sizeof(buf),fmt,ap);
545 LOG(CRIT,"Buffer overflow (max=%u) during PSTR printf",PSTR_MAX);
548 assert(i>=0 && i<=PSTR_MAX && !buf[i]);
549 vbpstrputstring(vb,buf);
552 char *vbpstrread(struct varbuf *vb)
554 unsigned PSTR_TYPE len,scan,chgd=0;
558 if (!vbpeek(vb,0,&len,sizeof(len))) return(NULL);
559 if (!VBCHKSIZE(vb,1+len)) return(NULL);
560 chk(buf=malloc(len+1));
561 vbdrop(vb,sizeof(len));
562 r=vbread(vb,buf,len); assert(r==len);
564 for (scan=0;scan<len;scan++)
570 LOG(CRIT,"'\\0's found (%u total) in read PSTR \"%s\", changed to '?'",chgd,buf);
574 size_t vbcopy(struct varbuf *vbd,struct varbuf *vbs,ssize_t count)
578 vbdebug(vbd,"vbcopy-dest");
579 vbdebug(vbs,"vbcopy-src");
580 dbg("vbcopy-count=%d\n",count);
581 got=vbsize(vbs,(count==-1?0:count));
582 if (count==-1 || count>got) count=got;
584 dbg("got=%u, vbd->free=%u, count=%d\n",got,vbd->free,count);
585 if (!count) return(got);
587 dbg("vbd->free=%d path\n",vbd->free);
588 vbdebug(vbd,"vbd->free-s:vbd");
589 assert(vbd->f && vbd->l);
590 r=vbread(vbs,vbd->l->buf+VBNSIZEL(vbd,vbd->l),(now=min(count,vbd->free))); assert(r==now);
591 dbg("now=%u,vbd->free=%u,count=%u\n",now,vbd->free,count);
594 vbdebug(vbd,"vbd->free-e:vbd");
595 if (!count) return(got);
598 dbg("vbs->done=%u\n",vbs->done);
600 assert(!VBEMPTY(vbs));
602 dbg("vbs->done=%d path\n",vbs->done);
603 vbdebug(vbs,"vbs->done-s:vbs");
604 vbdebug(vbd,"vbs->done-s:vbd");
606 vbgrow(vbd,(now=min(count,VBNSIZE(vbs,vbs->f))));
608 assert(vbd->l && vbd->l->size==now && vbd->free==now);
609 r=vbread(vbs,vbd->l->buf,now); assert(r==now);
613 dbg("in vbs->done: count=%d, now=%u\n",count,now);
614 vbdebug(vbs,"vbs->done-e:vbs");
615 vbdebug(vbd,"vbs->done-e:vbd");
616 if (!count) return(got);
619 vbdebug(vbs,"relink:vbs");
620 vbdebug(vbd,"relink:vbd");
621 while (count && VBNSIZEL(vbs,vbs->f)<=count) {
622 struct varbufnode *vbn=vbs->f;
624 if (!(vbs->f=vbn->next)) {
626 count+=(vbd->free=vbs->free);
640 if (!count) return(got);
642 vbdebug(vbs,"final:vbs");
643 vbdebug(vbd,"final:vbd");
645 assert(vbd->l && vbd->l->size>=count && vbd->free==vbd->l->size);
646 vbread(vbs,vbd->l->buf,count);
648 assert(vbd->free>=0);
652 unsigned short vbxsum(struct varbuf *vb)
654 unsigned short xsum=0;
656 struct varbufnode *vbn;
658 vbdebug(vb,"vbxsum");
662 size_t size=VBNSIZEL(vb,vbn);
664 xsum+=(unsigned char)vbn->buf[offs];
670 dbg("vbxsum=%u\n",(unsigned)xsum);
674 char vbremlast(struct varbuf *vb)
676 struct varbufnode *vbn;
678 vbdebug(vb,"vbremlast");
679 if (VBEMPTY(vb)) return(0);
680 assert(vb->l&&vb->free<=vb->l->size);
681 if (vb->free<vb->l->size) {
683 vbdebug(vb,"vbremlast-stdend");
686 assert(vb->f!=vb->l);
687 for (vbn=vb->f;vbn->next!=vb->l;vbn=vbn->next)
694 vbdebug(vb,"vbremlast-blasting-end");
698 void vbdrop(struct varbuf *vb,size_t len)
700 struct varbufnode *vbn;
702 assert(VBCHKSIZE(vb,len));
704 while (vb->f&&vb->done>=VBNSIZEL(vb,vb->f)) {
705 vb->done-=VBNSIZEL(vb,vb->f);
707 if (!(vb->f=vbn->next)) {
714 if (!vb->f) assert(!vb->done&&!vb->free&&!vb->l);
717 void vbgetlinef(struct varbuf *vb,FILE *f)
719 char buf[LOGF_FGETS_BUF],*s;
721 dbg("vbgetlinef(), tell=0x%lx\n",ftell(f));
723 if (!fgets(buf,sizeof(buf),f)) {
724 dbg("vbgetlinef: fgets=NULL\n");
726 FATAL(ERR,"linereading fail: %m");
728 dbg("vbgetlinef: fgets: %s\n",buf);
729 if ((s=strchr(buf,'\n'))) break;
732 vbwrite(vb,buf,s-buf);
733 dbg("vbgetlinef(f), ftell=0x%lx\n",ftell(f));
736 ssize_t vbcopyline(struct varbuf *vbd,struct varbuf *vbs)
739 if ((len=vbchrn(vbs,0,'\n',1))==-1) return(-1);
740 r=vbcopy(vbd,vbs,len); assert(r==len);
745 char vbdropline(struct varbuf *vb)
748 if ((len=vbchrn(vb,0,'\n',1))==-1) return(0);
753 char *vbmemorize(struct varbuf *vb,unsigned flg,size_t *sizep)
755 ssize_t len=vbsize(vb,0),r;
757 if (sizep) *sizep=len;
758 chk(s=malloc(len+!!(flg&VBMEM_ZERO)));
759 r=vbpeek(vb,(flg&VBMEM_REM?-1:0),s,len); assert(r==len);
760 if (flg&VBMEM_ZERO) {
762 fixupnulls(s,len,"vbmemorize");
764 if (flg&VBMEM_REM) assert(VBEMPTY(vb));
768 char *vbstringify(struct varbuf *vb,char rem)
769 { return vbmemorize(vb,VBMEM_ZERO|(rem?VBMEM_REM:0),NULL); }
771 const char *signames[]={
772 "HUP", "INT", "QUIT", "ILL", "TRAP", "ABRT", "IOT", "BUS", "FPE", "KILL",
773 "USR1", "SEGV", "USR2", "PIPE", "ALRM", "TERM", "STKFLT", "CHLD", "CONT",
774 "STOP", "TSTP", "TTIN", "TTOU", "URG", "XCPU", "XFSZ", "VTALRM", "PROF",
775 "WINCH", "IO", "PWR", "UNUSED" };
777 void abortsignal(int signo)
778 { //no reinstall! (deadlock!)
779 #ifdef FATALSIG_INSANE
782 signal(signo,SIG_DFL);
783 dbg("Got signal %d\n",signo);
787 struct varbuf *chat_vbout;
789 char *chat_cmdpars[CHAT_CMD_MAXPARS];
791 static void chatfn_help(void);
793 static const struct chat_cmdtab chat_cmdint[]={
794 {"help" ,0,chatfn_help ,"This help"},
795 {"quit" ,0,chatfn_quit ,"Close connection"},
796 {"exit" ,0,chatfn_quit ,"Close connection"},
799 static void chatfn_help(void)
802 const struct chat_cmdtab *cmd,*cmdt;
804 vbputstring(chat_vbout,"000 Available commands:\n");
806 for (i=0;i<NELEM(chat_cmdint);) {
807 if (cmdt->name) cmd=cmdt++;
808 else cmd=&chat_cmdint[i++];
809 vbprintf(chat_vbout,"000 %-10s[%d] - %s\n",cmd->name,(int)cmd->npars,cmd->help);
811 vbputstring(chat_vbout,"102 Help end.\n");
814 static inline void chat_parsepars(char *s)
819 if (*s) for (*s++='\0';*s&&isspace(*s);s++);
820 for (c=*s;c&&chat_cmdpar<CHAT_CMD_MAXPARS;chat_cmdpar++) {
822 for (chat_cmdpars[chat_cmdpar]=d=s;*s&&(quote||(!quote&&*s!=','));s++) {
823 if (*s=='"'||*s=='\'') {
824 if (quote==*s) { quote=0; continue; }
825 if (!quote) { quote=*s; continue; }
827 if (*s=='\\'&&s[1]) s++;
834 void chat_proccmd(const char *who,char *buf)
838 const struct chat_cmdtab *cmd,*cmdt;
840 for (cmds=buf;*cmds&&isspace(*cmds);cmds++);
841 for (s=cmds;*s&&!isspace(*s);s++);
843 vbputstring(chat_vbout,"104 Empty command.\n");
848 for (i=0;i<NELEM(chat_cmdint);) {
849 if (cmdt->name) cmd=cmdt++;
850 else cmd=&chat_cmdint[i++];
851 assert(cmd->npars<=CHAT_CMD_MAXPARS);
852 if (!strcmp(cmd->name,cmds)) break;
854 if (i<NELEM(chat_cmdint)) {
855 if (cmd->npars!=chat_cmdpar)
856 vbprintf(chat_vbout,"205 %d parameter%s found, %d expected!\n",chat_cmdpar,(chat_cmdpar==1?"":"s"),cmd->npars);
858 vbprintf(chat_vbout,"001 Running command: %s\n",cmds);
859 LOG(DEBUG,"%s is executing user command \"%s\"",who,cmds);
863 else vbprintf(chat_vbout,"206 Unknown command \"%s\"!\n",cmds);
866 void crfilter(char *sr)
870 if (*sr!='\r') *sw++=*sr;
874 static void tzchange(const char *tz)
876 static char *otz=NULL;
880 if ((otz=getenv("TZ"))) chk(otz=strdup(otz));
893 char *gmctime(time_t tm)
900 if ((s=strchr(r,'\n')))
906 unsigned char *bitshuffle(unsigned char *dst,unsigned char dstb,const unsigned char *src,unsigned char srcb,size_t bits,char lr)
908 unsigned char dstrem,*dstp,srcrem,now;
909 const unsigned char *srcp;
911 if (!dst) chk(dst=malloc((bits+dstb-1)/dstb));
912 dstrem=0; dstp=dst-1;
913 srcrem=0; srcp=src-1;
923 dbg("dstrem=%u,srcrem=%u,bits=%u\n",dstrem,srcrem,bits);
924 assert(dstrem&&srcrem);
925 now=min(dstrem,srcrem);
927 dbg("1:*dstp=0x%02x,*srcp=0x%02x,dstrem=%u,srcrem=%u,now=%u\n",*dstp,*srcp,dstrem,srcrem,now);
928 *dstp|=((*srcp>>(lr?srcrem-now:srcb-srcrem))&((1U<<now)-1))<<(lr?dstrem-now:dstb-dstrem);
932 dbg("2:*dstp=0x%02x,*srcp=0x%02x,dstrem=%u,srcrem=%u,now=%u\n",*dstp,*srcp,dstrem,srcrem,now);
937 char *enbase64(char *dst,const unsigned char *src,size_t bits)
941 if (!dst) chk(dst=malloc(((bits+23)/24)*4+1));
942 d=bitshuffle(dst,6,src,8,bits,1); assert(d==dst);
943 d=dst+(bits=(bits+5)/6);
944 for (s=dst;s<d;s++) switch (*s) {
945 case 0 ... 25: *s+='A'- 0; break;
946 case 26 ... 51: *s+='a'-26; break;
947 case 52 ... 61: *s+='0'-52; break;
948 case 62 : *s ='+' ; break;
949 case 63 : *s ='/' ; break;
952 while (bits++%4) *s++='=';
957 unsigned char *debase64(unsigned char *dst,const char *src,size_t *dstlp)
964 chk(src2=alloca(strlen(src))); /* +1 not needed */
965 for (sd=src2,s=src;*s;s++) switch (*s) {
966 case 'A' ... 'Z': *sd++=*s-('A'- 0); break;
967 case 'a' ... 'z': *sd++=*s-('a'-26); break;
968 case '0' ... '9': *sd++=*s-('0'-52); break;
969 case '+' : *sd++= ( 62); break;
970 case '/' : *sd++= ( 63); break;
972 /* only 0, 1 or 2 '='(s) permitted */
973 if (!s[1] || (s[1]=='=' && (!s[2] || (s[2]=='=' && !s[3]))))
976 default: return(NULL);
979 srcl=sd-src2; if ((srcl%4)==1) return(NULL);
981 if (!dst) chk(dst=malloc(dstl));
982 d=bitshuffle(dst,8,src2,6,dstl*8,1); assert(d==dst);
983 if (dstlp) *dstlp=dstl;