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