mirror of
https://git.FreeBSD.org/src.git
synced 2024-11-28 08:02:54 +00:00
Add the ability to match on device names attached to.
If a device is attached to ums4, you can reference this devname in the configuration file as ${DEVNAME} (a shell variable, yes).
This commit is contained in:
parent
f27f6c0076
commit
33ba9f8fee
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=53856
@ -9,7 +9,7 @@ device "ActiveWire board, firmware download"
|
||||
vendor 0x0854
|
||||
product 0x0100
|
||||
release 0x0000
|
||||
attach "/usr/local/bin/ezdownload -f /usr/local/share/usb/firmware/0854.0100.0_01.hex"
|
||||
attach "/usr/local/bin/ezdownload -f /usr/local/share/usb/firmware/0854.0100.0_01.hex ${DEVNAME}"
|
||||
|
||||
# The piece below has to be copied for every drive. It does not work for the
|
||||
# generic case, the umass storage class uses interface drivers. The info for
|
||||
@ -19,15 +19,14 @@ device "USB Zip drive"
|
||||
vendor 0x059b
|
||||
product 0x0001
|
||||
release 0x0100
|
||||
attach "/usr/bin/camcontrol rescan bus 0"
|
||||
attach "/sbin/camcontrol rescan bus 0"
|
||||
|
||||
# The entry below is for the Logitech mouse. Replace the product and vendor
|
||||
# id (and the device name of course) with the data for your mouse.
|
||||
#
|
||||
device "Logitech N48 USB mouse"
|
||||
vendor 0x046d
|
||||
product 0xc001
|
||||
attach "/usr/sbin/moused -p /dev/ums0 -I /var/run/moused.ums0.pid"
|
||||
device "Mouse"
|
||||
devname "ums[0-9]+"
|
||||
attach "/usr/sbin/moused -p /dev/${DEVNAME} -I /var/run/moused.${DEVNAME}.pid"
|
||||
|
||||
# The fallthrough entry: Nothing is specified, nothing is done. And it isn't
|
||||
# necessary at all :-). Just for pretty printing in debugging mode.
|
||||
|
@ -60,6 +60,7 @@
|
||||
#include <sys/errno.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/wait.h>
|
||||
#include <regex.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
|
||||
@ -121,6 +122,7 @@ event_name_t event_names[] = {
|
||||
#define CLASS_FIELD 4
|
||||
#define SUBCLASS_FIELD 5
|
||||
#define PROTOCOL_FIELD 6
|
||||
#define DEVNAME_FIELD 7
|
||||
|
||||
#define ATTACH_FIELD 8 /* command fields */
|
||||
#define DETACH_FIELD 9
|
||||
@ -135,6 +137,8 @@ typedef struct action_s {
|
||||
int class;
|
||||
int subclass;
|
||||
int protocol;
|
||||
char *devname;
|
||||
regex_t devname_regex;
|
||||
|
||||
char *attach; /* commands to execute */
|
||||
char *detach;
|
||||
@ -144,6 +148,11 @@ typedef struct action_s {
|
||||
|
||||
STAILQ_HEAD(action_list, action_s) actions = STAILQ_HEAD_INITIALIZER(actions);
|
||||
|
||||
typedef struct action_match_s {
|
||||
action_t *action;
|
||||
char *devname;
|
||||
} action_match_t;
|
||||
|
||||
|
||||
/* the function returns 0 for failure, 1 for all arguments found and 2 for
|
||||
* arguments left over in trail.
|
||||
@ -158,6 +167,7 @@ int set_release_field(action_t *action, char *args, char **trail);
|
||||
int set_class_field(action_t *action, char *args, char **trail);
|
||||
int set_subclass_field(action_t *action, char *args, char **trail);
|
||||
int set_protocol_field(action_t *action, char *args, char **trail);
|
||||
int set_devname_field(action_t *action, char *args, char **trail);
|
||||
int set_attach_field(action_t *action, char *args, char **trail);
|
||||
int set_detach_field(action_t *action, char *args, char **trail);
|
||||
|
||||
@ -177,6 +187,7 @@ config_field_t config_fields[] = {
|
||||
{CLASS_FIELD, "class", set_class_field},
|
||||
{SUBCLASS_FIELD, "subclass", set_subclass_field},
|
||||
{PROTOCOL_FIELD, "protocol", set_protocol_field},
|
||||
{DEVNAME_FIELD, "devname", set_devname_field},
|
||||
|
||||
{ATTACH_FIELD, "attach", set_attach_field},
|
||||
{DETACH_FIELD, "detach", set_detach_field},
|
||||
@ -189,7 +200,8 @@ config_field_t config_fields[] = {
|
||||
void print_event __P((struct usb_event *event));
|
||||
void print_action __P((action_t *action, int i));
|
||||
void print_actions __P((void));
|
||||
action_t *find_action __P((struct usb_device_info *devinfo));
|
||||
int find_action __P((struct usb_device_info *devinfo,
|
||||
action_match_t *action_match));
|
||||
|
||||
|
||||
void
|
||||
@ -354,6 +366,38 @@ set_protocol_field(action_t *action, char *args, char **trail)
|
||||
return(get_integer(args, &action->protocol, trail));
|
||||
}
|
||||
int
|
||||
set_devname_field(action_t *action, char *args, char **trail)
|
||||
{
|
||||
int match = get_string(args, &action->devname, trail);
|
||||
int len;
|
||||
int error;
|
||||
char *string;
|
||||
# define ERRSTR_SIZE 100
|
||||
char errstr[ERRSTR_SIZE];
|
||||
|
||||
if (match == 0)
|
||||
return(0);
|
||||
|
||||
len = strlen(action->devname);
|
||||
string = malloc(len + 14);
|
||||
if (string == NULL)
|
||||
return(0);
|
||||
|
||||
bcopy(action->devname, string+7, len); /* make some space for */
|
||||
bcopy("[[:<:]]", string, 7); /* beginning of word */
|
||||
bcopy("[[:>:]]", string+7+len, 7); /* and end of word */
|
||||
|
||||
error = regcomp(&action->devname_regex, string, REG_NOSUB|REG_EXTENDED);
|
||||
if (error) {
|
||||
errstr[0] = '\0';
|
||||
regerror(error, &action->devname_regex, errstr, ERRSTR_SIZE);
|
||||
fprintf(stderr, "%s:%d: %s\n", configfile, lineno, errstr);
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(match);
|
||||
}
|
||||
int
|
||||
set_attach_field(action_t *action, char *args, char **trail)
|
||||
{
|
||||
return(get_string(args, &action->attach, trail));
|
||||
@ -468,6 +512,7 @@ read_configuration(void)
|
||||
action->class = WILDCARD_INT;
|
||||
action->subclass = WILDCARD_INT;
|
||||
action->protocol = WILDCARD_INT;
|
||||
action->devname = WILDCARD_STRING;
|
||||
|
||||
/* Add it to the end of the list to preserve order */
|
||||
STAILQ_INSERT_TAIL(&actions, action, next);
|
||||
@ -534,6 +579,20 @@ print_event(struct usb_event *event)
|
||||
"clss=0x%04x subclss=0x%04x prtcl=0x%04x\n",
|
||||
devinfo->vendorNo, devinfo->productNo, devinfo->releaseNo,
|
||||
devinfo->class, devinfo->subclass, devinfo->protocol);
|
||||
|
||||
if (devinfo->devnames[0][0] != '\0') {
|
||||
char c = ' ';
|
||||
|
||||
printf(" device names:");
|
||||
for (i = 0; i < MAXDEVNAMES; i++) {
|
||||
if (devinfo->devnames[i][0] == '\0')
|
||||
break;
|
||||
|
||||
printf("%c%s", c, devinfo->devnames[i]);
|
||||
c = ',';
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -571,13 +630,15 @@ print_action(action_t *action, int i)
|
||||
action->subclass != WILDCARD_INT ||
|
||||
action->protocol != WILDCARD_INT)
|
||||
printf("\n");
|
||||
if (action->devname != WILDCARD_STRING)
|
||||
printf(" devname: %s\n", action->devname);
|
||||
|
||||
if (action->attach != NULL)
|
||||
printf("%s: attach='%s'\n",
|
||||
__progname, action->attach);
|
||||
printf(" attach='%s'\n",
|
||||
action->attach);
|
||||
if (action->detach != NULL)
|
||||
printf("%s: detach='%s'\n",
|
||||
__progname, action->detach);
|
||||
printf(" detach='%s'\n",
|
||||
action->detach);
|
||||
}
|
||||
|
||||
void
|
||||
@ -592,10 +653,38 @@ print_actions()
|
||||
printf("%s: %d action%s\n", __progname, i, (i == 1? "":"s"));
|
||||
}
|
||||
|
||||
action_t *
|
||||
find_action(struct usb_device_info *devinfo)
|
||||
|
||||
int
|
||||
match_devname(action_t *action, struct usb_device_info *devinfo)
|
||||
{
|
||||
int i;
|
||||
regmatch_t match;
|
||||
int error;
|
||||
|
||||
for (i = 0; i < MAXDEVNAMES; i++) {
|
||||
if (devinfo->devnames[i][0] == '\0')
|
||||
break;
|
||||
|
||||
error = regexec(&action->devname_regex, devinfo->devnames[i],
|
||||
1, &match, 0);
|
||||
if (error == 0) {
|
||||
if (verbose >= 2)
|
||||
printf("%s: %s matches %s\n", __progname,
|
||||
devinfo->devnames[i], action->devname);
|
||||
return(i);
|
||||
}
|
||||
}
|
||||
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
find_action(struct usb_device_info *devinfo, action_match_t *action_match)
|
||||
{
|
||||
action_t *action;
|
||||
char *devname = NULL;
|
||||
int match = -1;
|
||||
|
||||
STAILQ_FOREACH(action, &actions, next) {
|
||||
if ((action->vendor == WILDCARD_INT ||
|
||||
@ -609,24 +698,40 @@ find_action(struct usb_device_info *devinfo)
|
||||
(action->subclass == WILDCARD_INT ||
|
||||
action->subclass == devinfo->subclass) &&
|
||||
(action->protocol == WILDCARD_INT ||
|
||||
action->protocol == devinfo->protocol)) {
|
||||
action->protocol == devinfo->protocol) &&
|
||||
(action->devname == WILDCARD_STRING ||
|
||||
(match = match_devname(action, devinfo)) != -1)) {
|
||||
/* found match !*/
|
||||
if (verbose)
|
||||
printf("%s: Found action '%s' for %s, %s\n",
|
||||
if (match != -1)
|
||||
devname = devinfo->devnames[match];
|
||||
else if (devinfo->devnames[0][0] != '\0' &&
|
||||
devinfo->devnames[1][0] == '\0')
|
||||
/* if we have exactly 1 device name */
|
||||
devname = devinfo->devnames[0];
|
||||
|
||||
if (verbose) {
|
||||
printf("%s: Found action '%s' for %s, %s",
|
||||
__progname, action->name,
|
||||
devinfo->product, devinfo->vendor);
|
||||
return(action);
|
||||
if (devname)
|
||||
printf(" at %s", devname);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
action_match->action = action;
|
||||
action_match->devname = devname;
|
||||
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return(0);
|
||||
}
|
||||
|
||||
void
|
||||
execute_command(char *cmd)
|
||||
{
|
||||
pid_t pid;
|
||||
int pstat;
|
||||
struct sigaction ign, intact, quitact;
|
||||
sigset_t newsigblock, oldsigblock;
|
||||
int status;
|
||||
@ -671,11 +776,12 @@ execute_command(char *cmd)
|
||||
|
||||
execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL);
|
||||
|
||||
/* should only be reached in case of error */
|
||||
exit(127);
|
||||
} else {
|
||||
/* parent here */
|
||||
do {
|
||||
pid = waitpid(pid, &pstat, 0);
|
||||
pid = waitpid(pid, &status, 0);
|
||||
} while (pid == -1 && errno == EINTR);
|
||||
}
|
||||
(void) sigaction(SIGINT, &intact, NULL);
|
||||
@ -701,8 +807,8 @@ execute_command(char *cmd)
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
fprintf(stderr, "%s: '%s' caught signal %d\n",
|
||||
__progname, cmd, WTERMSIG(status));
|
||||
} else if (verbose) {
|
||||
printf("%s: '%s' is done\n", __progname, cmd);
|
||||
} else if (verbose >= 2) {
|
||||
printf("%s: '%s' is ok\n", __progname, cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -711,8 +817,9 @@ void
|
||||
process_event_queue(int fd)
|
||||
{
|
||||
struct usb_event event;
|
||||
int error;
|
||||
int len;
|
||||
action_t *action;
|
||||
action_match_t action_match;
|
||||
|
||||
for (;;) {
|
||||
len = read(fd, &event, sizeof(event));
|
||||
@ -742,16 +849,28 @@ process_event_queue(int fd)
|
||||
switch (event.ue_type) {
|
||||
case USB_EVENT_ATTACH:
|
||||
case USB_EVENT_DETACH:
|
||||
action = find_action(&event.ue_device);
|
||||
if (action == NULL)
|
||||
if (find_action(&event.ue_device, &action_match) == 0)
|
||||
/* nothing found */
|
||||
break;
|
||||
else if (verbose >= 2)
|
||||
print_action(action, 0);
|
||||
|
||||
if (event.ue_type == USB_EVENT_ATTACH && action->attach)
|
||||
execute_command(action->attach);
|
||||
if (event.ue_type == USB_EVENT_DETACH && action->detach)
|
||||
execute_command(action->detach);
|
||||
if (verbose >= 2)
|
||||
print_action(action_match.action, 0);
|
||||
|
||||
if (action_match.devname) {
|
||||
if (verbose >= 2)
|
||||
printf("%s: Setting DEVNAME='%s'\n",
|
||||
__progname, action_match.devname);
|
||||
|
||||
error = setenv("DEVNAME", action_match.devname, 1);
|
||||
if (error)
|
||||
fprintf(stderr, "%s: setenv(\"DEVNAME\", \"%s\",1) failed, %s\n",
|
||||
__progname, action_match.devname, strerror(errno));
|
||||
}
|
||||
|
||||
if (event.ue_type == USB_EVENT_ATTACH && action_match.action->attach)
|
||||
execute_command(action_match.action->attach);
|
||||
if (event.ue_type == USB_EVENT_DETACH && action_match.action->detach)
|
||||
execute_command(action_match.action->detach);
|
||||
|
||||
break;
|
||||
default:
|
||||
|
@ -77,8 +77,14 @@ Device Class
|
||||
Device Subclass
|
||||
.It protocol Ar id
|
||||
Device Protocol
|
||||
.It devicenames Ar string
|
||||
Device name, for example umass2, or ums0.
|
||||
.It devname Ar string
|
||||
Device name, for example umass2, or ums0. These device names can contain
|
||||
regular expressions. See
|
||||
.Xr regex 3
|
||||
and
|
||||
.Xr re_format 7 .
|
||||
The device name that is matched can be used in the commands below
|
||||
through adding ${DEVNAME} somewhere in that string.
|
||||
.El
|
||||
.Pp
|
||||
String arguments may be quoted. If a string argument contains a space or
|
||||
@ -102,9 +108,15 @@ and
|
||||
.Fl -v
|
||||
flags.
|
||||
.Pp
|
||||
Commands to be executed when the action is matched:
|
||||
.Bl -tag -width devicename\ <Id>
|
||||
.It attach Ar string
|
||||
Shell command to execute when a device is attached.
|
||||
.It detach Ar string
|
||||
Shell command to execute when a device is detached.
|
||||
.Sh EXAMPLES
|
||||
A sample entry to rescan the SCSI bus on connection of a
|
||||
.Tn "Iomega USB Zip Drive" .
|
||||
.Tn "Iomega USB Zip Drive" :
|
||||
.Bd -literal
|
||||
device "USB Zip drive"
|
||||
product 0x0001
|
||||
@ -112,6 +124,13 @@ A sample entry to rescan the SCSI bus on connection of a
|
||||
release 0x0100
|
||||
attach "/usr/bin/camcontrol rescan bus 0"
|
||||
.Ed
|
||||
.Pp
|
||||
To start up moused for a newly attached mouse:
|
||||
.Bd -literal
|
||||
device "Mouse"
|
||||
devname "ums[0-9]+
|
||||
attach "/usr/sbin/moused -p /dev/${DEVNAME} -I /var/run/moused.${DEVNAME}.pid"
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/pccard.conf -compact
|
||||
.It Pa /etc/usbd.conf
|
||||
|
Loading…
Reference in New Issue
Block a user