1 /* Error functions.
2  *
3  * Copyright 2010, Michael Cohen <sucdette@gmail.com>.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #include <string.h>
18 
19 #if !defined( WIN32 )
20 #include <pthread.h>
21 #endif
22 
23 #include "aff4_errors.h"
24 #include "class.h"
25 
26 #define ERROR_BUFF_SIZE 10240
27 
28 // Windows version not truely threadsafe for now
29 #if defined( WIN32 )
30 static char global_error_buffer[ERROR_BUFF_SIZE];
31 static int global_error_type = 0;
32 #else
33 /** These slots carry the TLS error keys */
34 static pthread_key_t error_str_slot;
35 static pthread_once_t error_once = PTHREAD_ONCE_INIT;
36 
37 static pthread_key_t error_value_slot;
38 #endif
39 
40 #if defined( WIN32 )
error_init(void)41 static void error_init(void) {
42   memset(global_error_buffer, 0, sizeof(global_error_buffer));
43 };
44 
45 #else
46 static void error_init(void);
47 
error_dest(void * slot)48 void error_dest(void *slot) {
49   if(slot) talloc_free(slot);
50 };
51 
error_init(void)52 void error_init(void) {
53   // We create the error buffer slots
54   if(pthread_key_create(&error_str_slot, error_dest) ||
55      pthread_key_create(&error_value_slot, error_dest)) {
56     printf("Unable to set up TLS variables\n");
57     abort();
58   };
59 };
60 #endif
61 
aff4_raise_errors(int t,const char * reason,...)62 DLL_PUBLIC void *aff4_raise_errors(int t, const char *reason, ...) {
63   char *error_buffer;
64   char tmp[ERROR_BUFF_SIZE];
65   // This has to succeed:
66   int *type = aff4_get_current_error(&error_buffer);
67 
68   if(reason) {
69     va_list ap;
70     va_start(ap, reason);
71 
72     vsnprintf(tmp, ERROR_BUFF_SIZE-1, reason,ap);
73     tmp[ERROR_BUFF_SIZE-1]=0;
74     va_end(ap);
75   };
76 
77   if(*type == EZero) {
78     *error_buffer = 0;
79 
80     //update the error type
81     *type = t;
82   } else {
83     strncat(error_buffer, "\n", ERROR_BUFF_SIZE -1 );
84   };
85 
86   strncat(error_buffer, tmp, ERROR_BUFF_SIZE-1);
87 
88   return NULL;
89 };
90 
91 #if defined( WIN32 )
aff4_get_current_error(char ** error_buffer)92 DLL_PUBLIC int *aff4_get_current_error(char **error_buffer) {
93   if(error_buffer != NULL) {
94     *error_buffer = global_error_buffer;
95   };
96   return &global_error_type;
97 };
98 
99 #else
aff4_get_current_error(char ** error_buffer)100 DLL_PUBLIC int *aff4_get_current_error(char **error_buffer) {
101   int *type;
102 
103   (void) pthread_once(&error_once, error_init);
104   type = (int *) pthread_getspecific(error_value_slot);
105 
106   // This is optional
107   if(error_buffer != NULL) {
108     *error_buffer = (char *) pthread_getspecific(error_str_slot);
109 
110     // If TLS buffers are not set we need to create them
111     // TODO: the TLS buffers need to be freed on exit.
112     if(*error_buffer == NULL) {
113       *error_buffer = (char *) talloc_size(NULL, ERROR_BUFF_SIZE);
114       pthread_setspecific(error_str_slot, *error_buffer);
115     };
116   };
117 
118   if(!type) {
119     type = (int *) talloc_size(NULL, ERROR_BUFF_SIZE);
120     pthread_setspecific(error_value_slot, type);
121   };
122 
123   return type;
124 };
125 #endif
126