예제 #1
0
파일: vinumioctl.c 프로젝트: MarginC/kame
/* ioctl routine */
int
vinumioctl(dev_t dev,
    u_long cmd,
    caddr_t data,
    int flag,
    struct thread *td)
{
    unsigned int objno;
    int error = 0;
    struct sd *sd;
    struct plex *plex;
    struct volume *vol;
    unsigned int index;					    /* for transferring config info */
    unsigned int sdno;					    /* for transferring config info */
    int fe;						    /* free list element number */
    struct _ioctl_reply *ioctl_reply = (struct _ioctl_reply *) data; /* struct to return */

    /* First, decide what we're looking at */
    switch (DEVTYPE(dev)) {
    case VINUM_SUPERDEV_TYPE:				    /* ordinary super device */
	ioctl_reply = (struct _ioctl_reply *) data;	    /* save the address to reply to */
	switch (cmd) {
#ifdef VINUMDEBUG
	case VINUM_DEBUG:
	    if (((struct debuginfo *) data)->changeit)	    /* change debug settings */
		debug = (((struct debuginfo *) data)->param);
	    else {
		if (debug & DEBUG_REMOTEGDB)
		    boothowto |= RB_GDB;		    /* serial debug line */
		else
		    boothowto &= ~RB_GDB;		    /* local ddb */
		Debugger("vinum debug");
	    }
	    ioctl_reply = (struct _ioctl_reply *) data;	    /* reinstate the address to reply to */
	    ioctl_reply->error = 0;
	    return 0;
#endif

	case VINUM_CREATE:				    /* create a vinum object */
	    error = lock_config();			    /* get the config for us alone */
	    if (error)					    /* can't do it, */
		return error;				    /* give up */
	    error = setjmp(command_fail);		    /* come back here on error */
	    if (error == 0)				    /* first time, */
		ioctl_reply->error = parse_user_config((char *) data, /* update the config */
		    &keyword_set);
	    else if (ioctl_reply->error == 0) {		    /* longjmp, but no error status */
		ioctl_reply->error = EINVAL;		    /* note that something's up */
		ioctl_reply->msg[0] = '\0';		    /* no message? */
	    }
	    unlock_config();
	    return 0;					    /* must be 0 to return the real error info */

	case VINUM_GETCONFIG:				    /* get the configuration information */
	    bcopy(&vinum_conf, data, sizeof(vinum_conf));
	    return 0;

	    /* start configuring the subsystem */
	case VINUM_STARTCONFIG:
	    return start_config(*(int *) data);		    /* just lock it.  Parameter is 'force' */

	    /*
	     * Move the individual parts of the config to user space.
	     *
	     * Specify the index of the object in the first word of data,
	     * and return the object there
	     */
	case VINUM_DRIVECONFIG:
	    index = *(int *) data;			    /* get the index */
	    if (index >= (unsigned) vinum_conf.drives_allocated) /* can't do it */
		return ENXIO;				    /* bang */
	    bcopy(&DRIVE[index], data, sizeof(struct _drive)); /* copy the config item out */
	    return 0;

	case VINUM_SDCONFIG:
	    index = *(int *) data;			    /* get the index */
	    if (index >= (unsigned) vinum_conf.subdisks_allocated) /* can't do it */
		return ENXIO;				    /* bang */
	    bcopy(&SD[index], data, sizeof(struct _sd));    /* copy the config item out */
	    return 0;

	case VINUM_PLEXCONFIG:
	    index = *(int *) data;			    /* get the index */
	    if (index >= (unsigned) vinum_conf.plexes_allocated) /* can't do it */
		return ENXIO;				    /* bang */
	    bcopy(&PLEX[index], data, sizeof(struct _plex)); /* copy the config item out */
	    return 0;

	case VINUM_VOLCONFIG:
	    index = *(int *) data;			    /* get the index */
	    if (index >= (unsigned) vinum_conf.volumes_allocated) /* can't do it */
		return ENXIO;				    /* bang */
	    bcopy(&VOL[index], data, sizeof(struct _volume)); /* copy the config item out */
	    return 0;

	case VINUM_PLEXSDCONFIG:
	    index = *(int *) data;			    /* get the plex index */
	    sdno = ((int *) data)[1];			    /* and the sd index */
	    if ((index >= (unsigned) vinum_conf.plexes_allocated) /* plex doesn't exist */
	    ||(sdno >= PLEX[index].subdisks))		    /* or it doesn't have this many subdisks */
		return ENXIO;				    /* bang */
	    bcopy(&SD[PLEX[index].sdnos[sdno]],		    /* copy the config item out */
		data,
		sizeof(struct _sd));
	    return 0;

	    /*
	     * We get called in two places: one from the
	     * userland config routines, which call us
	     * to complete the config and save it.  This
	     * call supplies the value 0 as a parameter.
	     *
	     * The other place is from the user "saveconfig"
	     * routine, which can only work if we're *not*
	     * configuring.  In this case, supply parameter 1.
	     */
	case VINUM_SAVECONFIG:
	    if (VFLAGS & VF_CONFIGURING) {		    /* must be us, the others are asleep */
		if (*(int *) data == 0)			    /* finish config */
		    finish_config(1);			    /* finish the configuration and update it */
		else
		    return EBUSY;			    /* can't do it now */
	    }
	    save_config();				    /* save configuration to disk */
	    return 0;

	case VINUM_RELEASECONFIG:			    /* release the config */
	    if (VFLAGS & VF_CONFIGURING) {		    /* must be us, the others are asleep */
		finish_config(0);			    /* finish the configuration, don't change it */
		save_config();				    /* save configuration to disk */
	    } else
		error = EINVAL;				    /* release what config? */
	    return error;

	case VINUM_INIT:
	    ioctl_reply = (struct _ioctl_reply *) data;	    /* reinstate the address to reply to */
	    ioctl_reply->error = 0;
	    return 0;

	case VINUM_RESETCONFIG:
	    if (vinum_inactive(0)) {			    /* if the volumes are not active */
		/*
		 * Note the open count.  We may be called from v, so we'll be open.
		 * Keep the count so we don't underflow
		 */
		free_vinum(1);				    /* clean up everything */
		log(LOG_NOTICE, "vinum: CONFIGURATION OBLITERATED\n");
		ioctl_reply = (struct _ioctl_reply *) data; /* reinstate the address to reply to */
		ioctl_reply->error = 0;
		return 0;
	    }
	    return EBUSY;

	case VINUM_SETSTATE:
	    setstate((struct vinum_ioctl_msg *) data);	    /* set an object state */
	    return 0;

	    /*
	     * Set state by force, without changing
	     * anything else.
	     */
	case VINUM_SETSTATE_FORCE:
	    setstate_by_force((struct vinum_ioctl_msg *) data);	/* set an object state */
	    return 0;

#ifdef VINUMDEBUG
	case VINUM_MEMINFO:
	    vinum_meminfo(data);
	    return 0;

	case VINUM_MALLOCINFO:
	    return vinum_mallocinfo(data);

	case VINUM_RQINFO:
	    return vinum_rqinfo(data);
#endif

	case VINUM_LABEL:				    /* label a volume */
	    ioctl_reply->error = write_volume_label(*(int *) data); /* index of the volume to label */
	    ioctl_reply->msg[0] = '\0';			    /* no message */
	    return 0;

	case VINUM_REMOVE:
	    remove((struct vinum_ioctl_msg *) data);	    /* remove an object */
	    return 0;

	case VINUM_GETFREELIST:				    /* get a drive free list element */
	    index = *(int *) data;			    /* get the drive index */
	    fe = ((int *) data)[1];			    /* and the free list element */
	    if ((index >= (unsigned) vinum_conf.drives_allocated) /* plex doesn't exist */
	    ||(DRIVE[index].state == drive_unallocated))
		return ENODEV;
	    if (fe >= DRIVE[index].freelist_entries)	    /* no such entry */
		return ENOENT;
	    bcopy(&DRIVE[index].freelist[fe],
		data,
		sizeof(struct drive_freelist));
	    return 0;

	case VINUM_RESETSTATS:
	    resetstats((struct vinum_ioctl_msg *) data);    /* reset object stats */
	    return 0;

	    /* attach an object to a superordinate object */
	case VINUM_ATTACH:
	    attachobject((struct vinum_ioctl_msg *) data);
	    return 0;

	    /* detach an object from a superordinate object */
	case VINUM_DETACH:
	    detachobject((struct vinum_ioctl_msg *) data);
	    return 0;

	    /* rename an object */
	case VINUM_RENAME:
	    renameobject((struct vinum_rename_msg *) data);
	    return 0;

	    /* replace an object */
	case VINUM_REPLACE:
	    replaceobject((struct vinum_ioctl_msg *) data);
	    return 0;

	case VINUM_DAEMON:
	    vinum_daemon();				    /* perform the daemon */
	    return 0;

	case VINUM_FINDDAEMON:				    /* check for presence of daemon */
	    return vinum_finddaemon();
	    return 0;

	case VINUM_SETDAEMON:				    /* set daemon flags */
	    return vinum_setdaemonopts(*(int *) data);

	case VINUM_GETDAEMON:				    /* get daemon flags */
	    *(int *) data = daemon_options;
	    return 0;

	case VINUM_PARITYOP:				    /* check/rebuild RAID-4/5 parity */
	    parityops((struct vinum_ioctl_msg *) data);
	    return 0;

	    /* move an object */
	case VINUM_MOVE:
	    moveobject((struct vinum_ioctl_msg *) data);
	    return 0;

	default:
	    /* FALLTHROUGH */
	    break;
	}

    case VINUM_DRIVE_TYPE:
    default:
	log(LOG_WARNING,
	    "vinumioctl: invalid ioctl from process %d (%s): %lx\n",
	    curthread->td_proc->p_pid,
	    curthread->td_proc->p_comm,
	    cmd);
	return EINVAL;

    case VINUM_SD_TYPE:
    case VINUM_RAWSD_TYPE:
	objno = Sdno(dev);

	sd = &SD[objno];

	switch (cmd) {
      case DIOCGDINFO:				    /* get disk label */
	    get_volume_label(sd->name, 1, sd->sectors, (struct disklabel *) data);
	    break;

	    /*
	     * We don't have this stuff on hardware,
	     * so just pretend to do it so that
	     * utilities don't get upset.
	     */
	case DIOCWDINFO:				    /* write partition info */
	case DIOCSDINFO:				    /* set partition info */
	    return 0;					    /* not a titty */

	default:
	    return ENOTTY;				    /* not my kind of ioctl */
	}

	return 0;					    /* pretend we did it */

    case VINUM_RAWPLEX_TYPE:
    case VINUM_PLEX_TYPE:
	objno = Plexno(dev);

	plex = &PLEX[objno];

	switch (cmd) {
	case DIOCGDINFO:				    /* get disk label */
	    get_volume_label(plex->name, 1, plex->length, (struct disklabel *) data);
	    break;

	    /*
	     * We don't have this stuff on hardware,
	     * so just pretend to do it so that
	     * utilities don't get upset.
	     */
	case DIOCWDINFO:				    /* write partition info */
	case DIOCSDINFO:				    /* set partition info */
	    return 0;					    /* not a titty */

	default:
	    return ENOTTY;				    /* not my kind of ioctl */
	}

	return 0;					    /* pretend we did it */

    case VINUM_VOLUME_TYPE:
	objno = Volno(dev);

	if ((unsigned) objno >= (unsigned) vinum_conf.volumes_allocated) /* not a valid volume */
	    return ENXIO;
	vol = &VOL[objno];
	if (vol->state != volume_up)			    /* not up, */
	    return EIO;					    /* I/O error */

	switch (cmd) {

	case DIOCGMEDIASIZE:
	    *(off_t *)data = vol->size << DEV_BSHIFT;
	    break;

	case DIOCGSECTORSIZE:
	    *(u_int *)data = DEV_BSIZE;
	    break;

	    /*
	     * We don't have this stuff on hardware,
	     * so just pretend to do it so that
	     * utilities don't get upset.
	     */
	case DIOCWDINFO:				    /* write partition info */
	case DIOCSDINFO:				    /* set partition info */
	    return 0;					    /* not a titty */

	case DIOCWLABEL:				    /* set or reset label writeable */
	    if ((flag & FWRITE) == 0)			    /* not writeable? */
		return EACCES;				    /* no, die */
	    if (*(int *) data != 0)			    /* set it? */
		vol->flags |= VF_WLABEL;		    /* yes */
	    else
		vol->flags &= ~VF_WLABEL;		    /* no, reset */
	    break;

	default:
	    return ENOTTY;				    /* not my kind of ioctl */
	}
	break;
    }
    return 0;						    /* XXX */
}
예제 #2
0
파일: riftty.cpp 프로젝트: kkawamura/riftty
int main(int argc, char* argv[])
{
    printf("START! pid = %d\n", getpid());

    if (!system("./restart.rb"))
        exit(1);

    if (signal(SIGUSR1, RestartHandler) == SIG_ERR) {
        fprintf(stderr, "An error occurred while setting a signal handler.\n");
        exit(1);
    }

    bool fullscreen = true;
    s_config = new AppConfig(fullscreen, false, 1280, 800);
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK);
    SDL_Window* displayWindow;
    SDL_Renderer* displayRenderer;

    uint32_t flags = SDL_WINDOW_OPENGL | (s_config->fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
	int err = SDL_CreateWindowAndRenderer(s_config->width, s_config->height, flags, &displayWindow, &displayRenderer);
	if (err == -1 || !displayWindow || !displayRenderer) {
		fprintf(stderr, "SDL_CreateWindowAndRenderer failed!\n");
	}

	SDL_RendererInfo displayRendererInfo;
    SDL_GetRendererInfo(displayRenderer, &displayRendererInfo);
    /* TODO: Check that we have OpenGL */
    if ((displayRendererInfo.flags & SDL_RENDERER_ACCELERATED) == 0 ||
        (displayRendererInfo.flags & SDL_RENDERER_TARGETTEXTURE) == 0) {
        /* TODO: Handle this. We have no render surface and not accelerated. */
        fprintf(stderr, "NO RENDERER wtf!\n");
    }

    atexit(SDL_Quit);

    JOYSTICK_Init();

    AppConfig& config = *s_config;
    config.title = "riftty";

    //SDL_WM_SetCaption(config.title.c_str(), config.title.c_str());
    //SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);

    /*
    // clear
    glClearColor(s_clearColor.x, s_clearColor.y, s_clearColor.z, s_clearColor.w);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    SDL_GL_SwapWindow(displayWindow);
    */

    RiftSetup();

    RenderInit();

    win_init();

    init_config();

    struct passwd *pw = getpwuid(getuid());
    const char *homedir = pw->pw_dir;
    char config_filename[512];
    strncpy(config_filename, homedir, 512);
    strncat(config_filename, "/.riftty", 512);
    load_config(config_filename);

    cs_init();  // TODO: code pages do not want

    // TODO: determine this based on window-size & font-size or vice versa.
    cfg.rows = 25;
    cfg.cols = 80;

    // TODO: load config from /etc/riffty or ~/.rifttyrc
    finish_config();
    win_reconfig();

    // TODO: get SHELL from env

    cs_reconfig(); // TODO: do not want

    term_init();
    term_reset();
    term_resize(cfg.rows, cfg.cols);

    // TODO:
    int font_width = 10;
    int font_height = 10;
    unsigned short term_width = font_width * cfg.cols;
    unsigned short term_height = font_height * cfg.rows;

    char login[128];
    strncpy(login, getlogin(), 128);
    const char* login_argv[] = {"login", "-pfl", login, NULL};
    unsigned short rows = cfg.rows;
    unsigned short cols = cfg.cols;
    winsize ws = {rows, cols, term_width, term_height};
    child_create(login_argv, &ws);

    bool done = false;
    while (!done)
    {
        JOYSTICK_ClearFlags();

        SDL_Event event;
        while (SDL_PollEvent(&event))
        {
            switch (event.type)
            {
            case SDL_QUIT:
                done = true;
                break;

            case SDL_MOUSEMOTION:
                if (event.motion.state & SDL_BUTTON(1)) {
                    // move touch
                }
                break;

            case SDL_MOUSEBUTTONDOWN:
                if (event.button.button == SDL_BUTTON_LEFT) {
                    // start touch
                }
                break;

            case SDL_MOUSEBUTTONUP:
                if (event.button.button == SDL_BUTTON_LEFT) {
                    // end touch
                }
                break;

            case SDL_JOYAXISMOTION:
                JOYSTICK_UpdateMotion(&event.jaxis);
                break;

            case SDL_JOYBUTTONDOWN:
            case SDL_JOYBUTTONUP:
                JOYSTICK_UpdateButton(&event.jbutton);
                break;

            case SDL_KEYDOWN:
            case SDL_KEYUP:
                if (ProcessKeyEvent(&event.key)) {
                    done = true;
                }
                break;
            }
        }

        if (!done)
        {
            if (s_needsRestart)
                Restart();

            unsigned int now = SDL_GetTicks();  // milliseconds
            float dt = (now - s_ticks) / 1000.0f;	// convert to seconds.
            s_ticks = now;

            //printf("fps = %.0f\n", 1.0f/dt);

            Process(dt);
            Render(dt);
        }
    }

    child_kill(true);
    win_shutdown();

    RiftShutdown();
    JOYSTICK_Shutdown();

    return 0;
}
예제 #3
0
/* ioctl routine */
int
vinumioctl(struct dev_ioctl_args *ap)
{
    cdev_t dev = ap->a_head.a_dev;
    u_long cmd = ap->a_cmd;
    caddr_t data = ap->a_data;
    int error;
    unsigned int index;					    /* for transferring config info */
    unsigned int sdno;					    /* for transferring config info */
    unsigned int objno;
    struct volume *vol;
    struct partinfo *dpart;
    int fe;						    /* free list element number */
    struct _ioctl_reply *ioctl_reply;			    /* struct to return */

    error = 0;

    /* First, decide what we're looking at */
    switch (DEVTYPE(dev)) {
    case VINUM_SUPERDEV_TYPE:				    /* ordinary super device */
	ioctl_reply = (struct _ioctl_reply *) data;	    /* save the address to reply to */
	switch (cmd) {
#ifdef VINUMDEBUG
	case VINUM_DEBUG:
	    if (((struct debuginfo *) data)->changeit)	    /* change debug settings */
		debug = (((struct debuginfo *) data)->param);
	    else {
		if (debug & DEBUG_REMOTEGDB)
		    boothowto |= RB_GDB;		    /* serial debug line */
		else
		    boothowto &= ~RB_GDB;		    /* local ddb */
		Debugger("vinum debug");
	    }
	    ioctl_reply = (struct _ioctl_reply *) data;	    /* reinstate the address to reply to */
	    ioctl_reply->error = 0;
	    break;
#endif

	case VINUM_CREATE:				    /* create a vinum object */
	    error = lock_config();			    /* get the config for us alone */
	    if (error)					    /* can't do it, */
		break;
	    error = setjmp(command_fail);		    /* come back here on error */
	    if (error == 0)				    /* first time, */
		ioctl_reply->error = parse_user_config((char *) data, /* update the config */
		    &keyword_set);
	    else if (ioctl_reply->error == 0) {		    /* longjmp, but no error status */
		error = 0;
		ioctl_reply->error = EINVAL;		    /* note that something's up */
		ioctl_reply->msg[0] = '\0';		    /* no message? */
	    }
	    unlock_config();
	    break;

	case VINUM_GETCONFIG:				    /* get the configuration information */
	    bcopy(&vinum_conf, data, sizeof(vinum_conf));
	    break;

	    /* start configuring the subsystem */
	case VINUM_STARTCONFIG:
	    error = start_config(*(int *) data);	    /* just lock it.  Parameter is 'force' */
	    break;

	case VINUM_DRIVECONFIG:
	    /*
	     * Move the individual parts of the config to user space.
	     *
	     * Specify the index of the object in the first word of data,
	     * and return the object there
	     */
	    index = *(int *) data;
	    if (index >= (unsigned)vinum_conf.drives_allocated) {
		error = ENXIO;
	    } else {
		bcopy(&DRIVE[index], data, sizeof(struct drive));
	    }
	    break;

	case VINUM_SDCONFIG:
	    index = *(int *) data;
	    if (index >= (unsigned) vinum_conf.subdisks_allocated) {
		error = ENXIO;
	    } else {
		bcopy(&SD[index], data, sizeof(struct sd));
	    }
	    break;

	case VINUM_PLEXCONFIG:
	    index = *(int *) data;
	    if (index >= (unsigned) vinum_conf.plexes_allocated) {
		error = ENXIO;
	    } else {
		bcopy(&PLEX[index], data, sizeof(struct plex));
	    }
	    break;

	case VINUM_VOLCONFIG:
	    index = *(int *) data;
	    if (index >= (unsigned) vinum_conf.volumes_allocated) {
		error = ENXIO;
	    } else {
		bcopy(&VOL[index], data, sizeof(struct volume));
	    }
	    break;

	case VINUM_PLEXSDCONFIG:
	    index = ((int *)data)[0];			    /* get the plex index */
	    sdno = ((int *)data)[1];			    /* and the sd index */
	    if ((index >= (unsigned) vinum_conf.plexes_allocated)
		||(sdno >= PLEX[index].subdisks)) {
		error = ENXIO;
	    } else {
		bcopy(&SD[PLEX[index].sdnos[sdno]], data, sizeof(struct sd));
	    }
	    break;
	case VINUM_SAVECONFIG:
	    /*
	     * We get called in two places: one from the
	     * userland config routines, which call us
	     * to complete the config and save it.  This
	     * call supplies the value 0 as a parameter.
	     *
	     * The other place is from the user "saveconfig"
	     * routine, which can only work if we're *not*
	     * configuring.  In this case, supply parameter 1.
	     */
	    if (VFLAGS & VF_CONFIGURING) {		    /* must be us, the others are asleep */
		if (*(int *) data == 0)			    /* finish config */
		    finish_config(1);			    /* finish the configuration and update it */
		else
		    error = EBUSY;
	    }
	    if (error == 0)
		save_config();				    /* save configuration to disk */
	    break;

	case VINUM_RELEASECONFIG:			    /* release the config */
	    if (VFLAGS & VF_CONFIGURING) {		    /* must be us, the others are asleep */
		finish_config(0);			    /* finish the configuration, don't change it */
		save_config();				    /* save configuration to disk */
	    } else {
		error = EINVAL;				    /* release what config? */
	    }
	    break;

	case VINUM_INIT:
	    ioctl_reply = (struct _ioctl_reply *) data;	    /* reinstate the address to reply to */
	    ioctl_reply->error = 0;
	    break;

	case VINUM_RESETCONFIG:
	    if (vinum_inactive(0)) {			    /* if the volumes are not active */
		/*
		 * Note the open count.  We may be called from v, so we'll be open.
		 * Keep the count so we don't underflow
		 */
		free_vinum(1);				    /* clean up everything */
		log(LOG_NOTICE, "vinum: CONFIGURATION OBLITERATED\n");
		ioctl_reply = (struct _ioctl_reply *) data; /* reinstate the address to reply to */
		ioctl_reply->error = 0;
	    } else {
		error = EBUSY;
	    }

	case VINUM_SETSTATE:
	    setstate((struct vinum_ioctl_msg *) data);	    /* set an object state */
	    break;

	    /*
	     * Set state by force, without changing
	     * anything else.
	     */
	case VINUM_SETSTATE_FORCE:
	    setstate_by_force((struct vinum_ioctl_msg *) data);	/* set an object state */
	    break;

#ifdef VINUMDEBUG
	case VINUM_MEMINFO:
	    vinum_meminfo(data);
	    break;

	case VINUM_MALLOCINFO:
	    error = vinum_mallocinfo(data);
	    break;

	case VINUM_RQINFO:
	    error = vinum_rqinfo(data);
	    break;
#endif

	case VINUM_REMOVE:
	    remove((struct vinum_ioctl_msg *) data);	    /* remove an object */
	    break;

	case VINUM_GETFREELIST:				    /* get a drive free list element */
	    index = *(int *) data;			    /* get the drive index */
	    fe = ((int *) data)[1];			    /* and the free list element */
	    if ((index >= (unsigned) vinum_conf.drives_allocated) /* plex doesn't exist */
		||(DRIVE[index].state == drive_unallocated)) {
		error = ENODEV;
	    } else if (fe >= DRIVE[index].freelist_entries) {
		error = ENOENT;
	    } else {
		bcopy(&DRIVE[index].freelist[fe], data,
		      sizeof(struct drive_freelist));
	    }
	    break;

	case VINUM_RESETSTATS:
	    resetstats((struct vinum_ioctl_msg *) data);    /* reset object stats */
	    break;

	    /* attach an object to a superordinate object */
	case VINUM_ATTACH:
	    attachobject((struct vinum_ioctl_msg *) data);
	    break;

	    /* detach an object from a superordinate object */
	case VINUM_DETACH:
	    detachobject((struct vinum_ioctl_msg *) data);
	    break;

	    /* rename an object */
	case VINUM_RENAME:
	    renameobject((struct vinum_rename_msg *) data);
	    break;

	    /* replace an object */
	case VINUM_REPLACE:
	    replaceobject((struct vinum_ioctl_msg *) data);
	    break;

	case VINUM_DAEMON:
	    vinum_daemon();				    /* perform the daemon */
	    break;

	case VINUM_FINDDAEMON:				    /* check for presence of daemon */
	    error = vinum_finddaemon();
	    break;

	case VINUM_SETDAEMON:				    /* set daemon flags */
	    error = vinum_setdaemonopts(*(int *) data);
	    break;

	case VINUM_GETDAEMON:				    /* get daemon flags */
	    *(int *) data = daemon_options;
	    break;

	case VINUM_PARITYOP:				    /* check/rebuild RAID-4/5 parity */
	    parityops((struct vinum_ioctl_msg *) data);
	    break;

	    /* move an object */
	case VINUM_MOVE:
	    moveobject((struct vinum_ioctl_msg *) data);
	    break;
	default:
	    error = EINVAL;
	    break;
	}
	break;
    case VINUM_LABEL:
    case VINUM_DRIVE_TYPE:
    case VINUM_SD_TYPE:
    case VINUM_RAWSD_TYPE:
    case VINUM_RAWPLEX_TYPE:
    case VINUM_PLEX_TYPE:
	error = EINVAL;
	break;
    case VINUM_VOLUME_TYPE:
	objno = Volno(dev);

	if ((unsigned)objno >= (unsigned)vinum_conf.volumes_allocated) {
	    error = ENXIO;
	    break;
	}
	vol = &VOL[objno];
	if (vol->state != volume_up) {
	    error = EIO;
	    break;
	}

	switch(cmd) {
	case DIOCGPART:
	    dpart = (void *)data;

	    bzero(dpart, sizeof(*dpart));
	    dpart->media_offset  = 0;
	    dpart->media_size    = (u_int64_t)vol->size * DEV_BSIZE;
	    dpart->media_blocks  = vol->size;
	    dpart->media_blksize = DEV_BSIZE;
	    dpart->fstype = FS_BSDFFS;
	    break;
	default:
	    error = EINVAL;
	}
	break;
    default:
	error = EINVAL;
	break;
    }
    if (error) {
	log(LOG_WARNING,
	    "vinumioctl: invalid ioctl from process %d (%s): %lx\n",
	    curproc->p_pid,
	    curproc->p_comm,
	    cmd);
    }
    return error;
}