PDA

View Full Version : Problem with hwsetup.c, booting from USB pen drive



ally85
07-30-2008, 12:40 PM
Hi everybody! I'm new in this forum.
I am installing a Linux distribution on a USB pen drive. Once I had configured the kernel, I have installed the bash shell, the grub and the following packages: coreutils, e2fsprogs, sysvinit, util-linux.
Now I want to automatically detect mouse when booting from the pen drive. I have modified the knoppix hwsetup.c file as follows:
/************************************************** **************************\
* HWSETUP - non-interactive hardware detection and configuration *
* loads modules, generates /dev links, no isapnp autoconfiguration (yet) *
* needs kudzu-devel (ver. 0.23 and up) *
* Author: Klaus Knopper <knopper@knopper.net> *
\************************************************* ***************************/

/* Needed for strcasestr */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <pci/pci.h>
#undef _i_wanna_build_this_crap_
/* #define _i_wanna_build_this_crap_ 1 */ /* Necessary for ISAPNP */
#include <kudzu/kudzu.h>
#if defined(_i_wanna_build_this_crap_)
#include "isapnp.h"
#endif

#define VERSION "HWSETUP 1.2, an automatic hardware configuration tool\n" \
"(C) 2006 Klaus Knopper <knoppix@knopper.net>\n\n"

/* Note: These are for Xfree 4, not Xorg. */
#define CARDSDB "/usr/share/hwdata/Cards"
#define XPATH "/usr/X11R6/bin/"
#define XMODPATH "/usr/X11R6/lib/modules/drivers/"

#define VERBOSE_PRINT 1
#define VERBOSE_PROMPT 2

#define SKIP_AUDIO 1
#define SKIP_SCSI 2

#define MAX_TIME 180 /* Maximum of seconds to run, total */
#define MAX_TIME_MODULE 4 /* Maximum time in seconds to wait until a module */
/* is successfully loaded before continuing */

#ifdef BLACKLIST
/* Do not, under any circumstances, load these modules automatically, */
/* even if in pcitable. (libkudzu may ignore this, and the KNOPPIX */
/* autoconfig scripts may probe them, too) */
char *blacklist[] =
{ "apm","agpgart","yenta_socket","i82092","i82365","tcic",
"pcmcia_core","ds","ohci1394","hisax", "hisax_fcpcipnp",
"hisax_isac","hisax_st5481",
/* Winmodems, unusable, can block sound slot */
"snd-atiixp-modem", "snd-intel8x0m","snd-via82xx-modem"
};
#endif

/* If a conflicting module in a row is already loaded, the new module will not be probed anymore */
#define CONFLICT_SET 2
struct conflict { char *name; int loaded; } conflicts [][CONFLICT_SET] =
{
{{ "ad1848",0}, {"snd-nm256",0}},
{{ "ali5455",0}, {"intel8x0",0}},
{{ "cmpci",0}, {"snd-cmipci",0}},
{{ "cs46xx",0}, {"snd-cs46xx",0}},
{{ "cs4281",0}, {"snd-cs4281",0}},
{{ "emu10k1",0}, {"snd-emu10k1",0}},
{{ "es1370",0}, {"snd-ens1370",0}},
{{ "es1371",0}, {"snd-ens1371",0}},
{{ "esssolo1",0}, {"snd-es1938",0}},
{{ "forte",0}, {"snd-fm801",0}},
{{ "i810_audio",0}, {"snd-intel8x0",0}},
{{ "maestro",0}, {"snd-es1960",0}},
{{ "maestro3",0}, {"snd-maestro3",0}},
{{ "nm256_audio",0}, {"snd-nm256",0}},
{{ "rme96xx",0}, {"snd-rme9652",0}},
{{ "sonicvibes",0}, {"snd-sonicvibes",0}},
{{ "trident",0}, {"snd-trident",0}},
{{ "via82cxxx_audio",0}, {"snd-via82xx",0}},
{{ "ymfpci",0}, {"snd-ymfpci",0}},
{{ "sk98lin",0}, {"skge",0}}
};

struct loaded_module { char *name; struct loaded_module *next; } *loaded_modules = NULL;

/* compare module names, case insensitive and with -/_ */
int modcmp(char *m1, char *m2)
{
if(!m1 || !m2) return 1;
for(;;)
{
int c1 = tolower(*m1);
int c2 = tolower(*m2);
if(c1 == '_') c1 = '-';
if(c2 == '_') c2 = '-';
if(c1 != c2) return 1;
if(!c1 || !c2) break;
m1++; m2++;
}
return 0;
}

/* returns true if module already loaded */
int check_loaded(char *name)
{
struct loaded_module *curr = loaded_modules;
while(curr)
{
if(name && curr->name && !modcmp(name, curr->name)) return 1;
curr = curr->next;
}
return 0;
}

/* Returns name of conflicting module, or NULL if no conflict */
char *check_conflict(char *name)
{
int i;
if(!name) return 0;
for(i=0; i<(sizeof(conflicts)/sizeof(struct conflict)/CONFLICT_SET); i++)
{
int j;
for(j=0; j<CONFLICT_SET; j++)
{
if(!modcmp(name,conflicts[i][j].name) &&
conflicts[i][!j].loaded) return conflicts[i][!j].name;
}
}
return NULL;
}

void set_conflict(char *name)
{
int i;
if(!name) return;
for(i=0; i<(sizeof(conflicts)/sizeof(struct conflict)/CONFLICT_SET); i++)
{
int j;
for(j=0; j<CONFLICT_SET; j++)
{
if(!modcmp(name,conflicts[i][j].name)) conflicts[i][j].loaded=1;
}
}
}

void check_proc_modules(void)
{
struct loaded_module *curr = NULL, *new = NULL;
FILE *f = fopen("/proc/modules", "r");
if(!f) return;
for(;;)
{
char buffer[1024], *name;
memset(buffer,0,sizeof(buffer));
if(!fgets(buffer,1024, f) || ferror(f)) break;
new = (struct loaded_module *) malloc(sizeof(struct loaded_module));
if(!new) { fclose(f); return; }
memset(new,0,sizeof(struct loaded_module));
if(!loaded_modules) { loaded_modules = curr = new; }
else
{
curr->next = new;
curr = curr->next;
}
name = strtok(buffer," ");
if(!name) continue;
curr->name = strdup(name);
set_conflict(name);
}
fclose(f);
}

char *get_description(struct device *d)
{
/* pci.ids lookup using the pci library, i.e. most likely /usr/share/misc/pci.ids */
static char devbuf[128];

memset(devbuf,0,sizeof(devbuf));
if(d)
{
static struct pci_access *pacc = NULL;
int vendorid, deviceid;
switch(d->bus)
{
case BUS_PCI: vendorid=((struct pciDevice *)d)->vendorId;
deviceid=((struct pciDevice *)d)->deviceId;
break;
case BUS_USB: vendorid=((struct usbDevice *)d)->vendorId;
deviceid=((struct usbDevice *)d)->deviceId;
break;
default: return d->desc;
}
if(!pacc)
{
if(!(pacc=pci_alloc())) return d->desc;
pci_init(pacc);
}
if(vendorid>0 && deviceid>0 &&
pci_lookup_name(pacc, devbuf, sizeof(devbuf),
PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
vendorid, deviceid, 0, 0))
{
devbuf[127]=0;
return devbuf;
}
}
return d->desc;
}

/* These need to be global, so we can kill them in case of problems */
pid_t wpid=0;

int syntax(char *option)
{
printf(VERSION);
if(option) fprintf(stderr,"hwsetup: Unknown option '%s'\n\n",option);
printf("Usage: hwsetup\n"
" -v be verbose\n"
" -p print rotating prompt\n"
" -a ignore audio devices\n"
" -s ignore scsi controllers\n"
" -n probe only, don't configure anything.\n");
return option?1:0;
}

pid_t startwheel(void) /* Feedback while detecting hardware */
{
char v[]="Autoconfiguring devices... ";
char r[]="/-\\|";
char *b="\b";
pid_t pid;
if((pid=fork())>0) return pid; /* return Child PID to Master process */
else if(pid==0)
{
int i,j;
/* Allow killing of process */
signal(SIGHUP,SIG_DFL);
signal(SIGINT,SIG_DFL);
signal(SIGTERM,SIG_DFL);
write(2,v,sizeof(v)-1);
for(i=j=0;;i++,j++)
{
if(j%8==7) write(2,"\033[42;32m \033[0m",13); /* a green space */
write(2,&r[i%4],1); write(2,b,1);
usleep(40000);
}
exit(0); /* Exit child process */
}
return 0;
}

int exists(char *filename)
{
struct stat s;
return !stat(filename,&s);
}

struct xinfo {
char xserver[16];
char xmodule[16];
char xdesc[128];
char xopts[128];
};


void hw_info(struct device *d)
{
enum deviceClass class=d->type;
enum deviceBus bus=d->bus;
char *unknown="UNKNOWN";
char *desc;
/* These used to be much easier when they were still arrays... */
char *classname=class==CLASS_UNSPEC?"UNSPEC": class==CLASS_OTHER?"OTHER":
class==CLASS_NETWORK?"NETWORK":class==CLASS_SCSI?"SCSI":
class==CLASS_VIDEO?"VIDEO": class==CLASS_AUDIO?"AUDIO":
class==CLASS_MOUSE?"MOUSE": class==CLASS_MODEM?"MODEM":
class==CLASS_CDROM?"CDROM": class==CLASS_TAPE?"TAPE":
class==CLASS_FLOPPY?"FLOPPY": class==CLASS_SCANNER?"SCANNER":
class==CLASS_HD?"HD": class==CLASS_RAID?"RAID":
class==CLASS_PRINTER?"PRINTER":class==CLASS_CAPTURE?"CAPTURE":
class==CLASS_USB?"USB": class==CLASS_MONITOR?"MONITOR":
class==CLASS_KEYBOARD?"KEYBOARD":unknown;
char *busname= bus==BUS_OTHER?"OTHER": bus==BUS_PCI? "PCI":
bus==BUS_SBUS?"SBUS": bus==BUS_PSAUX?"PSAUX":
bus==BUS_SERIAL?"SERIAL":bus==BUS_PARALLEL?"PARALLEL":
bus==BUS_SCSI?"SCSI": bus==BUS_IDE?"IDE":
bus==BUS_DDC?"DDC": bus==BUS_USB?"USB":
bus==BUS_KEYBOARD?"KEYBOARD":
#if defined(_i_wanna_build_this_crap_)
bus==BUS_ISAPNP?"ISAPNP":
#endif
unknown;
desc = get_description(d);
printf(
"---\n"
"class: %s\n"
"bus: %s\n"
"device: %s\n"
"driver: %s\n"
"desc: %s\n",classname, busname, d->device?d->device:"(null)",d->driver,
desc?desc:"(empty)");
}

/* rename /dev/mouse -> /dev/mouse1, /dev/mouse1 -> /dev/mouse2 recursive */
int checkmoveup(char *filename, int oldnum)
{
int newnum=oldnum+1;
char srcname[64], dstname[64];
struct stat buf;
sprintf(srcname,(oldnum>0)?"%.32s%d":"%.32s",filename,oldnum);
if(stat(srcname,&buf)) return 0; /* File does not exist, OK. */
sprintf(dstname,"%.32s%d",filename,newnum);
/* recursive if file exists, otherwise just rename it */
return (!stat(dstname,&buf) && checkmoveup(filename,newnum))?errno:
rename(srcname,dstname);
}

int link_dev(struct device *d, char *target, int tnum, int verbose)
{
const char devdir[]="/dev/";
if(d&&d->device)
{
char devname[64], dstname[64];
sprintf(devname,"%s%.32s",devdir,d->device);
sprintf(dstname,"%s%.32s",devdir,target);
if(checkmoveup(dstname, tnum)) return -1; /* Read-only FS?! */
if(tnum>0) sprintf(dstname,"%s%.32s%1d",devdir,target,tnum);
if(verbose&VERBOSE_PRINT) printf("symlink(%.32s,%.32s)\n",devname,dstname);
return symlink(devname,dstname);
}
return -1;
}

void segfault_handler(int dummy)
{
signal(SIGSEGV,SIG_IGN);
fprintf(stderr,"\nWARNING: Caught signal SEGV while executing modprobe.\n");
fflush(stderr);
}

void alarm_handler(int dummy)
{
signal(SIGALRM,SIG_IGN);
fprintf(stderr,"\nWARNING: Autodetection seems to hang,\n"
"please check your computers BIOS settings.\n");
fflush(stderr);
if(wpid) { kill(wpid,SIGTERM); usleep(2500000); kill(wpid,SIGKILL); wpid=0; }
exit(1); /* exit program */
}

int load_mod(char *m,int verbose)
{
int pstatus,i;
time_t now;
pid_t mpid;
char *cc;
if((m==NULL)||(!strcmp("unknown",m))||(!strcmp("ignore",m))|| check_loaded(m)) return 0;
#ifdef BLACKLIST
for(i=0;i<(sizeof(blacklist)/sizeof(char*));i++)
{
if(!modcmp(blacklist[i],m))
{
if(verbose&VERBOSE_PRINT) printf("not loading module %.32s (is in blacklist)\n",m);
return 0;
}
}
#endif
if((cc=check_conflict(m))!=NULL)
{
if(verbose&VERBOSE_PRINT) printf("not loading module %.32s (conflicts with loaded module '%.32s' for same device)\n", m, cc);
return 0;
}
if((mpid=fork())==0)
{ /* child process */
if(verbose&VERBOSE_PRINT) printf("modprobe(%.32s)\n",m);
signal(SIGSEGV,segfault_handler);
/* Send modprobe errors to /dev/null */
if(!(verbose&VERBOSE_PRINT)) freopen("/dev/null","w",stderr);
execl("/sbin/modprobe","modprobe",m,NULL);
exit(1);
}
now=time(0);
do
{
usleep(125000); /* Delay 1/8s */
/* We SHOULD wait for modprobe to finish! */
if(waitpid(mpid,&pstatus,WNOHANG)) break;
}
while((time(0) - now) < MAX_TIME_MODULE);
set_conflict(m);
return pstatus;
}


int writeconfig(char *name,struct device *d,int verbose)
{
FILE *f,*k;
const char *kconfig="/etc/sysconfig/knoppix";
char *desc;
unlink(name);
if((f=fopen(name,"w"))==NULL)
{ /* Read-only filesystem on /etc ?! */
fprintf(stderr,"Can't write to '%s': %s",name,strerror(errno));
return 1;
}
if((k=fopen(kconfig,"a"))==NULL) { fclose(f); return 1; }
if(verbose&VERBOSE_PRINT)
{
printf("write config(%s)\n",name);
printf("update config(%s)\n",kconfig);
}
desc = get_description(d);
switch(d->type)
{
case CLASS_MOUSE:
{
char *t1,*t2;
if(d->bus==BUS_PSAUX) { t1="ps2"; t2="PS/2"; }
else if(d->bus==BUS_USB) { t1="imps2"; t2="IMPS/2"; }
else { t1="ms"; t2="Microsoft"; }
fprintf(f,"MOUSETYPE=\"%s\"\nXMOUSETYPE=\"%s\"\n",t1,t2);
if(desc) fprintf(f,"FULLNAME=\"%s\"\n",desc),
fprintf(k,"MOUSE_FULLNAME=\"%s\"\n",desc);
if(d->device) fprintf(f,"DEVICE=\"/dev/%s\"\n",d->device),
fprintf(k,"MOUSE_DEVICE=\"/dev/%s\"\n",d->device);
}; break;
default: break;
}
fclose(f); fclose(k);
return 0;
}

int hw_setup(enum deviceClass dc, int verbose, int probeonly, int skip)
{
int i,mouse=0,cdrom=0,modem=0,scanner=0;
struct device **currentDevs, *d, *serialmouse=NULL, *usbmouse=NULL;
if(verbose&VERBOSE_PROMPT) wpid=startwheel();
currentDevs=probeDevices(dc,BUS_UNSPEC,PROBE_ALL);
if(verbose&VERBOSE_PROMPT&&wpid>0) { kill(wpid,SIGTERM); wpid=0; usleep(160000); write(2,"\033[0m Done.\n",11); }
if(currentDevs==NULL) return -1;
check_proc_modules(); /* Get currently loaded module list */
for(i=0;(d=currentDevs[i]);i++)
{
if(verbose&VERBOSE_PRINT) hw_info(d);
if(!probeonly)
{
#if defined(_i_wanna_build_this_crap_)
if(d->bus==BUS_ISAPNP&&configure_isapnp(d,verbose)) continue;
#endif
switch(d->type)
{
case CLASS_MOUSE: /* Choose serial over PS2/USB mouse IF present */
/* For some reason, PS/2 ALWAYS detects a mouse */
if(d->bus==BUS_SERIAL)
{ mouse=0; serialmouse=d; }
else if(d->bus==BUS_USB) /* Need usbdevfs for */
{ mouse=0; usbmouse=d; /* this to work */
load_mod(d->driver,verbose); }
if(!mouse)
writeconfig("/etc/sysconfig/mouse",d,verbose);
link_dev(d,"mouse",mouse++,verbose);
break;

default: /* do nothing */ break;
}
}
}
return 0;
}

int main(int argc, char **argv)
{
int i, verbose=0, probeonly=0, skip=0;
enum deviceClass dc=CLASS_UNSPEC;
for(i=1;i<argc;i++)
{
if(!strcasecmp(argv[i],"-v")) verbose|=VERBOSE_PRINT;
else if(!strcasecmp(argv[i],"-p")) verbose|=VERBOSE_PROMPT;
else if(!strcasecmp(argv[i],"-a")) skip|=SKIP_AUDIO;
else if(!strcasecmp(argv[i],"-s")) skip|=SKIP_SCSI;
else if(!strcasecmp(argv[i],"-n")) probeonly=1;
else return syntax(argv[i]);
}
/* Allow SIGTERM, SIGINT: rmmod depends on this. */
signal(SIGTERM,SIG_DFL); signal(SIGINT,SIG_DFL);
signal(SIGALRM,alarm_handler); alarm(MAX_TIME);
return hw_setup(dc,verbose,probeonly,skip);
}


and I have copied it into the bin folder of my pen drive.

Then I have written the following script to run the program:

#!/bin/bash
PATH=/sbin:/bin ; export PATH
hwsetup
cat /etc/sysconfig/mouse

I have copied it into the etc/init.d folder and I have created a symbolic link to it into the etc/rcS.d folder.
On booting from my pen drive I receive a segmentation fault error. It seems that the problem stands in the probeDevices function, but I don't understand why.

Could it be a problem with the kudzu library?

Thanks!
Antonella