util.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C), 2000-2002 by Contributors to the monit codebase. 
00003  * All Rights Reserved.
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License as
00007  * published by the Free Software Foundation; either version 2 of the
00008  * License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful, but
00011  * WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * General Public License for more details.
00014  * 
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software Foundation,
00017  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00018  */
00019 
00020 #include <config.h>
00021 
00022 #include <stdio.h>
00023 #include <stdarg.h>
00024 #include <errno.h>
00025 #include <ctype.h>
00026 #include <signal.h>
00027 #include <time.h>
00028 #include <stdlib.h>
00029 #include <sys/socket.h>
00030 #include <fcntl.h>
00031 
00032 #ifdef HAVE_UNISTD_H
00033 #include <unistd.h>
00034 #endif
00035 
00036 #ifdef HAVE_STRING_H
00037 #include <string.h>
00038 #endif
00039 
00040 #ifdef HAVE_STRINGS_H
00041 #include <strings.h>
00042 #endif
00043 
00044 #ifdef HAVE_SYS_TYPES_H
00045 #include <sys/types.h>
00046 #endif
00047 
00048 #ifdef HAVE_SYS_STAT_H
00049 #include <sys/stat.h>
00050 #endif
00051 
00052 #include "monitor.h"
00053 #include "engine.h"
00054 #include "md5.h"
00055 #include "base64.h"
00056 #include "alert.h"
00057 #include "monit_process.h"
00058 
00059 /* Private prototypes */
00060 static int is_unsafe(unsigned char *c);
00061 static char *is_str_defined(char *);
00062 static char *is_str_defined_default(char *);
00063 
00078 /* ------------------------------------------------------------------ Public */
00079 
00080 
00086 void error(const char *format, ...) {
00087   
00088   char msg[1024];
00089   va_list ap;
00090 
00091   ASSERT(format);
00092   
00093   va_start(ap,format);
00094   vsnprintf(msg, 1024, format, ap);
00095   va_end(ap);
00096   
00097   if(Run.have_tty) {
00098     
00099     fprintf(stderr,"%s", msg);
00100     fflush(stderr);
00101     
00102   } else {
00103     
00104     log("%s", msg);
00105     
00106   }
00107   
00108 }
00109 
00110 
00114 int is_strdefined(char *p) {
00115   
00116   return(p && *p);
00117   
00118 }
00119 
00120 
00126 char *stripfilename(char* path) {
00127   
00128   char *fname;
00129 
00130   ASSERT(path);
00131 
00132   fname= strrchr(path, '/');
00133   
00134   return(fname ? ++fname : path);
00135   
00136 }
00137 
00138 
00143 void chomp(char *string) {
00144   
00145   char *p;
00146 
00147   ASSERT(string);
00148 
00149   if((p= strchr(string, '\r')) || (p= strchr(string, '\n'))) *p= 0;
00150   
00151 }
00152 
00153 
00159 char *trim(char *s) {
00160 
00161   ASSERT(s);
00162   
00163   ltrim(s);
00164   rtrim(s);
00165 
00166   return s;
00167   
00168 }
00169 
00170 
00176 char *ltrim(char *s) {
00177 
00178   char *t= s;
00179 
00180   ASSERT(s);
00181 
00182   while(*t==' ' || *t=='\t' || *t=='\r' || *t=='\n') t++;
00183 
00184   return strcpy(s, t);
00185 
00186 }
00187 
00188 
00194 char *rtrim(char *s) {
00195   
00196   char *t= s;
00197 
00198   ASSERT(s);
00199 
00200   while(*s) s++; 
00201   while(*--s==' ' || *s=='\t' || *s=='\r' || *s=='\n') *s= '\0';
00202 
00203   return t;
00204   
00205 }
00206 
00207 
00214 char *trim_quotes(char *s) {
00215 
00216   char *t= s;
00217   char tmp=0;
00218 
00219   ASSERT(s);
00220 
00221   while(*t==39 || *t==34) {
00222 
00223     tmp=*t;
00224     t++;
00225     break;
00226 
00227   }  
00228 
00229   if(t[strlen(t)-1]==tmp) t[strlen(t)-1]= '\0';
00230 
00231   return strcpy(s, t);
00232 
00233 }
00234 
00235 
00242 int starts_with(char *a, char *b) {
00243 
00244   if((!a || !b) || *a!=*b) return FALSE;
00245 
00246   while(*a && *b) {
00247     
00248     if(*a++ != *b++) return FALSE;
00249     
00250   }
00251 
00252   return TRUE;
00253 
00254 }
00255 
00256 
00262 void handle_string_escapes(char *buf) {
00263 
00264   int editpos;
00265   int insertpos;
00266 
00267   ASSERT(buf);
00268 
00269   for(editpos=insertpos=0; *(buf+editpos)!='\0'; editpos++, insertpos++) {
00270 
00271     if(*(buf+editpos) == '\\' ) {
00272       
00273       switch(*(buf+editpos+1)) {
00274 
00275       case 'n': 
00276         *(buf+insertpos)='\n';
00277         editpos++;
00278     break;
00279 
00280       case 't':
00281         *(buf+insertpos)='\t';
00282         editpos++;
00283     break;
00284 
00285       case 'r':
00286         *(buf+insertpos)='\r';
00287         editpos++;
00288     break;
00289 
00290       case ' ':
00291         *(buf+insertpos)=' ';
00292         editpos++;
00293     break;
00294 
00295       case '\\':
00296         *(buf+insertpos)='\\';
00297         editpos++;
00298     break;
00299 
00300       default:
00301         *(buf+insertpos)=*(buf+editpos);
00302 
00303       }  
00304 
00305     } else {
00306 
00307       *(buf+insertpos)=*(buf+editpos);
00308 
00309     }  
00310 
00311   }
00312   *(buf+insertpos)='\0';
00313 
00314 }
00315 
00316 
00321 Process_T get_process(char *name) {
00322 
00323   Process_T p;
00324 
00325   ASSERT(name);
00326 
00327   for(p= processlist; p; p= p->next) {
00328     if(is(p->name, name)) {
00329       return p;
00330     }
00331   }
00332 
00333   return NULL;
00334 
00335 }
00336 
00337 
00343 int exist_process(char *name) {
00344 
00345   Process_T p;
00346 
00347   ASSERT(name);
00348 
00349   for(p= processlist; p; p= p->next)
00350       if(is(p->name, name))
00351       return TRUE;
00352 
00353   return FALSE;
00354 
00355 }
00356 
00357 
00361 void printrunlist() {
00362   
00363   printf("Runtime constants:\n");
00364   printf(" %-18s = %s\n", "Control file", is_str_defined(Run.controlfile));
00365   printf(" %-18s = %s\n", "Log file", is_str_defined(Run.logfile));
00366   printf(" %-18s = %s\n", "Pid file", is_str_defined(Run.pidfile));
00367   printf(" %-18s = %s\n", "Debug", Run.debug?"True":"False");
00368   printf(" %-18s = %s\n", "Log", Run.dolog?"True":"False");
00369   printf(" %-18s = %s\n", "Use syslog", Run.use_syslog?"True":"False");
00370   printf(" %-18s = %s\n", "Is Daemon", Run.isdaemon?"True":"False");
00371   printf(" %-18s = %s\n", "Use process engine", Run.doprocess?"True":"False");
00372   printf(" %-18s = %d seconds\n", "Poll time", Run.polltime);
00373   printf(" %-18s = %s\n", "Mail server", is_str_defined(Run.mailserver));
00374   printf(" %-18s = %s\n", "Mail from", is_str_defined(Run.MailFormat.from));
00375   printf(" %-18s = %s\n", "Mail subject",
00376      is_str_defined(Run.MailFormat.subject));
00377   printf(" %-18s = %-.20s%s\n", "Mail message",
00378      Run.MailFormat.message?
00379      Run.MailFormat.message:"(not defined)",
00380      Run.MailFormat.message?"..(truncated)":"");
00381      
00382   printf(" %-18s = %s\n", "Start monit httpd", Run.dohttpd?"True":"False");
00383 
00384 
00385   
00386   if(Run.dohttpd) {
00387     
00388     printf(" %-18s = %s\n", "httpd bind address",
00389        Run.bind_addr?Run.bind_addr:"Any/All");
00390     printf(" %-18s = %d\n", "httpd portnumber", Run.httpdport);
00391     printf(" %-18s = %s\n", "Use ssl encryption", Run.httpdssl?"True":"False");
00392 
00393     if(Run.httpdssl) {
00394 
00395       printf(" %-18s = %s\n", "PEM key/cert file", Run.httpsslpem);
00396 
00397       if(Run.httpsslclientpem!=NULL) {
00398     printf(" %-18s = %s\n", "Client cert file", Run.httpsslclientpem);
00399       } else {
00400     printf(" %-18s = %s\n", "Client cert file", "None");
00401       } 
00402 
00403       printf(" %-18s = %s\n", "Allow self certs", 
00404          Run.allowselfcert?"True":"False");
00405 
00406     }
00407 
00408     printf(" %-18s = %s\n", "httpd auth. style",
00409        Run.Auth.defined&&has_hosts_allow()?
00410        "Basic Authentication and Host allow list":
00411        Run.Auth.defined?"Basic Authentication":
00412        has_hosts_allow()?"Host allow list":
00413        "No authentication!");
00414      
00415   }
00416 
00417   printf("\n");
00418   
00419 }
00420 
00421 
00426 void printprocess(Process_T p) {
00427   
00428   Port_T n;
00429   Mail_T r;
00430   Resource_T q;
00431   Checksum_T c;
00432   Timestamp_T t;
00433   Dependant_T d;
00434 
00435   ASSERT(p);
00436  
00437   printf("%-21s = %s\n", "Process Name", p->name);
00438   printf(" %-20s = %s\n", "Group", is_str_defined(p->group));
00439   printf(" %-20s = %s\n", "Pid file", p->pidfile);
00440   printf(" %-20s = %s\n", "Monitoring mode", modenames[p->mode]);
00441   if(p->start)
00442     printf(" %-20s = %s\n", "Start program", is_str_defined(p->start->arg[0]));
00443   if(p->stop)
00444     printf(" %-20s = %s\n", "Stop program", is_str_defined(p->stop->arg[0]));
00445 
00446   for(c= p->checksumlist; c; c= c->next) {
00447     
00448     printf(" %-20s = %s %s\n", "Checksum", c->md5, c->file);
00449     
00450   }
00451 
00452   for(d= p->dependantlist; d; d= d->next)
00453     if(d->dependant != NULL)
00454       printf(" %-20s = %s\n", "Depends on Process", d->dependant);
00455 
00456   if(! p->portlist) {
00457     
00458     printf(" %-20s = (not defined)\n", "Host:Port");
00459     
00460   } else {
00461   
00462     for(n= p->portlist; n; n= n->next) {
00463     
00464       if(n->family == AF_INET) {
00465 
00466     if(n->ssl != NULL) {
00467 
00468       printf(" %-20s = %s:%d%s [protocol %s via SSL]\n", "Host:Port",
00469          n->hostname, n->port, n->request?n->request:"",
00470          n->protocol->name);
00471 
00472       if(n->certmd5 != NULL) {
00473 
00474         printf(" %-20s = %s\n", 
00475            "Server cert md5 sum",
00476            n->certmd5);
00477 
00478       }
00479 
00480     } else {
00481 
00482       printf(" %-20s = %s:%d%s [protocol %s]\n", "Host:Port",
00483          n->hostname, n->port, n->request?n->request:"",
00484          n->protocol->name);
00485 
00486     }
00487 
00488       } else if(n->family == AF_UNIX) {
00489 
00490         printf(" %-20s = %s [protocol %s]\n", "Unix Socket",
00491                n->pathname, n->protocol->name);
00492 
00493       }
00494     
00495     }
00496 
00497   }
00498   
00499   for(t= p->timestamplist; t; t= t->next) {
00500     
00501     printf(" %-20s = if %s %s %d second(s) then %s\n",
00502            "Timestamp",
00503            t->pathname,
00504            operatornames[t->operator],
00505            t->time,
00506            actionnames[t->action]);
00507     
00508   }
00509 
00510   if(! p->resourcelist) {
00511 
00512     printf(" %-20s = (not defined)\n", "Resource Limits");
00513 
00514   } 
00515     
00516   for(q= p->resourcelist; q; q= q->next) {
00517 
00518     switch(q->resource_id) {
00519 
00520     case RESOURCE_ID_CPU_PERCENT: 
00521 
00522       printf(" %-20s = if %s %.1f%% for %d cycle(s) then %s\n", 
00523          "CPU usage limit", 
00524          operatornames[q->operator], 
00525          q->limit/10.0, q->max_cycle, actionnames[q->action]);
00526       break;
00527 
00528     case RESOURCE_ID_MEM_PERCENT: 
00529 
00530       printf(" %-20s = if %s %.1f%% for %d cycle(s) then %s\n", 
00531          "Memory usage limit", 
00532          operatornames[q->operator], q->limit/10.0, q->max_cycle, 
00533          actionnames[q->action]);
00534       break;
00535 
00536     case RESOURCE_ID_MEM_KBYTE: 
00537 
00538       printf(" %-20s = if %s %ldkB for %d cycle(s) then %s\n", 
00539          "Memory amount limit", 
00540          operatornames[q->operator], q->limit, q->max_cycle, 
00541          actionnames[q->action]);
00542       break;
00543 
00544     case RESOURCE_ID_LOAD1: 
00545 
00546       printf(" %-20s = if %s %.1f for %d cycle(s) then %s\n", 
00547          "Load avg. (1min)", 
00548          operatornames[q->operator], q->limit/10.0, q->max_cycle, 
00549          actionnames[q->action]);
00550       break;
00551 
00552     case RESOURCE_ID_LOAD5: 
00553 
00554       printf(" %-20s = if %s %.1f for %d cycle(s) then %s\n", 
00555          "Load avg. (5min)", 
00556          operatornames[q->operator], q->limit/10.0, q->max_cycle, 
00557          actionnames[q->action]);
00558       break;
00559 
00560     case RESOURCE_ID_LOAD15: 
00561 
00562       printf(" %-20s = if %s %.1f for %d cycle(s) then %s\n", 
00563          "Load avg. (15min)", 
00564          operatornames[q->operator], q->limit/10.0, q->max_cycle, 
00565          actionnames[q->action]);
00566       break;
00567 
00568     }    
00569   }
00570 
00571   if(p->def_every)
00572       
00573     printf(" %-20s = Check process every %d cycles\n", "Every", p->every);
00574   
00575   else {
00576     
00577     printf(" %-20s = (not defined)\n", "Every");
00578     
00579   }
00580 
00581   if(p->def_timeout) {
00582     
00583     printf(" %-20s = Do timeout if %d restart within %d cycles\n",
00584        "Timeout", p->to_start, p->to_cycle);
00585     
00586   } else {
00587     
00588     printf(" %-20s = (not defined)\n", "Timeout");
00589     
00590   }
00591 
00592   for(r= p->maillist; r; r= r->next) {
00593     
00594     printf(" %-20s = %s\n", "Alert mail to", is_str_defined(r->to));
00595     printf("   %-18s = %s\n", "alert from", is_str_defined_default(r->from));
00596     printf("   %-18s = %s\n", "alert subject",
00597        is_str_defined_default(r->subject));
00598     printf("   %-18s = %-.20s%s\n", "alert message",
00599        is_str_defined_default(r->message),
00600        r->message?"..":"");
00601     printf("   %-18s = %s\n", "alert on timeout",
00602        r->alert_on_timeout?"yes":"no");
00603     printf("   %-18s = %s\n", "alert on restart",
00604          r->alert_on_restart?"yes":"no");
00605     printf("   %-18s = %s\n", "alert on checksum",
00606        r->alert_on_checksum?"yes":"no");
00607     printf("   %-18s = %s\n", "alert on resource",
00608        r->alert_on_resource?"yes":"no");
00609     printf("   %-18s = %s\n", "alert on stop",
00610        r->alert_on_stop?"yes":"no");
00611     printf("   %-18s = %s\n", "alert on timestamp",
00612        r->alert_on_timestamp?"yes":"no");
00613 
00614   }
00615 
00616   printf("\n");
00617   
00618 }
00619 
00620 
00624 void printprocesslist() {
00625 
00626   Process_T p;
00627   char ruler[STRLEN];
00628   
00629   printf("The process list contains the following entries:\n\n");
00630   
00631   for(p= processlist; p; p= p->next) {
00632     
00633     printprocess(p);
00634     
00635   }
00636 
00637   memset(ruler, '-', STRLEN);
00638   printf("%-.79s\n", ruler);
00639   
00640 }
00641 
00642 
00649 pid_t get_pid(char *pidfile) {
00650   
00651   FILE *file= NULL;
00652   int pid= -1;
00653 
00654   ASSERT(pidfile);
00655 
00656   if(! exist_file(pidfile)) {
00657     
00658     return(FALSE);
00659     
00660   }
00661 
00662   if(! isreg_file(pidfile)) {
00663     
00664     log("%s: pidfile '%s' is not a regular file\n",prog, pidfile);
00665     return(FALSE);
00666     
00667   }
00668   
00669   if((file= fopen(pidfile,"r")) == (FILE *)NULL) {
00670     
00671     log("%s: Error opening the pidfile '%s' -- %s\n",
00672     prog, pidfile, STRERROR);
00673     return(FALSE);
00674     
00675   }
00676 
00677   fscanf(file, "%d", &pid);
00678   fclose(file);
00679 
00680   if(pid == -1) {
00681     
00682     log("%s: pidfile `%s' does not contain a valid pidnumber\n",
00683     prog, pidfile);
00684     
00685     return (FALSE);
00686     
00687   }
00688 
00689   return (pid_t)pid;
00690   
00691 }
00692 
00693 
00698 int is_process_running(Process_T p) {
00699   
00700   pid_t  pid;
00701   int kill_return= 0;
00702 
00703   ASSERT(p);
00704   
00705   errno= 0;
00706 
00707   if((pid= get_pid(p->pidfile))) {
00708     
00709     if((kill_return= getpgid(pid)) > 0 || errno == EPERM)
00710     
00711       return pid;
00712     
00713   }
00714 
00715   return FALSE;
00716   
00717 }
00718 
00719 
00726 char *get_RFC1123date(long *date) {
00727 
00728   struct tm *tm_now;
00729   char D[STRLEN];
00730   time_t now= (date && (*date>0))?*date:time(&now);
00731   long timezone_h;
00732   long timezone_m;
00733   int datelen;
00734 
00735   time(&now);
00736   tzset();
00737   tm_now = localtime(&now);
00738 
00739 #if HAVE_STRUCT_TM_TM_GMTOFF
00740   timezone_h = tm_now->tm_gmtoff/3600;
00741   timezone_m = abs(tm_now->tm_gmtoff/60)%60;
00742 #else
00743   timezone_h = -(timezone/3600)+daylight;
00744   timezone_m = abs(timezone/60)%60;
00745 #endif
00746 
00747   datelen=strftime(D, STRLEN-7, "%a, %d %b %Y %H:%M:%S", tm_now);
00748 
00749   if(! datelen) {
00750 
00751     memset(D, 0, STRLEN);
00752                
00753   } else {
00754    
00755     snprintf(D+datelen, 7, " %+03ld%02ld", timezone_h, timezone_m);
00756 
00757   }
00758 
00759   return xstrdup(D);
00760   
00761 }
00762 
00763 
00768 char *get_ctime() {
00769   
00770   time_t now;
00771   char *buf = (char*)xmalloc(STRLEN);
00772   
00773   time(&now);
00774   snprintf(buf, STRLEN, "%s", ctime(&now));
00775 
00776   chomp(buf);
00777   
00778   return buf;
00779     
00780 }
00781 
00788 char *get_process_uptime(char *pidfile) {
00789 
00790   time_t ctime;
00791 
00792   ASSERT(pidfile);
00793 
00794   if( (ctime= get_timestamp(pidfile, S_IFREG)) ) {
00795     
00796     time_t now= time(&now);
00797     time_t since= now-ctime;
00798 
00799     return get_uptime(since);
00800     
00801   }
00802 
00803   return xstrdup("");
00804   
00805 }
00806 
00807   
00814 char *get_uptime(time_t delta) {
00815 
00816   static int min= 60;
00817   static int hour= 3600;
00818   static int day= 86400;
00819   long rest_d;
00820   long rest_h;
00821   long rest_m;
00822   char buf[STRLEN];
00823   char *p= buf;
00824 
00825   *buf= 0;
00826   
00827   if((rest_d= delta/day)>0) {
00828     p+= sprintf(p, "%ldd ", rest_d);
00829     delta-= rest_d*day;
00830   }
00831   if((rest_h= delta/hour)>0 || (rest_d > 0)) {
00832     p+= sprintf(p, "%ldh ", rest_h);
00833     delta-= rest_h*hour;
00834   }
00835   
00836   rest_m= delta/min;
00837   p+= sprintf(p, "%ldm ", rest_m);
00838   delta-= rest_m*min;
00839 
00840   return xstrdup(buf);
00841 
00842 }
00843 
00844 
00853 int set_md5sum(char **dest, char *file) {
00854 
00855   ASSERT(dest);
00856   ASSERT(file);
00857 
00858   if(! (*dest= get_md5sum(file)))
00859     return FALSE;
00860   
00861   return TRUE;
00862 
00863 }
00864     
00865 
00869 char *get_md5sum(char *file) {
00870 
00871   ASSERT(file);
00872 
00873   if(isreg_file(file)) {
00874     
00875     FILE *f= fopen(file, "r");
00876     
00877     if(f) {
00878       
00879       int i;
00880       unsigned char md5buf[16];
00881       char result[STRLEN];
00882       char *r= result;
00883       
00884       if(md5_stream(f, md5buf)) {
00885     
00886     fclose(f);
00887     
00888     return NULL;
00889     
00890       }
00891       
00892       fclose(f);
00893       
00894       for(i= 0; i < 16; ++i) {
00895     
00896     r+= sprintf(r, "%02x", md5buf[i]);
00897     
00898       }
00899     
00900       return (xstrdup(result));
00901       
00902     }
00903     
00904   }
00905   
00906   return NULL;
00907 
00908 }
00909 
00910 
00918 int check_md5(char *file, char *sum) {
00919 
00920   char *newSum;
00921 
00922   ASSERT(file);
00923   ASSERT(sum);
00924 
00925   newSum= get_md5sum(file);
00926 
00927   if(newSum) {
00928     
00929     int rv;
00930     
00931     rv= (!strncmp(sum, newSum, 31));
00932     free(newSum);
00933     
00934     return (rv);
00935     
00936   }
00937 
00938   return FALSE;
00939   
00940 }
00941 
00942 
00949 char *url_encode(char *uri) {
00950 
00951   static unsigned char hexchars[]= "0123456789ABCDEF";
00952   register int x, y;
00953   unsigned char *str;
00954 
00955   ASSERT(uri);
00956 
00957   str= (unsigned char *)xmalloc(3 * strlen(uri) + 1);
00958 
00959   for(x = 0, y = 0; uri[x]; x++, y++) {
00960 
00961     if(is_unsafe(&uri[x])) {
00962       str[y++] = '%';
00963       str[y++] = hexchars[(unsigned char) uri[x] >> 4];
00964       str[y] = hexchars[(unsigned char) uri[x] & 0xf];
00965     } else str[y]= (unsigned char)uri[x];
00966 
00967   }
00968 
00969   str[y] = '\0';
00970 
00971   return ((char *) str);
00972 
00973 }
00974 
00975 
00981 char *get_basic_authentication_header() {
00982 
00983   if(Run.Auth.defined) {
00984     
00985     char *b64;
00986     char buf[STRLEN];
00987     char *auth= xmalloc(STRLEN+1);
00988     
00989     snprintf(buf, STRLEN, "%s:%s", Run.Auth.uname, Run.Auth.passwd);
00990     encode_base64(&b64, strlen(buf), buf);
00991     snprintf(auth, STRLEN, "Authorization: Basic %s\r\n", b64);
00992     free(b64);
00993     
00994     return auth;
00995 
00996   }
00997       
00998   return xstrdup("\r\n");
00999 
01000 }
01001 
01002 
01009 char *format(const char *s, va_list ap) {
01010 
01011   int n;
01012   int size= STRLEN;
01013   char *buf= xmalloc(size);
01014 
01015   ASSERT(s);
01016     
01017   while(TRUE) {
01018       
01019     n= vsnprintf(buf, size, s, ap);
01020     
01021     if(n > -1 && n < size)
01022         break;
01023     
01024     if(n > -1)
01025         size= n+1;
01026     else
01027         size*= 2;
01028     
01029     buf= xresize(buf, size);
01030     
01031   }
01032   
01033   return buf;
01034 
01035 }
01036 
01037 
01042 void redirect_stdfd() {
01043 
01044   int i;
01045   
01046   Run.have_tty= FALSE;
01047   for(i= 0; i < 3; i++)
01048       if(close(i) == -1 || open("/dev/null", O_RDWR) != i)
01049       error("Cannot reopen standard file descriptor (%d) -- %s\n", i, STRERROR);
01050   
01051 }
01052 
01053 
01054 /* ----------------------------------------------------------------- Private */
01055 
01056 
01061 static char *is_str_defined(char *var) {
01062   
01063   return (is_strdefined(var)?var:"(not defined)");
01064   
01065 }
01066 
01067 
01072 static char *is_str_defined_default(char *var) {
01073 
01074   return (is_strdefined(var)?var:"(default)");
01075 
01076 }
01077 
01078 
01084 static int is_unsafe(unsigned char *c) {
01085 
01086   int i;
01087   static unsigned char unsafe[]= "<>\"#{}|\\^~[]`";
01088 
01089   ASSERT(c);
01090   
01091   if(33>*c || *c>176)
01092       return TRUE;
01093   
01094   if(*c=='%') {
01095     if( isxdigit(*(c + 1)) && isxdigit(*(c + 2)) ) return FALSE;
01096     return TRUE;
01097   }
01098 
01099   for(i=0; unsafe[i]; i++)
01100     if(*c==unsafe[i]) return TRUE;
01101 
01102   return FALSE;
01103 
01104 }
01105