summaryrefslogtreecommitdiffstats
path: root/src/generic.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/generic.c')
-rw-r--r--src/generic.c400
1 files changed, 400 insertions, 0 deletions
diff --git a/src/generic.c b/src/generic.c
new file mode 100644
index 0000000..f23792d
--- /dev/null
+++ b/src/generic.c
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2002 Red Hat, Inc.
+ *
+ * This is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ident "$Id: generic.c,v 1.1 2002/11/18 19:53:21 nalin Exp $"
+
+#include "../config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fnmatch.h>
+#include <limits.h>
+#include <nss.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "parsers.h"
+#include <pwd.h>
+
+#define CHUNK_SIZE LINE_MAX
+#define FALSE 0
+#define TRUE (!FALSE)
+
+static const char *skip_names[] = {
+ "*~",
+ "*.rpmsave",
+ "*.rpmorig",
+ "*.rpmnew",
+};
+
+static int
+skip_file_by_name(const char *filename)
+{
+ int i;
+ for (i = 0; i < sizeof(skip_names) / sizeof(skip_names[0]); i++) {
+ if (fnmatch(skip_names[i], filename, 0) == 0) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static char *
+read_line(FILE *fp)
+{
+ char *buffer;
+ size_t buflen, length;
+
+ buflen = CHUNK_SIZE;
+ length = 0;
+ buffer = malloc(CHUNK_SIZE);
+ if (buffer == NULL) {
+ return NULL;
+ }
+ memset(buffer, 0, buflen);
+
+ while (fgets(buffer + length, buflen - length, fp) != NULL) {
+ length = strlen(buffer);
+ if (length > 0) {
+ if (buffer[length - 1] == '\n') {
+ break;
+ } else {
+ buflen += CHUNK_SIZE;
+ buffer = realloc(buffer, buflen);
+ if (buffer == NULL) {
+ return NULL;
+ }
+ memset(buffer + length, 0, buflen - length);
+ }
+ }
+ }
+
+ if (strlen(buffer) == 0) {
+ free(buffer);
+ return NULL;
+ }
+
+ if ((length > 0) && (buffer[length - 1] == '\n')) {
+ buffer[length - 1] = '\0';
+ }
+
+ return buffer;
+}
+
+static enum nss_status
+getgen(struct STRUCTURE *result,
+#ifdef GET_EXTRA_CRITERIA
+ GET_EXTRA_CRITERIA,
+#endif
+ char *buffer, size_t buflen, int *errnop,
+ int (*compare)(const void *compare_data, struct STRUCTURE *structure),
+ const void *compare_data)
+{
+ DIR *dir = NULL;
+ FILE *fp = NULL;
+ struct STRUCTURE structure;
+ struct dirent *ent = NULL;
+ struct stat st;
+ char path[PATH_MAX], *line;
+
+ /* Start reading the directory. */
+ dir = opendir(SYSCONFDIR "/" FILENAME ".d");
+ if (dir == NULL) {
+ *errnop = errno;
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ /* Iterate over each file in the directory. */
+ while ((ent = readdir(dir)) != NULL) {
+ /* If the file has a certain name, skip it. */
+ if (skip_file_by_name(ent->d_name)) {
+ continue;
+ }
+
+ /* Figure out the full name of the file. */
+ snprintf(path, sizeof(path), SYSCONFDIR "/" FILENAME ".d/%s",
+ ent->d_name);
+
+ /* If we can't open it, skip it. */
+ fp = fopen(path, "r");
+ if (fp == NULL) {
+ continue;
+ }
+
+ /* If we can't stat() it, or it's not a regular file or
+ * a symlink, skip it. */
+ if ((fstat(fileno(fp), &st) != 0) ||
+ (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))) {
+ fclose(fp);
+ continue;
+ }
+
+ /* Read the next line. */
+ while ((line = read_line(fp)) != NULL) {
+ /* If we had trouble parsing it, continue. */
+ if (parser(line, &structure,
+ (struct parser_data*) buffer, buflen,
+ errnop) == 0) {
+ free(line);
+ continue;
+ }
+ /* If it matches, close the file and the directory,
+ * and return the answer. */
+ if ((compare(compare_data, &structure) == 0) &&
+#ifdef CHECK_EXTRA_CRITERIA
+ CHECK_EXTRA_CRITERIA(&structure) &&
+#endif
+ TRUE) {
+ *result = structure;
+ free(line);
+ fclose(fp);
+ closedir(dir);
+ return NSS_STATUS_SUCCESS;
+ }
+
+ /* Free this line. */
+ free(line);
+ }
+
+ /* Close this file. */
+ fclose(fp);
+ }
+
+ /* Close this directory. */
+ closedir(dir);
+
+ /* Tell the caller that we didn't find anything. */
+ return NSS_STATUS_NOTFOUND;
+}
+#if defined(getnam) && defined(getnam_field)
+static int
+compare_name(const void *compare_data, struct STRUCTURE *structure)
+{
+#ifdef getnam_fields
+ int i;
+ if (structure->getnam_fields != NULL) {
+ for (i = 0; structure->getnam_fields[i] != NULL; i++) {
+ if (strcmp(structure->getnam_fields[i],
+ (const char *)compare_data) == 0) {
+ return 0;
+ }
+ }
+ }
+#endif
+ return strcmp(structure->getnam_field, (const char *)compare_data);
+}
+enum nss_status
+getnam(const char *name,
+#ifdef GET_EXTRA_CRITERIA
+ GET_EXTRA_CRITERIA,
+#endif
+ struct STRUCTURE *result, char *buffer, size_t buflen, int *errnop )
+{
+ return getgen(result,
+#ifdef EXTRA_CRITERIA_NAMES
+ EXTRA_CRITERIA_NAMES,
+#endif
+ buffer, buflen, errnop,
+ compare_name, (const void*) name);
+}
+#endif
+#if defined(getnum) && defined(getnum_type) && defined(getnum_field)
+static int
+compare_number(const void *compare_data, struct STRUCTURE *structure)
+{
+ return (structure->getnum_field != (getnum_type) compare_data);
+}
+enum nss_status
+getnum(getnum_type number,
+#ifdef GET_EXTRA_CRITERIA
+ GET_EXTRA_CRITERIA,
+#endif
+ struct STRUCTURE *result, char *buffer, size_t buflen, int *errnop )
+{
+ return getgen(result,
+#ifdef EXTRA_CRITERIA_NAMES
+ EXTRA_CRITERIA_NAMES,
+#endif
+ buffer, buflen, errnop,
+ compare_number, (const void*) number);
+}
+#endif
+#if defined(setent) && defined(getent) && defined(endent)
+
+static pthread_mutex_t enumeration_lock = PTHREAD_MUTEX_INITIALIZER;
+#define LOCK() pthread_mutex_lock(&enumeration_lock)
+#define UNLOCK() pthread_mutex_unlock(&enumeration_lock)
+static DIR *dir = NULL;
+static FILE *fp = NULL;
+
+enum nss_status
+endent(void)
+{
+ /* Close the directory and the current file. */
+ LOCK();
+ if (fp != NULL) {
+ fclose(fp);
+ fp = NULL;
+ }
+ if (dir != NULL) {
+ closedir(dir);
+ dir = NULL;
+ }
+ UNLOCK();
+ return NSS_STATUS_UNAVAIL;
+}
+enum nss_status
+setent(int stayopen)
+{
+ /* Close and reopen the directory. */
+ endent();
+ LOCK();
+ dir = opendir(SYSCONFDIR "/" FILENAME ".d");
+ UNLOCK();
+ return NSS_STATUS_UNAVAIL;
+}
+enum nss_status
+getent(struct STRUCTURE *result, char *buffer, size_t buflen, int *errnop)
+{
+ char path[PATH_MAX], *line;
+ struct dirent *ent;
+ struct stat st;
+ struct STRUCTURE structure;
+
+ LOCK();
+
+ /* If we don't have a current directory, try to reset. */
+ if (dir == NULL) {
+ setent(TRUE);
+ /* If we couldn't open the directory, then we'd better just
+ * give up now. */
+ if (dir == NULL) {
+ UNLOCK();
+ return NSS_STATUS_NOTFOUND;
+ }
+ }
+
+ do {
+ /* If we don't have a current file, try to open the next file
+ * in the directory. */
+ if ((fp == NULL) || feof(fp)) {
+ if (fp != NULL) {
+ fclose(fp);
+ fp = NULL;
+ }
+
+ do {
+ /* Read the next entry in the directory. */
+ ent = readdir(dir);
+ if (ent == NULL) {
+ closedir(dir);
+ dir = NULL;
+ continue;
+ }
+
+ /* If the file has a certain name, skip it. */
+ if (skip_file_by_name(ent->d_name)) {
+ continue;
+ }
+
+ /* Formulate the full path name and try to
+ * open it. */
+ snprintf(path, sizeof(path),
+ SYSCONFDIR "/" FILENAME ".d/%s",
+ ent->d_name);
+ fp = fopen(path, "r");
+
+ /* If we failed to open the file, move on. */
+ if (fp == NULL) {
+ continue;
+ }
+
+ /* If we can't stat() the file, move on. */
+ if (fstat(fileno(fp), &st) != 0) {
+ fclose(fp);
+ fp = NULL;
+ continue;
+ }
+
+ /* If the file isn't normal or a symlink,
+ * move on. */
+ if (!S_ISREG(st.st_mode) &&
+ !S_ISLNK(st.st_mode)) {
+ fclose(fp);
+ fp = NULL;
+ continue;
+ }
+ } while ((dir != NULL) && (fp == NULL));
+ }
+
+ /* If we're out of data, return NOTFOUND. */
+ if ((dir == NULL) || (fp == NULL)) {
+ UNLOCK();
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ /* Read a line from the file. */
+ line = read_line(fp);
+ if (line == NULL) {
+ fclose(fp);
+ fp = NULL;
+ continue;
+ }
+
+ /* Try to parse the line. */
+ if (parser(line, &structure,
+ (struct parser_data*) buffer, buflen,
+ errnop) != 0) {
+ free(line);
+ *result = structure;
+ UNLOCK();
+ return NSS_STATUS_SUCCESS;
+ }
+
+ /* Try the next entry. */
+ free(line);
+ } while (1);
+
+ /* We never really get here, but oh well. */
+ UNLOCK();
+ return NSS_STATUS_UNAVAIL;
+}
+#endif
+
+#ifdef IMPLEMENT_MAIN
+int
+main(int argc, char **argv)
+{
+ struct passwd pwd;
+ char buffer[LINE_MAX];
+ int error;
+ if (getnum(500, &pwd, buffer, sizeof(buffer),
+ &error) == NSS_STATUS_SUCCESS) {
+ printf("%s:%ld\n", pwd.pw_name, (long) pwd.pw_uid);
+ }
+ while (getent(&pwd, buffer, sizeof(buffer),
+ &error) == NSS_STATUS_SUCCESS) {
+ printf("%s:%ld\n", pwd.pw_name, (long) pwd.pw_uid);
+ }
+ return 0;
+}
+#endif