📄 zftape-ctl.c
字号:
mtftseg->mt_mode); if (mtftseg->mt_result < 0) { /* a negativ result is not an ioctl error. if * the user wants to read damaged tapes, * it's up to her/him */ TRACE_EXIT 0; } if (copy_to_user(mtftseg->mt_data, zft_deblock_buf, mtftseg->mt_result) != 0) { TRACE_EXIT -EFAULT; } TRACE_EXIT 0;}#endif#ifdef MTIOCWRFTSEG/* * write a floppy tape segment. This version features writing of * deleted address marks, and gracefully ignores the (software) * ft_formatted flag to support writing of header segments after * formatting. */static int mtiocwrftseg(struct mtftseg * mtftseg, int arg_size){ int result; TRACE_FUN(ft_t_flow); TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCWRFTSEG"); if (zft_write_protected || zft_qic_mode) { TRACE_EXIT -EACCES; } if (arg_size != sizeof(struct mtftseg)) { TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", arg_size); } if (zft_offline) { TRACE_EXIT -ENXIO; } if (mtftseg->mt_mode != FT_WR_ASYNC && mtftseg->mt_mode != FT_WR_MULTI && mtftseg->mt_mode != FT_WR_SINGLE && mtftseg->mt_mode != FT_WR_DELETE) { TRACE_ABORT(-EINVAL, ft_t_info, "invalid write mode"); } /* * We don't check for ft_formatted, because this gives * only the software status of the driver. * * We assume that the user knows what it is * doing. And rely on the low level stuff to fail * when the tape isn't formatted. We only make sure * that The header segment buffer is allocated, * because it holds the bad sector map. */ if (zft_hseg_buf == NULL) { TRACE_EXIT -ENXIO; } if (mtftseg->mt_mode != FT_WR_DELETE) { if (copy_from_user(zft_deblock_buf, mtftseg->mt_data, FT_SEGMENT_SIZE) != 0) { TRACE_EXIT -EFAULT; } } mtftseg->mt_result = ftape_write_segment(mtftseg->mt_segno, zft_deblock_buf, mtftseg->mt_mode); if (mtftseg->mt_result >= 0 && mtftseg->mt_mode == FT_WR_SINGLE) { /* * a negativ result is not an ioctl error. if * the user wants to write damaged tapes, * it's up to her/him */ if ((result = ftape_loop_until_writes_done()) < 0) { mtftseg->mt_result = result; } } TRACE_EXIT 0;}#endif #ifdef MTIOCVOLINFO/* * get information about volume positioned at. */static int mtiocvolinfo(struct mtvolinfo *volinfo, int arg_size){ const zft_volinfo *volume; TRACE_FUN(ft_t_flow); TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCVOLINFO"); if (arg_size != sizeof(struct mtvolinfo)) { TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", arg_size); } if (zft_offline) { TRACE_EXIT -ENXIO; } if (!ft_formatted) { TRACE_EXIT -EACCES; } TRACE_CATCH(zft_def_idle_state(),); volume = zft_find_volume(zft_pos.seg_pos); volinfo->mt_volno = volume->count; volinfo->mt_blksz = volume->blk_sz == 1 ? 0 : volume->blk_sz; volinfo->mt_size = volume->size >> 10; volinfo->mt_rawsize = ((zft_calc_tape_pos(volume->end_seg + 1) >> 10) - (zft_calc_tape_pos(volume->start_seg) >> 10)); volinfo->mt_cmpr = volume->use_compression; TRACE_EXIT 0;}#endif#ifdef ZFT_OBSOLETE static int mtioc_zftape_getblksz(struct mtblksz *blksz, int arg_size){ TRACE_FUN(ft_t_flow); TRACE(ft_t_noise, "\n" KERN_INFO "Mag tape ioctl command: MTIOC_ZTAPE_GETBLKSZ\n" KERN_INFO "This ioctl is here merely for compatibility.\n" KERN_INFO "Please use MTIOCVOLINFO instead"); if (arg_size != sizeof(struct mtblksz)) { TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", arg_size); } if (zft_offline) { TRACE_EXIT -ENXIO; } if (!ft_formatted) { TRACE_EXIT -EACCES; } TRACE_CATCH(zft_def_idle_state(),); blksz->mt_blksz = zft_find_volume(zft_pos.seg_pos)->blk_sz; TRACE_EXIT 0;}#endif#ifdef MTIOCGETSIZE/* * get the capacity of the tape cartridge. */static int mtiocgetsize(struct mttapesize *size, int arg_size){ TRACE_FUN(ft_t_flow); TRACE(ft_t_noise, "Mag tape ioctl command: MTIOC_ZFTAPE_GETSIZE"); if (arg_size != sizeof(struct mttapesize)) { TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", arg_size); } if (zft_offline) { TRACE_EXIT -ENXIO; } if (!ft_formatted) { TRACE_EXIT -EACCES; } TRACE_CATCH(zft_def_idle_state(),); size->mt_capacity = (unsigned int)(zft_capacity>>10); size->mt_used = (unsigned int)(zft_get_eom_pos()>>10); TRACE_EXIT 0;}#endifstatic int mtiocpos(struct mtpos *mtpos, int arg_size){ int result; TRACE_FUN(ft_t_flow); TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCPOS"); if (arg_size != sizeof(struct mtpos)) { TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", arg_size); } result = mt_tell((int *)&mtpos->mt_blkno); TRACE_EXIT result;}#ifdef MTIOCFTFORMAT/* * formatting of floppy tape cartridges. This is intended to be used * together with the MTIOCFTCMD ioctl and the new mmap feature *//* * This function uses ftape_decode_header_segment() to inform the low * level ftape module about the new parameters. * * It erases the hseg_buf. The calling process must specify all * parameters to assure proper operation. * * return values: -EINVAL - wrong argument size * -EINVAL - if ftape_decode_header_segment() failed. */static int set_format_parms(struct ftfmtparms *p, __u8 *hseg_buf){ ft_trace_t old_level = TRACE_LEVEL; TRACE_FUN(ft_t_flow); TRACE(ft_t_noise, "MTIOCFTFORMAT operation FTFMT_SETPARMS"); memset(hseg_buf, 0, FT_SEGMENT_SIZE); PUT4(hseg_buf, FT_SIGNATURE, FT_HSEG_MAGIC); /* fill in user specified parameters */ hseg_buf[FT_FMT_CODE] = (__u8)p->ft_fmtcode; PUT2(hseg_buf, FT_SPT, p->ft_spt); hseg_buf[FT_TPC] = (__u8)p->ft_tpc; hseg_buf[FT_FHM] = (__u8)p->ft_fhm; hseg_buf[FT_FTM] = (__u8)p->ft_ftm; /* fill in sane defaults to make ftape happy. */ hseg_buf[FT_FSM] = (__u8)128; /* 128 is hard wired all over ftape */ if (p->ft_fmtcode == fmt_big) { PUT4(hseg_buf, FT_6_HSEG_1, 0); PUT4(hseg_buf, FT_6_HSEG_2, 1); PUT4(hseg_buf, FT_6_FRST_SEG, 2); PUT4(hseg_buf, FT_6_LAST_SEG, p->ft_spt * p->ft_tpc - 1); } else { PUT2(hseg_buf, FT_HSEG_1, 0); PUT2(hseg_buf, FT_HSEG_2, 1); PUT2(hseg_buf, FT_FRST_SEG, 2); PUT2(hseg_buf, FT_LAST_SEG, p->ft_spt * p->ft_tpc - 1); } /* Synchronize with the low level module. This is particularly * needed for unformatted cartridges as the QIC std was previously * unknown BUT is needed to set data rate and to calculate timeouts. */ TRACE_CATCH(ftape_calibrate_data_rate(p->ft_qicstd&QIC_TAPE_STD_MASK), _res = -EINVAL); /* The following will also recalcualte the timeouts for the tape * length and QIC std we want to format to. * abort with -EINVAL rather than -EIO */ SET_TRACE_LEVEL(ft_t_warn); TRACE_CATCH(ftape_decode_header_segment(hseg_buf), SET_TRACE_LEVEL(old_level); _res = -EINVAL); SET_TRACE_LEVEL(old_level); TRACE_EXIT 0;}/* * Return the internal SOFTWARE status of the kernel driver. This does * NOT query the tape drive about its status. */static int get_format_parms(struct ftfmtparms *p, __u8 *hseg_buffer){ TRACE_FUN(ft_t_flow); TRACE(ft_t_noise, "MTIOCFTFORMAT operation FTFMT_GETPARMS"); p->ft_qicstd = ft_qic_std; p->ft_fmtcode = ft_format_code; p->ft_fhm = hseg_buffer[FT_FHM]; p->ft_ftm = hseg_buffer[FT_FTM]; p->ft_spt = ft_segments_per_track; p->ft_tpc = ft_tracks_per_tape; TRACE_EXIT 0;}static int mtiocftformat(struct mtftformat *mtftformat, int arg_size){ int result; union fmt_arg *arg = &mtftformat->fmt_arg; TRACE_FUN(ft_t_flow); TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCFTFORMAT"); if (zft_offline) { if (ft_no_tape) { TRACE_ABORT(-ENXIO, ft_t_info, "no tape present"); } else { TRACE_ABORT(-ENXIO, ft_t_info, "drive is offline"); } } if (zft_qic_mode) { TRACE_ABORT(-EACCES, ft_t_info, "driver needs to be in raw mode for this ioctl"); } if (zft_hseg_buf == NULL) { TRACE_CATCH(zft_vcalloc_once(&zft_hseg_buf, FT_SEGMENT_SIZE),); } zft_header_read = 0; switch(mtftformat->fmt_op) { case FTFMT_SET_PARMS: TRACE_CATCH(set_format_parms(&arg->fmt_parms, zft_hseg_buf),); TRACE_EXIT 0; case FTFMT_GET_PARMS: TRACE_CATCH(get_format_parms(&arg->fmt_parms, zft_hseg_buf),); TRACE_EXIT 0; case FTFMT_FORMAT_TRACK: if ((ft_formatted && zft_check_write_access(&zft_pos) < 0) || (!ft_formatted && zft_write_protected)) { TRACE_ABORT(-EACCES, ft_t_info, "Write access denied"); } TRACE_CATCH(ftape_format_track(arg->fmt_track.ft_track, arg->fmt_track.ft_gap3),); TRACE_EXIT 0; case FTFMT_STATUS: TRACE_CATCH(ftape_format_status(&arg->fmt_status.ft_segment),); TRACE_EXIT 0; case FTFMT_VERIFY: TRACE_CATCH(ftape_verify_segment(arg->fmt_verify.ft_segment, (SectorMap *)&arg->fmt_verify.ft_bsm),); TRACE_EXIT 0; default: TRACE_ABORT(-EINVAL, ft_t_err, "Invalid format operation"); } TRACE_EXIT result;}#endif#ifdef MTIOCFTCMD/* * send a QIC-117 command to the drive, with optional timeouts, * parameter and result bits. This is intended to be used together * with the formatting ioctl. */static int mtiocftcmd(struct mtftcmd *ftcmd, int arg_size){ int i; TRACE_FUN(ft_t_flow); TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCFTCMD"); if (!capable(CAP_SYS_ADMIN)) { TRACE_ABORT(-EPERM, ft_t_info, "need CAP_SYS_ADMIN capability to send raw qic-117 commands"); } if (zft_qic_mode) { TRACE_ABORT(-EACCES, ft_t_info, "driver needs to be in raw mode for this ioctl"); } if (arg_size != sizeof(struct mtftcmd)) { TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", arg_size); } if (ftcmd->ft_wait_before) { TRACE_CATCH(ftape_ready_wait(ftcmd->ft_wait_before, &ftcmd->ft_status),); } if (ftcmd->ft_status & QIC_STATUS_ERROR) goto ftmtcmd_error; if (ftcmd->ft_result_bits != 0) { TRACE_CATCH(ftape_report_operation(&ftcmd->ft_result, ftcmd->ft_cmd, ftcmd->ft_result_bits),); } else { TRACE_CATCH(ftape_command(ftcmd->ft_cmd),); if (ftcmd->ft_status & QIC_STATUS_ERROR) goto ftmtcmd_error; for (i = 0; i < ftcmd->ft_parm_cnt; i++) { TRACE_CATCH(ftape_parameter(ftcmd->ft_parms[i]&0x0f),); if (ftcmd->ft_status & QIC_STATUS_ERROR) goto ftmtcmd_error; } } if (ftcmd->ft_wait_after != 0) { TRACE_CATCH(ftape_ready_wait(ftcmd->ft_wait_after, &ftcmd->ft_status),); }ftmtcmd_error: if (ftcmd->ft_status & QIC_STATUS_ERROR) { TRACE(ft_t_noise, "error status set"); TRACE_CATCH(ftape_report_error(&ftcmd->ft_error, &ftcmd->ft_cmd, 1),); } TRACE_EXIT 0; /* this is not an i/o error */}#endif/* IOCTL routine called by kernel-interface code */int _zft_ioctl(unsigned int command, void __user * arg){ int result; union { struct mtop mtop; struct mtget mtget; struct mtpos mtpos;#ifdef MTIOCRDFTSEG struct mtftseg mtftseg;#endif#ifdef MTIOCVOLINFO struct mtvolinfo mtvolinfo;#endif#ifdef MTIOCGETSIZE struct mttapesize mttapesize;#endif#ifdef MTIOCFTFORMAT struct mtftformat mtftformat;#endif#ifdef ZFT_OBSOLETE struct mtblksz mtblksz;#endif#ifdef MTIOCFTCMD struct mtftcmd mtftcmd;#endif } krnl_arg; int arg_size = _IOC_SIZE(command); int dir = _IOC_DIR(command); TRACE_FUN(ft_t_flow); /* This check will only catch arguments that are too large ! */ if (dir & (_IOC_READ | _IOC_WRITE) && arg_size > sizeof(krnl_arg)) { TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", arg_size); } if (dir & _IOC_WRITE) { if (copy_from_user(&krnl_arg, arg, arg_size) != 0) { TRACE_EXIT -EFAULT; } } TRACE(ft_t_flow, "called with ioctl command: 0x%08x", command); switch (command) { case MTIOCTOP: result = mtioctop(&krnl_arg.mtop, arg_size); break; case MTIOCGET: result = mtiocget(&krnl_arg.mtget, arg_size); break; case MTIOCPOS: result = mtiocpos(&krnl_arg.mtpos, arg_size); break;#ifdef MTIOCVOLINFO case MTIOCVOLINFO: result = mtiocvolinfo(&krnl_arg.mtvolinfo, arg_size); break;#endif#ifdef ZFT_OBSOLETE case MTIOC_ZFTAPE_GETBLKSZ: result = mtioc_zftape_getblksz(&krnl_arg.mtblksz, arg_size); break;#endif#ifdef MTIOCRDFTSEG case MTIOCRDFTSEG: /* read a segment via ioctl */ result = mtiocrdftseg(&krnl_arg.mtftseg, arg_size); break;#endif#ifdef MTIOCWRFTSEG case MTIOCWRFTSEG: /* write a segment via ioctl */ result = mtiocwrftseg(&krnl_arg.mtftseg, arg_size); break;#endif#ifdef MTIOCGETSIZE case MTIOCGETSIZE: result = mtiocgetsize(&krnl_arg.mttapesize, arg_size); break;#endif#ifdef MTIOCFTFORMAT case MTIOCFTFORMAT: result = mtiocftformat(&krnl_arg.mtftformat, arg_size); break;#endif#ifdef MTIOCFTCMD case MTIOCFTCMD: result = mtiocftcmd(&krnl_arg.mtftcmd, arg_size); break;#endif default: result = -EINVAL; break; } if ((result >= 0) && (dir & _IOC_READ)) { if (copy_to_user(arg, &krnl_arg, arg_size) != 0) { TRACE_EXIT -EFAULT; } } TRACE_EXIT result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -