]> andersk Git - nss_nonlocal.git/blob - walk_nss.h
Guard one-time initialization with memory barriers
[nss_nonlocal.git] / walk_nss.h
1 /*
2  * walk_nss.h
3  * NSS walking template for nss_nonlocal proxy
4  *
5  * Copyright © 2011 Anders Kaseorg <andersk@mit.edu> and Tim Abbott
6  * <tabbott@mit.edu>
7  *
8  * This file is part of nss_nonlocal.
9  *
10  * nss_nonlocal is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public License
12  * as published by the Free Software Foundation; either version 2.1 of
13  * the License, or (at your option) any later version.
14  *
15  * nss_nonlocal is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with nss_nonlocal; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23  * 02110-1301  USA
24  */
25
26 {
27     static bool initialized = false;
28     static service_user *startp;
29     static void *fct_start;
30
31     service_user *nip;
32     union {
33         __typeof__(self) l;
34         void *ptr;
35     } fct;
36     int old_errno = errno;
37
38     if (!initialized) {
39         if (w.lookup(&startp, w.fct_name, &fct_start) != 0) {
40             *w.status = NSS_STATUS_UNAVAIL;
41             goto walk_nss_out;
42         }
43         __sync_synchronize();
44         initialized = true;
45     }
46
47     nip = startp;
48     fct.ptr = fct_start;
49
50     if (w.buf != NULL) {
51         *w.buf = malloc(*w.buflen);
52         errno = old_errno;
53         if (*w.buf == NULL) {
54             *w.status = NSS_STATUS_TRYAGAIN;
55             *w.errnop = ENOMEM;
56             goto walk_nss_out;
57         }
58     }
59
60     do {
61     walk_nss_morebuf:
62         if (fct.ptr == NULL)
63             *w.status = NSS_STATUS_UNAVAIL;
64         else if (self != NULL && fct.l == self)
65             *w.status = NSS_STATUS_NOTFOUND;
66         else
67             *w.status = DL_CALL_FCT(fct.l, args);
68         if (*w.status == NSS_STATUS_TRYAGAIN &&
69             w.errnop != NULL && *w.errnop == ERANGE) {
70             if (w.buf == NULL)
71                 break;
72             free(*w.buf);
73             *w.buflen *= 2;
74             *w.buf = malloc(*w.buflen);
75             errno = old_errno;
76             if (*w.buf == NULL) {
77                 *w.errnop = ENOMEM;
78                 goto walk_nss_out;
79             }
80             goto walk_nss_morebuf;
81         }
82     } while (__nss_next(&nip, w.fct_name, &fct.ptr, *w.status, 0) == 0);
83
84     if (w.buf != NULL && *w.status != NSS_STATUS_SUCCESS) {
85         free(*w.buf);
86         *w.buf = NULL;
87     }
88
89  walk_nss_out:
90     ;
91 }
This page took 0.046437 seconds and 5 git commands to generate.