Imported Upstream version 2.1.2
[platform/upstream/cups.git] / cups / globals.c
1 /*
2  * "$Id: globals.c 12480 2015-02-03 12:36:34Z msweet $"
3  *
4  *   Global variable access routines for CUPS.
5  *
6  *   Copyright 2007-2013 by Apple Inc.
7  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
8  *
9  *   These coded instructions, statements, and computer programs are the
10  *   property of Apple Inc. and are protected by Federal copyright
11  *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
12  *   which should have been included with this file.  If this file is
13  *   file is missing or damaged, see the license at "http://www.cups.org/".
14  *
15  *   This file is subject to the Apple OS-Developed Software exception.
16  *
17  * Contents:
18  *
19  *   _cupsGlobalLock()    - Lock the global mutex.
20  *   _cupsGlobals()       - Return a pointer to thread local storage
21  *   _cupsGlobalUnlock()  - Unlock the global mutex.
22  *   DllMain()            - Main entry for library.
23  *   cups_fix_path()      - Fix a file path to use forward slashes consistently.
24  *   cups_globals_alloc() - Allocate and initialize global data.
25  *   cups_globals_free()  - Free global data.
26  *   cups_globals_init()  - Initialize environment variables.
27  */
28
29 /*
30  * Include necessary headers...
31  */
32
33 #include "cups-private.h"
34
35
36 /*
37  * Local globals...
38  */
39
40
41 #ifdef DEBUG
42 static int              cups_global_index = 0;
43                                         /* Next thread number */
44 #endif /* DEBUG */
45 static _cups_threadkey_t cups_globals_key = _CUPS_THREADKEY_INITIALIZER;
46                                         /* Thread local storage key */
47 #ifdef HAVE_PTHREAD_H
48 static pthread_once_t   cups_globals_key_once = PTHREAD_ONCE_INIT;
49                                         /* One-time initialization object */
50 #endif /* HAVE_PTHREAD_H */
51 #if defined(HAVE_PTHREAD_H) || defined(WIN32)
52 static _cups_mutex_t    cups_global_mutex = _CUPS_MUTEX_INITIALIZER;
53                                         /* Global critical section */
54 #endif /* HAVE_PTHREAD_H || WIN32 */
55
56
57 /*
58  * Local functions...
59  */
60
61 #ifdef WIN32
62 static void             cups_fix_path(char *path);
63 #endif /* WIN32 */
64 static _cups_globals_t  *cups_globals_alloc(void);
65 #if defined(HAVE_PTHREAD_H) || defined(WIN32)
66 static void             cups_globals_free(_cups_globals_t *g);
67 #endif /* HAVE_PTHREAD_H || WIN32 */
68 #ifdef HAVE_PTHREAD_H
69 static void             cups_globals_init(void);
70 #endif /* HAVE_PTHREAD_H */
71
72
73 /*
74  * '_cupsGlobalLock()' - Lock the global mutex.
75  */
76
77 void
78 _cupsGlobalLock(void)
79 {
80 #ifdef HAVE_PTHREAD_H
81   pthread_mutex_lock(&cups_global_mutex);
82 #elif defined(WIN32)
83   EnterCriticalSection(&cups_global_mutex.m_criticalSection);
84 #endif /* HAVE_PTHREAD_H */
85 }
86
87
88 /*
89  * '_cupsGlobals()' - Return a pointer to thread local storage
90  */
91
92 _cups_globals_t *                       /* O - Pointer to global data */
93 _cupsGlobals(void)
94 {
95   _cups_globals_t *cg;                  /* Pointer to global data */
96
97
98 #ifdef HAVE_PTHREAD_H
99  /*
100   * Initialize the global data exactly once...
101   */
102
103   pthread_once(&cups_globals_key_once, cups_globals_init);
104 #endif /* HAVE_PTHREAD_H */
105
106  /*
107   * See if we have allocated the data yet...
108   */
109
110   if ((cg = (_cups_globals_t *)_cupsThreadGetData(cups_globals_key)) == NULL)
111   {
112    /*
113     * No, allocate memory as set the pointer for the key...
114     */
115
116     if ((cg = cups_globals_alloc()) != NULL)
117       _cupsThreadSetData(cups_globals_key, cg);
118   }
119
120  /*
121   * Return the pointer to the data...
122   */
123
124   return (cg);
125 }
126
127
128 /*
129  * '_cupsGlobalUnlock()' - Unlock the global mutex.
130  */
131
132 void
133 _cupsGlobalUnlock(void)
134 {
135 #ifdef HAVE_PTHREAD_H
136   pthread_mutex_unlock(&cups_global_mutex);
137 #elif defined(WIN32)
138   LeaveCriticalSection(&cups_global_mutex.m_criticalSection);
139 #endif /* HAVE_PTHREAD_H */
140 }
141
142
143 #ifdef WIN32
144 /*
145  * 'DllMain()' - Main entry for library.
146  */
147
148 BOOL WINAPI                             /* O - Success/failure */
149 DllMain(HINSTANCE hinst,                /* I - DLL module handle */
150         DWORD     reason,               /* I - Reason */
151         LPVOID    reserved)             /* I - Unused */
152 {
153   _cups_globals_t *cg;                  /* Global data */
154
155
156   (void)hinst;
157   (void)reserved;
158
159   switch (reason)
160   {
161     case DLL_PROCESS_ATTACH :           /* Called on library initialization */
162         InitializeCriticalSection(&cups_global_mutex.m_criticalSection);
163
164         if ((cups_globals_key = TlsAlloc()) == TLS_OUT_OF_INDEXES)
165           return (FALSE);
166         break;
167
168     case DLL_THREAD_DETACH :            /* Called when a thread terminates */
169         if ((cg = (_cups_globals_t *)TlsGetValue(cups_globals_key)) != NULL)
170           cups_globals_free(cg);
171         break;
172
173     case DLL_PROCESS_DETACH :           /* Called when library is unloaded */
174         if ((cg = (_cups_globals_t *)TlsGetValue(cups_globals_key)) != NULL)
175           cups_globals_free(cg);
176
177         TlsFree(cups_globals_key);
178         DeleteCriticalSection(&cups_global_mutex.m_criticalSection);
179         break;
180
181     default:
182         break;
183   }
184
185   return (TRUE);
186 }
187 #endif /* WIN32 */
188
189
190 /*
191  * 'cups_globals_alloc()' - Allocate and initialize global data.
192  */
193
194 static _cups_globals_t *                /* O - Pointer to global data */
195 cups_globals_alloc(void)
196 {
197   _cups_globals_t *cg = malloc(sizeof(_cups_globals_t));
198                                         /* Pointer to global data */
199 #ifdef WIN32
200   HKEY          key;                    /* Registry key */
201   DWORD         size;                   /* Size of string */
202   static char   installdir[1024] = "",  /* Install directory */
203                 confdir[1024] = "",     /* Server root directory */
204                 localedir[1024] = "";   /* Locale directory */
205 #endif /* WIN32 */
206
207
208   if (!cg)
209     return (NULL);
210
211  /*
212   * Clear the global storage and set the default encryption and password
213   * callback values...
214   */
215
216   memset(cg, 0, sizeof(_cups_globals_t));
217   cg->encryption     = (http_encryption_t)-1;
218   cg->password_cb    = (cups_password_cb2_t)_cupsGetPassword;
219   cg->any_root       = -1;
220   cg->expired_certs  = -1;
221   cg->validate_certs = -1;
222
223 #ifdef DEBUG
224  /*
225   * Friendly thread ID for debugging...
226   */
227
228   cg->thread_id = ++ cups_global_index;
229 #endif /* DEBUG */
230
231  /*
232   * Then set directories as appropriate...
233   */
234
235 #ifdef WIN32
236   if (!installdir[0])
237   {
238    /*
239     * Open the registry...
240     */
241
242     strlcpy(installdir, "C:/Program Files/cups.org", sizeof(installdir));
243
244     if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\cups.org", 0, KEY_READ,
245                       &key))
246     {
247      /*
248       * Grab the installation directory...
249       */
250
251       char  *ptr;                       /* Pointer into installdir */
252
253       size = sizeof(installdir);
254       RegQueryValueEx(key, "installdir", NULL, NULL, installdir, &size);
255       RegCloseKey(key);
256
257       for (ptr = installdir; *ptr;)
258       {
259         if (*ptr == '\\')
260         {
261           if (ptr[1])
262             *ptr++ = '/';
263           else
264             *ptr = '\0';                /* Strip trailing \ */
265         }
266         else if (*ptr == '/' && !ptr[1])
267           *ptr = '\0';                  /* Strip trailing / */
268         else
269           ptr ++;
270       }
271     }
272
273     snprintf(confdir, sizeof(confdir), "%s/conf", installdir);
274     snprintf(localedir, sizeof(localedir), "%s/locale", installdir);
275   }
276
277   if ((cg->cups_datadir = getenv("CUPS_DATADIR")) == NULL)
278     cg->cups_datadir = installdir;
279
280   if ((cg->cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
281     cg->cups_serverbin = installdir;
282
283   if ((cg->cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL)
284     cg->cups_serverroot = confdir;
285
286   if ((cg->cups_statedir = getenv("CUPS_STATEDIR")) == NULL)
287     cg->cups_statedir = confdir;
288
289   if ((cg->localedir = getenv("LOCALEDIR")) == NULL)
290     cg->localedir = localedir;
291
292 #else
293 #  ifdef HAVE_GETEUID
294   if ((geteuid() != getuid() && getuid()) || getegid() != getgid())
295 #  else
296   if (!getuid())
297 #  endif /* HAVE_GETEUID */
298   {
299    /*
300     * When running setuid/setgid, don't allow environment variables to override
301     * the directories...
302     */
303
304     cg->cups_datadir    = CUPS_DATADIR;
305     cg->cups_serverbin  = CUPS_SERVERBIN;
306     cg->cups_serverroot = CUPS_SERVERROOT;
307     cg->cups_statedir   = CUPS_STATEDIR;
308     cg->localedir       = CUPS_LOCALEDIR;
309   }
310   else
311   {
312    /*
313     * Allow directories to be overridden by environment variables.
314     */
315
316     if ((cg->cups_datadir = getenv("CUPS_DATADIR")) == NULL)
317       cg->cups_datadir = CUPS_DATADIR;
318
319     if ((cg->cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
320       cg->cups_serverbin = CUPS_SERVERBIN;
321
322     if ((cg->cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL)
323       cg->cups_serverroot = CUPS_SERVERROOT;
324
325     if ((cg->cups_statedir = getenv("CUPS_STATEDIR")) == NULL)
326       cg->cups_statedir = CUPS_STATEDIR;
327
328     if ((cg->localedir = getenv("LOCALEDIR")) == NULL)
329       cg->localedir = CUPS_LOCALEDIR;
330   }
331 #endif /* WIN32 */
332
333   return (cg);
334 }
335
336
337 /*
338  * 'cups_globals_free()' - Free global data.
339  */
340
341 #if defined(HAVE_PTHREAD_H) || defined(WIN32)
342 static void
343 cups_globals_free(_cups_globals_t *cg)  /* I - Pointer to global data */
344 {
345   _cups_buffer_t        *buffer,        /* Current read/write buffer */
346                         *next;          /* Next buffer */
347
348
349   if (cg->last_status_message)
350     _cupsStrFree(cg->last_status_message);
351
352   for (buffer = cg->cups_buffers; buffer; buffer = next)
353   {
354     next = buffer->next;
355     free(buffer);
356   }
357
358   cupsArrayDelete(cg->leg_size_lut);
359   cupsArrayDelete(cg->ppd_size_lut);
360   cupsArrayDelete(cg->pwg_size_lut);
361
362   httpClose(cg->http);
363
364 #ifdef HAVE_SSL
365   _httpFreeCredentials(cg->tls_credentials);
366 #endif /* HAVE_SSL */
367
368   cupsFileClose(cg->stdio_files[0]);
369   cupsFileClose(cg->stdio_files[1]);
370   cupsFileClose(cg->stdio_files[2]);
371
372   cupsFreeOptions(cg->cupsd_num_settings, cg->cupsd_settings);
373
374   free(cg);
375 }
376 #endif /* HAVE_PTHREAD_H || WIN32 */
377
378
379 #ifdef HAVE_PTHREAD_H
380 /*
381  * 'cups_globals_init()' - Initialize environment variables.
382  */
383
384 static void
385 cups_globals_init(void)
386 {
387  /*
388   * Register the global data for this thread...
389   */
390
391   pthread_key_create(&cups_globals_key, (void (*)(void *))cups_globals_free);
392 }
393 #endif /* HAVE_PTHREAD_H */
394
395
396 /*
397  * End of "$Id: globals.c 12480 2015-02-03 12:36:34Z msweet $".
398  */