(root)/
glibc-2.38/
nss/
nss_files_data.c
       1  /* Returns a pointer to the global nss_files data structure.
       2     Copyright (C) 2021-2023 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.   */
      28  struct nss_files_data
      29  {
      30    struct nss_files_per_file_data files[nss_file_count];
      31  };
      32  
      33  /* For use with allocate_once.  */
      34  static void *nss_files_global;
      35  static void *
      36  nss_files_global_allocate (void *closure)
      37  {
      38    struct nss_files_data *result = malloc (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.  */
      50  static 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 (&nss_files_global,
      55                                                 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.  */
      75  static 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  
      93  enum 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 (*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  
     115  libc_hidden_def (__nss_files_data_open)
     116  
     117  void
     118  __nss_files_data_put (struct nss_files_per_file_data *data)
     119  {
     120    __libc_lock_unlock (data->lock);
     121  }
     122  libc_hidden_def (__nss_files_data_put)
     123  
     124  enum 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 (&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  }
     140  libc_hidden_def (__nss_files_data_setent)
     141  
     142  enum 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  }
     161  libc_hidden_def (__nss_files_data_endent)