2021-10-11 19:38:01 -03:00

424 lines
8.1 KiB
C
Executable File

#pragma ident "@(#)rem_drv.c 1.6 95/01/12 SMI"
/*
* Copyright (c) 1993 by Sun Microsystems, Inc.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <libintl.h>
#include <string.h>
#include <fcntl.h>
#include <sys/buf.h>
#include <sys/stat.h>
#include <sys/modctl.h>
#include <sys/wait.h>
#include <limits.h>
#include <malloc.h>
#include <locale.h>
#include "addrem.h"
#include "errmsg.h"
static int get_major_number(char *, major_t *);
static void get_mod(char *, int *);
static int devfs_clean(char *);
static int devfs_alias_clean(char *);
static void *get_aliases(char *, char *);
static void usage();
main(int argc, char *argv[])
{
int opt;
char *basedir = NULL;
int server = 0;
char *driver_name = NULL;
major_t major;
FILE *fp;
FILE *reconfig_fp;
struct stat buf;
int modid;
char maj_num[MAX_STR_MAJOR + 1];
char dummy[FILENAME_MAX + 1];
char ret_str[MAXLEN_NAM_TO_MAJ_ENT + 1];
int found;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
#endif
(void) textdomain(TEXT_DOMAIN);
/* must be run by root */
if (getuid() != 0) {
(void) fprintf(stderr, gettext(ERR_NOT_ROOT));
exit(1);
}
while ((opt = getopt(argc, argv, "b:")) != -1) {
switch (opt) {
case 'b' :
server = 1;
basedir = calloc(strlen(optarg) + 1, 1);
if (basedir == NULL) {
(void) fprintf(stderr, gettext(ERR_NO_MEM));
exit(1);
}
(void) strcat(basedir, optarg);
break;
case '?' :
usage();
exit(1);
}
}
if (argv[optind] != NULL) {
driver_name = calloc(strlen(argv[optind]) + 1, 1);
if (driver_name == NULL) {
(void) fprintf(stderr, gettext(ERR_NO_MEM));
exit(1);
}
(void) strcat(driver_name, argv[optind]);
/*
* check for extra args
*/
if ((optind + 1) != argc) {
usage();
exit(1);
}
} else {
usage();
exit(1);
}
/* set up add_drv filenames */
if ((build_filenames(basedir)) == ERROR) {
exit(1);
}
/* must be only running version of add_drv/rem_drv */
if ((stat(add_rem_lock, &buf) == -1) && errno == ENOENT) {
fp = fopen(add_rem_lock, "a");
(void) fclose(fp);
} else {
(void) fprintf(stderr,
gettext(ERR_PROG_IN_USE));
exit(1);
}
if ((some_checking(1, 1)) == ERROR)
err_exit();
if (!server) {
if ((get_major_number(driver_name, &major)) == ERROR) {
err_exit();
}
/* get the module id for this driver */
get_mod(driver_name, &modid);
/* module is installed */
if (modid != -1) {
if (modctl(MODUNLOAD, modid) < 0) {
perror(NULL);
(void) fprintf(stderr, gettext(ERR_MODUN),
driver_name);
}
}
}
if (devfs_alias_clean(driver_name) == ERROR) {
(void) fprintf(stderr,
gettext(ERR_DEVFSALCLEAN),
driver_name);
}
if (devfs_clean(driver_name) == ERROR) {
(void) fprintf(stderr,
gettext(ERR_DEVFSCLEAN), driver_name);
}
/*
* add driver to rem_name_to_major; if this fails, don`t
* delete from name_to_major
*/
if (get_file_entry(driver_name, name_to_major, ret_str,
&found) == ERROR) {
(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
rem_name_to_major);
err_exit();
}
/* no entry in REM_NAM_TO_MAJ */
if (found == UNIQUE) {
(void) fprintf(stderr, gettext(ERR_NOT_INSTALLED),
driver_name);
err_exit();
}
if (sscanf(ret_str, "%s%s", dummy, maj_num) != 2) {
(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
rem_name_to_major);
err_exit();
}
if (append_to_file(driver_name, maj_num,
rem_name_to_major, ' ', " ") == ERROR) {
(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
rem_name_to_major);
err_exit();
}
/*
* delete references to driver in add_drv/rem_drv database
*/
remove_entry(CLEAN_ALL, driver_name);
exit_unlock();
/*
* Create reconfigure file; want the driver removed
* from kernel data structures upon reboot
*/
reconfig_fp = fopen(RECONFIGURE, "a");
(void) fclose(reconfig_fp);
return (NOERR);
}
/* get major number from kernel, not name_to_major */
int
get_major_number(
char *driver_name,
major_t *major_number)
{
major_t major;
if (modctl(MODGETMAJBIND, driver_name, strlen(driver_name) + 1,
&major) < 0) {
perror(NULL);
(void) fprintf(stderr, gettext(ERR_NO_MAJ), driver_name);
return (ERROR);
} else {
*major_number = major;
return (NOERR);
}
}
void
get_mod(char *driver_name, int *mod)
{
struct modinfo modinfo;
modinfo.mi_id = -1;
modinfo.mi_info = MI_INFO_ALL;
do {
/*
* If we are at the end of the list of loaded modules
* then set *mod = -1 and return
*/
if (modctl(MODINFO, 0, &modinfo) < 0) {
*mod = -1;
return;
}
*mod = modinfo.mi_id;
} while (strcmp(driver_name, modinfo.mi_name) != 0);
}
int
devfs_clean(char *driver_name)
{
char devname[PATH_MAX + FILENAME_MAX + 1];
char dev_colon[FILENAME_MAX + 1];
char dev_at[FILENAME_MAX + 1];
char dev_clone[FILENAME_MAX + 1];
int fd[2];
int fdhold[2];
int child;
int waitstat;
if (pipe(fd)) {
perror(NULL);
(void) fprintf(stderr, gettext(ERR_PIPE));
return (ERROR);
}
if (pipe(fdhold)) {
perror(NULL);
(void) fprintf(stderr, gettext(ERR_PIPE));
return (ERROR);
}
/* save values of stdin/stout for next call */
(void) dup2(1, fdhold[1]);
(void) dup2(0, fdhold[0]);
if ((child = fork()) == 0) {
(void) close(1);
(void) dup(fd[1]);
(void) close(fd[1]);
(void) close(fd[0]);
(void) strcpy(dev_colon, driver_name);
(void) strcat(dev_colon, ":*");
(void) strcpy(dev_at, driver_name);
(void) strcat(dev_at, "@*");
(void) strcpy(dev_clone, "clone:");
(void) strcat(dev_clone, driver_name);
(void) execl("/usr/bin/find", "find", devfs_root, "(", "-name",
dev_colon, "-o", "-name", dev_at, "-o", "-name",
dev_clone, ")", "-print", 0);
/* i really shouldn`t ever be here .... */
perror(NULL);
(void) fprintf(stderr, gettext(ERR_EXEC));
}
/*
* Close writer end of pipe so catch EOF
*/
(void) close(0);
(void) dup(fd[0]);
(void) close(fd[0]);
(void) close(fd[1]);
(void) close(1);
devname[0] = '\0';
while ((gets(devname)) != NULL) {
if (unlink(devname)) {
perror(NULL);
(void) fprintf(stderr, gettext(ERR_UNLINK), devname);
}
}
(void) waitpid(child, &waitstat, 0);
/*
* reset stdin/stdout
*/
(void) dup2(fdhold[1], 1);
(void) dup2(fdhold[0], 0);
return (NOERR);
}
int
devfs_alias_clean(char *driver)
{
char *alias_list = NULL;
char *prev;
char *current;
char one_alias[FILENAME_MAX];
int status = NOERR;
alias_list = get_aliases(driver, DRIVER_ALIAS);
if (alias_list == NULL) {
return (NOERR);
}
prev = alias_list;
do {
current = get_entry(prev, one_alias, ' ');
if (devfs_clean(one_alias) == ERROR) {
status = ERROR;
}
prev = current;
} while (*current != '\0');
return (status);
}
/*
* Search thru <file_name> for <driver_name>
* if found, add next field to matches list
* return matches list
* Assumption: file format: <driver_name> <string>
* Assumption: may be 0-n entries for any given driver
*/
void *
get_aliases(
char *driver_name,
char *file_name)
{
FILE *fp;
char drv[MAX_STR_MAJOR + 1];
char entry[FILENAME_MAX + 1];
char line[MAX_N2M_ALIAS_LINE + 1];
int first_match = 1;
char *matches = NULL;
char *tmp_match;
int len;
fp = fopen(file_name, "r");
if (fp == NULL) {
perror(NULL);
(void) fprintf(stderr, gettext(ERR_CANNOT_OPEN),
file_name);
return (NULL);
}
while ((fgets(line, sizeof (line), fp) != 0)) {
if (sscanf(line, "%s%s", drv, entry) != 2) {
(void) fprintf(stderr, gettext(ERR_BAD_LINE),
file_name, line);
continue;
}
if (strcmp(driver_name, drv) == 0) {
if (first_match) {
matches = calloc(strlen(entry) +2, 1);
if (matches == NULL) {
perror(NULL);
(void) fprintf(stderr,
gettext(ERR_NO_MEM));
return (NULL);
}
(void) strcpy(matches, entry);
first_match = 0;
} else {
len = strlen(matches) + strlen(entry) + 2;
tmp_match = realloc(matches, len);
matches = tmp_match;
(void) strcat(matches, " ");
(void) strcat(matches, entry);
}
}
}
(void) fclose(fp);
return (matches);
}
static void
usage()
{
(void) fprintf(stderr, gettext(REM_USAGE1));
}