1213 lines
34 KiB
C
1213 lines
34 KiB
C
static char sccsid[] = "@(#)00 1.12 src/bos/usr/lib/methods/cfglft/cfglft.c, lftdd, bos41J, 9516B_all 4/18/95 10:02:50";
|
|
/*
|
|
* COMPONENT_NAME: (LFTDD) LFT configuration routine
|
|
*
|
|
* FUNCTIONS:
|
|
*
|
|
* main, build_dds, make_special_files,
|
|
* err_exit, err_undo1, err_undo2
|
|
*
|
|
* ORIGIN: 27
|
|
*
|
|
* IBM CONFIDENTIAL -- (IBM Confidential Restricted when
|
|
* combined with the aggregated modules for this product)
|
|
* SOURCE MATERIALS
|
|
* (C) COPYRIGHT International Business Machines Corp. 1994
|
|
* Unpublished Work
|
|
* All Rights Reserved
|
|
* Licensed Material - Property of IBM
|
|
*
|
|
* US Government Users Restricted Rights - Use, duplication or
|
|
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
|
|
*/
|
|
|
|
|
|
/* Include files needed for this module follow */
|
|
#include <lft.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <stdlib.h>
|
|
#include <sys/sysmacros.h>
|
|
#include <sys/sysconfig.h>
|
|
#include <sys/device.h>
|
|
|
|
|
|
/* device configuration include files */
|
|
#include <sys/cfgodm.h>
|
|
#include <sys/cfgdb.h>
|
|
#include <cf.h>
|
|
#include "cfgdebug.h"
|
|
|
|
#include "ttycfg.h"
|
|
#include "ldtty.h"
|
|
#include "stream_tioc.h"
|
|
|
|
#include <sys/stropts.h>
|
|
#include <sys/sad.h>
|
|
|
|
|
|
/* Set permissions for special file */
|
|
#define MODE S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
|
|
|
|
/* define path for lft device */
|
|
#define DEV_PATH "/dev/"
|
|
|
|
/* modules info */
|
|
#define LDTERM_MODULE "ldterm"
|
|
#define TIOC_MODULE "tioc"
|
|
#define ADMINDEV "/dev/sad"
|
|
|
|
/* Define strings for inittab file */
|
|
#define LFTID "\"lft\""
|
|
#define LFTON "\"lft:2:respawn:/usr/sbin/getty /dev/lft0\""
|
|
|
|
/*
|
|
* NAME: build_dds
|
|
*
|
|
* FUNCTION:
|
|
* build_dds will allocate memory for the dds structure, reporting any
|
|
* errors, then open the Customized Attribute Class to get the attribute
|
|
* objects needed for filling the dds structure.
|
|
*
|
|
* EXECUTION ENVIRONMENT:
|
|
* This function is called from the device independent module used
|
|
* for configuring all devices.
|
|
*
|
|
* RETURNS:
|
|
* 0 on success
|
|
* positive return code on failure
|
|
*
|
|
*/
|
|
build_dds(lname, dds_out, size)
|
|
char *lname; /* logical name of device */
|
|
char **dds_out; /* pointer to dds structure for return */
|
|
int *size; /* pointer to dds structure size */
|
|
{
|
|
lft_dds_t *dds; /* pointer to dds structure */
|
|
struct CuAt cuat; /* customized attribute object */
|
|
struct CuAt *cuat_ptr; /* customized attribute object */
|
|
struct PdAt pdat; /* predefined attribute object */
|
|
struct PdAt *pdat_ptr; /* predefined attribute object */
|
|
struct PdAt *pdat_ptr2; /* predefined attribute object */
|
|
struct objlistinfo pdat_info; /* result of search stats */
|
|
struct CuDv *cudv, *cudv_ptr2; /* ptr to customized device object */
|
|
struct CuDv cudv_obj; /* custom device obj for odm_get_obj*/
|
|
struct objlistinfo cudv_info; /* result of search stats */
|
|
ulong value; /* temp variable to get value into */
|
|
char temp[256];
|
|
char crit[256]; /* search criteria string */
|
|
char def_dsp[NAMESIZE]; /* holds name of default display */
|
|
dev_t devno; /* used to obtain device number */
|
|
struct CuAt *get_attrval(); /* get_attribute value routine */
|
|
int rc,x,i,index; /* temporary variables */
|
|
int nbr_displays; /* number of displays found */
|
|
int tmp_fd; /* temp file descriptor */
|
|
int font_id;
|
|
int kbd_fnd; /* Did we find a keyboard */
|
|
static char font_files[LFTNUMFONTS][FILE_NAME_LEN]; /* font file names */
|
|
static char swkbd_file[FILE_NAME_LEN]; /* swkbd file name */
|
|
|
|
/*
|
|
* The first thing to do is get the total number of displays
|
|
* that are available to the lft. Once we have this number we can then
|
|
* allocate the memory for the dds structure.
|
|
*/
|
|
|
|
/* Get a list of adapter types belonging to the lft from the PdAt */
|
|
pdat_ptr = pdat_ptr2 = (struct PdAt *)odm_get_list(PdAt_CLASS,
|
|
"deflt='graphics' AND attribute='belongs_to'",&pdat_info,1,1);
|
|
if ( pdat_ptr == (struct PdAt *) -1 )
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","odm_get_list",-1,
|
|
CFG_ODM_PDAT, UNIQUE_1);
|
|
DEBUG_0("build_dds : error in retrieving displays from PdAt\n");
|
|
return(E_ODMGET);
|
|
}
|
|
|
|
/* loop thru each adapter type to get total number of displays */
|
|
for (i = 1,nbr_displays=0;pdat_ptr && i<=pdat_info.num; i++,pdat_ptr++)
|
|
{
|
|
/* get number of available displays for each display type */
|
|
sprintf(crit,"PdDvLn = '%s' AND status = '%d'",
|
|
pdat_ptr->uniquetype, AVAILABLE);
|
|
cudv = (struct CuDv *)
|
|
odm_get_list(CuDv_CLASS,crit,&cudv_info,1,1);
|
|
if ( cudv == (struct CuDv *) -1 )
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","odm_get_list",-1,
|
|
CFG_ODM_CUDV, UNIQUE_2);
|
|
DEBUG_0("build_dds : error getting list from CuDv\n");
|
|
if(pdat_ptr2)
|
|
odm_free_list(pdat_ptr2, &pdat_info);
|
|
return(E_ODMGET);
|
|
}
|
|
if(cudv)
|
|
{
|
|
/* add number of displays found to the total */
|
|
nbr_displays += cudv_info.num;
|
|
odm_free_list(cudv, &cudv_info);
|
|
}
|
|
}
|
|
|
|
/* Check if any displays were found, if not the LFT method fails. */
|
|
if( nbr_displays == 0 )
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft",NULL,0,
|
|
CFG_NO_DISPS, UNIQUE_3);
|
|
DEBUG_0("build_dds: no displays configured\n");
|
|
if(pdat_ptr2)
|
|
odm_free_list(pdat_ptr2, &pdat_info);
|
|
return(E_NODEPENDENT);
|
|
}
|
|
|
|
/*
|
|
* Obtain size of device specific dds structure. The lft_dds structure
|
|
* already has an array of 1 display structures in it so we need
|
|
* to add the number of displays found minus one display structures.
|
|
*/
|
|
|
|
*size = sizeof(lft_dds_t) + ((nbr_displays -1) * sizeof(lft_disp_t));
|
|
|
|
/* allocate the space required for the dds structure */
|
|
if( (dds = (lft_dds_t *) malloc(*size)) == NULL )
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","malloc",0, CFG_NO_MEM,
|
|
UNIQUE_4);
|
|
DEBUG_0("build_dds : malloc failed for dds structure\n");
|
|
if(pdat_ptr2)
|
|
odm_free_list(pdat_ptr2, &pdat_info);
|
|
return(E_MALLOC);
|
|
}
|
|
|
|
/* zero out the dds */
|
|
bzero( dds, *size);
|
|
|
|
/*
|
|
* Get all the font pathnames from the CuAt and PdAt. Copy each
|
|
* font filename into the dds.
|
|
* Store the total number of fonts found in the dds.
|
|
*/
|
|
dds->number_of_fonts = 0;
|
|
for( i = 0; i < LFTNUMFONTS; i++ )
|
|
{
|
|
sprintf(crit, "font%d_path", i+1);
|
|
if( get_attrval(lname, crit, temp, &value, &rc) == NULL )
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","getattr",0,
|
|
CFG_ODM_CUAT, UNIQUE_5);
|
|
DEBUG_1("font%d_path not found\n", i + 1);
|
|
}
|
|
if( temp[0] != '\0' )
|
|
{
|
|
strcpy(font_files[dds->number_of_fonts], temp);
|
|
++dds->number_of_fonts;
|
|
}
|
|
}
|
|
|
|
if( dds->number_of_fonts == 0 )
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft",NULL,0, CFG_NO_FONTS,
|
|
UNIQUE_6);
|
|
DEBUG_1("No fonts for %s\n", lname);
|
|
if(pdat_ptr2)
|
|
odm_free_list(pdat_ptr2, &pdat_info);
|
|
return(E_DDS);
|
|
}
|
|
|
|
dds->font_file_name = (char*) font_files[0];
|
|
|
|
/*
|
|
* Search the ODM for all available displays for the lft and store
|
|
* all the corresponding information in the array of display structures.
|
|
* Get the default display name and set its corresponding display
|
|
* index in the dds. Check for a custom font associated with each
|
|
* display and store the results into the display structure.
|
|
* Store the total number of displays found.
|
|
*/
|
|
|
|
/* Get the default display name */
|
|
if( (cuat_ptr = getattr(lname,"default_disp",FALSE,&rc)) == NULL )
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","getattr",0,
|
|
CFG_ODM_CUAT,UNIQUE_7);
|
|
DEBUG_0("build_dds : error getting default_disp from CuAt\n");
|
|
if(pdat_ptr2)
|
|
odm_free_list(pdat_ptr2, &pdat_info);
|
|
return(E_ODMGET);
|
|
}
|
|
strcpy(def_dsp, cuat_ptr->value);
|
|
|
|
|
|
/*
|
|
loop thru each adapter type for a list of available adapters
|
|
The index variable points to the current display in the array
|
|
of display info. It gets incremented each time a new available
|
|
display is found
|
|
*/
|
|
pdat_ptr = pdat_ptr2;
|
|
dds->default_disp_index = -1; /* set default index to -1 */
|
|
for ( i = 1, index = 0; pdat_ptr && i <= pdat_info.num; i++,pdat_ptr++)
|
|
{
|
|
/*
|
|
* Get a list of available adapter device names from the list
|
|
* of adapter types. The names come from the 'name' field of
|
|
* the CuDv class. (ie.. 'ppr0'). The 'status' field having a
|
|
* value of 1 means the given adapter is available.
|
|
*/
|
|
sprintf(crit,"PdDvLn = '%s' AND status = '%d'",
|
|
pdat_ptr->uniquetype, AVAILABLE);
|
|
cudv = cudv_ptr2 = (struct CuDv *)
|
|
odm_get_list(CuDv_CLASS,crit,&cudv_info,1,1);
|
|
if ( cudv == (struct CuDv *) -1 )
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","odm_get_list",-1,
|
|
CFG_ODM_CUDV,UNIQUE_8);
|
|
DEBUG_0("build_dds : error getting list from CuDv\n");
|
|
if(pdat_ptr2)
|
|
odm_free_list(pdat_ptr2, &pdat_info);
|
|
return(E_ODMGET);
|
|
}
|
|
|
|
/*
|
|
* loop thru list of available adapters, storing the device
|
|
* name and devno for each available display into the dds
|
|
* display structure. If a custom font exists for a display
|
|
* then store it in the associated display structure.
|
|
*/
|
|
for (x = 1; cudv && x <= cudv_info.num; x++, cudv++, index++)
|
|
{
|
|
/* store devno and devname into display structure */
|
|
if((rc=get_devno(cudv->name,
|
|
&dds->displays[index].devno)) != E_OK)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft",
|
|
"get_devno",rc,
|
|
CFG_BAD_DEVNO,UNIQUE_9);
|
|
DEBUG_1("build_dds : error getting devno \
|
|
of display %s\n", cudv->name);
|
|
if(pdat_ptr2)
|
|
odm_free_list(pdat_ptr2, &pdat_info);
|
|
return(rc);
|
|
}
|
|
strcpy(dds->displays[index].devname, cudv->name);
|
|
|
|
/* if display is default, then store index into dds */
|
|
if( ! strcmp(def_dsp, cudv->name) )
|
|
dds->default_disp_index = index;
|
|
|
|
/*
|
|
* Check if custom font exists for display. If legal
|
|
* font index found then store it otherwise store -1
|
|
* and remove it from CuAt if it exists.
|
|
*/
|
|
dds->displays[index].font_index = -1;
|
|
sprintf(crit,"name='%s' AND attribute='custom_font'",
|
|
cudv->name);
|
|
|
|
if((rc = (int)odm_get_first(CuAt_CLASS,crit,&cuat)) > 0)
|
|
{
|
|
font_id = atoi(cuat.value);
|
|
if( font_id >= 0 &&
|
|
font_id < dds->number_of_fonts)
|
|
{
|
|
dds->displays[index].font_index =
|
|
font_id;
|
|
}
|
|
else
|
|
{
|
|
/* invalid custom font so remove it */
|
|
odm_rm_obj(CuAt_CLASS, crit);
|
|
}
|
|
}
|
|
|
|
} /* for all available displays */
|
|
if(cudv_ptr2)
|
|
odm_free_list(cudv_ptr2, &cudv_info);
|
|
|
|
} /* for all adapter types */
|
|
if(pdat_ptr2)
|
|
odm_free_list(pdat_ptr2, &pdat_info);
|
|
|
|
/* store the total number of displays found. */
|
|
dds->number_of_displays = nbr_displays;
|
|
|
|
/*
|
|
* if a default display was found in the CuAt and that display was
|
|
* not available to the lft, or no default display was found in the
|
|
* CuAt, then force the default_disp attribute in the ODM to the
|
|
* first display found and set the default index to zero.
|
|
*/
|
|
if ( (def_dsp[0] != '\0' && dds->default_disp_index == -1) ||
|
|
( def_dsp[0] == '\0') )
|
|
{
|
|
strcpy(cuat_ptr->value, dds->displays[0].devname);
|
|
if( putattr(cuat_ptr) == -1 )
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","putattr",-1,
|
|
CFG_ODM_CUAT,UNIQUE_10);
|
|
DEBUG_0("build_dds : error updating default_disp \
|
|
in the CuAt\n");
|
|
return(E_ODMGET);
|
|
}
|
|
dds->default_disp_index = 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* All keyboards have the attribute 'sys_kbd' defined in their PdAt
|
|
* class. The odm_get_list function is used to create a list of
|
|
* these. The uniquetype from this list is used to look for the
|
|
* logical name in the CuDv class (PdDvLn = <uniquetype> and status =
|
|
* AVAILABLE).
|
|
*/
|
|
|
|
pdat_ptr = pdat_ptr2 = (struct PdAt *) odm_get_list(PdAt_CLASS,
|
|
"attribute = 'sys_kbd'", &pdat_info,1,1);
|
|
if (pdat_ptr == (struct PdAt *) -1)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","odm_get_list",-1,
|
|
CFG_ODM_PDAT,UNIQUE_11);
|
|
DEBUG_0("build_dds: error retrieving keyboard information \
|
|
from PdAt\n");
|
|
return(E_ODMGET);
|
|
}
|
|
|
|
/*
|
|
* We now have the list - walk this to find the keyboard that is
|
|
* in the available state and get its logical name.
|
|
*/
|
|
for (i = 1, kbd_fnd = 0; pdat_ptr && i <=pdat_info.num; i++,pdat_ptr++)
|
|
{
|
|
sprintf(crit, "PdDvLn = '%s' AND status = '%d'",
|
|
pdat_ptr->uniquetype, AVAILABLE);
|
|
rc = (int) odm_get_obj(CuDv_CLASS,crit,&cudv_obj, ODM_FIRST);
|
|
if(rc == -1) /* Failed */
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","odm_get_obj",-1,
|
|
CFG_ODM_CUDV,UNIQUE_12);
|
|
DEBUG_0("build_dds: Could not retrieve keyboard \
|
|
information from CuDv\n");
|
|
if(pdat_ptr2)
|
|
odm_free_list(pdat_ptr2, &pdat_info);
|
|
return(E_NOCuDv);
|
|
}
|
|
if(rc == 0) /* no entry found */
|
|
continue; /* go get the next */
|
|
|
|
if( (rc = get_devno(cudv_obj.name, &dds->kbd.devno)) != 0 )
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","get_devno",rc,
|
|
CFG_BAD_DEVNO,UNIQUE_13);
|
|
DEBUG_1("build_dds : error getting devno of \
|
|
keyboard %s\n", cudv_obj.name);
|
|
if(pdat_ptr2)
|
|
odm_free_list(pdat_ptr2, &pdat_info);
|
|
return(rc);
|
|
}
|
|
strcpy(dds->kbd.devname, cudv_obj.name);
|
|
kbd_fnd++;
|
|
break;
|
|
} /* end of for */
|
|
|
|
if(pdat_ptr2)
|
|
odm_free_list(pdat_ptr2, &pdat_info);
|
|
|
|
if(!kbd_fnd) /* no keyboard ! */
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft",NULL,-1,
|
|
CFG_NO_KYBD,UNIQUE_14);
|
|
DEBUG_0("build_dds : No available system keyboard found.\n");
|
|
#ifdef KBDRQD
|
|
return(-1);
|
|
#else
|
|
dds->kbd.devno = -1;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Search the PdAt class for a 'fkproc' attribute. If one is found
|
|
* then set the 'start_fkproc' member of the dds to true. This flag
|
|
* is used by the lft driver to indicate whether the font server
|
|
* process needs to be invoked.
|
|
*/
|
|
|
|
pdat_ptr = (struct PdAt *)odm_get_list(PdAt_CLASS,
|
|
"attribute = 'fkproc'",&pdat_info,1,1);
|
|
if ( pdat_ptr == (struct PdAt *) -1 )
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","odm_get_list",-1,
|
|
CFG_ODM_PDAT,UNIQUE_15);
|
|
DEBUG_0("build_dds : error in retrieving 'fkproc' from PdAt\n");
|
|
return(E_ODMGET);
|
|
}
|
|
if ( pdat_ptr && pdat_info.num > 0)
|
|
dds->start_fkproc = TRUE;
|
|
else
|
|
dds->start_fkproc = FALSE;
|
|
|
|
if(pdat_ptr) /* done with the list so free it */
|
|
odm_free_list(pdat_ptr, &pdat_info);
|
|
|
|
/*
|
|
* Get the pathname to the software keyboard file and copy the
|
|
* the pathname into the dds. Before copying in the pathname
|
|
* be sure the file can be opened. If it can't then try the
|
|
* filename from the PdAt.
|
|
*/
|
|
if( get_attrval(lname, "swkb_path", temp, &value, &rc) == NULL )
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","get_attrval",0,
|
|
CFG_ODM_CUAT,UNIQUE_16);
|
|
DEBUG_0("cfglft: found no swkb_path\n");
|
|
return(rc);
|
|
}
|
|
if( (tmp_fd = open(temp, O_RDONLY)) != -1 )
|
|
{
|
|
/* Open ok so copy in the pathname */
|
|
strcpy( swkbd_file, temp);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The open failed probably from a path stored in the CuAt.
|
|
* Lets now try to open the default file stored in the PdAt.
|
|
*/
|
|
strcpy(crit, "attribute = 'swkb_path'");
|
|
if ((rc = (int)odm_get_first(PdAt_CLASS, crit, &pdat)) <= 0)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","odm_get_first",
|
|
rc, CFG_ODM_PDAT,UNIQUE_17);
|
|
DEBUG_2("cfglft: crit=%s found no objects,rc = %d\n",
|
|
crit,rc);
|
|
return(E_NOATTR);
|
|
}
|
|
|
|
if( (tmp_fd = open(pdat.deflt, O_RDONLY)) == -1 )
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","open",-1,
|
|
CFG_NO_SWKBD,UNIQUE_18);
|
|
DEBUG_1("Can't open keyboard file : %s\n",pdat.deflt);
|
|
return(E_DDS);
|
|
}
|
|
else
|
|
{
|
|
strcpy( swkbd_file, pdat.deflt);
|
|
}
|
|
}
|
|
dds->swkbd_file = swkbd_file;
|
|
close(tmp_fd); /* close the swkb file */
|
|
|
|
/* Copy the lft logical device name and devno to dds */
|
|
strcpy(dds->lft.devname, lname);
|
|
|
|
/* store dds pointer to be returned */
|
|
*dds_out = (char *)dds;
|
|
|
|
/* Retrieve the 3 timeout values used by Display Power Manager */
|
|
for( i = 0; i < 3; i++ )
|
|
{
|
|
sprintf(crit, "pwr_mgr_t%d", i+1);
|
|
if( (cuat_ptr = getattr(lname,crit,FALSE,&rc)) == NULL )
|
|
{
|
|
/* There is a problem with non CCM graphics adapter during
|
|
* installation. What happens is that on a system with more
|
|
* one adapter, only one display is turned on. Consequently,
|
|
* one only see one message "hit Fx to select this display as
|
|
* the console for installation". This is confusing for users.
|
|
* Therefore, to fix this problem, we have to move the PdAts
|
|
* for DPMS from lft.add into a separate file, so that we don't
|
|
* find it during installation. The lft packaging is modified to
|
|
* install this new .add so that we can enable DPMS during normal
|
|
* boot.
|
|
*/
|
|
dds->pwr_mgr_time[i] = 0; /* zero disable DPMS during non normal boot */
|
|
continue;
|
|
}
|
|
dds->pwr_mgr_time[i] = atoi(cuat_ptr->value) * 60; /* convert minutes into seconds */
|
|
}
|
|
|
|
|
|
/*
|
|
* Find the console
|
|
*/
|
|
if (( cuat_ptr = getattr("sys0", "syscons", FALSE, &rc )) == NULL )
|
|
{
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
* If the console is not defined (i.e., users have not selected it), set this flag
|
|
* to tell the LFT DD start DPMS. Note this flag take precedence over the first
|
|
* zero time-out value
|
|
*/
|
|
if (strcmp(cuat_ptr->value,"") == 0)
|
|
{
|
|
dds->enable_dpms = 0; /* don't start DPMS */
|
|
}
|
|
else
|
|
{
|
|
dds->enable_dpms = 1; /* enable DPMS */
|
|
}
|
|
|
|
|
|
return(E_OK);
|
|
}
|
|
|
|
|
|
/*
|
|
* NAME: make_special_files
|
|
*
|
|
* FUNCTION: Device dependent routine creating the devices special files
|
|
* in /dev
|
|
*
|
|
* EXECUTION ENVIRONMENT:
|
|
* This function is called from the main module.
|
|
*
|
|
* RETURNS:
|
|
* 0 - success
|
|
* positive return code on failure
|
|
*/
|
|
int
|
|
make_special_files(lname, devno)
|
|
char *lname; /* logical device name */
|
|
dev_t devno; /* major/minor number */
|
|
{
|
|
char devpath[256]; /* path to special file */
|
|
struct stat buf;
|
|
extern int errno;
|
|
|
|
/* form the full pathname for the lft special file */
|
|
strcat( strcpy(devpath, DEV_PATH), lname);
|
|
|
|
/* attempt to make the special file for lft */
|
|
if (mknod(devpath,MODE,devno))
|
|
{
|
|
/* mknod failed so see what error was */
|
|
if (errno != EEXIST)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","mknode",
|
|
errno, CFG_BAD_SP_FILE,UNIQUE_19);
|
|
DEBUG_1("make_special_files: can't mknod %s\n",devpath);
|
|
return(E_MKSPECIAL);
|
|
}
|
|
|
|
/* device already exists so get status on it */
|
|
if (stat(devpath,&buf))
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","stat",
|
|
errno, CFG_BAD_SP_FILE,UNIQUE_20);
|
|
DEBUG_1("make_special_files: cannot stat %s\n",devpath);
|
|
return(E_MKSPECIAL);
|
|
}
|
|
/* check if devno of new matches devno of existing file */
|
|
/* and file format is correct */
|
|
if ( major(buf.st_rdev)==major(devno) &&
|
|
minor(buf.st_rdev)==minor(devno) &&
|
|
((buf.st_mode & (S_IFMT|S_ISVTX)) == S_IFCHR))
|
|
return(E_OK);
|
|
|
|
/* unlink existing special file name */
|
|
if (unlink(devpath))
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","unlink",
|
|
errno, CFG_BAD_SP_FILE,UNIQUE_21);
|
|
DEBUG_1("make_special_files:can't unlink %s\n",devpath);
|
|
return(E_MKSPECIAL);
|
|
}
|
|
|
|
/* try mknod again */
|
|
if (mknod(devpath,MODE,devno))
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","mknode",
|
|
errno, CFG_BAD_SP_FILE,UNIQUE_22);
|
|
DEBUG_1("make_special_files: can't mknod %s\n",devpath);
|
|
return(E_MKSPECIAL);
|
|
}
|
|
}
|
|
|
|
chmod(devpath, MODE); /* give new file correct permissions */
|
|
|
|
return(E_OK);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* NAME: main
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* The purpose of cfglft is to configure the LFT pseudo device into
|
|
* the system and make it ready for use. It is called with the name
|
|
* of the logical device representing the LFT and possibly a flag
|
|
* representing which phase the configuration is taking place in.
|
|
*
|
|
* EXECUTION ENVIRONMENT:
|
|
*
|
|
* RETURNS:
|
|
*/
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
struct cfg_dd cfg; /* sysconfig command structure */
|
|
|
|
char *logical_name; /* logical name to configure */
|
|
char sstring[256]; /* search criteria pointer */
|
|
|
|
struct CuDv cusobj; /* customized device object storage */
|
|
struct PdDv preobj; /* predefined device object storage */
|
|
struct CuAt *cuat_ptr; /* customized attribute object */
|
|
|
|
mid_t kmid; /* module id from loader */
|
|
dev_t devno; /* device number for config_dd */
|
|
|
|
long majorno, minorno; /* major and minor numbers */
|
|
long *minor_ptr; /* pointer returned by getminor */
|
|
int how_many; /* number of minors in list */
|
|
int ipl_phase; /* ipl phase: 0=run,1=phase1,2=phase2 */
|
|
int rc; /* return codes go here */
|
|
char *outp, *errp; /* stdout and stderr for odm_run_method *
|
|
|
|
extern int optind; /* for getopt function */
|
|
extern char *optarg; /* for getopt function */
|
|
int errflg,c; /* used in parsing parameters */
|
|
|
|
|
|
/* Parse the input parameters */
|
|
|
|
ipl_phase = RUNTIME_CFG;
|
|
errflg = 0;
|
|
logical_name = NULL;
|
|
|
|
while ((c = getopt(argc,argv,"l:12")) != EOF)
|
|
{
|
|
switch (c)
|
|
{
|
|
case 'l': /* logical name parameter */
|
|
if (logical_name != NULL)
|
|
errflg++;
|
|
logical_name = optarg;
|
|
break;
|
|
case '1': /* phase 1 of IPL */
|
|
if (ipl_phase != RUNTIME_CFG)
|
|
errflg++;
|
|
ipl_phase = PHASE1;
|
|
break;
|
|
case '2': /* phase 2 of IPL */
|
|
if (ipl_phase != RUNTIME_CFG)
|
|
errflg++;
|
|
ipl_phase = PHASE2;
|
|
break;
|
|
default:
|
|
errflg++;
|
|
}
|
|
}
|
|
if (errflg)
|
|
{
|
|
/* error parsing parameters */
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft",NULL,0,CFG_BAD_PARMS,UNIQUE_23);
|
|
DEBUG_0("cfglft: command line error\n");
|
|
exit(E_ARGS);
|
|
}
|
|
|
|
/* Validate logical name was specified */
|
|
if (strncmp(logical_name, "lft", 3) )
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft",NULL,0,CFG_BAD_LNAME,UNIQUE_24);
|
|
DEBUG_0("cfglft: logical name must be specified\n");
|
|
exit(E_LNAME);
|
|
}
|
|
|
|
/* Start up odm. */
|
|
if ((rc = odm_initialize()) < 0)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","odm_initialize",-1,
|
|
CFG_ODM_INIT, UNIQUE_25);
|
|
DEBUG_0("cfglft: odm_initialize() failed\n");
|
|
exit(E_ODMINIT);
|
|
}
|
|
|
|
/* Search CuDv for customized object with the logical name passed in */
|
|
|
|
sprintf(sstring, "name = '%s'", logical_name);
|
|
if ((rc = (int)odm_get_first(CuDv_CLASS, sstring, &cusobj)) == 0)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","odm_get_first",0,
|
|
CFG_ODM_CUDV, UNIQUE_26);
|
|
DEBUG_1("cfglft: No CuDv object found for %s\n", logical_name);
|
|
err_exit(E_NOCuDv);
|
|
}
|
|
else if (rc == -1)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","odm_get_first",-1,
|
|
CFG_ODM_CUDV, UNIQUE_27);
|
|
DEBUG_1("cfglft: ODM failure getting CuDv, crit=%s\n",sstring);
|
|
err_exit(E_ODMGET);
|
|
}
|
|
|
|
/*
|
|
* Get the predefined object for this device. This object is located
|
|
* searching the predefined devices object class based on the unique
|
|
* type link descriptor found in the CuDv class.
|
|
*/
|
|
sprintf(sstring, "uniquetype = '%s'", cusobj.PdDvLn_Lvalue);
|
|
if ((rc = (int)odm_get_first(PdDv_CLASS, sstring, &preobj)) == 0)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","odm_get_first",0,
|
|
CFG_ODM_PDDV, UNIQUE_28);
|
|
DEBUG_1("cfglft: found no PdDv object for crit=%s\n", sstring);
|
|
err_exit(E_NOPdDv);
|
|
}
|
|
else if (rc == -1)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","odm_get_first",-1,
|
|
CFG_ODM_PDDV, UNIQUE_29);
|
|
DEBUG_1("cfglft: ODM failure getting PdDv, crit=%s\n",sstring);
|
|
err_exit(E_ODMGET);
|
|
}
|
|
|
|
/*
|
|
* If this device is being configured during an ipl phase, then
|
|
* display this device's LED value on the system LEDs.
|
|
*/
|
|
if (ipl_phase != RUNTIME_CFG)
|
|
setleds(preobj.led);
|
|
|
|
/*
|
|
* Check to see if the device is already defined.
|
|
* We actually go about the business of configuring the device
|
|
* only if the device is defined. Configuring the device in this
|
|
* case refers to the process of checking for attribute consistency,
|
|
* building a DDS, loading the driver, etc...
|
|
*/
|
|
if (cusobj.status == DEFINED)
|
|
{
|
|
if (cusobj.chgstatus == MISSING)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft",NULL,0,CFG_DEV_MISSING,
|
|
UNIQUE_30);
|
|
DEBUG_1("cfglft: device %s is MISSING\n",logical_name);
|
|
err_exit(E_DEVSTATE);
|
|
}
|
|
|
|
/* create and initialize the dds structure for the lft */
|
|
if ((rc = build_dds(logical_name, &cfg.ddsptr, &cfg.ddslen))
|
|
!= E_OK)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","build_dds",rc,
|
|
CFG_BAD_DDS, UNIQUE_31);
|
|
DEBUG_1("cfglft: error building dds, rc=%d\n", rc)
|
|
err_exit(rc);
|
|
}
|
|
|
|
/*
|
|
* Check to see if the device has a device driver. If it
|
|
* does, then call loadext(). If needed, this function
|
|
* will load the driver and return the driver's kernel
|
|
* module id (kmid). If the device has a driver, then the
|
|
* device driver instance field in the device's customized
|
|
* object will be a pathname to the device driver in the
|
|
* directory /etc/drivers.
|
|
*/
|
|
if (strcmp(preobj.DvDr, "") != 0)
|
|
{
|
|
/* Call loadext() to load device driver. */
|
|
if ((cfg.kmid = loadext(preobj.DvDr, TRUE, FALSE))
|
|
== NULL)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","loadext",0,
|
|
CFG_BAD_LOAD, UNIQUE_32);
|
|
DEBUG_1("cfglft: error loading driver %s\n",
|
|
preobj.DvDr);
|
|
err_exit(E_LOADEXT);
|
|
}
|
|
|
|
/*
|
|
* genmajor() will create a major number for this device
|
|
* if one has not been created yet. If one already
|
|
* exists, it will return that one.
|
|
*/
|
|
if ((majorno = genmajor(preobj.DvDr)) == -1)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","genmajor",-1,
|
|
CFG_BAD_MAJOR, UNIQUE_33);
|
|
DEBUG_0("cfglft:error creating major number\n");
|
|
err_undo1(preobj.DvDr); /* unload driver */
|
|
err_exit(E_MAJORNO);
|
|
}
|
|
|
|
/* Create minor number. */
|
|
minor_ptr = getminor(majorno, &how_many, logical_name);
|
|
if (minor_ptr == NULL || how_many == 0)
|
|
{
|
|
if((minor_ptr = genminor(logical_name, majorno,
|
|
-1,1,1,1)) == NULL)
|
|
{
|
|
reldevno(logical_name, TRUE);
|
|
err_undo1(preobj.DvDr);
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft",
|
|
"genminor",0,
|
|
CFG_BAD_MINOR,
|
|
UNIQUE_34);
|
|
DEBUG_0("cfglft: error creating minor \
|
|
number\n")
|
|
err_exit(E_MINORNO);
|
|
}
|
|
}
|
|
minorno = *minor_ptr;
|
|
|
|
/* Create devno for this device */
|
|
cfg.devno = makedev(majorno, minorno);
|
|
((lft_dds_t*)cfg.ddsptr)->lft.devno = cfg.devno;
|
|
|
|
/* Now call sysconfig() to configure the driver. */
|
|
cfg.cmd = CFG_INIT;
|
|
if (sysconfig(SYS_CFGDD, &cfg,
|
|
sizeof(struct cfg_dd )) == -1)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","sysconfig",-1,
|
|
CFG_BAD_INIT, UNIQUE_35);
|
|
DEBUG_1("cfglft: error configuring driver %s\n",
|
|
logical_name);
|
|
err_undo1(preobj.DvDr);
|
|
err_exit(E_CFGINIT);
|
|
}
|
|
|
|
/*
|
|
* Now make the special files that this device will
|
|
* be accessed through.
|
|
*/
|
|
if ((rc = make_special_files(logical_name, cfg.devno))
|
|
!= E_OK)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft",
|
|
"make_special_files",rc,
|
|
CFG_BAD_SP_FILE, UNIQUE_36);
|
|
DEBUG_2("cfglft: error making special file \
|
|
for %s, devno=0x%x\n",
|
|
logical_name, cfg.devno);
|
|
err_undo2(cfg.devno);
|
|
err_undo1(preobj.DvDr);
|
|
err_exit(rc);
|
|
}
|
|
|
|
/* Push on the ldterm and tioc streams modules */
|
|
if ((rc = lft_autopush(cfg.devno)) != SUCCESS )
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","lft_autopush",
|
|
rc, CFG_BAD_STREAM, UNIQUE_37);
|
|
DEBUG_1("cfglft: error pushing streams modules \
|
|
for %s\n", logical_name);
|
|
err_undo2(cfg.devno);
|
|
err_undo1(preobj.DvDr);
|
|
err_exit(rc);
|
|
}
|
|
|
|
} /* end if (device has a driver) then ... */
|
|
|
|
/*
|
|
* Update the customized object to reflect the device's
|
|
* current status. The device status field should be
|
|
* changed to AVAILABLE, and, if they were generated, the
|
|
* device's major & minor numbers should be updated.
|
|
*/
|
|
cusobj.status = AVAILABLE;
|
|
if ((rc = odm_change_obj(CuDv_CLASS, &cusobj)) < 0)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","odm_change_obj",-1,
|
|
CFG_ODM_CUDV, UNIQUE_38);
|
|
DEBUG_0("cfglft: ODM failure updating CuDv object\n");
|
|
err_undo2(cfg.devno);
|
|
err_undo1(preobj.DvDr);
|
|
unlink(DEV_PATH);
|
|
err_exit(E_ODMUPDATE);
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
The following checks for the pathname of the console - lft or tty
|
|
The console device pathname is a customizes attribute belonging
|
|
to the system object - sys0. We use getattr to search the CuAt
|
|
first followed by PdAt if nothing is found in CuAt
|
|
*/
|
|
if( (cuat_ptr = getattr("sys0","syscons",FALSE,&rc)) == NULL )
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","getattr",0,
|
|
CFG_ODM_CUAT,UNIQUE_39);
|
|
DEBUG_0("cfglft : error getting syscons from CuAt\n");
|
|
return(E_ODMGET);
|
|
}
|
|
/*
|
|
If the value for attribute syscons is not lft0, we will make
|
|
an entry in the /etc/inittab file using the mkitab command.
|
|
If the value for attribute syscons is lft0, it implies that
|
|
the system console is set to lft therefore we should delete any
|
|
lft entry in the inittab file so that multiple gettys do not
|
|
occur on the lft.
|
|
*/
|
|
|
|
rc = odm_run_method("/usr/sbin/lsitab", LFTID, &outp, &errp);
|
|
if ( strncmp("lft0", cuat_ptr->value + 5, 4) != 0 )
|
|
{
|
|
if(rc == 1 && cuat_ptr->value[0] != '\0')
|
|
{
|
|
/* LFT is not console and not in inittab, so create it */
|
|
rc = odm_run_method("/usr/sbin/mkitab", LFTON, &outp, &errp);
|
|
if(rc == -1)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft", "odm_run_method",0,
|
|
CFG_BAD_INIT, UNIQUE_40);
|
|
DEBUG_0("cfglft: error updating inittab using mkitab.\n");
|
|
}
|
|
}
|
|
else if(rc == 0 && cuat_ptr->value[0] == '\0')
|
|
{
|
|
/* Console is not defined and has LFT in inittab, so remove it */
|
|
rc = odm_run_method("/usr/sbin/rmitab", LFTID, &outp, &errp);
|
|
if(rc == -1)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft", "odm_run_method",0,
|
|
CFG_BAD_INIT, UNIQUE_46);
|
|
DEBUG_0("cfglft: error updating inittab using rmitab.\n");
|
|
}
|
|
}
|
|
}
|
|
else if(rc == 0)
|
|
{
|
|
/* LFT is the console and has entry in inittab, so remove it */
|
|
rc = odm_run_method("/usr/sbin/rmitab", LFTID, &outp, &errp);
|
|
if(rc == -1)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft", "odm_run_method",0,
|
|
CFG_BAD_INIT, UNIQUE_47);
|
|
DEBUG_0("cfglft: error updating inittab using rmitab.\n");
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Terminate the ODM and exit with success
|
|
*/
|
|
odm_terminate();
|
|
exit(E_OK);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* NAME: lft_autopush
|
|
*
|
|
* FUNCTION: Loads the ldterm and tioc streams modules and then makes
|
|
* a ioctl call to SAD to autopush them on the lft stream.
|
|
*
|
|
* EXECUTION ENVIRONMENT:
|
|
*
|
|
* This routine is to be used only within this file.
|
|
* This function make all stuff concerning lft stream part cfg.
|
|
* Mainly :
|
|
* - Loads the necessary modules
|
|
* - Passes them the dds (if they have one)
|
|
* - invokes the sad driver to auto push them
|
|
*
|
|
* RETURNS:
|
|
* 0 = SUCCESS
|
|
*/
|
|
|
|
int
|
|
lft_autopush(dev_t devno)
|
|
{
|
|
struct strapush modules_list; /* list of modules to push */
|
|
struct cfg_kmod cfg; /* structure for module configuration */
|
|
struct ldterm_dds l_dds;
|
|
struct tioc_dds t_dds;
|
|
|
|
int file_desc;
|
|
int cr;
|
|
|
|
/*
|
|
The ldterm and tioc dds structures are needed to allow the
|
|
strload counter to be set properly.
|
|
*/
|
|
bzero((char * )&l_dds, sizeof(struct ldterm_dds));
|
|
l_dds.which_dds = LDTERM_DDS;
|
|
|
|
bzero((char * )&t_dds, sizeof(struct tioc_dds));
|
|
t_dds.which_dds = TIOC_DDS;
|
|
|
|
/*
|
|
Zero the module_list structure. The information in this
|
|
structure is retured by the streams_ioctl in ucfglft.
|
|
*/
|
|
bzero((char *)&modules_list, sizeof(struct strapush));
|
|
|
|
/*
|
|
Then We've to loadext the two modules (LDTERM and TIOC) got from the
|
|
list in ODM and call their sysconfig entry:
|
|
- LDTERM
|
|
- TIOC
|
|
*/
|
|
cfg.cmd = CFG_INIT;
|
|
cfg.mdiptr = (caddr_t)&l_dds;
|
|
cfg.mdilen = sizeof (struct ldterm_dds);
|
|
cfg.kmid = loadext(LDTERM_MODULE, TRUE, FALSE);
|
|
cr = sysconfig(SYS_CFGKMOD, &cfg, sizeof(cfg));
|
|
if(cr)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","loadext",cr,
|
|
CFG_BAD_LOAD, UNIQUE_41);
|
|
DEBUG_1("cfglft: error loading ldterm. rc = %d\n",cr);
|
|
return (cr);
|
|
}
|
|
cfg.cmd = CFG_INIT;
|
|
cfg.mdiptr = (caddr_t)&t_dds;
|
|
cfg.mdilen = sizeof (struct tioc_dds);
|
|
cfg.kmid = loadext(TIOC_MODULE, TRUE, FALSE);
|
|
cr = sysconfig(SYS_CFGKMOD, &cfg, sizeof(cfg));
|
|
if(cr)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","loadext",cr,
|
|
CFG_BAD_LOAD, UNIQUE_42);
|
|
DEBUG_1("cfglft: error loading tioc. rc = %d\n",cr);
|
|
return (cr);
|
|
}
|
|
|
|
/* Opens sad device */
|
|
file_desc = stream_open(ADMINDEV, O_RDWR);
|
|
|
|
|
|
/*
|
|
And this is the interface with SAD driver to register the auto-push.
|
|
*/
|
|
strncpy(modules_list.sap_list[0],LDTERM_MODULE,sizeof(LDTERM_MODULE));
|
|
strncpy(modules_list.sap_list[1],TIOC_MODULE,sizeof(TIOC_MODULE));
|
|
modules_list.sap_cmd = SAP_ONE;
|
|
modules_list.sap_major = major(devno);
|
|
modules_list.sap_minor = minor(devno);
|
|
modules_list.sap_lastminor = 0;
|
|
modules_list.sap_npush = 2;
|
|
|
|
|
|
/* Calls sad to push these modules at next open of the line */
|
|
cr = stream_ioctl(file_desc, SAD_SAP, &modules_list);
|
|
stream_close(file_desc);
|
|
if(cr != 0)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","loadext",cr,
|
|
CFG_BAD_LOAD, UNIQUE_43);
|
|
DEBUG_1("cfglft: error in SAD_SAP: rc = %d\n",cr);
|
|
}
|
|
return (cr);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* NAME: err_exit
|
|
*
|
|
* FUNCTION: Terminates ODM. Used to back out on an error.
|
|
*
|
|
* EXECUTION ENVIRONMENT:
|
|
*
|
|
* This routine is to be used only within this file.
|
|
*
|
|
* NOTES:
|
|
*
|
|
* err_exit( exitcode )
|
|
* exitcode = The error exit code.
|
|
*
|
|
* RETURNS:
|
|
* None
|
|
*/
|
|
|
|
err_exit(exitcode)
|
|
char exitcode;
|
|
{
|
|
/*
|
|
* Terminate the ODM
|
|
*/
|
|
odm_terminate();
|
|
|
|
exit(exitcode);
|
|
}
|
|
|
|
|
|
/*
|
|
* NAME: err_undo1
|
|
*
|
|
* FUNCTION: Unloads the device's device driver. Used to back out on an
|
|
* error.
|
|
*
|
|
* EXECUTION ENVIRONMENT:
|
|
*
|
|
* This routine is to be used only within this file.
|
|
*
|
|
* NOTES:
|
|
*
|
|
* void
|
|
* err_undo1( DvDr )
|
|
* DvDr = pointer to device driver name.
|
|
*
|
|
* RETURNS:
|
|
* None
|
|
*/
|
|
|
|
err_undo1(DvDr)
|
|
char *DvDr; /* pointer to device driver name */
|
|
{
|
|
/* unload driver */
|
|
if (loadext(DvDr,FALSE,FALSE) == NULL)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","loadext",0,
|
|
CFG_BAD_UNLOAD, UNIQUE_44);
|
|
DEBUG_0("cfglft: error unloading driver\n");
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* NAME: err_undo2
|
|
*
|
|
* FUNCTION: Terminates the device. Used to back out on an error.
|
|
*
|
|
* EXECUTION ENVIRONMENT:
|
|
*
|
|
* This routine is to be used only within this file.
|
|
*
|
|
* NOTES:
|
|
*
|
|
* void
|
|
* err_undo2( devno )
|
|
* devno = The device's devno.
|
|
*
|
|
* RETURNS:
|
|
* None
|
|
*/
|
|
|
|
err_undo2(devno)
|
|
dev_t devno; /* The device's devno */
|
|
{
|
|
struct cfg_dd cfg; /* sysconfig command structure */
|
|
|
|
/* terminate device */
|
|
cfg.devno = devno;
|
|
cfg.kmid = (mid_t)0;
|
|
cfg.ddsptr = (caddr_t) NULL;
|
|
cfg.ddslen = (int)0;
|
|
cfg.cmd = CFG_TERM;
|
|
|
|
if (sysconfig(SYS_CFGDD,&cfg,sizeof(struct cfg_dd)) == -1)
|
|
{
|
|
cfg_lfterr(NULL,"CFGLFT","cfglft","sysconfig",-1,
|
|
CFG_BAD_TERM, UNIQUE_45);
|
|
DEBUG_0("cfglft: error unconfiguring device\n");
|
|
}
|
|
return;
|
|
}
|