]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/libopensrf/utils.c
a3ca2abc769f06432b6de9490a9541ec92d58771
[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 /**
16         @file utils.c
17         
18         @brief A collection of various low-level utility functions.
19         
20         About half of these functions concern the growing_buffer structure,
21         a sort of poor man's string class that allocates more space for
22         itself as needed.
23 */
24 #include <opensrf/utils.h>
25 #include <opensrf/log.h>
26 #include <errno.h>
27
28 /**
29         @brief A thin wrapper for malloc().
30         
31         @param size How many bytes to allocate.
32         @return a pointer to the allocated memory.
33
34         If the allocation fails, safe_malloc calls exit().  Consequently the
35         calling code doesn't have to check for NULL.
36
37         Currently safe_malloc() initializes the allocated buffer to all-bits-zero.
38         However the calling code should not rely on this behavior, because it is
39         likely to change.  If you need your buffer filled with all-bits-zero, then
40         call safe_calloc() instead, or fill it yourself by calling memset().
41 */
42 inline void* safe_malloc( int size ) {
43         void* ptr = (void*) malloc( size );
44         if( ptr == NULL ) {
45                 osrfLogError( OSRF_LOG_MARK, "Out of Memory" );
46                 exit(99);
47         }
48         memset( ptr, 0, size ); // remove this after safe_calloc transition
49         return ptr;
50 }
51
52 /**
53         @brief A thin wrapper for calloc().
54         
55         @param size How many bytes to allocate.
56         @return a pointer to the allocated memory.
57
58         If the allocation fails, safe_calloc calls exit().  Consequently the
59         calling code doesn't have to check for NULL.
60  */
61 inline void* safe_calloc( int size ) {
62         void* ptr = (void*) calloc( 1, size );
63         if( ptr == NULL ) {
64                 osrfLogError( OSRF_LOG_MARK, "Out of Memory" );
65                 exit(99);
66         }
67         return ptr;
68 }
69
70 /**
71         @brief Saves a pointer to the beginning of the argv[] array from main().  See init_proc_title().
72 */
73 static char** global_argv = NULL;
74 /**
75         @brief Saves the length of the argv[] array from main().  See init_proc_title().
76  */
77 static int global_argv_size = 0;
78
79 /**
80         @brief Save the size and location of the argv[] array.
81         @param argc The argc parameter to main().
82         @param argv The argv parameter to main().
83         @return zero.
84
85         Save a pointer to the argv[] array in the local static variable
86         global_argv.  Add up the lengths of the strings in the argv[]
87         array, subtract 2, and store the result in the local variable
88         global_argv_size.
89
90         The return value, being invariant, is useless.
91
92         This function prepares for a subsequent call to set_proc_title().
93 */
94 int init_proc_title( int argc, char* argv[] ) {
95
96         global_argv = argv;
97
98         int i = 0;
99         while( i < argc ) {
100                 int len = strlen( global_argv[i]);
101                 osrf_clearbuf( global_argv[i], len );
102                 global_argv_size += len;
103                 i++;
104         }
105
106         global_argv_size -= 2;
107         return 0;
108 }
109
110 /**
111         @brief Replace the name of the running executable.
112         @param format A printf-style format string.  Subsequent parameters, if any,
113                 provide values to be formatted and inserted into the format string.
114         @return Length of the resulting string (or what the length would be if the
115                 receiving buffer were big enough to hold it), or -1 in case of an encoding
116                 error.  Note: because some older versions of snprintf() don't work correctly,
117                 this function may return -1 if the string is truncated for lack of space.
118
119         Formats a string as directed, and uses it to replace the name of the
120         currently running executable.  This replacement string is what will
121         be seen and reported by utilities such as ps and top.
122
123         The replacement string goes into a location identified by a previous call
124         to init_proc_title().
125
126         WARNING: this function makes assumptions about the memory layout of
127         the argv[] array.  ANSI C does not guarantee that these assumptions
128         are correct.
129 */
130 int set_proc_title( const char* format, ... ) {
131         VA_LIST_TO_STRING(format);
132         osrf_clearbuf( *(global_argv), global_argv_size);
133         return snprintf( *(global_argv), global_argv_size, VA_BUF );
134 }
135
136 /**
137         @brief Determine current date and time to high precision.
138         @return Current date and time as seconds since the Epoch.
139
140         Used for profiling.  The time resolution is system-dependent but is no finer
141         than microseconds.
142 */
143 double get_timestamp_millis( void ) {
144         struct timeval tv;
145         gettimeofday(&tv, NULL);
146         double time     = (int)tv.tv_sec        + ( ((double)tv.tv_usec / 1000000) );
147         return time;
148 }
149
150
151 /**
152         @brief Set designated file status flags for an open file descriptor.
153         @param fd The file descriptor to be tweaked.
154         @param flags A set of bitflags.
155         @return 0 if successful, -1 or if not.
156
157         Whatever bits are set in the flags parameter become set in the file status flags of
158         the file descriptor -- subject to the limitation that the only bits affected (at
159         least on Linux) are O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK.
160
161         See also clr_fl().
162 */
163 int set_fl( int fd, int flags ) {
164         
165         int val;
166
167         if( (val = fcntl( fd, F_GETFL, 0) ) < 0 ) 
168                 return -1;
169
170         val |= flags;
171
172         if( fcntl( fd, F_SETFL, val ) < 0 ) 
173                 return -1;
174
175         return 0;
176 }
177         
178 /**
179         @brief Clear designated file status flags for an open file descriptor.
180         @param fd The file descriptor to be tweaked.
181         @param flags A set of bitflags.
182         @return 0 if successful, or -1 if not.
183
184         Whatever bits are set in the flags parameter become cleared in the file status flags
185         of the file descriptor -- subject to the limitation that the only bits affected (at
186         least on Linux) are O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK.
187
188         See also set_fl().
189  */
190 int clr_fl( int fd, int flags ) {
191         
192         int val;
193
194         if( (val = fcntl( fd, F_GETFL, 0) ) < 0 ) 
195                 return -1;
196
197         val &= ~flags;
198
199         if( fcntl( fd, F_SETFL, val ) < 0 ) 
200                 return -1;
201
202         return 0;
203 }
204
205 /**
206         @brief Determine how lohg a string will be after printf-style formatting.
207         @param format The format string.
208         @param args The variable-length list of arguments
209         @return If successful: the length of the string that would be created, plus 1 for
210                 a terminal nul, plus another 1, presumably to be on the safe side.  If unsuccessful
211                 due to a formatting error: 1.
212
213         WARNINGS: the first parameter is not checked for NULL.  The return value in case of an
214         error is not obviously sensible.
215 */
216 long va_list_size(const char* format, va_list args) {
217         int len = 0;
218         len = vsnprintf(NULL, 0, format, args);
219         va_end(args);
220         return len + 2;
221 }
222
223
224 /**
225         @brief Format a printf-style string into a newly allocated buffer.
226         @param format The format string.  Subsequent parameters, if any, will be
227                 formatted and inserted into the resulting string.
228         @return A pointer to the string so created.
229
230         The calling code is responsible for freeing the string.
231 */
232 char* va_list_to_string(const char* format, ...) {
233
234         long len = 0;
235         va_list args;
236         va_list a_copy;
237
238         va_copy(a_copy, args);
239         va_start(args, format);
240
241         char* buf = safe_malloc( va_list_size(format, args) );
242         *buf = '\0';
243
244         va_start(a_copy, format);
245         vsnprintf(buf, len - 1, format, a_copy);
246         va_end(a_copy);
247         return buf;
248 }
249
250 // ---------------------------------------------------------------------------------
251 // Flesh out a ubiqitous growing string buffer
252 // ---------------------------------------------------------------------------------
253
254 /**
255         @brief Create a growing_buffer containing an empty string.
256         @param num_initial_bytes The initial size of the internal buffer, not counting the
257                 terminal nul.
258         @return A pointer to the newly created growing_buffer.
259
260         The value of num_initial_bytes should typically be a plausible guess of how big
261         the string will ever be.  However the guess doesn't have to accurate, because more
262         memory will be allocated as needed.
263
264         The calling code is responsible for freeing the growing_buffer by calling buffer_free()
265         or buffer_release().
266 */
267 growing_buffer* buffer_init(int num_initial_bytes) {
268
269         if( num_initial_bytes > BUFFER_MAX_SIZE ) return NULL;
270
271         size_t len = sizeof(growing_buffer);
272
273         growing_buffer* gb;
274         OSRF_MALLOC(gb, len);
275
276         gb->n_used = 0;/* nothing stored so far */
277         gb->size = num_initial_bytes;
278         OSRF_MALLOC(gb->buf, gb->size + 1);
279
280         return gb;
281 }
282
283
284 /**
285         @brief Allocate more memory for a growing_buffer.
286         @param gb A pointer to the growing_buffer.
287         @param total_len How much total memory we need for the buffer.
288         @return 0 if successful, or 1 if not.
289
290         This function fails if it is asked to allocate BUFFER_MAX_SIZE
291         or more bytes.
292 */
293 static int buffer_expand( growing_buffer* gb, size_t total_len ) {
294
295         // We do not check to see if the buffer is already big enough.  It is the
296         //responsibility of the calling function to call this only when necessary.
297
298         // Make sure the request is not excessive
299         
300         if( total_len >= BUFFER_MAX_SIZE ) {
301                 fprintf(stderr, "Buffer reached MAX_SIZE of %lu",
302                                 (unsigned long) BUFFER_MAX_SIZE );
303                 buffer_free( gb );
304                 return 1;
305         }
306
307         // Pick a big enough buffer size, but don't exceed a maximum
308         
309         while( total_len >= gb->size ) {
310                 gb->size *= 2;
311         }
312
313         if( gb->size > BUFFER_MAX_SIZE )
314                 gb->size = BUFFER_MAX_SIZE;
315
316         // Allocate and populate the new buffer
317         
318         char* new_data;
319         OSRF_MALLOC( new_data, gb->size );
320         memcpy( new_data, gb->buf, gb->n_used );
321         new_data[ gb->n_used ] = '\0';
322
323         // Replace the old buffer
324         
325         free( gb->buf );
326         gb->buf = new_data;
327         return 0;
328 }
329
330
331 /**
332         @brief Append a formatted string to a growing_buffer.
333         @param gb A pointer to the growing_buffer.
334         @param format A printf-style format string.  Subsequent parameters, if any, will be
335                 formatted and inserted into the resulting string.
336         @return If successful,the length of the resulting string; otherwise -1.
337
338         This function fails if either of the first two parameters is NULL,
339         or if the resulting string requires BUFFER_MAX_SIZE or more bytes.
340 */
341 int buffer_fadd(growing_buffer* gb, const char* format, ... ) {
342
343         if(!gb || !format) return -1; 
344
345         long len = 0;
346         va_list args;
347         va_list a_copy;
348
349         va_copy(a_copy, args);
350
351         va_start(args, format);
352         len = va_list_size(format, args);
353
354         char buf[len];
355         osrf_clearbuf(buf, sizeof(buf));
356
357         va_start(a_copy, format);
358         vsnprintf(buf, len - 1, format, a_copy);
359         va_end(a_copy);
360
361         return buffer_add(gb, buf);
362 }
363
364
365 /**
366         @brief Appends a string to a growing_buffer.
367         @param gb A pointer to the growing_buffer.
368         @param data A pointer to the string to be appended.
369         @return If successful, the length of the resulting string; or if not, -1.
370 */
371 int buffer_add(growing_buffer* gb, const char* data) {
372         if(!(gb && data)) return -1;
373
374         int data_len = strlen( data );
375
376         if(data_len == 0) return gb->n_used;
377
378         int total_len = data_len + gb->n_used;
379
380         if( total_len >= gb->size ) {
381                 if( buffer_expand( gb, total_len ) )
382                         return -1;
383         }
384
385         strcpy( gb->buf + gb->n_used, data );
386         gb->n_used = total_len;
387         return total_len;
388 }
389
390 /**
391         @brief Append a specified number of characters to a growing_buffer.
392         @param gb A pointer to the growing_buffer.
393         @param data A pointer to the characters to be appended.
394         @param n How many characters to be append.
395         @return If sccessful, the length of the resulting string; or if not, -1.
396
397         If the characters to be appended include an embedded nul byte, it will be appended
398         along with the others.  The results are likely to be unpleasant.
399 */
400 int buffer_add_n(growing_buffer* gb, const char* data, size_t n) {
401         if(!(gb && data)) return -1;
402
403         if(n == 0) return 0;
404
405         int total_len = n + gb->n_used;
406
407         if( total_len >= gb->size ) {
408                 if( buffer_expand( gb, total_len ) )
409                         return -1;
410         }
411
412         memcpy( gb->buf + gb->n_used, data, n );
413         gb->buf[total_len] = '\0';
414         gb->n_used = total_len;
415         return total_len;
416 }
417
418
419 /**
420         @brief Reset a growing_buffer so that it contains an empty string.
421         @param gb A pointer to the growing_buffer.
422         @return 0 if successful, -1 if not.
423 */
424 int buffer_reset( growing_buffer *gb){
425         if( gb == NULL ) { return -1; }
426         if( gb->buf == NULL ) { return -1; }
427         osrf_clearbuf( gb->buf, gb->size );
428         gb->n_used = 0;
429         gb->buf[ 0 ] = '\0';
430         return gb->n_used;
431 }
432
433 /**
434         @brief Free a growing_buffer and return a pointer to the string inside.
435         @param gb A pointer to the growing_buffer.
436         @return A pointer to the string previously contained by the growing buffer.
437
438         The calling code is responsible for freeing the string.
439
440         This function is equivalent to buffer_data() followed by buffer_free().  However
441         it is more efficient, because it avoids calls to strudup and free().
442 */
443 char* buffer_release( growing_buffer* gb) {
444         char* s = gb->buf;
445         s[gb->n_used] = '\0';
446         free( gb );
447         return s;
448 }
449
450 /**
451         @brief Free a growing_buffer and its contents.
452         @param gb A pointer to the growing_buffer.
453         @return 1 if successful, or 0 if not (because the input parameter is NULL).
454 */
455 int buffer_free( growing_buffer* gb ) {
456         if( gb == NULL )
457                 return 0;
458         free( gb->buf );
459         free( gb );
460         return 1;
461 }
462
463 /**
464         @brief Create a copy of the string inside a growing_buffer.
465         @param gb A pointer to the growing_buffer.
466         @return A pointer to the newly created copy.
467
468         The growing_buffer itself is not affected.
469
470         The calling code is responsible for freeing the string.
471 */
472 char* buffer_data( const growing_buffer *gb) {
473         return strdup( gb->buf );
474 }
475
476 /**
477         @brief Remove the last character from a growing_buffer.
478         @param gb A pointer to the growing_buffer.
479         @return The character removed (or a nul byte if the string is already empty).
480 */
481 char buffer_chomp(growing_buffer* gb) {
482         char c = '\0';
483     if(gb && gb->n_used > 0) {
484             gb->n_used--;
485                 c = gb->buf[gb->n_used];
486             gb->buf[gb->n_used] = '\0';
487     }
488     return c;
489 }
490
491
492 /**
493         @brief Append a single character to a growing_buffer.
494         @param gb A pointer to the growing_buffer.
495         @param c The character to be appended.
496         @return The length of the resulting string.
497
498         If the character appended is a nul byte it will still be appended as if
499         it were a normal character.  The results are likely to be unpleasant.
500 */
501 int buffer_add_char(growing_buffer* gb, char c ) {
502         if(gb && gb->buf) {
503
504                 int total_len = gb->n_used + 1;
505
506                 if( total_len >= gb->size ) {
507                         if( buffer_expand( gb, total_len ) )
508                                 return -1;
509                 }
510         
511                 gb->buf[ gb->n_used ]   = c;
512                 gb->buf[ ++gb->n_used ] = '\0';
513                 return gb->n_used;
514         } else
515                 return 0;
516 }
517
518
519 /**
520         @brief Translate a UTF8 string into escaped ASCII, suitable for JSON.
521         @param string The input string to be translated.
522         @param size The length of the input string (need not be accurate).
523         @param full_escape Boolean; true turns on the escaping of certain
524                 special characters.
525         @return A pointer to the translated version of the string.
526
527         Deprecated.  Use buffer_append_utf8() instead.
528
529         If full_escape is non-zero, the translation will escape certain
530         certain characters with a backslash, according to the conventions
531         used in C and other languages: quotation marks, bell characters,
532         form feeds, horizontal tabs, carriage returns, line feeds, and
533         backslashes.  A character with a numerical value less than 32, and
534         not one of the special characters mentioned above, will be
535         translated to a backslash followed by four hexadecimal characters.
536
537         If full_escape is zero, the translation will (incorrectly) leave
538         these characters unescaped and unchanged.
539
540         The calling code is responsible for freeing the returned string.
541 */
542 char* uescape( const char* string, int size, int full_escape ) {
543
544         if( NULL == string )
545                 return NULL;
546         
547         growing_buffer* buf = buffer_init(size + 64);
548         int clen = 0;
549         int idx = 0;
550         unsigned long int c = 0x0;
551
552         while (string[idx]) {
553
554                 c = 0x0;
555
556                 if ((unsigned char)string[idx] >= 0x80) { // not ASCII
557
558                         if ((unsigned char)string[idx] >= 0xC0 && (unsigned char)string[idx] <= 0xF4) { // starts a UTF8 string
559
560                                 clen = 1;
561                                 if (((unsigned char)string[idx] & 0xF0) == 0xF0) {
562                                         clen = 3;
563                                         c = (unsigned char)string[idx] ^ 0xF0;
564
565                                 } else if (((unsigned char)string[idx] & 0xE0) == 0xE0) {
566                                         clen = 2;
567                                         c = (unsigned char)string[idx] ^ 0xE0;
568
569                                 } else if (((unsigned char)string[idx] & 0xC0) == 0xC0) {
570                                         clen = 1;
571                                         c = (unsigned char)string[idx] ^ 0xC0;
572                                 }
573
574                                 for (;clen;clen--) {
575
576                                         idx++; // look at the next byte
577                                         c = (c << 6) | ((unsigned char)string[idx] & 0x3F); // add this byte worth
578
579                                 }
580
581                                 buffer_fadd(buf, "\\u%04x", c);
582
583                         } else {
584                                 buffer_free(buf);
585                                 return NULL;
586                         }
587
588                 } else {
589                         c = string[idx];
590
591                         /* escape the usual suspects */
592                         if(full_escape) {
593                                 switch(c) {
594                                         case '"':
595                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
596                                                 OSRF_BUFFER_ADD_CHAR(buf, '"');
597                                                 break;
598         
599                                         case '\b':
600                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
601                                                 OSRF_BUFFER_ADD_CHAR(buf, 'b');
602                                                 break;
603         
604                                         case '\f':
605                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
606                                                 OSRF_BUFFER_ADD_CHAR(buf, 'f');
607                                                 break;
608         
609                                         case '\t':
610                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
611                                                 OSRF_BUFFER_ADD_CHAR(buf, 't');
612                                                 break;
613         
614                                         case '\n':
615                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
616                                                 OSRF_BUFFER_ADD_CHAR(buf, 'n');
617                                                 break;
618         
619                                         case '\r':
620                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
621                                                 OSRF_BUFFER_ADD_CHAR(buf, 'r');
622                                                 break;
623
624                                         case '\\':
625                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
626                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
627                                                 break;
628
629                                         default:
630                                                 if( c < 32 ) buffer_fadd(buf, "\\u%04x", c);
631                                                 else OSRF_BUFFER_ADD_CHAR(buf, c);
632                                 }
633
634                         } else {
635                                 OSRF_BUFFER_ADD_CHAR(buf, c);
636                         }
637                 }
638
639                 idx++;
640         }
641
642         return buffer_release(buf);
643 }
644
645
646 /**
647         @brief Become a proper daemon.
648         @return 0 if successful, or -1 if not.
649
650         Call fork().  The parent exits.  The child moves to the root
651         directory, detaches from the terminal, and redirects the
652         standard streams (stdin, stdout, stderr) to /dev/null.
653 */
654 int daemonize( void ) {
655         pid_t f = fork();
656
657         if (f == -1) {
658                 osrfLogError( OSRF_LOG_MARK, "Failed to fork!" );
659                 return -1;
660
661         } else if (f == 0) { // We're in the child now...
662                 
663                 // Change directories.  Otherwise whatever directory
664                 // we're in couldn't be deleted until the program
665                 // terminated -- possibly causing some inconvenience.
666                 chdir( "/" );
667
668                 /* create new session */
669                 setsid();
670
671                 // Now that we're no longer attached to a terminal,
672                 // we don't want any traffic on the standard streams
673                 freopen( "/dev/null", "r", stdin );
674                 freopen( "/dev/null", "w", stdout );
675                 freopen( "/dev/null", "w", stderr );
676                 
677                 return 0;
678
679         } else { // We're in the parent...
680                 _exit(0);
681         }
682 }
683
684
685 /**
686         @brief Determine whether a string represents a decimal integer.
687         @param s A pointer to the string.
688         @return 1 if the string represents a decimal integer, or 0 if it
689         doesn't.
690
691         To qualify as a decimal integer, the string must consist entirely
692         of optional leading white space, an optional leading sign, and
693         one or more decimal digits.  In addition, the number must be
694         representable as a long.
695 */
696 int stringisnum(const char* s) {
697         char* w;
698         strtol(s, &w, 10);
699         return *w ? 0 : 1;
700 }
701         
702
703
704 /**
705         @brief Translate a printf-style formatted string into an MD5 message digest.
706         @param text The format string.  Subsequent parameters, if any, provide values to be
707                 formatted and inserted into the format string.
708         @return A pointer to a string of 32 hexadecimal characters.
709
710         The calling code is responsible for freeing the returned string.
711
712         This function is a wrapper for some public domain routines written by David Madore,
713         Ron Rivest, and Colin Plumb.
714 */
715 char* md5sum( const char* text, ... ) {
716
717         struct md5_ctx ctx;
718         unsigned char digest[16];
719
720         MD5_start (&ctx);
721
722         VA_LIST_TO_STRING(text);
723
724         int i;
725         for ( i=0 ; i != strlen(VA_BUF) ; i++ )
726                 MD5_feed (&ctx, VA_BUF[i]);
727
728         MD5_stop (&ctx, digest);
729
730         char buf[16];
731         char final[ 1 + 2 * sizeof( digest ) ];
732         final[0] = '\0';
733
734         for ( i=0 ; i<16 ; i++ ) {
735                 snprintf(buf, sizeof(buf), "%02x", digest[i]);
736                 strcat( final, buf );
737         }
738
739         return strdup(final);
740
741 }
742
743 /**
744         @brief Determine whether a given file descriptor is valid.
745         @param fd The file descriptor to be checked.
746         @return 0 if the file descriptor is valid, or -1 if it isn't.
747
748         The most likely reason a file descriptor would be invalid is if it isn't open.
749 */
750 int osrfUtilsCheckFileDescriptor( int fd ) {
751
752         fd_set tmpset;
753         FD_ZERO(&tmpset);
754         FD_SET(fd, &tmpset);
755
756         struct timeval tv;
757         tv.tv_sec = 0;
758         tv.tv_usec = 0;
759
760         if( select(fd + 1, &tmpset, NULL, NULL, &tv) == -1 ) {
761                 if( errno == EBADF ) return -1;
762         }
763
764         return 0;
765 }
766