/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

#ident	"@(#)main.c	1.4	92/07/14 SMI"       /* SVr4.0 1.7 */

/*
 *  devattr.c
 *
 *  Contains the following:
 *	devattr		Command that returns [specific] attributes for
 *			a device.
 */

/*
 *  devattr [-v] device [attr [...]]
 *
 *	This command searches the device table file for the device specified.
 *	If it finds the device (matched either by alias or major and minor 
 *	device number), it extracts the attribute(s) specified and writes 
 *	that value to the standard output stream (stdout).
 *
 *	The command writes the values of the attributes to stdout one per 
 *	line, in the order that they were requested.  If the -v option is 
 *	requested, it writes the attributes in the form <attr>='<value>' where
 *	<attr> is the name of the attribute and <value> is the value of that 
 *	attribute.
 *
 *  Returns:
 *	0	The command succeeded
 *	1	The command syntax is incorrect,
 *		An invalid option was used,
 *		An internal error occurred that prevented completion
 *	2	The device table could not be opened for reading.
 *	3	The requested device was not found in the device table
 *	4	A requested attribute was not defined for the device
 */

/*
 *  Header files referenced:
 *	<sys/types.h>	UNIX System Data Types
 *	<stdio.h>	C standard I/O definitions
 *	<string.h>	C string manipulation definitions
 *	<errno.h>	Error-code definitions
 *	<fmtmsg.h>	Standard message display definitions
 *	<devmgmt.h>	Device management headers
 */

#include	<sys/types.h>
#include	<stdio.h>
#include	<string.h>
#include	<errno.h>
#include	<fmtmsg.h>
#include	<devmgmt.h>
#include	<stdlib.h>


/*
 *  External functions and variables referenced (not defined by header files)
 *
 *	getopt()	Function that parses options from the command-line
 *	optind		Index of the next argument to process
 *	opterr		Flag for getopt() TRUE tells the command to write 
 *			an error message, FALSE disables writing error-
 *			messages by getopt().
 *	putenv()	Put a value into the environment
 *	exit()		Return to invocation environment
 *	_opendevtab()	Open the device table
 *	_devtabpath()	Get the pathname of the device table
 */

int		_opendevtab();
char	       *_devtabpath();

/*
 *  Local constant definitions
 *	TRUE		Boolean TRUE
 *	FALSE		Boolean FALSE
 *	NULL		Null address
 */

#ifndef	TRUE
#define	TRUE	1
#endif

#ifndef	FALSE
#define	FALSE	0
#endif

#ifndef	NULL
#define	NULL	0
#endif


/*
 *  Messages
 *	M_USAGE		Usage error
 *	M_ERROR		Unexpected internal error
 *	M_NODEV		Device not found in the device table
 *	M_NOATTR	Attribute not found
 *	M_DEVTAB	Can't open the device table
 */

#define	M_USAGE		"usage: devattr [-v] device [attribute [...]]"
#define	M_ERROR		"Internal error, errno=%d"
#define	M_NODEV		"Device not found in the device table: %s"
#define	M_NOATTR	"Attrubute not found: %s"
#define	M_DEVTAB	"Cannot open the device table: %s"


/* 
 * Exit codes:
 *	EX_OK		All's well that ends well
 *	EX_ERROR	Some problem caused termination
 *	EX_DEVTAB	Device table could not be opened
 *	EX_NODEV	The device wasn't found in the device table
 *	EX_NOATTR	A requested attribute wasn't defined for the device
 */

#define	EX_OK 		0
#define	EX_ERROR	1
#define	EX_DEVTAB	2
#define	EX_NODEV	3
#define	EX_NOATTR	4


/*
 *  Macros
 *	stdmsg(r,l,s,t)	    Standard Message Generator
 *				r	Recoverability flag
 *				l	Standard Label
 *				s	Severity
 *				t	Text
 */

#define	stdmsg(r,l,s,t)	(void) fmtmsg(MM_PRINT|MM_UTIL|r,l,s,t,MM_NULLACT,MM_NULLTAG)


/*
 *  Local static data
 *	lbl	Buffer for the command label (for messages)
 *	txt		Buffer for the text of messages
 */

static char	lbl[MM_MXLABELLN+1];
static char	txt[MM_MXTXTLN+1];

/*
 *  main()
 *
 *	Implements the command "devattr".   This function parses the command 
 *	line, then calls the devattr() function looking for the specified 
 *	device and the requested attribute.  It writes the information to
 *	the standard output file in the requested format.
 *
 * Exits:
 *	0	The command succeeded
 *	1	The command syntax is incorrect,
 *		An invalid option was used,
 *		An internal error occurred that prevented completion
 *	2	The device table could not be opened for reading.
 *	3	The requested device was not found in the device table
 *	4	A requested attribute was not defined for the device
 */

main(argc, argv)
	int	argc;		/* Number of arguments */
	char   *argv[];		/* Pointer to arguments */
{

	/* Automatic data */
	char   *cmdname;		/* Pointer to command name */
	char   *device;			/* Pointer to device name */
	char   *attr;			/* Pointer to current attribute */
	char   *value;			/* Pointer to current attr value */
	char   *p;			/* Temporary character pointer */
	char  **argptr;			/* Pointer into argv[] list */
	int	syntaxerr;		/* TRUE if invalid option seen */
	int	noerr;			/* TRUE if all's well in processing */
	int	v_seen;			/* TRUE if -v is on the command-line */
	int	exitcode;		/* Value to return */
	int	severity;		/* Message severity */
	int	c;			/* Temp char value */


	/*
	 *  Parse the command-line.
	 */

	syntaxerr = FALSE;
	v_seen = FALSE;

	/* Extract options */
	opterr = FALSE;
	while ((c = getopt(argc, argv, "v")) != EOF) switch(c) {

	    /* -v option:  No argument, may be seen only once */
	    case 'v':
		if (!v_seen) v_seen = TRUE;
		else syntaxerr = TRUE;
		break;

	    /* Unknown option */
	    default:
		syntaxerr = TRUE;
	    break;
	}

	/* Build the command name */
	cmdname = argv[0];
	if ((p = strrchr(cmdname, '/')) != (char *) NULL) cmdname = p+1;
	(void) strcat(strcpy(lbl, "UX:"), cmdname);

	/* Make only the text-component of messages appear (remove this in SVR4.1) */
	(void) putenv("MSGVERB=text");

	/* 
	 * Check for a usage error 
	 *  - invalid option
	 *  - arg count < 2
	 *  - arg count < 3 && -v used 
	 */

	if (syntaxerr || (argc < (optind+1))) {
	    stdmsg(MM_NRECOV, lbl, MM_ERROR, M_USAGE);
	    exit(EX_ERROR);
	}

	/* Open the device file (if there's one to be opened) */
	if (!_opendevtab("r")) {
	    if (p = _devtabpath()) {
		(void) sprintf(txt, M_DEVTAB, p);
		exitcode = EX_DEVTAB;
		severity = MM_ERROR;
	    } else {
		(void) sprintf(txt, M_ERROR, errno);
		exitcode = EX_ERROR;
		severity = MM_HALT;
	    }
	    stdmsg(MM_NRECOV, lbl, severity, txt);
	    exit(exitcode);
	}


	/* 
	 *  Get the list of known attributes for the device.  This does 
	 *  two things.  First, it verifies that the device is known in the 
	 *  device table.  Second, it gets the attributes to list just in 
	 *  case no attributes were specified.  Then, set a pointer to the 
	 *  list of attributes to be extracted and listed...  
	 */

	device = argv[optind];
	if ((argptr = listdev(device)) == (char **) NULL) {
	    if (errno == ENODEV) {
		(void) sprintf(txt, M_NODEV, device);
		exitcode = EX_NODEV;
		severity = MM_ERROR;
	    } else {
		(void) sprintf(txt, M_ERROR, errno);
		exitcode = EX_ERROR;
		severity = MM_HALT;
	    }
	    stdmsg(MM_NRECOV, lbl, severity, txt);
	    exit(exitcode);
	}
	if (argc > (optind+1)) argptr = &argv[optind+1];


	/*
	 *  List attributes.  If a requested attribute is not defined, 
	 *  list the value of that attribute as null.  (Using shell 
	 *  variables as the model for this.)
	 */

	exitcode = EX_OK;
	noerr = TRUE;
	while (noerr && ((attr = *argptr++) != (char *) NULL)) {
	    if (!(value = devattr(device, attr))) {
		if (errno == EINVAL) {
		    value = "";
		    (void) sprintf(txt, M_NOATTR, attr);
		    /* stdmsg(MM_RECOVER, lbl, MM_WARNING, txt); */
		    exitcode = EX_NOATTR;
		} else {
		    noerr = FALSE;
		    (void) sprintf(txt, M_ERROR, errno);
		    stdmsg(MM_NRECOV, lbl, MM_ERROR, txt);
		    exitcode = EX_ERROR;
		}
	    }
	    if (noerr && v_seen) {
		(void) fputs(attr, stdout);
		(void) fputs("='", stdout);
		for (p = value ; *p ; p++) {
		    (void) putc(*p, stdout);
		    if (*p == '\'') (void) fputs("\"'\"'", stdout);
		}
		(void) fputs("'\n", stdout);
	    } else if (noerr) {
		(void) fputs(value, stdout);
		(void) putc('\n', stdout);
	    }
	}

	/* Exit */
	exit(exitcode);
#ifdef	lint
	return(0);
#endif
}
