/[monit]/monit/util.c
ViewVC logotype

Contents of /monit/util.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.55 - (show annotations) (download)
Fri Feb 14 08:22:33 2003 UTC (21 years, 3 months ago) by martinp
Branch: MAIN
CVS Tags: release-3-2
Changes since 1.54: +2 -2 lines
File MIME type: text/plain
Change my mail address :)

1 /*
2 * Copyright (C), 2000-2003 by Contributors to the monit codebase.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include <config.h>
21
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <errno.h>
25 #include <ctype.h>
26 #include <signal.h>
27 #include <time.h>
28 #include <stdlib.h>
29 #include <sys/socket.h>
30 #include <fcntl.h>
31
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35
36 #ifdef HAVE_STRING_H
37 #include <string.h>
38 #endif
39
40 #ifdef HAVE_STRINGS_H
41 #include <strings.h>
42 #endif
43
44 #ifdef HAVE_SYS_TYPES_H
45 #include <sys/types.h>
46 #endif
47
48 #ifdef HAVE_SYS_STAT_H
49 #include <sys/stat.h>
50 #endif
51
52 #include "monitor.h"
53 #include "engine.h"
54 #include "md5.h"
55 #include "base64.h"
56 #include "alert.h"
57 #include "monit_process.h"
58
59 /* Private prototypes */
60 static int is_unsafe(unsigned char *c);
61 static char *is_str_defined(char *);
62 static char *is_str_defined_default(char *);
63
64 /**
65 * General purpose utility methods.
66 *
67 * @author Jan-Henrik Haukeland, <hauk@tildeslash.com>
68 * @author "Martin Pala" <martin.pala@iol.cz>
69 * @author Christian Hopp <chopp@iei.tu-clausthal.de>
70 * @author Michael Amster, <mamster@webeasy.com>
71 *
72 * @version \$Id: util.c,v 1.54 2003/02/11 21:27:39 martinp Exp $
73 *
74 * @file
75 */
76
77
78 /* ------------------------------------------------------------------ Public */
79
80
81 /**
82 * Print a formated message to stderr
83 * or to the logfile if no tty exist
84 * @param format A formate (printf-style) string
85 */
86 void error(const char *format, ...) {
87
88 char msg[1024];
89 va_list ap;
90
91 ASSERT(format);
92
93 va_start(ap,format);
94 vsnprintf(msg, 1024, format, ap);
95 va_end(ap);
96
97 if(Run.have_tty) {
98
99 fprintf(stderr,"%s", msg);
100 fflush(stderr);
101
102 } else {
103
104 log("%s", msg);
105
106 }
107
108 }
109
110
111 /**
112 * @return TRUE if the string parameter is defined, otherwise FALSE
113 */
114 int is_strdefined(char *p) {
115
116 return(p && *p);
117
118 }
119
120
121 /**
122 * Strip the path and return only the filename
123 * @param path A file path string
124 * @return the basename
125 */
126 char *stripfilename(char* path) {
127
128 char *fname;
129
130 ASSERT(path);
131
132 fname= strrchr(path, '/');
133
134 return(fname ? ++fname : path);
135
136 }
137
138
139 /**
140 * Removes everything from the first newline (CR|LF)
141 * @param string A string to be chomped
142 */
143 void chomp(char *string) {
144
145 char *p;
146
147 ASSERT(string);
148
149 if((p= strchr(string, '\r')) || (p= strchr(string, '\n'))) *p= 0;
150
151 }
152
153
154 /**
155 * Remove leading and trailing space from the string
156 * @param s A string
157 * @return s with leading and trailing spaces removed
158 */
159 char *trim(char *s) {
160
161 ASSERT(s);
162
163 ltrim(s);
164 rtrim(s);
165
166 return s;
167
168 }
169
170
171 /**
172 * Remove leading white space [ \t\r\n] from the string.
173 * @param s A string
174 * @return s with leading spaces removed
175 */
176 char *ltrim(char *s) {
177
178 char *t= s;
179
180 ASSERT(s);
181
182 while(*t==' ' || *t=='\t' || *t=='\r' || *t=='\n') t++;
183
184 return strcpy(s, t);
185
186 }
187
188
189 /**
190 * Remove trailing white space [ \t\r\n] from the string
191 * @param s A string
192 * @return s with trailing spaces removed
193 */
194 char *rtrim(char *s) {
195
196 char *t= s;
197
198 ASSERT(s);
199
200 while(*s) s++;
201 while(*--s==' ' || *s=='\t' || *s=='\r' || *s=='\n') *s= '\0';
202
203 return t;
204
205 }
206
207
208 /**
209 * Remove any enclosing quotes ["'] from the string
210 * @param s A string
211 * @return s with any enclosed quotes removed
212 */
213
214 char *trim_quotes(char *s) {
215
216 char *t= s;
217 char tmp=0;
218
219 ASSERT(s);
220
221 while(*t==39 || *t==34) {
222
223 tmp=*t;
224 t++;
225 break;
226
227 }
228
229 if(t[strlen(t)-1]==tmp) t[strlen(t)-1]= '\0';
230
231 return strcpy(s, t);
232
233 }
234
235
236 /**
237 * Return TRUE if the string <i>a</i> starts with the string <i>b</i>.
238 * @param a The string to search for b in
239 * @param b The sub-string to test a against
240 * @return TRUE if a starts with b, otherwise FALSE
241 */
242 int starts_with(char *a, char *b) {
243
244 if((!a || !b) || *a!=*b) return FALSE;
245
246 while(*a && *b) {
247
248 if(*a++ != *b++) return FALSE;
249
250 }
251
252 return TRUE;
253
254 }
255
256
257 /**
258 * Exchanges \escape sequences in a string
259 * @param buf A string
260 */
261
262 void handle_string_escapes(char *buf) {
263
264 int editpos;
265 int insertpos;
266
267 ASSERT(buf);
268
269 for(editpos=insertpos=0; *(buf+editpos)!='\0'; editpos++, insertpos++) {
270
271 if(*(buf+editpos) == '\\' ) {
272
273 switch(*(buf+editpos+1)) {
274
275 case 'n':
276 *(buf+insertpos)='\n';
277 editpos++;
278 break;
279
280 case 't':
281 *(buf+insertpos)='\t';
282 editpos++;
283 break;
284
285 case 'r':
286 *(buf+insertpos)='\r';
287 editpos++;
288 break;
289
290 case ' ':
291 *(buf+insertpos)=' ';
292 editpos++;
293 break;
294
295 case '\\':
296 *(buf+insertpos)='\\';
297 editpos++;
298 break;
299
300 default:
301 *(buf+insertpos)=*(buf+editpos);
302
303 }
304
305 } else {
306
307 *(buf+insertpos)=*(buf+editpos);
308
309 }
310
311 }
312 *(buf+insertpos)='\0';
313
314 }
315
316
317 /**
318 * @param name A process name as stated in the config file
319 * @return the named process or NULL if not found
320 */
321 Process_T get_process(char *name) {
322
323 Process_T p;
324
325 ASSERT(name);
326
327 for(p= processlist; p; p= p->next) {
328 if(is(p->name, name)) {
329 return p;
330 }
331 }
332
333 return NULL;
334
335 }
336
337
338 /**
339 * @param name A process name as stated in the config file
340 * @return TRUE if the process name exist in the
341 * processlist, otherwise FALSE
342 */
343 int exist_process(char *name) {
344
345 Process_T p;
346
347 ASSERT(name);
348
349 for(p= processlist; p; p= p->next)
350 if(is(p->name, name))
351 return TRUE;
352
353 return FALSE;
354
355 }
356
357
358 /**
359 * Print the Runtime object
360 */
361 void printrunlist() {
362
363 printf("Runtime constants:\n");
364 printf(" %-18s = %s\n", "Control file", is_str_defined(Run.controlfile));
365 printf(" %-18s = %s\n", "Log file", is_str_defined(Run.logfile));
366 printf(" %-18s = %s\n", "Pid file", is_str_defined(Run.pidfile));
367 printf(" %-18s = %s\n", "Debug", Run.debug?"True":"False");
368 printf(" %-18s = %s\n", "Log", Run.dolog?"True":"False");
369 printf(" %-18s = %s\n", "Use syslog", Run.use_syslog?"True":"False");
370 printf(" %-18s = %s\n", "Is Daemon", Run.isdaemon?"True":"False");
371 printf(" %-18s = %s\n", "Use process engine", Run.doprocess?"True":"False");
372 printf(" %-18s = %d seconds\n", "Poll time", Run.polltime);
373 printf(" %-18s = %s\n", "Mail server", is_str_defined(Run.mailserver));
374 printf(" %-18s = %s\n", "Mail from", is_str_defined(Run.MailFormat.from));
375 printf(" %-18s = %s\n", "Mail subject",
376 is_str_defined(Run.MailFormat.subject));
377 printf(" %-18s = %-.20s%s\n", "Mail message",
378 Run.MailFormat.message?
379 Run.MailFormat.message:"(not defined)",
380 Run.MailFormat.message?"..(truncated)":"");
381
382 printf(" %-18s = %s\n", "Start monit httpd", Run.dohttpd?"True":"False");
383
384
385
386 if(Run.dohttpd) {
387
388 printf(" %-18s = %s\n", "httpd bind address",
389 Run.bind_addr?Run.bind_addr:"Any/All");
390 printf(" %-18s = %d\n", "httpd portnumber", Run.httpdport);
391 printf(" %-18s = %s\n", "Use ssl encryption", Run.httpdssl?"True":"False");
392
393 if(Run.httpdssl) {
394
395 printf(" %-18s = %s\n", "PEM key/cert file", Run.httpsslpem);
396
397 if(Run.httpsslclientpem!=NULL) {
398 printf(" %-18s = %s\n", "Client cert file", Run.httpsslclientpem);
399 } else {
400 printf(" %-18s = %s\n", "Client cert file", "None");
401 }
402
403 printf(" %-18s = %s\n", "Allow self certs",
404 Run.allowselfcert?"True":"False");
405
406 }
407
408 printf(" %-18s = %s\n", "httpd auth. style",
409 Run.Auth.defined&&has_hosts_allow()?
410 "Basic Authentication and Host allow list":
411 Run.Auth.defined?"Basic Authentication":
412 has_hosts_allow()?"Host allow list":
413 "No authentication!");
414
415 }
416
417 printf("\n");
418
419 }
420
421
422 /**
423 * Print a process object
424 * @param p A Process_T object
425 */
426 void printprocess(Process_T p) {
427
428 Port_T n;
429 Mail_T r;
430 Resource_T q;
431 Checksum_T c;
432 Timestamp_T t;
433 Dependant_T d;
434
435 ASSERT(p);
436
437 printf("%-21s = %s\n", "Process Name", p->name);
438 printf(" %-20s = %s\n", "Group", is_str_defined(p->group));
439 printf(" %-20s = %s\n", "Pid file", p->pidfile);
440 printf(" %-20s = %s\n", "Monitoring mode", modenames[p->mode]);
441 if(p->start)
442 printf(" %-20s = %s\n", "Start program", is_str_defined(p->start->arg[0]));
443 if(p->stop)
444 printf(" %-20s = %s\n", "Stop program", is_str_defined(p->stop->arg[0]));
445
446 for(c= p->checksumlist; c; c= c->next) {
447
448 printf(" %-20s = %s %s\n", "Checksum", c->md5, c->file);
449
450 }
451
452 for(d= p->dependantlist; d; d= d->next)
453 if(d->dependant != NULL)
454 printf(" %-20s = %s\n", "Depends on Process", d->dependant);
455
456 if(! p->portlist) {
457
458 printf(" %-20s = (not defined)\n", "Host:Port");
459
460 } else {
461
462 for(n= p->portlist; n; n= n->next) {
463
464 if(n->family == AF_INET) {
465
466 if(n->ssl != NULL) {
467
468 printf(" %-20s = %s:%d%s [protocol %s via SSL]\n", "Host:Port",
469 n->hostname, n->port, n->request?n->request:"",
470 n->protocol->name);
471
472 if(n->certmd5 != NULL) {
473
474 printf(" %-20s = %s\n",
475 "Server cert md5 sum",
476 n->certmd5);
477
478 }
479
480 } else {
481
482 printf(" %-20s = %s:%d%s [protocol %s]\n", "Host:Port",
483 n->hostname, n->port, n->request?n->request:"",
484 n->protocol->name);
485
486 }
487
488 } else if(n->family == AF_UNIX) {
489
490 printf(" %-20s = %s [protocol %s]\n", "Unix Socket",
491 n->pathname, n->protocol->name);
492
493 }
494
495 }
496
497 }
498
499 for(t= p->timestamplist; t; t= t->next) {
500
501 printf(" %-20s = if %s %s %d second(s) then %s\n",
502 "Timestamp",
503 t->pathname,
504 operatornames[t->operator],
505 t->time,
506 actionnames[t->action]);
507
508 }
509
510 if(! p->resourcelist) {
511
512 printf(" %-20s = (not defined)\n", "Resource Limits");
513
514 }
515
516 for(q= p->resourcelist; q; q= q->next) {
517
518 switch(q->resource_id) {
519
520 case RESOURCE_ID_CPU_PERCENT:
521
522 printf(" %-20s = if %s %.1f%% for %d cycle(s) then %s\n",
523 "CPU usage limit",
524 operatornames[q->operator],
525 q->limit/10.0, q->max_cycle, actionnames[q->action]);
526 break;
527
528 case RESOURCE_ID_MEM_PERCENT:
529
530 printf(" %-20s = if %s %.1f%% for %d cycle(s) then %s\n",
531 "Memory usage limit",
532 operatornames[q->operator], q->limit/10.0, q->max_cycle,
533 actionnames[q->action]);
534 break;
535
536 case RESOURCE_ID_MEM_KBYTE:
537
538 printf(" %-20s = if %s %ldkB for %d cycle(s) then %s\n",
539 "Memory amount limit",
540 operatornames[q->operator], q->limit, q->max_cycle,
541 actionnames[q->action]);
542 break;
543
544 case RESOURCE_ID_LOAD1:
545
546 printf(" %-20s = if %s %.1f for %d cycle(s) then %s\n",
547 "Load avg. (1min)",
548 operatornames[q->operator], q->limit/10.0, q->max_cycle,
549 actionnames[q->action]);
550 break;
551
552 case RESOURCE_ID_LOAD5:
553
554 printf(" %-20s = if %s %.1f for %d cycle(s) then %s\n",
555 "Load avg. (5min)",
556 operatornames[q->operator], q->limit/10.0, q->max_cycle,
557 actionnames[q->action]);
558 break;
559
560 case RESOURCE_ID_LOAD15:
561
562 printf(" %-20s = if %s %.1f for %d cycle(s) then %s\n",
563 "Load avg. (15min)",
564 operatornames[q->operator], q->limit/10.0, q->max_cycle,
565 actionnames[q->action]);
566 break;
567
568 }
569 }
570
571 if(p->def_every)
572
573 printf(" %-20s = Check process every %d cycles\n", "Every", p->every);
574
575 else {
576
577 printf(" %-20s = (not defined)\n", "Every");
578
579 }
580
581 if(p->def_timeout) {
582
583 printf(" %-20s = Do timeout if %d restart within %d cycles\n",
584 "Timeout", p->to_start, p->to_cycle);
585
586 } else {
587
588 printf(" %-20s = (not defined)\n", "Timeout");
589
590 }
591
592 for(r= p->maillist; r; r= r->next) {
593
594 printf(" %-20s = %s\n", "Alert mail to", is_str_defined(r->to));
595 printf(" %-18s = %s\n", "alert from", is_str_defined_default(r->from));
596 printf(" %-18s = %s\n", "alert subject",
597 is_str_defined_default(r->subject));
598 printf(" %-18s = %-.20s%s\n", "alert message",
599 is_str_defined_default(r->message),
600 r->message?"..":"");
601 printf(" %-18s = %s\n", "alert on timeout",
602 r->alert_on_timeout?"yes":"no");
603 printf(" %-18s = %s\n", "alert on restart",
604 r->alert_on_restart?"yes":"no");
605 printf(" %-18s = %s\n", "alert on checksum",
606 r->alert_on_checksum?"yes":"no");
607 printf(" %-18s = %s\n", "alert on resource",
608 r->alert_on_resource?"yes":"no");
609 printf(" %-18s = %s\n", "alert on stop",
610 r->alert_on_stop?"yes":"no");
611 printf(" %-18s = %s\n", "alert on timestamp",
612 r->alert_on_timestamp?"yes":"no");
613
614 }
615
616 printf("\n");
617
618 }
619
620
621 /**
622 * Print all the processes in the processlist
623 */
624 void printprocesslist() {
625
626 Process_T p;
627 char ruler[STRLEN];
628
629 printf("The process list contains the following entries:\n\n");
630
631 for(p= processlist; p; p= p->next) {
632
633 printprocess(p);
634
635 }
636
637 memset(ruler, '-', STRLEN);
638 printf("%-.79s\n", ruler);
639
640 }
641
642
643 /**
644 * Open and read the pid from the given pidfile.
645 * @param pidfile A pidfile with full path
646 * @return the pid (TRUE) or FALSE if the pid could
647 * not be read from the file
648 */
649 pid_t get_pid(char *pidfile) {
650
651 FILE *file= NULL;
652 int pid= -1;
653
654 ASSERT(pidfile);
655
656 if(! exist_file(pidfile)) {
657
658 return(FALSE);
659
660 }
661
662 if(! isreg_file(pidfile)) {
663
664 log("%s: pidfile '%s' is not a regular file\n",prog, pidfile);
665 return(FALSE);
666
667 }
668
669 if((file= fopen(pidfile,"r")) == (FILE *)NULL) {
670
671 log("%s: Error opening the pidfile '%s' -- %s\n",
672 prog, pidfile, STRERROR);
673 return(FALSE);
674
675 }
676
677 fscanf(file, "%d", &pid);
678 fclose(file);
679
680 if(pid == -1) {
681
682 log("%s: pidfile `%s' does not contain a valid pidnumber\n",
683 prog, pidfile);
684
685 return (FALSE);
686
687 }
688
689 return (pid_t)pid;
690
691 }
692
693
694 /**
695 * @return TRUE (i.e. the running pid id) if
696 * the process is running, otherwise FALSE
697 */
698 int is_process_running(Process_T p) {
699
700 pid_t pid;
701 int kill_return= 0;
702
703 ASSERT(p);
704
705 errno= 0;
706
707 if((pid= get_pid(p->pidfile))) {
708
709 if((kill_return= getpgid(pid)) > 0 || errno == EPERM)
710
711 return pid;
712
713 }
714
715 memset(p->procinfo, 0, sizeof *(p->procinfo));
716
717 return FALSE;
718
719 }
720
721
722 /**
723 * Returns a (RFC1123) Date string. If the given date
724 * is NULL compute the date now.
725 * @param date
726 * @return a date string alligned with RFC1123
727 */
728 char *get_RFC1123date(long *date) {
729
730 struct tm *tm_now;
731 char D[STRLEN];
732 time_t now= (date && (*date>0))?*date:time(&now);
733 long timezone_h;
734 long timezone_m;
735 int datelen;
736
737 time(&now);
738 tzset();
739 tm_now = localtime(&now);
740
741 #if HAVE_STRUCT_TM_TM_GMTOFF
742 timezone_h = tm_now->tm_gmtoff/3600;
743 timezone_m = abs(tm_now->tm_gmtoff/60)%60;
744 #else
745 timezone_h = -(timezone/3600)+(tm_now->tm_isdst>0);
746 timezone_m = abs(timezone/60)%60;
747 #endif
748
749 datelen=strftime(D, STRLEN-7, "%a, %d %b %Y %H:%M:%S", tm_now);
750
751 if(! datelen) {
752
753 memset(D, 0, STRLEN);
754
755 } else {
756
757 snprintf(D+datelen, 7, " %+03ld%02ld", timezone_h, timezone_m);
758
759 }
760
761 return xstrdup(D);
762
763 }
764
765
766 /**
767 * Get a non \n terminated ctime
768 * @return a ctime string (i.e. date)
769 */
770 char *get_ctime() {
771
772 time_t now;
773 char *buf = (char*)xmalloc(STRLEN);
774
775 time(&now);
776 snprintf(buf, STRLEN, "%s", ctime(&now));
777
778 chomp(buf);
779
780 return buf;
781
782 }
783
784 /**
785 * Compute an uptime string for a process based on the ctime
786 * from the pidfile. The caller must free the returned string.
787 * @param pidfile A process pidfile
788 * @return an uptime string
789 */
790 char *get_process_uptime(char *pidfile) {
791
792 time_t ctime;
793
794 ASSERT(pidfile);
795
796 if( (ctime= get_timestamp(pidfile, S_IFREG)) ) {
797
798 time_t now= time(&now);
799 time_t since= now-ctime;
800
801 return get_uptime(since);
802
803 }
804
805 return xstrdup("");
806
807 }
808
809
810 /**
811 * Compute an uptime string based on the delta time in seconds. The
812 * caller must free the returned string.
813 * @param delta seconds.
814 * @return an uptime string
815 */
816 char *get_uptime(time_t delta) {
817
818 static int min= 60;
819 static int hour= 3600;
820 static int day= 86400;
821 long rest_d;
822 long rest_h;
823 long rest_m;
824 char buf[STRLEN];
825 char *p= buf;
826
827 *buf= 0;
828
829 if((rest_d= delta/day)>0) {
830 p+= sprintf(p, "%ldd ", rest_d);
831 delta-= rest_d*day;
832 }
833 if((rest_h= delta/hour)>0 || (rest_d > 0)) {
834 p+= sprintf(p, "%ldh ", rest_h);
835 delta-= rest_h*hour;
836 }
837
838 rest_m= delta/min;
839 p+= sprintf(p, "%ldm ", rest_m);
840 delta-= rest_m*min;
841
842 return xstrdup(buf);
843
844 }
845
846
847 /**
848 * Compute a md5 checksum for the given file and save the result
849 * in an allocated area pointed to by dest. The caller is responsible
850 * for freeing dest.
851 * @param dest a pointer to an allocated area with the computed md5 sum
852 * @param file The name of file to compute a md5 sum for
853 * @return TRUE if success otherwise FALSE.
854 */
855 int set_md5sum(char **dest, char *file) {
856
857 ASSERT(dest);
858 ASSERT(file);
859
860 if(! (*dest= get_md5sum(file)))
861 return FALSE;
862
863 return TRUE;
864
865 }
866
867
868 /**
869 * @return a md5 checksum for the given file, or NULL if error.
870 */
871 char *get_md5sum(char *file) {
872
873 ASSERT(file);
874
875 if(isreg_file(file)) {
876
877 FILE *f= fopen(file, "r");
878
879 if(f) {
880
881 int i;
882 unsigned char md5buf[16];
883 char result[STRLEN];
884 char *r= result;
885
886 if(md5_stream(f, md5buf)) {
887
888 fclose(f);
889
890 return NULL;
891
892 }
893
894 fclose(f);
895
896 for(i= 0; i < 16; ++i) {
897
898 r+= sprintf(r, "%02x", md5buf[i]);
899
900 }
901
902 return (xstrdup(result));
903
904 }
905
906 }
907
908 return NULL;
909
910 }
911
912
913 /**
914 * @param file A file to open and compute a md5 checksum for
915 * @param sum A previous checksum computed for this file
916 * @return TRUE if computation of md5sum on the given file, is equal
917 * to the given sum, otherwise return FALSE. FALSE is also returned if
918 * md5_stream fails.
919 */
920 int check_md5(char *file, char *sum) {
921
922 char *newSum;
923
924 ASSERT(file);
925 ASSERT(sum);
926
927 newSum= get_md5sum(file);
928
929 if(newSum) {
930
931 int rv;
932
933 rv= (!strncmp(sum, newSum, 31));
934 free(newSum);
935
936 return (rv);
937
938 }
939
940 return FALSE;
941
942 }
943
944
945 /**
946 * Escape an uri string converting unsafe characters to a hex (%xx)
947 * representation. The caller must free the returned string.
948 * @param uri an uri string
949 * @return the escaped string
950 */
951 char *url_encode(char *uri) {
952
953 static unsigned char hexchars[]= "0123456789ABCDEF";
954 register int x, y;
955 unsigned char *str;
956
957 ASSERT(uri);
958
959 str= (unsigned char *)xmalloc(3 * strlen(uri) + 1);
960
961 for(x = 0, y = 0; uri[x]; x++, y++) {
962
963 if(is_unsafe(&uri[x])) {
964 str[y++] = '%';
965 str[y++] = hexchars[(unsigned char) uri[x] >> 4];
966 str[y] = hexchars[(unsigned char) uri[x] & 0xf];
967 } else str[y]= (unsigned char)uri[x];
968
969 }
970
971 str[y] = '\0';
972
973 return ((char *) str);
974
975 }
976
977
978 /**
979 * @return a Basic Authentication Authorization string (RFC 2617),
980 * with credentials from the Run object, The string "\r\n" if
981 * credentials are not defined.
982 */
983 char *get_basic_authentication_header() {
984
985 if(Run.Auth.defined) {
986
987 char *b64;
988 char buf[STRLEN];
989 char *auth= xmalloc(STRLEN+1);
990
991 snprintf(buf, STRLEN, "%s:%s", Run.Auth.uname, Run.Auth.passwd);
992 encode_base64(&b64, strlen(buf), buf);
993 snprintf(auth, STRLEN, "Authorization: Basic %s\r\n", b64);
994 free(b64);
995
996 return auth;
997
998 }
999
1000 return xstrdup("\r\n");
1001
1002 }
1003
1004
1005 /**
1006 * Do printf style format line parsing
1007 * @param s format string
1008 * @param ap variable argument list
1009 * @return buffer with parsed string
1010 */
1011 char *format(const char *s, va_list ap) {
1012
1013 int n;
1014 int size= STRLEN;
1015 char *buf= xmalloc(size);
1016
1017 ASSERT(s);
1018
1019 while(TRUE) {
1020
1021 n= vsnprintf(buf, size, s, ap);
1022
1023 if(n > -1 && n < size)
1024 break;
1025
1026 if(n > -1)
1027 size= n+1;
1028 else
1029 size*= 2;
1030
1031 buf= xresize(buf, size);
1032
1033 }
1034
1035 return buf;
1036
1037 }
1038
1039
1040 /**
1041 * Redirect the standard file descriptors to /dev/null and route any
1042 * error messages to the log file.
1043 */
1044 void redirect_stdfd() {
1045
1046 int i;
1047
1048 Run.have_tty= FALSE;
1049 for(i= 0; i < 3; i++)
1050 if(close(i) == -1 || open("/dev/null", O_RDWR) != i)
1051 error("Cannot reopen standard file descriptor (%d) -- %s\n", i, STRERROR);
1052
1053 }
1054
1055
1056 /* ----------------------------------------------------------------- Private */
1057
1058
1059 /**
1060 * Returns the value of the variable if defined or the String
1061 * "(not defined)"
1062 */
1063 static char *is_str_defined(char *var) {
1064
1065 return (is_strdefined(var)?var:"(not defined)");
1066
1067 }
1068
1069
1070 /**
1071 * Returns the value of the variable if defined or the String
1072 * "(default)"
1073 */
1074 static char *is_str_defined_default(char *var) {
1075
1076 return (is_strdefined(var)?var:"(default)");
1077
1078 }
1079
1080
1081 /**
1082 * Returns TRUE if the given char is url unsafe
1083 * @param c A unsigned char
1084 * @return TRUE if the char is in the set of unsafe URL Characters
1085 */
1086 static int is_unsafe(unsigned char *c) {
1087
1088 int i;
1089 static unsigned char unsafe[]= "<>\"#{}|\\^~[]`";
1090
1091 ASSERT(c);
1092
1093 if(33>*c || *c>176)
1094 return TRUE;
1095
1096 if(*c=='%') {
1097 if( isxdigit(*(c + 1)) && isxdigit(*(c + 2)) ) return FALSE;
1098 return TRUE;
1099 }
1100
1101 for(i=0; unsafe[i]; i++)
1102 if(*c==unsafe[i]) return TRUE;
1103
1104 return FALSE;
1105
1106 }
1107

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26