/* hwmatch.c - Match hardware against a whitelist/blacklist. */ /* * GRUB -- GRand Unified Bootloader * Copyright (C) 2011 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRUB is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GRUB. If not, see . */ #include #include #include #include #include #include #include #include #include GRUB_MOD_LICENSE ("GPLv3+"); /* Context for grub_cmd_hwmatch. */ struct hwmatch_ctx { grub_file_t matches_file; int class_match; int match; }; /* Helper for grub_cmd_hwmatch. */ static int hwmatch_iter (grub_pci_device_t dev, grub_pci_id_t pciid, void *data) { struct hwmatch_ctx *ctx = data; grub_pci_address_t addr; grub_uint32_t class, baseclass, vendor, device; grub_pci_id_t subpciid; grub_uint32_t subvendor, subdevice, subclass; char *id, *line; addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); class = grub_pci_read (addr); baseclass = class >> 24; if (ctx->class_match != baseclass) return 0; vendor = pciid & 0xffff; device = pciid >> 16; addr = grub_pci_make_address (dev, GRUB_PCI_REG_SUBVENDOR); subpciid = grub_pci_read (addr); subclass = (class >> 16) & 0xff; subvendor = subpciid & 0xffff; subdevice = subpciid >> 16; id = grub_xasprintf ("v%04xd%04xsv%04xsd%04xbc%02xsc%02x", vendor, device, subvendor, subdevice, baseclass, subclass); grub_file_seek (ctx->matches_file, 0); while ((line = grub_file_getline (ctx->matches_file)) != NULL) { char *anchored_line; regex_t regex; int ret; if (! *line || *line == '#') { grub_free (line); continue; } anchored_line = grub_xasprintf ("^%s$", line); ret = regcomp (®ex, anchored_line, REG_EXTENDED | REG_NOSUB); grub_free (anchored_line); if (ret) { grub_free (line); continue; } ret = regexec (®ex, id, 0, NULL, 0); regfree (®ex); grub_free (line); if (! ret) { ctx->match = 1; return 1; } } return 0; } static grub_err_t grub_cmd_hwmatch (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) { struct hwmatch_ctx ctx = { .match = 0 }; char *match_str; if (argc < 2) return grub_error (GRUB_ERR_BAD_ARGUMENT, "list file and class required"); ctx.matches_file = grub_file_open (args[0]); if (! ctx.matches_file) return grub_errno; ctx.class_match = grub_strtol (args[1], 0, 10); grub_pci_iterate (hwmatch_iter, &ctx); match_str = grub_xasprintf ("%d", ctx.match); grub_env_set ("match", match_str); grub_free (match_str); grub_file_close (ctx.matches_file); return GRUB_ERR_NONE; } static grub_command_t cmd; GRUB_MOD_INIT(hwmatch) { cmd = grub_register_command ("hwmatch", grub_cmd_hwmatch, N_("MATCHES-FILE CLASS"), N_("Match PCI devices.")); } GRUB_MOD_FINI(hwmatch) { grub_unregister_command (cmd); }