diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 7 | ||||
-rw-r--r-- | src/Makefile.in | 473 | ||||
-rw-r--r-- | src/cfg.c | 87 | ||||
-rw-r--r-- | src/compat.c | 59 | ||||
-rw-r--r-- | src/duser.c | 307 | ||||
-rw-r--r-- | src/log.c | 77 | ||||
-rw-r--r-- | src/user.c | 577 | ||||
-rw-r--r-- | src/util.c | 95 |
8 files changed, 1682 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..45d46ef --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,7 @@ +sbin_PROGRAMS= duser + +duser_SOURCES= duser.c \ + user.c \ + util.c \ + log.c \ + cfg.c diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..498c72f --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,473 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +sbin_PROGRAMS = duser$(EXEEXT) +subdir = src +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(sbindir)" +PROGRAMS = $(sbin_PROGRAMS) +am_duser_OBJECTS = duser.$(OBJEXT) user.$(OBJEXT) util.$(OBJEXT) \ + log.$(OBJEXT) cfg.$(OBJEXT) +duser_OBJECTS = $(am_duser_OBJECTS) +duser_LDADD = $(LDADD) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(duser_SOURCES) +DIST_SOURCES = $(duser_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +duser_SOURCES = duser.c \ + user.c \ + util.c \ + log.c \ + cfg.c + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)" + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(sbindir)" && rm -f $$files + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) +duser$(EXEEXT): $(duser_OBJECTS) $(duser_DEPENDENCIES) + @rm -f duser$(EXEEXT) + $(LINK) $(duser_OBJECTS) $(duser_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cfg.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/duser.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/user.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(sbindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-sbinPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-sbinPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-sbinPROGRAMS ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-sbinPROGRAMS install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-sbinPROGRAMS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/cfg.c b/src/cfg.c new file mode 100644 index 0000000..b30bd3f --- /dev/null +++ b/src/cfg.c @@ -0,0 +1,87 @@ +/** +* duser - Manage MajorDomo lists +* Copyright (C) 2011 Joseph Hunkeler <jhunkeler@gmail.com, jhunk@stsci.edu> +* +* This file is part of duser. +* +* duser is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* duser 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 General Public License +* along with duser. If not, see <http://www.gnu.org/licenses/>. +**/ + +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include "duser.h" +#include "cfg.h" + +FILE *cfgfp; + +int cfg_open(const char* filename) +{ + if((cfgfp = fopen(filename, "r")) == NULL) + return errno; + else + return 0; +} + +void cfg_close() +{ + fclose(cfgfp); +} + +//Value of key +int cfg_get_key(char* val, const char* key) +{ + + if(cfgfp == NULL) + return -1; + + if((fseek(cfgfp, 0L, SEEK_SET)) != 0) + return errno; + + char buffer[CFG_MAX]; + char *buf = buffer; //= (char*)malloc(sizeof(char) * CFG_MAX+1); + if(buffer == NULL) + { + fprintf(stderr, "%s: %s\n", SELF, strerror(errno)); + exit(1); + } + + int i = 0; + while(!feof(cfgfp)) + { + memset(buffer, 0L, CFG_MAX); + fgets(buffer, CFG_MAX, cfgfp); + if((strcasestr(buffer, key))) + { + while(buf) + { + if(isspace(*buf)) + { + strncpy(val, &buf[i+1], CFG_MAX); + val[strlen(val)-1] = 0; + break; + } + buf++; + } + i++; + break; + } + } + + return 0; +} diff --git a/src/compat.c b/src/compat.c new file mode 100644 index 0000000..d729229 --- /dev/null +++ b/src/compat.c @@ -0,0 +1,59 @@ +/** +* duser - Manage MajorDomo lists +* Copyright (C) 2011 Joseph Hunkeler <jhunkeler@gmail.com, jhunk@stsci.edu> +* +* This file is part of duser. +* +* duser is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* duser 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 General Public License +* along with duser. If not, see <http://www.gnu.org/licenses/>. +**/ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include "compat.h" + +#ifndef HAVE_STRCHRNUL +#undef strchrnul +char *strchrnul(const char* s, int c) +{ + while(*s && *s != c) + { + s++; + } + return (char*)s; +} +#endif + +#ifndef HAVE_STRCASESTR +#undef strcasestr +char *strcasestr(const char *s, const char *find) +{ + char c, sc; + size_t len; + + if ((c = *find++) != 0) { + c = tolower((unsigned char)c); + len = strlen(find); + do { + do { + if ((sc = *s++) == 0) + return (NULL); + } while ((char)tolower((unsigned char)sc) != c); + } while (strncasecmp(s, find, len) != 0); + s--; + } + return ((char *)s); +} +#endif + diff --git a/src/duser.c b/src/duser.c new file mode 100644 index 0000000..8f5603f --- /dev/null +++ b/src/duser.c @@ -0,0 +1,307 @@ +/** +* duser - Manage MajorDomo lists +* Copyright (C) 2011 Joseph Hunkeler <jhunkeler@gmail.com, jhunk@stsci.edu> +* +* This file is part of duser. +* +* duser is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* duser 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 General Public License +* along with duser. If not, see <http://www.gnu.org/licenses/>. +**/ + +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dirent.h> +#include <limits.h> +#include <ctype.h> +#include <errno.h> +#include <sys/stat.h> +#include <unistd.h> +#include <time.h> +#include <fcntl.h> +#include <libgen.h> + +#include "version.h" +#include "cfg.h" +#include "duser.h" + +char list_path[PATH_MAX]; +char logfile[PATH_MAX]; +static char progname[FILENAME_MAX]; + +int CMD_FLAG_NOOPT = 0; +int CMD_FLAG_DEL = 0; +int CMD_FLAG_DEL_ALL = 0; +int CMD_FLAG_DEL_LIST = 0; +int CMD_FLAG_MOD = 0; +int CMD_FLAG_ADD = 0; +int CMD_FLAG_LIST = 0; +int CMD_FLAG_HELP = 0; +int CMD_FLAG_LOOK = 0; +int CMD_FLAG_NEW = 0; +int CMD_FLAG_NULL = 0; + +void version() +{ + printf("%s v%s.%s%s (%s %s)\n", + progname, VER_MAJOR, VER_MINOR, VER_OTH, __DATE__, __TIME__); +} + +void usage() +{ + version(); + printf("Usage: %s command [address [list]]\n", progname); + printf("Commands:\n"); + printf(" help This usage statement\n"); + printf(" add Add a user to a list\n"); + printf(" del Delete a user from a list\n"); + printf(" delA Delete a user from all lists\n"); + printf(" delL Completely delete a mailing list\n"); + printf(" mod Modify a user in a list\n"); + printf(" new Creates a new list\n"); + printf(" list Find and list a user in all lists\n"); + printf(" look Find user in specific list\n"); + printf("\n"); + exit(0); +} + +int main(int argc, char* argv[]) +{ + strncpy(progname, argv[0], strlen(argv[0])); + if((cfg_open(CFG_PATH)) == 0) + { + cfg_get_key(list_path, "path"); + cfg_get_key(logfile, "logfile"); + cfg_close(); + } + else + { + fprintf(stderr, "%s: %s: %s\n", SELF, CFG_PATH, strerror(errno)); + return -1; + } + + char filename[PATH_MAX]; + record_t *rec; + const char* needle = argv[2]; + const char* single_list = argv[3]; + + if(single_list) + snprintf(filename, PATH_MAX, "%s%s", list_path, single_list); + + if(argc < 3) + { + usage(); + return 0; + } + + stats_init(&processed); + user_cmd(argc, argv); + + if((strval(needle)) != 0) + { + fprintf(stderr, "%s: Invalid string\n", SELF); + exit(1); + } + + if(CMD_FLAG_DEL) + { + if(needle == NULL) + { + printf("You must specify an email address\n"); + return -1; + } + else if(single_list == NULL) + { + printf("You must specify a list to remove '%s' from\n", needle); + return -1; + } + + + if((rec = find_in_file(filename, needle)) == NULL) + { + printf("'%s' not found in '%s'\n", needle, basename(filename)); + return -1; + } + + printf("Please review the information below:\n\n"); + printf("Email: %s\n", rec->name); + printf("At line: %d\n", rec->index); + printf("In File: %s\n", basename(rec->file)); + printf("\nDo you wish to wish to delete this record? [y/N] "); + + char choice = getchar(); + if((user_choice(choice)) == 0) + { + if((user_del(rec)) > 0) + { + printf("Record deleted\n"); + COM(SELF, "Commmand: DELETE\n"); + COM(SELF, "'%s' deleted from '%s' at line %d\n", rec->name, basename(rec->file), rec->index); + } + } + else + { + printf("Aborting...\n"); + } + return 0; + } + + if(CMD_FLAG_DEL_ALL) + { + user_del_all(needle); + return 0; + } + + if(CMD_FLAG_DEL_LIST) + { + user_del_list(needle); + return 0; + } + + if(CMD_FLAG_ADD) + { + if(needle == NULL) + { + printf("You must specify an email address\n"); + return -1; + } + else if(single_list == NULL) + { + printf("You must specify a list in which to add '%s' to\n", needle); + return -1; + } + + printf("Please review the information below:\n\n");; + printf("Email: %s\n", needle); + printf("In File: %s\n", basename(filename)); + printf("\nDo you wish to wish to add this record? [y/N] "); + + char choice = getchar(); + if((user_choice(choice)) == 0) + { + if((user_add(filename, needle)) > 0) + { + printf("Record added\n"); + COM(SELF, "Commmand: ADD\n"); + COM(SELF, "'%s' added to '%s'\n", needle, basename(filename)); + } + } + else + { + printf("Aborting...\n"); + } + return 0; + } + if(CMD_FLAG_MOD) + { + if(needle == NULL) + { + printf("You must specify an email address\n"); + return -1; + } + else if(single_list == NULL) + { + printf("You must specify a list in which to modify '%s' in\n", needle); + return -1; + } + + fprintf(stderr, "Not implemented, sorry.\n"); + return 0; + } + if(CMD_FLAG_LIST) + { + if(needle == NULL) + { + printf("You must specify an email address\n"); + return -1; + } + user_list(needle); + return 0; + } + if(CMD_FLAG_LOOK) + { + if(needle == NULL) + { + printf("You must specify an email address\n"); + return -1; + } + else if(single_list == NULL) + { + printf("You must specify a list in which to find '%s' in\n", needle); + return -1; + } + + rec = find_in_file(filename, needle); + if(rec) + { + if(rec->match) + { + printf("Found '%s' at line %d of list '%s'\n", rec->name, rec->index, basename(rec->file)); + } + else + { + printf("Corrupt record? This is not supposed to happen.\n"); + return -1; + } + } + else + { + printf("Not found in '%s'\n", single_list); + } + return 0; + } + if(CMD_FLAG_NEW) + { + memset(filename, 0L, PATH_MAX); + snprintf(filename, PATH_MAX, "%s%s", list_path, needle); + + if(needle == NULL) + { + printf("You must specify a list to create\n"); + return -1; + } + + printf("Please review the information below:\n\n");; + printf("File: %s\n", filename); + printf("\nDo you wish to wish to create this list? [y/N] "); + + char choice = getchar(); + if((user_choice(choice)) == 0) + { + if((user_new_list(filename)) == 0) + { + printf("List added\n"); + COM(SELF, "Commmand: NEW\n"); + COM(SELF, "Created new list '%s'\n", basename(filename)); + } + } + else + { + printf("Aborting...\n"); + } + return 0; + } + if(CMD_FLAG_HELP) + { + usage(); + } + if(CMD_FLAG_NULL) + { + fprintf(stderr, "Command not specified\n"); + exit(1); + } + + return 0; +} diff --git a/src/log.c b/src/log.c new file mode 100644 index 0000000..c0c1051 --- /dev/null +++ b/src/log.c @@ -0,0 +1,77 @@ +/** +* duser - Manage MajorDomo lists +* Copyright (C) 2011 Joseph Hunkeler <jhunkeler@gmail.com, jhunk@stsci.edu> +* +* This file is part of duser. +* +* duser is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* duser 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 General Public License +* along with duser. If not, see <http://www.gnu.org/licenses/>. +**/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <sys/types.h> +#include <unistd.h> +#include <limits.h> +#include <errno.h> +#include <time.h> +#include "duser.h" + +extern char logfile[PATH_MAX]; +//extern char* logfile; + +int logcleanup() +{ + int status = 0; + if((status = access(logfile, W_OK)) == 0) + { + status = unlink(logfile); + } + + return status; +} + +int COM(const char* func, char *format, ...) +{ + struct tm *logtm; + time_t logtime = time(NULL); + char timestr[64]; + char *str = (char*)malloc(sizeof(char) * 256); + char tmpstr[255]; + int n; + + FILE *logfp = NULL; + logfp = fopen(logfile, "a+"); + if(logfp == NULL) + { + fprintf(stderr, "Unable to open %s\n", logfile); + exit(1); + } + + va_list args; + va_start (args, format); + n = vsprintf (str, format, args); + va_end (args); + + logtm = localtime(&logtime); + + snprintf(timestr, sizeof(timestr), "%02d-%02d-%02d %02d:%02d:%02d", logtm->tm_year+1900, logtm->tm_mon+1, logtm->tm_mday, logtm->tm_hour, logtm->tm_min, logtm->tm_sec); + snprintf(tmpstr, sizeof(tmpstr), "%s %d _%s_: %s", timestr, getuid(), func, str); + fprintf(logfp, "%s", tmpstr); + fclose(logfp); + + free(str); + return 0; +} diff --git a/src/user.c b/src/user.c new file mode 100644 index 0000000..72a7c13 --- /dev/null +++ b/src/user.c @@ -0,0 +1,577 @@ +/** +* duser - Manage MajorDomo lists +* Copyright (C) 2011 Joseph Hunkeler <jhunkeler@gmail.com, jhunk@stsci.edu> +* +* This file is part of duser. +* +* duser is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* duser 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 General Public License +* along with duser. If not, see <http://www.gnu.org/licenses/>. +**/ + +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dirent.h> +#include <limits.h> +#include <ctype.h> +#include <errno.h> +#include <sys/stat.h> +#include <unistd.h> +#include <time.h> +#include <fcntl.h> +#include <libgen.h> +#ifdef _NLINUX_ +# define HAVE_STRCHRNUL +# define HAVE_STRCASESTR +#endif +#include "duser.h" + +extern char list_path[PATH_MAX]; +extern char logfile[PATH_MAX]; +static char progname[FILENAME_MAX]; +extern int CMD_FLAG_NOOPT; +extern int CMD_FLAG_DEL; +extern int CMD_FLAG_DEL_ALL; +extern int CMD_FLAG_DEL_LIST; +extern int CMD_FLAG_MOD; +extern int CMD_FLAG_ADD; +extern int CMD_FLAG_LIST; +extern int CMD_FLAG_HELP; +extern int CMD_FLAG_LOOK; +extern int CMD_FLAG_NEW; +extern int CMD_FLAG_NULL; + + +int user_del_list(const char* filename) +{ + char tmp[PATH_MAX]; + snprintf(tmp, PATH_MAX, "%s%s", list_path, filename); + + if((access(tmp, F_OK|W_OK)) != 0) + { + fprintf(stderr, "FATAL: %s: %s: %s\n", SELF, tmp, strerror(errno)); + return -1; + } + + printf("\n!!!WARNING!!!\n"); + printf("You are about to delete the mailing list '%s'\n\n", basename(tmp)); + printf("Are SURE you want to continue? [y/N]"); + int choice = getchar(); + if((user_choice(choice)) != 0) + { + printf("Aborting...\n"); + exit(1); + } + else + { + COM(SELF, "Command: DELETE LIST\n"); + if((unlink(tmp)) != 0) + { + fprintf(stderr, "FATAL: %s: %s: %s\n", SELF, tmp, strerror(errno)); + return errno; + } + else + { + COM(SELF, "List '%s' deleted\n", basename(tmp)); + printf("Deleted list: '%s'\n", basename(tmp)); + } + } + + return 0; +} + +int user_del_all(const char* needle) +{ + processed.files = get_file_count(list_path); + char** list; + char tmp[PATH_MAX]; + record_t *rp; + list = get_file_list(list_path, processed.files); + + int i = 0; + for(i = 0 ; list[i] != NULL ; i++) + { + rp = NULL; + snprintf(tmp, PATH_MAX, "%s%s", list_path, list[i]); + if((rp = find_in_file(tmp, needle)) != NULL) + { + printf("%20s\t%5d%23s\n", basename(rp->file), rp->index, rp->name); + processed.matches++; + } + } + + printf("\n%d matches\t%d files\t%d lines parsed\n", + processed.matches, processed.files, processed.lines); + + if(processed.matches < 1) + { + free_file_list(list); + return -1; + } + + printf("\n!!!WARNING!!!\n"); + printf("You are about to delete '%s' from every list\n", needle); + printf("that it appears in!\n\n"); + printf("Are SURE you want to continue? [y/N]"); + + int choice = getchar(); + if((user_choice(choice)) != 0) + { + printf("Aborting...\n"); + exit(1); + } + else + { + COM(SELF, "Commmand: DELETE\n"); + for(i = 0 ; list[i] != NULL ; i++) + { + rp = NULL; + snprintf(tmp, PATH_MAX, "%s%s", list_path, list[i]); + if((rp = find_in_file(tmp, needle)) != NULL) + { + if((user_del(rp)) > 0) + { + COM(SELF, "'%s' deleted from '%s' at line %d\n", rp->name, basename(rp->file), rp->index); + printf("'%s' deleted from '%s'\n", rp->name, basename(rp->file)); + } + } + } + } + free_file_list(list); + return 0; + +} + +int user_del(record_t* rec) +{ + FILE *tfp; + FILE *fp; + int i = 0; + int fd = 0; + int bytes = 0; + int bytes_total = 0; + char buf[REGEX_MAX]; + char tmpfile[255]; + snprintf(tmpfile, sizeof(tmpfile), "/tmp/duser.%s.XXXXXX", basename(rec->file)); + if((fd = mkstemp(tmpfile)) < 0 || (tfp = fdopen(fd, "r+")) == NULL) + { + if(fd != -1) + { + close(fd); + unlink(tmpfile); + } + fprintf(stderr, "FATAL: %s: %s: %s\n", SELF, tmpfile, strerror(errno)); + exit(1); + } + + if((fp = fopen(rec->file, "r")) == NULL) + { + fprintf(stderr, "FATAL: %s: %s: %s\n", SELF, rec->file, strerror(errno)); + exit(1); + } + + while(!feof(fp)) + { + memset(buf, 0, sizeof(buf)); + fgets(buf, REGEX_MAX, fp); + buf[strlen(buf) - 1] = '\0'; + if((strncmp(buf, rec->name, strlen(rec->name))) != 0 && (i != rec->index)) + { + buf[strlen(buf)] = '\n'; + bytes = write(fd, buf, strlen(buf)); + } + i++; + } + //Rewind the temp file + lseek(fd, 0L, SEEK_SET); + //Close the original file + fclose(fp); + //Truncate original and copy data from tmp to original + if((fp = fopen(rec->file, "w+")) == NULL) + { + fprintf(stderr, "FATAL: %s: %s: %s\n", SELF, rec->file, strerror(errno)); + exit(1); + } + + i = 0; + while(!feof(tfp)) + { + memset(buf, 0, sizeof(buf)); + fgets(buf, REGEX_MAX, tfp); + buf[strlen(buf) - 1] = '\0'; + if((strncmp(buf, rec->name, strlen(rec->name))) != 0 && (i != rec->index)) + { + buf[strlen(buf)] = '\n'; + if(buf[0] == '\n') + buf[0] = '\0'; + + bytes = fwrite(buf, strlen(buf), 1, fp); + bytes_total += bytes; + } + } + + fclose(fp); + close(fd); + unlink(tmpfile); + + if(bytes_total) + return bytes_total; + + return 0; +} + + +// VERIFY that the record is proper (useful for deletion of users) +int find_in_file_ex(record_t* rec) +{ + int match = -1; + char buf[REGEX_MAX]; + FILE *fp; + + if((fp = fopen(rec->file, "r")) == NULL) + { + fprintf(stderr, "FATAL: %s: %s: %s\n", SELF, rec->file, strerror(errno)); + return -1; + } + + while(!feof(fp)) + { + fgets(buf, REGEX_MAX, fp); + buf[strlen(buf) - 1] = '\0'; + if((strncmp(buf, rec->name, strlen(rec->name))) == 0) + { + match = 1; + break; + } + } + + fclose(fp); + return match; +} + +record_t* find_in_file(const char* filename, const char* needle) +{ + //regmatch_t pmatch[10]; + //regex_t preg; + record_t record, *rptr; + rptr = &record; + rptr->index = 0; + rptr->match = 0; + + int index = 0; + + FILE *fp; + char *fname = strdup(filename); + + if((fp = fopen(fname, "r")) == NULL) + { + fprintf(stderr, "FATAL: %s: %s: %s\n", SELF, basename(fname), strerror(errno)); + exit(1); + } + strncpy(rptr->file, fname, PATH_MAX); + while(!feof(fp)) + { + char cmp[REGEX_MAX]; + memset(cmp, 0L, REGEX_MAX); + fgets(cmp, REGEX_MAX, fp); + cmp[strlen(cmp)-1] = '\0'; + if((strfind(cmp, needle)) == 0) + { + snprintf(rptr->name, REGEX_MAX, "%s", cmp); + rptr->match = 1; + rptr->index = index; + } + index++; + processed.lines++; + } + + free(fname); + fclose(fp); + if(rptr->match) + return rptr; + else + return NULL; + +} + +int get_file_count(const char* path) +{ + DIR *dp = NULL; + struct dirent *ep = NULL; + int file_count = 0; + + if((dp = opendir(path)) == NULL) + { + fprintf(stderr, "FATAL: %s: %s: %s\n", SELF, path, strerror(errno)); + exit(1); + } + + while((ep = readdir(dp))) + { +#ifdef _NLINUX_ + char path[PATH_MAX]; + struct stat st; + snprintf(path, PATH_MAX, "%s%s", list_path, ep->d_name); + if((stat(path, &st)) == 0) + { + if(S_ISREG(st.st_mode)) + { + if(!strstr(ep->d_name, ".")) + { + file_count++; + } + } + } +#else + if(ep->d_type == DT_REG && !strstr(ep->d_name, ".")) + { + file_count++; + } +#endif + } + closedir(dp); + + return file_count; +} + +void free_file_list(char** list) +{ + int i = 0; + for( i = 0 ; list[i] != NULL ; i++ ) + { + free(list[i]); + } + free(list); +} + +char** get_file_list(const char* path, int count) +{ + DIR *dp = NULL; + struct dirent *ep = NULL; + int i = 0; + + if((dp = opendir(path)) == NULL) + { + perror("opendir"); + exit(1); + } + + char **list = (char**)calloc(count, REGEX_MAX); + if(list == NULL) + { + perror("calloc"); + exit(1); + } + while((ep = readdir(dp))) + { +#ifdef _NLINUX_ + char path[PATH_MAX]; + struct stat st; + snprintf(path, PATH_MAX, "%s%s", list_path, ep->d_name); + if((stat(path, &st)) == 0) + { + if(S_ISREG(st.st_mode)) + { + if(!strstr(ep->d_name, ".")) + { + list[i] = (char*)malloc(sizeof(char) * strlen(ep->d_name)+1); + memset(list[i], 0L, strlen(ep->d_name)+1); + strncpy(list[i], ep->d_name, strlen(ep->d_name)+1); + i++; + } + } + } +#else + if(ep->d_type == DT_REG && !strstr(ep->d_name, ".")) + { + list[i] = (char*)malloc(sizeof(char) * strlen(ep->d_name)+1); + memset(list[i], 0L, strlen(ep->d_name)+1); + strncpy(list[i], ep->d_name, strlen(ep->d_name)+1); + i++; + } +#endif + } + closedir(dp); + return list; +} + + +int user_list(const char* needle) +{ + processed.files = get_file_count(list_path); + char** list = get_file_list(list_path, processed.files); + if(list == NULL) + { + fprintf(stderr, "abort\n"); + exit(1); + } + + printf("%20s%12s%16s\n", "List", "At line", "Match"); + printf("\t\t%s\n", "====================================="); + int i = 0; + for(i = 0 ; list[i] != NULL ; i++) + { + char tmp[PATH_MAX]; + snprintf(tmp, PATH_MAX, "%s%s", list_path, list[i]); + record_t *rp; + if((rp = find_in_file(tmp, needle)) != NULL) + { + printf(FMTLIST, basename(rp->file), rp->index, rp->name); + processed.matches++; + } + } + free_file_list(list); + + printf("\n%d matches\t%d files\t%d lines parsed\n", + processed.matches, processed.files, processed.lines); + return 0; +} + +int user_add(const char* filename, const char* needle) +{ + int bytes = 0; + record_t *rp; + char *fname = strdup(filename); + char *newline = NULL; + char buf[REGEX_MAX]; + FILE *fp; + if((access(filename, W_OK|F_OK)) != 0) + { + fprintf(stderr, "FATAL: %s: %s: %s\n", SELF, filename, strerror(errno)); + return -1; + } + + if((fp = fopen(filename, "r+")) == NULL) + { + fprintf(stderr, "FATAL: %s: %s: %s\n", SELF, filename, strerror(errno)); + return -1; + } + + if((rp = find_in_file(filename, needle)) != NULL) + { + fprintf(stderr, "%s: '%s' already exists in '%s'\n", SELF, needle, basename(fname)); + return -1; + } + rewind(fp); + //Go to end of file and find out what's where + fseek(fp, 0L, SEEK_END); + fgets(buf, REGEX_MAX, fp); + + //Check for a newline at the end of the file. + //If so, add one. If not, do not add a preceding newline. + if((newline = strchrnul(buf, '\n')) != NULL) + { + snprintf(buf, REGEX_MAX, "%s\n", needle); + } + else + { + //probably very rarely used. + snprintf(buf, REGEX_MAX, "\n%s\n", needle); + } + + bytes = fwrite(buf, strlen(buf), 1, fp); + //fputs(buf, fp); + fflush(fp); + free(fname); + fclose(fp); + return bytes; +} + +int user_cmd(const int argc, char* argv[]) +{ + const char* cmd = argv[1]; + + if(argc < 2) + return CMD_FLAG_NULL; + + if(cmd) + { + if((strncmp(cmd, "del", strlen(cmd))) == 0) + { + CMD_FLAG_DEL = 1; + } + if((strncmp(cmd, "delA", strlen(cmd))) == 0) + { + CMD_FLAG_DEL_ALL = 1; + } + if((strncmp(cmd, "delL", strlen(cmd))) == 0) + { + CMD_FLAG_DEL_LIST = 1; + } + if((strncmp(cmd, "add", strlen(cmd))) == 0) + { + CMD_FLAG_ADD = 1; + } + if((strncmp(cmd, "mod", strlen(cmd))) == 0) + { + CMD_FLAG_MOD = 1; + } + if((strncmp(cmd, "new", strlen(cmd))) == 0) + { + CMD_FLAG_NEW = 1; + } + if((strncmp(cmd, "list", strlen(cmd))) == 0) + { + CMD_FLAG_LIST = 1; + } + if((strncmp(cmd, "look", strlen(cmd))) == 0) + { + CMD_FLAG_LOOK = 1; + } + if((strncmp(cmd, "help", strlen(cmd))) == 0) + { + CMD_FLAG_HELP = 1; + } + } + + return 0; +} + + +int user_new_list(const char* fname) +{ + char *filename = strdup(fname); + char *timestr; + char message[BUFSIZ]; + FILE *fp = NULL; + time_t ttm; + struct tm *tmptr; + + if((access(filename, F_OK)) == 0) + { + fprintf(stderr, "%s: %s: File already exists\n", SELF, basename(filename)); + return -1; + } + + if((fp = fopen(filename, "w+")) == NULL) + { + fprintf(stderr, "FATAL: %s: %s: %s\n", SELF, basename(filename), strerror(errno)); + return -1; + } + + time(&ttm); + tmptr = localtime(&ttm); + timestr = asctime(tmptr); + timestr[strlen(timestr)-1] = '\0'; + snprintf(message, BUFSIZ, "#\n# Created by %s on %s. UID %d\n#\n", basename(progname), timestr, getuid()); + fputs(message, fp); + fflush(fp); + fclose(fp); + + free(filename); + return 0; +} + + diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..4d5f58c --- /dev/null +++ b/src/util.c @@ -0,0 +1,95 @@ +/** +* duser - Manage MajorDomo lists +* Copyright (C) 2011 Joseph Hunkeler <jhunkeler@gmail.com, jhunk@stsci.edu> +* +* This file is part of duser. +* +* duser is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* duser 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 General Public License +* along with duser. If not, see <http://www.gnu.org/licenses/>. +**/ + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include "duser.h" + +void stats_init(stats_t *s) +{ + s->lines = 0; + s->files = 0; + s->matches = 0; + s->added = 0; + s->deleted = 0; + s->modified = 0; +} + +int user_choice(char c) +{ + if(c == 'y' || c == 'Y') + return 0; + + return 1; +} + +int check_cmd_string(char** args, const char* str2, int count) +{ + int i = 0; + while(i < count) + { + if((strncmp(args[i], str2, strlen(args[i]))) == 0) + { + return 0; + } + i++; + } + return -1; +} + +//I'm using this until regex can get its head out of its... +//toilet bowl. +int strfind(const char* str1, const char* str2) +{ + if((strcasestr(str1, str2)) != 0) + { + if((strcasecmp(str1, str2)) == 0) + return 0; + } + return -1; +} + +int strval(const char* str) +{ + const char* bad = "!#$%^&*()+={}[]|\\<>,"; + unsigned int i = 0; + unsigned int ibad = 0; + for(i = 0 ; i < strlen(str) ; i++) + { + unsigned char c = str[i]; + if((i == 0) && !(isalpha(c))) + { + return -1; + } + for(ibad = 0 ; ibad <= strlen(bad) ; ibad++) + { + if(str[i] == bad[ibad]) + { + return -1; + } + } + } + + return 0; +} + |