908145b91772e7e1dd00d0a43ee78b9bc1c615f8
[OpenSRF.git] / src / libopensrf / utils.c
1 /*
2 Copyright (C) 2005  Georgia Public Library Service 
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13 */
14
15 #include <opensrf/utils.h>
16 #include <opensrf/log.h>
17 #include <errno.h>
18
19 inline void* safe_malloc( int size ) {
20         void* ptr = (void*) malloc( size );
21         if( ptr == NULL ) {
22                 osrfLogError( OSRF_LOG_MARK, "Out of Memory" );
23                 exit(99);
24         }
25         memset( ptr, 0, size );
26         return ptr;
27 }
28
29 /****************
30  The following static variables, and the following two functions,
31  overwrite the argv array passed to main().  The purpose is to
32  change the program name as reported by ps and similar utilities.
33
34  Warning: this code makes the non-portable assumption that the
35  strings to which argv[] points are contiguous in memory.  The
36  C Standard makes no such guarantee.
37  ****************/
38 static char** global_argv = NULL;
39 static int global_argv_size = 0;
40
41 int init_proc_title( int argc, char* argv[] ) {
42
43         global_argv = argv;
44
45         int i = 0;
46         while( i < argc ) {
47                 int len = strlen( global_argv[i]);
48                 bzero( global_argv[i++], len );
49                 global_argv_size += len;
50         }
51
52         global_argv_size -= 2;
53         return 0;
54 }
55
56 int set_proc_title( char* format, ... ) {
57         VA_LIST_TO_STRING(format);
58         bzero( *(global_argv), global_argv_size );
59         return snprintf( *(global_argv), global_argv_size, VA_BUF );
60 }
61
62
63 /* utility method for profiling */
64 double get_timestamp_millis() {
65         struct timeval tv;
66         gettimeofday(&tv, NULL);
67         double time     = (int)tv.tv_sec        + ( ((double)tv.tv_usec / 1000000) );
68         return time;
69 }
70
71
72 /* setting/clearing file flags */
73 int set_fl( int fd, int flags ) {
74         
75         int val;
76
77         if( (val = fcntl( fd, F_GETFL, 0) ) < 0 ) 
78                 return -1;
79
80         val |= flags;
81
82         if( fcntl( fd, F_SETFL, val ) < 0 ) 
83                 return -1;
84
85         return 0;
86 }
87         
88 int clr_fl( int fd, int flags ) {
89         
90         int val;
91
92         if( (val = fcntl( fd, F_GETFL, 0) ) < 0 ) 
93                 return -1;
94
95         val &= ~flags;
96
97         if( fcntl( fd, F_SETFL, val ) < 0 ) 
98                 return -1;
99
100         return 0;
101 }
102
103 long va_list_size(const char* format, va_list args) {
104         int len = 0;
105         len = vsnprintf(NULL, 0, format, args);
106         va_end(args);
107         len += 2;
108         return len;
109 }
110
111
112 char* va_list_to_string(const char* format, ...) {
113
114         long len = 0;
115         va_list args;
116         va_list a_copy;
117
118         va_copy(a_copy, args);
119
120         va_start(args, format);
121         len = va_list_size(format, args);
122
123         char buf[len];
124         memset(buf, 0, len);
125
126         va_start(a_copy, format);
127         vsnprintf(buf, len - 1, format, a_copy);
128         va_end(a_copy);
129         return strdup(buf);
130 }
131
132 // ---------------------------------------------------------------------------------
133 // Flesh out a ubiqitous growing string buffer
134 // ---------------------------------------------------------------------------------
135
136 growing_buffer* buffer_init(int num_initial_bytes) {
137
138         if( num_initial_bytes > BUFFER_MAX_SIZE ) return NULL;
139
140         size_t len = sizeof(growing_buffer);
141
142         growing_buffer* gb;
143         OSRF_MALLOC(gb, len);
144
145         gb->n_used = 0;/* nothing stored so far */
146         gb->size = num_initial_bytes;
147         OSRF_MALLOC(gb->buf, gb->size + 1);
148
149         return gb;
150 }
151
152
153 int buffer_fadd(growing_buffer* gb, const char* format, ... ) {
154
155         if(!gb || !format) return 0; 
156
157         long len = 0;
158         va_list args;
159         va_list a_copy;
160
161         va_copy(a_copy, args);
162
163         va_start(args, format);
164         len = va_list_size(format, args);
165
166         char buf[len];
167         memset(buf, 0, len);
168
169         va_start(a_copy, format);
170         vsnprintf(buf, len - 1, format, a_copy);
171         va_end(a_copy);
172
173         return buffer_add(gb, buf);
174
175 }
176
177
178 int buffer_add(growing_buffer* gb, char* data) {
179         if(!(gb && data)) return 0;
180
181         int data_len = strlen( data );
182
183         if(data_len == 0) return 0;
184
185         int total_len = data_len + gb->n_used;
186
187         if( total_len >= gb->size ) {
188                 while( total_len >= gb->size ) {
189                         gb->size *= 2;
190                 }
191         
192                 if( gb->size > BUFFER_MAX_SIZE ) {
193                         osrfLogError( OSRF_LOG_MARK, "Buffer reached MAX_SIZE of %d", BUFFER_MAX_SIZE );
194                         buffer_free( gb );
195                         return 0;
196                 }
197         
198                 char* new_data;
199                 OSRF_MALLOC(new_data, gb->size );
200         
201                 strcpy( new_data, gb->buf );
202                 free( gb->buf );
203                 gb->buf = new_data;
204         }
205
206         strcat( gb->buf, data );
207         gb->n_used = total_len;
208         return total_len;
209 }
210
211
212 int buffer_reset( growing_buffer *gb){
213         if( gb == NULL ) { return 0; }
214         if( gb->buf == NULL ) { return 0; }
215         memset( gb->buf, 0, gb->size );
216         gb->n_used = 0;
217         return 1;
218 }
219
220 /* Return a pointer to the text within a growing_buffer, */
221 /* while destroying the growing_buffer itself.           */
222
223 char* buffer_release( growing_buffer* gb) {
224         char* s = gb->buf;
225         s[gb->n_used] = '\0';
226         free( gb );
227         return s;
228 }
229
230 /* Destroy a growing_buffer and the text it contains */
231
232 int buffer_free( growing_buffer* gb ) {
233         if( gb == NULL ) 
234                 return 0;
235         free( gb->buf );
236         free( gb );
237         return 1;
238 }
239
240 char* buffer_data( growing_buffer *gb) {
241         return strdup( gb->buf );
242 }
243
244
245 /*
246 #define OSRF_BUFFER_ADD_CHAR(gb, c)\
247         do {\
248                 if(gb) {\
249                         if(gb->n_used < gb->size - 1)\
250                                 gb->buf[gb->n_used++] = c;\
251                         else\
252                                 buffer_add_char(gb, c);\
253                 }\
254         }while(0)
255         */
256
257 int buffer_add_char(growing_buffer* gb, char c) {
258         char buf[2];
259         buf[0] = c;
260         buf[1] = '\0';
261         buffer_add(gb, buf);
262         return 1;
263 }
264
265
266
267 char* uescape( const char* string, int size, int full_escape ) {
268
269         growing_buffer* buf = buffer_init(size + 64);
270         int clen = 0;
271         int idx = 0;
272         unsigned long int c = 0x0;
273
274         while (string[idx]) {
275
276                 c = 0x0;
277
278                 if ((unsigned char)string[idx] >= 0x80) { // not ASCII
279
280                         if ((unsigned char)string[idx] >= 0xC0 && (unsigned char)string[idx] <= 0xF4) { // starts a UTF8 string
281
282                                 clen = 1;
283                                 if (((unsigned char)string[idx] & 0xF0) == 0xF0) {
284                                         clen = 3;
285                                         c = (unsigned char)string[idx] ^ 0xF0;
286
287                                 } else if (((unsigned char)string[idx] & 0xE0) == 0xE0) {
288                                         clen = 2;
289                                         c = (unsigned char)string[idx] ^ 0xE0;
290
291                                 } else if (((unsigned char)string[idx] & 0xC0) == 0xC0) {
292                                         clen = 1;
293                                         c = (unsigned char)string[idx] ^ 0xC0;
294                                 }
295
296                                 for (;clen;clen--) {
297
298                                         idx++; // look at the next byte
299                                         c = (c << 6) | ((unsigned char)string[idx] & 0x3F); // add this byte worth
300
301                                 }
302
303                                 buffer_fadd(buf, "\\u%04x", c);
304
305                         } else {
306                                 buffer_free(buf);
307                                 return NULL;
308                         }
309
310                 } else {
311                         c = string[idx];
312
313                         /* escape the usual suspects */
314                         if(full_escape) {
315                                 switch(c) {
316                                         case '"':
317                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
318                                                 OSRF_BUFFER_ADD_CHAR(buf, '"');
319                                                 break;
320         
321                                         case '\b':
322                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
323                                                 OSRF_BUFFER_ADD_CHAR(buf, 'b');
324                                                 break;
325         
326                                         case '\f':
327                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
328                                                 OSRF_BUFFER_ADD_CHAR(buf, 'f');
329                                                 break;
330         
331                                         case '\t':
332                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
333                                                 OSRF_BUFFER_ADD_CHAR(buf, 't');
334                                                 break;
335         
336                                         case '\n':
337                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
338                                                 OSRF_BUFFER_ADD_CHAR(buf, 'n');
339                                                 break;
340         
341                                         case '\r':
342                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
343                                                 OSRF_BUFFER_ADD_CHAR(buf, 'r');
344                                                 break;
345
346                                         case '\\':
347                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
348                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
349                                                 break;
350
351                                         default:
352                                                 if( c < 32 ) buffer_fadd(buf, "\\u%04x", c);
353                                                 else OSRF_BUFFER_ADD_CHAR(buf, c);
354                                 }
355
356                         } else {
357                                 OSRF_BUFFER_ADD_CHAR(buf, c);
358                         }
359                 }
360
361                 idx++;
362         }
363
364         char* d = buffer_data(buf);
365         buffer_free(buf);
366         return d;
367 }
368
369
370 // A function to turn a process into a daemon 
371 int daemonize() {
372         pid_t f = fork();
373
374         if (f == -1) {
375                 osrfLogError( OSRF_LOG_MARK, "Failed to fork!" );
376                 return -1;
377
378         } else if (f == 0) { // We're in the child now...
379                 
380                 // Change directories.  Otherwise whatever directory
381                 // we're in couldn't be deleted until the program
382                 // terminated -- possibly causing some inconvenience.
383                 chdir( "/" );
384
385                 /* create new session */
386                 setsid();
387
388                 // Now that we're no longer attached to a terminal,
389                 // we don't want any traffic on the standard streams
390                 freopen( "/dev/null", "r", stdin );
391                 freopen( "/dev/null", "w", stdout );
392                 freopen( "/dev/null", "w", stderr );
393                 
394                 return 0;
395
396         } else { // We're in the parent...
397                 _exit(0);
398         }
399 }
400
401
402 /* Return 1 if the string represents an integer,  */
403 /* as recognized by strtol(); Otherwise return 0. */
404
405 int stringisnum(char* s) {
406         char* w;
407         strtol(s, &w, 10);
408         return *w ? 0 : 1;
409 }
410         
411
412
413 char* file_to_string(const char* filename) {
414
415         if(!filename) return NULL;
416
417         int len = 1024;
418         char buf[len];
419         bzero(buf, len);
420         growing_buffer* gb = buffer_init(len);
421
422         FILE* file = fopen(filename, "r");
423         if(!file) {
424                 osrfLogError( OSRF_LOG_MARK, "Unable to open file [%s]", filename );
425                 return NULL;
426         }
427
428         while(fgets(buf, len - 1, file)) {
429                 buffer_add(gb, buf);
430                 bzero(buf, len);
431         }
432
433         fclose(file);
434
435         char* data = buffer_data(gb);
436         buffer_free(gb);
437         return data;
438 }
439
440
441 char* md5sum( char* text, ... ) {
442
443         struct md5_ctx ctx;
444         unsigned char digest[16];
445
446         MD5_start (&ctx);
447
448         VA_LIST_TO_STRING(text);
449
450         int i;
451         for ( i=0 ; i != strlen(VA_BUF) ; i++ )
452                 MD5_feed (&ctx, VA_BUF[i]);
453
454         MD5_stop (&ctx, digest);
455
456         char buf[16];
457         memset(buf,0,16);
458
459         char final[256];
460         memset(final,0,256);
461
462         for ( i=0 ; i<16 ; i++ ) {
463                 sprintf(buf, "%02x", digest[i]);
464                 strcat( final, buf );
465         }
466
467         return strdup(final);
468
469 }
470
471 int osrfUtilsCheckFileDescriptor( int fd ) {
472
473         fd_set tmpset;
474         FD_ZERO(&tmpset);
475         FD_SET(fd, &tmpset);
476
477         struct timeval tv;
478         tv.tv_sec = 0;
479         tv.tv_usec = 0;
480
481         if( select(fd + 1, &tmpset, NULL, NULL, &tv) == -1 ) {
482                 if( errno == EBADF ) return -1;
483         }
484
485         return 0;
486 }
487