1/* Returns a pointer to the global nss_files data structure.
2 Copyright (C) 2021-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19#include <nss_files.h>
20
21#include <allocate_once.h>
22#include <errno.h>
23#include <netdb.h>
24#include <nss.h>
25#include <stdlib.h>
26
27/* This collects all per file-data. */
28struct nss_files_data
29{
30 struct nss_files_per_file_data files[nss_file_count];
31};
32
33/* For use with allocate_once. */
34static void *nss_files_global;
35static void *
36nss_files_global_allocate (void *closure)
37{
38 struct nss_files_data *result = malloc (size: sizeof (*result));
39 if (result != NULL)
40 {
41 for (int i = 0; i < nss_file_count; ++i)
42 {
43 result->files[i].stream = NULL;
44 __libc_lock_init (result->files[i].lock);
45 }
46 }
47 return result;
48}
49/* Like __nss_files_data_open, but does not perform the open call. */
50static enum nss_status
51__nss_files_data_get (struct nss_files_per_file_data **pdata,
52 enum nss_files_file file, int *errnop, int *herrnop)
53{
54 struct nss_files_data *data = allocate_once (place: &nss_files_global,
55 allocate: nss_files_global_allocate,
56 NULL, NULL);
57 if (data == NULL)
58 {
59 if (errnop != NULL)
60 *errnop = errno;
61 if (herrnop != NULL)
62 {
63 __set_h_errno (NETDB_INTERNAL);
64 *herrnop = NETDB_INTERNAL;
65 }
66 return NSS_STATUS_TRYAGAIN;
67 }
68
69 *pdata = &data->files[file];
70 __libc_lock_lock ((*pdata)->lock);
71 return NSS_STATUS_SUCCESS;
72}
73
74/* Helper function for opening the backing file at PATH. */
75static enum nss_status
76__nss_files_data_internal_open (struct nss_files_per_file_data *data,
77 const char *path)
78{
79 enum nss_status status = NSS_STATUS_SUCCESS;
80
81 if (data->stream == NULL)
82 {
83 data->stream = __nss_files_fopen (path);
84
85 if (data->stream == NULL)
86 status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
87 }
88
89 return status;
90}
91
92
93enum nss_status
94__nss_files_data_open (struct nss_files_per_file_data **pdata,
95 enum nss_files_file file, const char *path,
96 int *errnop, int *herrnop)
97{
98 enum nss_status status = __nss_files_data_get (pdata, file, errnop, herrnop);
99 if (status != NSS_STATUS_SUCCESS)
100 return status;
101
102 /* Be prepared that the set*ent function was not called before. */
103 if ((*pdata)->stream == NULL)
104 {
105 int saved_errno = errno;
106 status = __nss_files_data_internal_open (data: *pdata, path);
107 __set_errno (saved_errno);
108 if (status != NSS_STATUS_SUCCESS)
109 __nss_files_data_put (*pdata);
110 }
111
112 return status;
113}
114
115libc_hidden_def (__nss_files_data_open)
116
117void
118__nss_files_data_put (struct nss_files_per_file_data *data)
119{
120 __libc_lock_unlock (data->lock);
121}
122libc_hidden_def (__nss_files_data_put)
123
124enum nss_status
125__nss_files_data_setent (enum nss_files_file file, const char *path)
126{
127 struct nss_files_per_file_data *data;
128 enum nss_status status = __nss_files_data_get (pdata: &data, file, NULL, NULL);
129 if (status != NSS_STATUS_SUCCESS)
130 return status;
131
132 if (data->stream == NULL)
133 status = __nss_files_data_internal_open (data, path);
134 else
135 rewind (data->stream);
136
137 __nss_files_data_put (data);
138 return status;
139}
140libc_hidden_def (__nss_files_data_setent)
141
142enum nss_status
143__nss_files_data_endent (enum nss_files_file file)
144{
145 /* No cleanup is necessary if not initialized. */
146 struct nss_files_data *data = atomic_load_acquire (&nss_files_global);
147 if (data == NULL)
148 return NSS_STATUS_SUCCESS;
149
150 struct nss_files_per_file_data *fdata = &data->files[file];
151 __libc_lock_lock (fdata->lock);
152 if (fdata->stream != NULL)
153 {
154 fclose (fdata->stream);
155 fdata->stream = NULL;
156 }
157 __libc_lock_unlock (fdata->lock);
158
159 return NSS_STATUS_SUCCESS;
160}
161libc_hidden_def (__nss_files_data_endent)
162

source code of glibc/nss/nss_files_data.c