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