Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: Re: Implementation of simple newuser module (how to start?)



Here is an initial attempt at the zsh/newuser module.

Note the logic:  the module is loaded and immediately unloaded just
before .zshenv would be run, and under exactly the same conditions (so
/etc/zshenv has just been executed if it exists).  This seems to me to
be about the best choice.  It does mean that the module will be run if
the shell is non-interactive; it is up to the newuser script or whatever
it calls to handle this.  (This might be made clearer in the manual
entry, or alternatively the module could only be run for an interactive
shell.)

I haven't provided any newuser file yet.  Arrangements will have to be
made to instal that: not entirely sure where from, since it's not a
function, possibly Etc which at least has a Makefile.  However, this
should be good enough to play around with your own ideas.  (When I've
worked out how to install it, I may provide an initial newuser file
which simply creates .zshrc with a comment.)

Please suggest improvements to the manual entry if I've made it too
tortuous.

Index: configure.ac
===================================================================
RCS file: /cvsroot/zsh/zsh/configure.ac,v
retrieving revision 1.34
diff -u -r1.34 configure.ac
--- configure.ac	31 May 2005 07:44:11 -0000	1.34
+++ configure.ac	20 Jul 2005 13:59:34 -0000
@@ -286,6 +286,30 @@
 AC_SUBST(sitefndir)dnl
 AC_SUBST(FUNCTIONS_SUBDIRS)dnl
 
+dnl Directories for scripts such as newuser.
+
+ifdef([scriptdir],[undefine([scriptdir])])dnl
+AC_ARG_ENABLE(scriptdir,
+[  --enable-scriptdir=DIR     the directory in which to install scripts],
+dnl ${VERSION} to be determined at compile time.
+[if test $enableval = yes; then
+  scriptdir=${datadir}/${tzsh_name}/'${VERSION}'
+else
+  scriptdir="$enableval"
+fi], [scriptdir=${datadir}/${tzsh_name}/'${VERSION}'])
+
+ifdef([sitescriptdir],[undefine([sitescriptdir])])dnl
+AC_ARG_ENABLE(site-scriptdir,
+[  --enable-site-scriptdir=DIR  same for site scripts (not version specific)],
+[if test $enableval = yes; then
+  sitescriptdir=${datadir}/${tzsh_name}
+else
+  sitescriptdir="$enableval"
+fi], [sitescriptdir=${datadir}/${tzsh_name}])
+
+AC_SUBST(scriptdir)dnl
+AC_SUBST(sitescriptdir)dnl
+
 dnl Do you want maildir support?
 ifdef([maildir_support],[undefine([maildir_support])])dnl
 AH_TEMPLATE([MAILDIR_SUPPORT],
Index: Config/defs.mk.in
===================================================================
RCS file: /cvsroot/zsh/zsh/Config/defs.mk.in,v
retrieving revision 1.9
diff -u -r1.9 defs.mk.in
--- Config/defs.mk.in	4 Feb 2005 16:59:40 -0000	1.9
+++ Config/defs.mk.in	20 Jul 2005 13:59:35 -0000
@@ -43,6 +43,8 @@
 datadir         = @datadir@
 fndir           = @fndir@
 sitefndir       = @sitefndir@
+scriptdir       = @scriptdir@
+sitescriptdir   = @sitescriptdir@
 htmldir         = $(datadir)/$(tzsh)/htmldoc
 
 # compilation
Index: Doc/Makefile.in
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Makefile.in,v
retrieving revision 1.24
diff -u -r1.24 Makefile.in
--- Doc/Makefile.in	6 May 2005 15:53:02 -0000	1.24
+++ Doc/Makefile.in	20 Jul 2005 13:59:35 -0000
@@ -59,7 +59,8 @@
 Zsh/mod_computil.yo \
 Zsh/mod_datetime.yo Zsh/mod_deltochar.yo \
 Zsh/mod_example.yo Zsh/mod_files.yo \
-Zsh/mod_mapfile.yo Zsh/mod_mathfunc.yo Zsh/mod_parameter.yo Zsh/mod_pcre.yo \
+Zsh/mod_mapfile.yo Zsh/mod_mathfunc.yo Zsh/mod_newuser.yo \
+Zsh/mod_parameter.yo Zsh/mod_pcre.yo \
 Zsh/mod_sched.yo Zsh/mod_socket.yo \
 Zsh/mod_stat.yo  Zsh/mod_system.yo Zsh/mod_tcp.yo \
 Zsh/mod_termcap.yo Zsh/mod_terminfo.yo \
Index: Doc/Zsh/mod_newuser.yo
===================================================================
RCS file: Doc/Zsh/mod_newuser.yo
diff -N Doc/Zsh/mod_newuser.yo
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Doc/Zsh/mod_newuser.yo	20 Jul 2005 13:59:36 -0000
@@ -0,0 +1,37 @@
+COMMENT(!MOD!zsh/newuser
+Arrange for files for new users to be installed.
+!MOD!)
+The tt(zsh/newuser) module is loaded at boot if it is
+available, the tt(RCS) option is set, and the tt(PRIVILEGED) option is not
+set (all three are true by default).  This takes
+place immediately after commands in the global tt(zshenv) file (typically
+tt(/etc/zshenv)), if any, have been executed.  If the module is not
+available it is silently ignored by the shell; the module may safely be
+removed from tt($MODULE_PATH) by the administrator if it is not required.
+
+On loading, the module tests if any of the start-up files tt(.zshenv),
+tt(.zprofile), tt(.zshrc) or tt(.zlogin) exist in the directory given by
+the environment variable tt(ZDOTDIR), or the user's home directory if that
+is not set.
+
+If none of the start-up files were found, the module then looks for the
+file tt(newuser) first in a sitewide directory, usually the parent
+directory of the tt(site-functions) directory, and if that is not found the
+module searches in a version-specific directory, usually the parent of the
+tt(functions) directory containing version-specific functions.  (These
+directories can be configured when zsh is built using the
+tt(--enable-site-scriptdir=)var(dir) and tt(--enable-scriptdir=)var(dir)
+flags to tt(configure), respectively; the defaults are
+var(prefix)tt(/share/zsh) and var(prefix)tt(/share/zsh/$ZSH_VERSION) where
+the default var(prefix) is tt(/usr/local).)
+
+If the file tt(newuser) is found, it is then sourced in the same manner as
+a start-up file.  The file is expected to contain code to install start-up
+files for the user, however any valid shell code will be executed.
+
+The tt(zsh/newuser) module is then unconditionally unloaded.
+
+Note that it is possible to achieve exactly the same effect as the
+tt(zsh/newuser) module by adding code to tt(/etc/zshenv).  The module
+exists simply to allow the shell to make arrangements for new users without
+the need for invervention by package maintainers and system administrators.
Index: Src/init.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/init.c,v
retrieving revision 1.54
diff -u -r1.54 init.c
--- Src/init.c	15 Jul 2005 17:41:53 -0000	1.54
+++ Src/init.c	20 Jul 2005 13:59:36 -0000
@@ -948,8 +948,20 @@
 #ifdef GLOBAL_ZSHENV
 	source(GLOBAL_ZSHENV);
 #endif
+
 	if (isset(RCS) && unset(PRIVILEGED))
+	{
+	    /*
+	     * Always attempt to load the newuser module to perform
+	     * checks for new zsh users.  Don't care if we can't load it.
+	     */
+	    if (load_module_silence("zsh/newuser", 1)) {
+		/* Unload it immediately. */
+		unload_named_module("zsh/newuser", "zsh", 1);
+	    }
+
 	    sourcehome(".zshenv");
+	}
 	if (islogin) {
 #ifdef GLOBAL_ZPROFILE
 	    if (isset(RCS) && isset(GLOBALRCS))
Index: Src/module.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/module.c,v
retrieving revision 1.17
diff -u -r1.17 module.c
--- Src/module.c	12 Jan 2005 12:19:06 -0000	1.17
+++ Src/module.c	20 Jul 2005 13:59:36 -0000
@@ -434,12 +434,12 @@
 
 /**/
 static void *
-do_load_module(char const *name)
+do_load_module(char const *name, int silent)
 {
     void *ret;
 
     ret = try_load_module(name);
-    if (!ret) {
+    if (!ret && !silent) {
 	int waserr = errflag;
 	zerr("failed to load module: %s", name, 0);
 	errflag = waserr;
@@ -452,11 +452,12 @@
 
 /**/
 static void *
-do_load_module(char const *name)
+do_load_module(char const *name, int silent)
 {
     int waserr = errflag;
 
-    zerr("failed to load module: %s", name, 0);
+    if (!silent)
+	zerr("failed to load module: %s", name, 0);
     errflag = waserr;
 
     return NULL;
@@ -748,6 +749,13 @@
 mod_export int
 load_module(char const *name)
 {
+    return load_module_silence(name, 0);
+}
+
+/**/
+mod_export int
+load_module_silence(char const *name, int silent)
+{
     Module m;
     void *handle = NULL;
     Linkedmod linked;
@@ -755,7 +763,8 @@
     int set;
 
     if (!modname_ok(name)) {
-	zerr("invalid module name `%s'", name, 0);
+	if (!silent)
+	    zerr("invalid module name `%s'", name, 0);
 	return 0;
     }
     /*
@@ -766,7 +775,7 @@
     queue_signals();
     if (!(node = find_module(name, 1, &name))) {
 	if (!(linked = module_linked(name)) &&
-	    !(handle = do_load_module(name))) {
+	    !(handle = do_load_module(name, silent))) {
 	    unqueue_signals();
 	    return 0;
 	}
@@ -811,7 +820,7 @@
     m->flags |= MOD_BUSY;
     if (m->deps)
 	for (n = firstnode(m->deps); n; incnode(n))
-	    if (!load_module((char *) getdata(n))) {
+	    if (!load_module_silence((char *) getdata(n), silent)) {
 		m->flags &= ~MOD_BUSY;
 		unqueue_signals();
 		return 0;
@@ -820,7 +829,7 @@
     if (!m->u.handle) {
 	handle = NULL;
 	if (!(linked = module_linked(name)) &&
-	    !(handle = do_load_module(name))) {
+	    !(handle = do_load_module(name, silent))) {
 	    unqueue_signals();
 	    return 0;
 	}
@@ -886,7 +895,7 @@
 	    return 0;
 	}
     } else
-	ret = load_module(module);
+	ret = load_module_silence(module, 0);
     unqueue_signals();
 
     return ret;
@@ -1549,6 +1558,50 @@
     return 0;
 }
 
+
+/**/
+int
+unload_named_module(char *modname, char *nam, int silent)
+{
+    const char *mname;
+    LinkNode node;
+    Module m;
+    int ret = 0;
+
+    node = find_module(modname, 1, &mname);
+    if (node) {
+	LinkNode mn, dn;
+	int del = 0;
+
+	for (mn = firstnode(modules); mn; incnode(mn)) {
+	    m = (Module) getdata(mn);
+	    if (m->deps && m->u.handle)
+		for (dn = firstnode(m->deps); dn; incnode(dn))
+		    if (!strcmp((char *) getdata(dn), mname)) {
+			if (m->flags & MOD_UNLOAD)
+			    del = 1;
+			else {
+			    zwarnnam(nam, "module %s is in use by another module and cannot be unloaded", mname, 0);
+			    return 1;
+			}
+		    }
+	}
+	m = (Module) getdata(node);
+	if (del)
+	    m->wrapper++;
+	if (unload_module(m, node))
+	    ret = 1;
+	if (del)
+	    m->wrapper--;
+    } else if (!silent) {
+	zwarnnam(nam, "no such module %s", modname, 0);
+	ret = 1;
+    }
+
+    return ret;
+}
+
+
 /**/
 static int
 bin_zmodload_load(char *nam, char **args, Options ops)
@@ -1558,39 +1611,9 @@
     int ret = 0;
     if(OPT_ISSET(ops,'u')) {
 	/* unload modules */
-	const char *mname = *args;
 	for(; *args; args++) {
-	    node = find_module(*args, 1, &mname);
-	    if (node) {
-		LinkNode mn, dn;
-		int del = 0;
-
-		for (mn = firstnode(modules); mn; incnode(mn)) {
-		    m = (Module) getdata(mn);
-		    if (m->deps && m->u.handle)
-			for (dn = firstnode(m->deps); dn; incnode(dn))
-			    if (!strcmp((char *) getdata(dn), mname)) {
-				if (m->flags & MOD_UNLOAD)
-				    del = 1;
-				else {
-				    zwarnnam(nam, "module %s is in use by another module and cannot be unloaded", mname, 0);
-				    ret = 1;
-				    goto cont;
-				}
-			    }
-		}
-		m = (Module) getdata(node);
-		if (del)
-		    m->wrapper++;
-		if (unload_module(m, node))
-		    ret = 1;
-		if (del)
-		    m->wrapper--;
-	    } else if (!OPT_ISSET(ops,'i')) {
-		zwarnnam(nam, "no such module %s", *args, 0);
+	    if (unload_named_module(*args, nam, OPT_ISSET(ops,'i')))
 		ret = 1;
-	    }
-	    cont: ;
 	}
 	return ret;
     } else if(!*args) {
@@ -1645,7 +1668,7 @@
 	    /* This is a definition for an autoloaded condition, load the *
 	     * module if we haven't tried that already. */
 	    if (f) {
-		load_module(p->module);
+		load_module_silence(p->module, 0);
 		f = 0;
 		p = NULL;
 	    } else {
@@ -2086,7 +2109,7 @@
 
 		removemathfunc(q, p);
 
-		load_module(n);
+		load_module_silence(n, 0);
 
 		return getmathfunc(name, 0);
 	    }
Index: Src/zsh.mdd
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/zsh.mdd,v
retrieving revision 1.12
diff -u -r1.12 zsh.mdd
--- Src/zsh.mdd	15 Feb 2005 18:32:39 -0000	1.12
+++ Src/zsh.mdd	20 Jul 2005 13:59:36 -0000
@@ -38,6 +38,12 @@
 
 zshpaths.h: Makemod $(CONFIG_INCS)
 	@echo '#define MODULE_DIR "'$(MODDIR)'"' > zshpaths.h.tmp
+	@if test x$(sitescriptdir) != xno; then \
+	  echo '#define SITESCRIPT_DIR "'$(sitescriptdir)'"' >> zshpaths.h.tmp; \
+	fi
+	@if test x$(scriptdir) != xno; then \
+	  echo '#define SCRIPT_DIR "'$(scriptdir)'"' >> zshpaths.h.tmp; \
+	fi
 	@if test x$(sitefndir) != xno; then \
 	  echo '#define SITEFPATH_DIR "'$(sitefndir)'"' >> zshpaths.h.tmp; \
 	fi
Index: Src/Modules/newuser.c
===================================================================
RCS file: Src/Modules/newuser.c
diff -N Src/Modules/newuser.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Src/Modules/newuser.c	20 Jul 2005 13:59:36 -0000
@@ -0,0 +1,99 @@
+/*
+ * newuser.c - handler for easy setup for new zsh users
+ *
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 2005 Peter Stephenson
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Peter Stephenson or the Zsh Development Group be liable
+ * to any party for direct, indirect, special, incidental, or consequential
+ * damages arising out of the use of this software and its documentation,
+ * even if Peter Stephenson and the Zsh Development Group have been advised of
+ * the possibility of such damage.
+ *
+ * Peter Stephenson and the Zsh Development Group specifically disclaim any
+ * warranties, including, but not limited to, the implied warranties of
+ * merchantability and fitness for a particular purpose.  The software
+ * provided hereunder is on an "as is" basis, and Peter Stephenson and the
+ * Zsh Development Group have no obligation to provide maintenance,
+ * support, updates, enhancements, or modifications.
+ *
+ */
+
+#include "newuser.mdh"
+#include "newuser.pro"
+
+#include "../zshpaths.h"
+
+/**/
+int
+setup_(UNUSED(Module m))
+{
+    return 0;
+}
+
+/**/
+static int
+check_dotfile(const char *dotdir, const char *fname)
+{
+    VARARR(char, buf, strlen(dotdir) + strlen(fname) + 2);
+    sprintf(buf, "%s/%s", dotdir, fname);
+
+    return access(buf, F_OK);
+}
+
+/**/
+int
+boot_(UNUSED(Module m))
+{
+    const char *dotdir = getsparam("ZDOTDIR");
+    const char *spaths[] = {
+#ifdef SITESCRIPT_DIR
+	SITESCRIPT_DIR,
+#endif
+#ifdef SCRIPT_DIR
+	SCRIPT_DIR,
+#endif
+	0 };
+    const char **sp;
+
+    if (!dotdir)
+	dotdir = home;
+
+    if (check_dotfile(dotdir, ".zshenv") == 0 ||
+	check_dotfile(dotdir, ".zprofile") == 0 ||
+	check_dotfile(dotdir, ".zshrc") == 0 ||
+	check_dotfile(dotdir, ".zlogin") == 0)
+	return 0;
+
+    for (sp = spaths; *sp; sp++) {
+	VARARR(char, buf, strlen(*sp) + 9);
+	sprintf(buf, "%s/newuser", *sp);
+
+	if (!source(buf))
+	    break;
+    }
+
+    return 0;
+}
+
+/**/
+int
+cleanup_(UNUSED(Module m))
+{
+    return 0;
+}
+
+/**/
+int
+finish_(UNUSED(Module m))
+{
+    return 0;
+}
Index: Src/Modules/newuser.mdd
===================================================================
RCS file: Src/Modules/newuser.mdd
diff -N Src/Modules/newuser.mdd
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Src/Modules/newuser.mdd	20 Jul 2005 13:59:36 -0000
@@ -0,0 +1,12 @@
+name=zsh/newuser
+link=dynamic
+# We will always try to load newuser, but there is
+# no error if it fails.
+load=no
+
+objects="newuser.o"
+
+:<<\Make
+newuser.o:  ../zshpaths.h
+
+Make

-- 
Peter Stephenson <pws@xxxxxxx>                  Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070


**********************************************************************
This email and any files transmitted with it are confidential and
intended solely for the use of the individual or entity to whom they
are addressed. If you have received this email in error please notify
the system manager.

**********************************************************************



Messages sorted by: Reverse Date, Date, Thread, Author