/* * Get Device Id from an open file descriptor */ int devid_get(int fd, ddi_devid_t *devidp) { int len = 0; dev_t dev; struct stat statb; ddi_devid_t mydevid; if (fstat(fd, &statb) != 0) return (-1); /* If not char or block device, then error */ if (!S_ISCHR(statb.st_mode) && !S_ISBLK(statb.st_mode)) return (-1); #ifndef __APPLE__ /* Get the device id size */ dev = statb.st_rdev; if (modctl(MODSIZEOF_DEVID, dev, &len) != 0) return (-1); /* Allocate space to return device id */ if ((mydevid = (ddi_devid_t)malloc(len)) == NULL) return (-1); /* Get the device id */ if (modctl(MODGETDEVID, dev, len, mydevid) != 0) { free(mydevid); return (-1); } /* Return the device id copy */ *devidp = mydevid; #endif return (0); }
int main(int argc, char **argv) { modctl_load_t cmdargs; prop_dictionary_t props; char *propsstr; int ch; int flags; flags = 0; props = prop_dictionary_create(); while ((ch = getopt(argc, argv, "b:fi:s:")) != -1) { switch (ch) { case 'b': parse_param(props, optarg, parse_bool_param); break; case 'f': flags |= MODCTL_LOAD_FORCE; break; case 'i': parse_param(props, optarg, parse_int_param); break; case 's': parse_param(props, optarg, parse_string_param); break; default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc != 1) usage(); propsstr = prop_dictionary_externalize(props); if (propsstr == NULL) errx(EXIT_FAILURE, "Failed to process properties"); cmdargs.ml_filename = argv[0]; cmdargs.ml_flags = flags; cmdargs.ml_props = propsstr; cmdargs.ml_propslen = strlen(propsstr); if (modctl(MODCTL_LOAD, &cmdargs)) { err(EXIT_FAILURE, NULL); } free(propsstr); prop_object_release(props); exit(EXIT_SUCCESS); }
static int loadprivs(const char *infile) { char *line, *col; FILE *in; struct fileentry *fep; int res = 0; in = fopen(infile, "r"); if (in == NULL) return (0); while ((fep = fgetline(in)) != NULL && fep->entry != NULL) { line = fep->entry; if (*line == '\0') continue; line[strlen(line)-1] = '\0'; col = strchr(line, ':'); if (col != NULL) { major_t maj; *col = '\0'; if (modctl(MODGETMAJBIND, line, col - line + 1, &maj) != 0) continue; line = col + 1; } if (modctl(MODALLOCPRIV, line) != 0) { (void) err_print("modctl(MODALLOCPRIV, %s): %s\n", line, strerror(errno)); res = -1; } } return (res); }
/* * Use of the dev filesystem's private readdir does (not trigger * the implicit device reconfiguration) to determine if a directory * is empty. * * Note: only useable with paths mounted on an instance of the * dev filesystem. * * Does not return the . and .. entries. * Empty directories are returned as an zero-length list. * ENOENT is returned as a NULL list pointer. */ static int finddev_emptydir_devfs(const char *path) { int rv; int empty; rv = modctl(MODDEVEMPTYDIR, path, strlen(path), &empty); if (rv == 0) { return (empty); } return (0); }
RTDECL(int) RTKrnlModLoadedQueryInfoAll(PRTKRNLMODINFO pahKrnlModInfo, uint32_t cEntriesMax, uint32_t *pcEntries) { AssertReturn(VALID_PTR(pahKrnlModInfo) || cEntriesMax == 0, VERR_INVALID_PARAMETER); uint32_t cKmodsLoaded = RTKrnlModLoadedGetCount(); if (cEntriesMax < cKmodsLoaded) { if (*pcEntries) *pcEntries = cKmodsLoaded; return VERR_BUFFER_OVERFLOW; } int rc = VINF_SUCCESS; int iId = -1; unsigned idxKrnlModInfo = 0; struct modinfo ModInfo; ModInfo.mi_info = MI_INFO_ALL | MI_INFO_CNT; ModInfo.mi_id = iId; ModInfo.mi_nextid = iId; do { int rcSol = modctl(MODINFO, iId, &ModInfo); if (rcSol < 0) { rc = RTErrConvertFromErrno(errno); if (rc == VERR_INVALID_PARAMETER && idxKrnlModInfo > 0) rc = VINF_SUCCESS; break; } ModInfo.mi_name[MODMAXNAMELEN - 1] = '\0'; /* Paranoia. */ rc = rtKrnlModSolInfoCreate(&ModInfo, &pahKrnlModInfo[idxKrnlModInfo]); if (RT_SUCCESS(rc)) idxKrnlModInfo++; iId = ModInfo.mi_id; } while (iId != -1); if (RT_FAILURE(rc)) { /* Rollback */ while (idxKrnlModInfo-- > 0) RTKrnlModInfoRelease(pahKrnlModInfo[idxKrnlModInfo]); } else if (pcEntries) *pcEntries = idxKrnlModInfo; return rc; }
/* * Get the minor name */ int devid_get_minor_name(int fd, char **minor_namep) { int len = 0; dev_t dev; int spectype; char *myminor_name; struct stat statb; if (fstat(fd, &statb) != 0) return (-1); /* If not a char or block device, then return an error */ if (!S_ISCHR(statb.st_mode) && !S_ISBLK(statb.st_mode)) return (-1); spectype = statb.st_mode & S_IFMT; dev = statb.st_rdev; #ifndef __APPLE__ /* Get the minor name size */ if (modctl(MODSIZEOF_MINORNAME, dev, spectype, &len) != 0) return (-1); /* Allocate space for the minor name */ if ((myminor_name = (char *)malloc(len)) == NULL) return (-1); /* Get the minor name */ if (modctl(MODGETMINORNAME, dev, spectype, len, myminor_name) != 0) { free(myminor_name); return (-1); } /* return the minor name copy */ *minor_namep = myminor_name; #endif return (0); }
/* * Return true if a device exists * If the path refers into the /dev filesystem, use a * private interface to query if the device exists but * without triggering an implicit reconfig if it does not. * Note: can only function properly with absolute pathnames * and only functions for persisted global /dev names, ie * those managed by devfsadm. For paths other than * /dev, stat(2) is sufficient. */ int device_exists(const char *devname) { int rv; struct stat st; if (GLOBAL_DEV_PATH(devname)) { rv = modctl(MODDEVEXISTS, devname, strlen(devname)); return ((rv == 0) ? 1 : 0); } if (stat(devname, &st) == 0) return (1); return (0); }
/*ARGSUSED*/ static void * attach_devices(void *arg) { di_node_t root_node; sleep(60); /* let booting finish first */ if ((root_node = di_init("/", DINFOFORCE)) == DI_NODE_NIL) { logerror("Failed to attach devices."); return (NULL); } di_fini(root_node); /* * Unload all the modules. */ (void) modctl(MODUNLOAD, 0); return (NULL); }
RTDECL(uint32_t) RTKrnlModLoadedGetCount(void) { uint32_t cKmodsLoaded = 0; int iId = -1; struct modinfo ModInfo; ModInfo.mi_info = MI_INFO_ALL | MI_INFO_CNT; ModInfo.mi_id = iId; ModInfo.mi_nextid = iId; do { int rcSol = modctl(MODINFO, iId, &ModInfo); if (rcSol < 0) break; cKmodsLoaded++; iId = ModInfo.mi_id; } while (iId != -1); return cKmodsLoaded; }
RTDECL(int) RTKrnlModLoadedQueryInfo(const char *pszName, PRTKRNLMODINFO phKrnlModInfo) { AssertPtrReturn(pszName, VERR_INVALID_POINTER); AssertPtrReturn(phKrnlModInfo, VERR_INVALID_POINTER); int rc = VERR_NOT_FOUND; int iId = -1; struct modinfo ModInfo; ModInfo.mi_info = MI_INFO_ALL | MI_INFO_CNT; ModInfo.mi_id = iId; ModInfo.mi_nextid = iId; do { int rcSol = modctl(MODINFO, iId, &ModInfo); if (rcSol < 0) { rc = RTErrConvertFromErrno(errno); break; } if (ModInfo.mi_id != -1) { ModInfo.mi_name[MODMAXNAMELEN - 1] = '\0'; /* Paranoia. */ if (!RTStrCmp(pszName, &ModInfo.mi_name[0])) { rc = rtKrnlModSolInfoCreate(&ModInfo, phKrnlModInfo); break; } } iId = ModInfo.mi_id; } while (iId != -1); return rc; }
static int loadpolicy(const char *infile) { char *line; int nalloc = 0, cnt = 0; char *mem = NULL; devplcysys_t *dp, *dflt = NULL; FILE *in; struct fileentry *fep; int res; char *maj; char *tok; char *min; in = fopen(infile, "r"); if (in == NULL) { err_print(OPEN_FAILED, infile, strerror(errno)); return (-1); } while ((fep = fgetline(in)) != NULL && fep->entry != NULL) { line = fep->entry; if (cnt >= nalloc) { nalloc += PLCY_CHUNK; mem = realloc(mem, nalloc * devplcysys_sz); if (mem == NULL) { err_print(MALLOC_FAILED, nalloc * devplcysys_sz); return (-1); } /* Readjust pointer to dflt after realloc */ if (dflt != NULL) /* LINTED: alignment */ dflt = (devplcysys_t *)mem; } maj = strtok(line, "\n\t "); if (maj == NULL) continue; /* LINTED: alignment */ dp = (devplcysys_t *)(mem + devplcysys_sz * cnt); if (strcmp(maj, "*") == 0) { if (dflt != NULL) { err_print(DPLCY_ONE_DFLT, infile); return (-1); } (void) memset(dp, 0, devplcysys_sz); dp->dps_maj = DEVPOLICY_DFLT_MAJ; dflt = dp; } else { if (dflt == NULL) { err_print(DPLCY_FIRST, infile); return (-1); } (void) memcpy(dp, dflt, devplcysys_sz); min = strchr(maj, ':'); if (min != NULL) { *min++ = '\0'; if (strchr(min, ':') != NULL) { (void) fprintf(stderr, "Too many ``:'' in entry\n"); return (-1); } } else min = "*"; /* Silently ignore unknown devices. */ if (modctl(MODGETMAJBIND, maj, strlen(maj) + 1, &dp->dps_maj) != 0) continue; if (*min == '(') { /* Numeric minor range */ char type; if (parse_minor_range(min, &dp->dps_lomin, &dp->dps_himin, &type) == -1) { err_print(INVALID_MINOR, min); return (-1); } dp->dps_isblock = type == 'b'; } else { if (strlen(min) >= sizeof (dp->dps_minornm)) { err_print(MINOR_TOO_LONG, maj, min); return (-1); } (void) strcpy(dp->dps_minornm, min); } } while (tok = strtok(NULL, "\n\t ")) { if (parse_plcy_token(tok, dp)) { err_print(BAD_ENTRY, fep->startline, fep->orgentry); return (-1); } } cnt++; } if (fep == NULL) { if (feof(in)) err_print(UNEXPECTED_EOF, infile); else err_print(NO_MEMORY); return (-1); } qsort(mem, cnt, devplcysys_sz, qcmp); if ((res = modctl(MODSETDEVPOLICY, cnt, devplcysys_sz, mem)) != 0) err_print("modctl(MODSETDEVPOLICY): %s\n", strerror(errno)); return (res); }
/* * Use of the dev filesystem's private readdir does not trigger * the implicit device reconfiguration. * * Note: only useable with paths mounted on an instance of the * dev filesystem. * * Does not return the . and .. entries. * Empty directories are returned as an zero-length list. * ENOENT is returned as a NULL list pointer. */ static int finddev_readdir_devfs(const char *path, finddevhdl_t *handlep) { struct finddevhdl *handle; int n; int rv; int64_t bufsiz; char *pathlist; char *p; int len; *handlep = NULL; handle = calloc(1, sizeof (struct finddevhdl)); if (handle == NULL) return (ENOMEM); handle->npaths = 0; handle->curpath = 0; handle->paths = NULL; rv = modctl(MODDEVREADDIR, path, strlen(path), NULL, &bufsiz); if (rv != 0) { free(handle); return (rv); } for (;;) { assert(bufsiz != 0); if ((pathlist = malloc(bufsiz)) == NULL) { free(handle); return (ENOMEM); } rv = modctl(MODDEVREADDIR, path, strlen(path), pathlist, &bufsiz); if (rv == 0) { for (n = 0, p = pathlist; (len = strlen(p)) > 0; p += len+1) { n++; } handle->npaths = n; handle->paths = calloc(n, sizeof (char *)); if (handle->paths == NULL) { free(handle); free(pathlist); return (ENOMEM); } for (n = 0, p = pathlist; (len = strlen(p)) > 0; p += len+1, n++) { handle->paths[n] = strdup(p); if (handle->paths[n] == NULL) { finddev_close((finddevhdl_t)handle); free(pathlist); return (ENOMEM); } } *handlep = (finddevhdl_t)handle; free(pathlist); return (0); } free(pathlist); switch (errno) { case EAGAIN: break; case ENOENT: default: free(handle); return (errno); } } /*NOTREACHED*/ }
int main(int argc, char *argv[]) { int opt; char *basedir = NULL, *driver_name = NULL; int server = 0, mod_unloaded = 0; int modid, found; char maj_num[MAX_STR_MAJOR + 1]; int err; (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/mod_drv/rem_drv */ enter_lock(); if ((check_perms_aliases(1, 1)) == ERROR) err_exit(); if ((check_name_to_major(R_OK | W_OK)) == ERROR) err_exit(); /* look up the major number of the driver being removed. */ if ((found = get_major_no(driver_name, name_to_major)) == ERROR) { (void) fprintf(stderr, gettext(ERR_MAX_MAJOR), name_to_major); err_exit(); } if (found == UNIQUE) { (void) fprintf(stderr, gettext(ERR_NOT_INSTALLED), driver_name); err_exit(); } if (!server) { mod_unloaded = 1; /* get the module id for this driver */ get_modid(driver_name, &modid); /* module is installed */ if (modid != -1) { if (modctl(MODUNLOAD, modid) < 0) { perror(NULL); (void) fprintf(stderr, gettext(ERR_MODUN), driver_name); mod_unloaded = 0; } } /* unload driver.conf file */ if (modctl(MODUNLOADDRVCONF, (major_t)found) < 0) { perror(NULL); (void) fprintf(stderr, gettext("cannot unload %s.conf\n"), driver_name); } } if (mod_unloaded && (modctl(MODREMMAJBIND, (major_t)found) < 0)) { perror(NULL); (void) fprintf(stderr, gettext(ERR_MODREMMAJ), found); } /* * add driver to rem_name_to_major; if this fails, don`t * delete from name_to_major */ (void) sprintf(maj_num, "%d", found); 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(); } /* * If removing the driver from the running system, notify * kernel dynamically to remove minor perm entries. */ if (basedir == NULL || (strcmp(basedir, "/") == 0)) { err = devfs_rm_minor_perm(driver_name, log_minorperm_error); if (err != 0) { (void) fprintf(stderr, gettext(ERR_UPDATE_PERM), driver_name, err); } } /* * delete references to driver in add_drv/rem_drv database */ remove_entry(CLEAN_ALL, driver_name); /* * Clean up any dangling devfs shadow nodes for this * driver so that, in the event the driver is re-added * to the system, newly created nodes won't incorrectly * pick up these stale shadow node permissions. */ if (basedir == NULL || (strcmp(basedir, "/") == 0)) { err = modctl(MODREMDRVCLEANUP, driver_name, 0, NULL); if (err != 0) { (void) fprintf(stderr, gettext(ERR_REMDRV_CLEANUP), driver_name, err); } } exit_unlock(); return (NOERR); }
int main(int argc, char **argv) { struct iovec iov; modstat_t *ms; size_t len; const char *name; char sbuf[32]; int ch; name = NULL; while ((ch = getopt(argc, argv, "n:")) != -1) { switch (ch) { case 'n': name = optarg; break; default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc != 0) usage(); for (len = 4096;;) { iov.iov_base = malloc(len); iov.iov_len = len; if (modctl(MODCTL_STAT, &iov)) { err(EXIT_FAILURE, "modctl(MODCTL_STAT)"); } if (len >= iov.iov_len) { break; } free(iov.iov_base); len = iov.iov_len; } printf("NAME\t\tCLASS\tSOURCE\tREFS\tSIZE\tREQUIRES\n"); len = iov.iov_len / sizeof(modstat_t); for (ms = iov.iov_base; len != 0; ms++, len--) { if (name != NULL && strcmp(ms->ms_name, name) != 0) { continue; } if (ms->ms_required[0] == '\0') { ms->ms_required[0] = '-'; ms->ms_required[1] = '\0'; } if (ms->ms_size == 0) { sbuf[0] = '-'; sbuf[1] = '\0'; } else { snprintf(sbuf, sizeof(sbuf), "%u", ms->ms_size); } printf("%-16s%s\t%s\t%d\t%s\t%s\n", ms->ms_name, classes[ms->ms_class], sources[ms->ms_source], ms->ms_refcnt, sbuf, ms->ms_required); } exit(EXIT_SUCCESS); }
/* * Convert the specified devid/minor_name into a devid_nmlist_t array * with names that resolve into /devices or /dev depending on search_path. * * The man page indicates that: * * This function traverses the file tree, starting at search_path. * * This is not true, we reverse engineer the paths relative to * the specified search path to avoid attaching all devices. */ int devid_deviceid_to_nmlist( char *search_path, ddi_devid_t devid, char *minor_name, devid_nmlist_t **retlist) { char *cp; int dev; char *paths = NULL; char *path; int lens; #ifndef __APPLE__ di_devlink_handle_t dlh = NULL; #endif int ret = -1; #ifndef __APPLE__ struct devlink_cbinfo cbi; #endif struct nmlist *nlh = NULL; struct nmlist *nl; devid_nmlist_t *rl; int nret; int nagain = 0; int err = 0; *retlist = NULL; /* verify valid search path starts with "/devices" or "/dev" */ if ((strcmp(search_path, "/devices") == 0) || (strncmp(search_path, "/devices/", 9) == 0)) dev = 0; else if ((strcmp(search_path, "/dev") == 0) || (strncmp(search_path, "/dev/", 5) == 0)) dev = 1; else { errno = EINVAL; return (-1); } #ifndef __APPLE__ /* translate devid/minor_name to /devices paths */ again: if (modctl(MODDEVID2PATHS, devid, minor_name, 0, &lens, NULL) != 0) goto out; if ((paths = (char *)malloc(lens)) == NULL) goto out; if (modctl(MODDEVID2PATHS, devid, minor_name, 0, &lens, paths) != 0) { if ((errno == EAGAIN) && (nagain++ < DEVICEID_NMLIST_NRETRY)) { free(paths); paths = NULL; goto again; } goto out; } /* * initialize for /devices path to /dev path translation. To reduce * overhead we reuse the last snapshot if DEVICEID_NMLIST_SLINK is set. */ if (dev) { dlh = devid_deviceid_to_nmlist_dlh; if (dlh && !(devid_deviceid_to_nmlist_flg & DEVICEID_NMLIST_SLINK)) { (void) di_devlink_fini(&dlh); dlh = devid_deviceid_to_nmlist_dlh = NULL; } if ((dlh == NULL) && ((dlh = di_devlink_init(NULL, 0)) == NULL)) goto out; } /* * iterate over all the devtspectype resolutions of the devid and * convert them into the appropriate path form and add items to return * to the nmlist list; */ for (path = paths; *path; path += strlen(path) + 1) { if (dev) { /* add /dev entries */ cbi.cbi_nlhp = &nlh; cbi.cbi_search_path = search_path; cbi.cbi_error = 0; (void) di_devlink_walk(dlh, NULL, path, devid_deviceid_to_nmlist_link, (void *)&cbi, devlink_callback); if (cbi.cbi_error) goto out; } else { /* add /devices entry */ cp = malloc(strlen("/devices") + strlen(path) + 1); (void) strcpy(cp, "/devices"); (void) strcat(cp, path); if (strncmp(cp, search_path, strlen(search_path)) == 0) { if (nmlist_add(&nlh, cp) == NULL) { free(cp); goto out; } } free(cp); } } /* convert from nmlist to retlist array */ for (nl = nlh, nret = 0; nl; nl = nl->nl_next) nret++; if (nret == 0) { err = ENODEV; goto out; } if ((*retlist = calloc(nret + 1, sizeof (devid_nmlist_t))) == NULL) { err = ENOMEM; goto out; } for (nl = nlh, rl = *retlist; nl; nl = nl->nl_next, rl++) { rl->devname = nl->nl_devname; rl->dev = nl->nl_dev; } rl->devname = NULL; rl->dev = NODEV; ret = 0; out: while ((nl = nlh) != NULL) { /* free the nmlist */ nlh = nl->nl_next; free(nl); } if (paths) free(paths); if (dlh) { if ((ret == 0) && (devid_deviceid_to_nmlist_flg & DEVICEID_NMLIST_SLINK)) devid_deviceid_to_nmlist_dlh = dlh; else (void) di_devlink_fini(&dlh); } if (ret && *retlist) free(*retlist); if (ret && err != 0) errno = err; #endif return (ret); }