/*
 *	Network Queueing System (NQS)
 *  This version of NQS is Copyright (C) 1992  John Roman
 *
 *  This program 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 1, 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 General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/*
*  PROJECT:     Network Queueing System
*  AUTHOR:      John Roman
*
*  Modification history:
*
*       Version Who     When            Description
*       -------+-------+---------------+-------------------------
*       V01.10  JRR                     Initial version.
*       V01.20  JRR     12-Feb-1992	Fix up problems with static routines.
*	V01.3	JRR	17-Jun-1992	Added header.
*	V01.4	JRR	09-Mar-1993	Added Boeing enhancement for files.
*/
/*++ nqsmkdirs.c - Network Queueing System
 *
 * $Source: /usr2/jrroma/nqs/nqs-3.34/utility/RCS/nqsmkdirs.c,v $
 *
 * DESCRIPTION:
 *
 *
 *	Construct all of the subdirectories used by NQS to store
 *	request control, data, output, and transaction state files.
 *
 *
 *	Author:
 *	-------
 *	Brent A. Kingsbury, Sterling Software Incorporated.
 *	March 6, 1986.
 *
 *
 * STANDARDS VIOLATIONS:
 *   None.
 *
 * REVISION HISTORY: ($Revision: 1.4 $ $Date: 1993/07/13 21:35:00 $ $State: Exp $)
 * $Log: nqsmkdirs.c,v $
 * Revision 1.4  1993/07/13  21:35:00  jrroma
 * Version 3.34
 *
 * Revision 1.3  92/12/22  15:54:25  jrroma
 * Version 3.30
 * 
 * Revision 1.2  92/02/12  10:44:26  jrroma
 * Fix problem with static routines.
 * 
 * Revision 1.1  92/02/12  10:42:12  jrroma
 * Initial revision
 * 
 *
 */

#include <grp.h>
#include <pwd.h>
#include <errno.h>
#include "nqs.h"			/* NQS types and definitions */
#include "nqsdirs.h"			/* NQS directory and file hierarchy */

#ifndef __CEXTRACT__
#if __STDC__

static void makedirectory ( int no_of_subdirs, char *parent_name, uid_t owner_uid, gid_t owner_gid );

#else /* __STDC__ */

static void makedirectory (/* int no_of_subdirs, char *parent_name, uid_t owner_uid, gid_t owner_gid */);

#endif /* __STDC__ */
#endif /* __CEXTRACT__ */


extern char *sys_errlist[];		/* Error list explanation */

/*** main
 *
 *
 *	int main():
 */
main ()
{
	struct group *group;		/* Group entry for NQS_GROUP */
	struct passwd *passwd;		/* Password entry for NQS_OWNER */
	char *base_dir;


        if ( ! buildenv()) {
                fprintf (stderr, "Unable to establish directory ");
                fprintf (stderr, "independent environment.\n");
                fflush (stdout);
                fflush (stderr);
                exit(1);                /* Exit */
        }
	if (getuid() != 0) {
		/*
		 *  You must be running as root to run this utility.
		 */
		printf ("Utility [nqsmkdirs]:  User is not root.\n");
		printf ("Utility [nqsmkdirs]:  Aborting.\n");
		fflush (stdout);
		fflush (stderr);
		exit (1);
	}
	/*
	 *  We are definitely running as root.
	 *  Verify that the NQS_GROUP as defined in the NQS Makefile
	 *  exists, and set our real group-id to be NQS_GROUP.
	 */
#ifndef	NQS_GROUP
The symbol NQS_GROUP must be exported from the Makefile invocation.
#else
	group = getgrnam (NQS_GROUP);
#endif
	if (group == (struct group *) 0) {
		/*
		 *  The NQS_GROUP as configured is not known on the
		 *  local system!
		 */
		printf ("Utility [nqsmkdirs]:  NQS_GROUP def invalid.\n");
		printf ("Utility [nqsmkdirs]:  Aborting.\n");
		fflush (stdout);
		fflush (stderr);
		exit (2);
	}
	if (setgid (group->gr_gid) == -1) {
		/*
		 *  The setgid() call failed!
		 */
		printf ("Utility [nqsmkdirs]:  Unable to setgid (%1d).\n",
			group->gr_gid);
		printf ("Utility [nqsmkdirs]:  Reason: %s.\n",
			sys_errlist [errno]);
		printf ("Utility [nqsmkdirs]:  Aborting.\n");
		fflush (stdout);
		fflush (stderr);
		exit (3);
	}
	/*
	 *  Verify that the NQS_OWNER as defined in the NQS Makefile
	 *  exists.
	 */
#ifndef	NQS_OWNER
The symbol NQS_OWNER must be exported from the Makefile invocation.
#else
	passwd = getpwnam (NQS_OWNER);
#endif
	if (passwd == (struct passwd *) 0) {
		/*
		 *  The NQS_OWNER as configured is not known on the
		 *  local system!
		 */
		printf ("Utility [nqsmkdirs]:  NQS_OWNER def invalid.\n");
		printf ("Utility [nqsmkdirs]:  Aborting.\n");
		fflush (stdout);
		fflush (stderr);
		exit (4);
	}
	/*
	 *  Change our directory to the NQS root directory to begin
	 *  our work.
	 */
        base_dir = getfilnam (Nqs_root, SPOOLDIR);
        if (base_dir == (char *)NULL) {
                printf ("Utility [rnqsmkdirs]:  Unable to determine ");
                printf ("root directory name.\n");
                exit (5);
        }

	if (chdir (base_dir) == -1) {
		/*
		 *  Unable to change directory to the NQS root directory.
		 */
		printf ("Utility [nqsmkdirs]:  Unable to chdir to %s.\n", base_dir);
		printf ("Utility [nqsmkdirs]:  Reason: %s.\n",
			sys_errlist [errno]);
		printf ("Utility [nqsmkdirs]:  Aborting.\n");
		relfilnam (base_dir);
		fflush (stdout);
		fflush (stderr);
		exit (5);
	}
	relfilnam (base_dir);
	/*
	 *  The subdirectories that we are going to create, must be created
	 *  with a mode of 777.  Therefore, we clear the umask....
	 */
	umask (0);
	/*
	 *  Build the necessary subdirectories.
	 */
	makedirectory (MAX_CTRLSUBDIRS, Nqs_control,
		      (uid_t) passwd->pw_uid, (gid_t) group->gr_gid);
	makedirectory (MAX_DATASUBDIRS, Nqs_data,
		      (uid_t) passwd->pw_uid, (gid_t) group->gr_gid);
	makedirectory (MAX_OUTPSUBDIRS, Nqs_output,
		      (uid_t) passwd->pw_uid, (gid_t) group->gr_gid);
	makedirectory (MAX_TDSCSUBDIRS, Nqs_transact,
		      (uid_t) passwd->pw_uid, (gid_t) group->gr_gid);
	printf ("Utility [nqsmkdirs]:  NQS database subdirectory ");
	printf ("construction is complete.\n");
	printf ("Utility [nqsmkdirs]:  Exiting.\n");
	fflush (stdout);
	fflush (stderr);
	sync();				/* Schedule all dirty system I/O */
					/* buffers for writing (so that */
					/* directory blocks refering to the */
					/* newly created files will be */
					/* securely written to disk */
	exit (0);
}


/*** makedirectory()
 *
 *
 *	void makedirectory():
 *
 *	Construct the subdirectories for the specified NQS database parent
 *	directory.
 */
static void makedirectory (no_of_subdirs, parent_name, owner_uid, owner_gid)
int no_of_subdirs;			/* #of subdirectories to create */
char *parent_name;			/* Name of parent directory */
uid_t owner_uid;			/* Owner user-id */
gid_t owner_gid;			/* Owner group-id */
{
	char *argv [4];			/* Argv() to mkdir() */
	char *envp [1];			/* Envp() to mkdir() */
	char path [MAX_PATHNAME+1];	/* NQS pathname */
	register int i;			/* Iteration counter */
	int waitstatus;			/* Child wait status */
	int childpid;			/* Child process-id */
#if	HPUX
	char	command[512];
#endif

	/*
	 *  Loop to create the control-file directory subdirectories.
	 */
	for (i = 0; i < no_of_subdirs; i++) {
		childpid = fork();
		if (childpid == -1) {
			/*
			 *  The fork was not successful!
			 */
			printf ("Utility [nqsmkdirs]:  Unable to fork() ");
			printf ("mkdir process.\n");
			printf ("Utility [nqsmkdirs]:  Reason: %s.\n",
				sys_errlist [errno]);
			printf ("Utility [nqsmkdirs]:  Aborting.\n");
			fflush (stdout);
			fflush (stderr);
			sync();		/* Schedule all dirty system I/O */
					/* buffers for writing (so that */
					/* directory blocks refering to the */
					/* newly created files will be */
					/* securely written to disk */
			exit (6);
		}
		if (childpid == 0) {
			/*
			 *  We are the child mkdir process.
			 */
			pack6name (path, parent_name, (int) i, (char *) 0,
				   0L, 0, 0L, 0, 0, 0);
#if	HPUX
			sprintf(command, "mkdir -p %s",path);
			printf ("Utility [nqsmkdirs]:  Executing: %s.\n",
				command);
			system(command);
			exit(0);
#else
#if	DECOSF
			argv [0] = "mkdir";
#else
			argv [0] = "-mkdir";
#endif
			argv [1] = path;
			argv [2] = (char *) 0;
			envp [0] = (char *) 0;
			/*
			 *  Create the named directory.
			 */
			printf ("Utility [nqsmkdirs]:  Creating: %s.\n",
				path);
#if	DECOSF
			execve ("/sbin/mkdir", argv, envp);
#else
			execve ("/bin/mkdir", argv, envp);
#endif
			/*
			 *  The execve() failed!
			 */
			printf ("Utility [nqsmkdirs]:  Unable to execve() ");
			printf ("mkdir program.\n");
			printf ("Utility [nqsmkdirs]:  Reason: %s.\n",
				sys_errlist [errno]);
			printf ("Utility [nqsmkdirs]:  Exiting.\n");
			fflush (stdout);
			fflush (stderr);
			kill (getpid(), 9);	/* Kill ourselves so */
						/* that the parent aborts */
						/* as well */
#endif
		}
		/*
		 *  As the parent, we wait for the mkdir process
		 *  to complete.
		 */
		while (wait (&waitstatus) == -1 && errno == EINTR)
			;
		/*
		 *  The child has exited.
		 */
		if ((waitstatus & 0xFF) == 0) {
			/*
			 *  The mkdir process exited normally.
			 */
			printf ("Utility [nqsmkdirs]:  mkdir exited (%1d).\n",
			       (waitstatus >> 8) & 0xFF);
		}
		else if ((waitstatus & 0xFF00) == 0) {
			/*
			 *  The mkdir process was terminated by a signal!
			 */
			printf ("Utility [nqsmkdirs]:  mkdir terminated ");
			printf ("by signal (%1d).\n", waitstatus & 0x7F);
			printf ("Utility [nqsmkdirs]:  Aborting.\n");
			fflush (stdout);
			fflush (stderr);
			sync();		/* Schedule all dirty system I/O */
					/* buffers for writing (so that */
					/* directory blocks refering to the */
					/* newly created files will be */
					/* securely written to disk */
			exit (7);
		}
		else {
			/*
			 *  The mkdir program stopped!
			 */
			printf ("Utility [nqsmkdirs]:  mkdir stopped by ");
			printf ("signal (%1d).\n", (waitstatus >> 8) & 0xFF);
			printf ("Utility [nqsmkdirs]:  Aborting.\n");
			fflush (stdout);
			fflush (stderr);
			sync();		/* Schedule all dirty system I/O */
					/* buffers for writing (so that */
					/* directory blocks refering to the */
					/* newly created files will be */
					/* securely written to disk */
			exit (8);
		}
		/*
		 *  Change the mode of any previously existing subdirectories
		 *  to 777.
		 */
		chmod (path, 0777);
		/*
		 *  Change the owner and group of any previously existing
		 *  subdirectories to NQS_OWNER and NQS_GROUP.
		 */
		chown (path, (int) owner_uid, (int) owner_gid);
	}
}
