コード例 #1
0
ファイル: vtlcart.c プロジェクト: fishky/mhvtl
int position_to_block(uint32_t blk_number, uint8_t *sam_stat)
{
	if (!tape_loaded(sam_stat))
		return -1;

	MHVTL_DBG(2, "Position to block %d", blk_number);

	if (mam.MediumType == MEDIA_TYPE_WORM)
		OK_to_write = 0;

	if (blk_number > eod_blk_number) {
		sam_blank_check(E_END_OF_DATA, sam_stat);
		MHVTL_DBG(1, "End of data detected while positioning");
		return position_to_eod(sam_stat);
	}

	/* Treat a position to block zero specially, as it has different
	   semantics than other blocks when the tape is WORM.
	*/

	if (blk_number == 0)
		return rewind_tape(sam_stat);
	else
		return read_header(blk_number, sam_stat);
}
コード例 #2
0
ファイル: ssc.c プロジェクト: aroundrobin/mhvtl
uint8_t ssc_rewind(struct scsi_cmd *cmd)
{
	struct priv_lu_ssc *lu_priv;
	uint8_t *sam_stat;
	int retval;

	lu_priv = cmd->lu->lu_private;
	sam_stat = &cmd->dbuf_p->sam_stat;

	MHVTL_DBG(1, "Rewinding (%ld) **", (long)cmd->dbuf_p->serialNo);

	current_state = MHVTL_STATE_REWIND;

	switch (lu_priv->tapeLoaded) {
	case TAPE_UNLOADED:
		mkSenseBuf(NOT_READY, E_MEDIUM_NOT_PRESENT, sam_stat);
		return SAM_STAT_CHECK_CONDITION;
		break;
	case TAPE_LOADED:
		retval = rewind_tape(sam_stat);
		if (retval < 0) {
			mkSenseBuf(NOT_READY, E_MEDIUM_FMT_CORRUPT, sam_stat);
			return SAM_STAT_CHECK_CONDITION;
		}
		break;
	default:
		mkSenseBuf(NOT_READY, E_MEDIUM_FMT_CORRUPT, sam_stat);
		return SAM_STAT_CHECK_CONDITION;
		break;
	}

	return SAM_STAT_GOOD;
}
コード例 #3
0
ファイル: vtlcart_v1_mtr.c プロジェクト: markh794/mhvtl
int position_to_block(uint32_t blk_no, uint8_t *sam_stat)
{
	MHVTL_DBG(1, "position_to_block");
	if (!tape_loaded(sam_stat))
		return -1;

	if (MediumType == MEDIA_TYPE_WORM)
		OK_to_write = 0;

	if (blk_no < raw_pos.hdr.blk_number &&
				raw_pos.hdr.blk_number - blk_no > blk_no) {
		if (rewind_tape(sam_stat))
			return -1;
	}
	while (raw_pos.hdr.blk_number != blk_no) {
		if (raw_pos.hdr.blk_number > blk_no) {
			if (skip_to_prev_header(sam_stat) == -1)
				return -1;
		} else {
			if (skip_to_next_header(sam_stat) == -1)
				return -1;
		}
	}
	return 0;
}
コード例 #4
0
ファイル: ssc.c プロジェクト: aroundrobin/mhvtl
uint8_t ssc_load_unload(struct scsi_cmd *cmd)
{
	struct priv_lu_ssc *lu_priv;
	uint8_t *sam_stat;
	int load;

	lu_priv = cmd->lu->lu_private;
	sam_stat = &cmd->dbuf_p->sam_stat;

	load = cmd->scb[4] & 0x01;

	current_state = (load) ? MHVTL_STATE_LOADING : MHVTL_STATE_UNLOADING;

	if (cmd->scb[4] & 0x04) { /* EOT bit */
		MHVTL_ERR("EOT bit set on load. Not supported");
		mkSenseBuf(ILLEGAL_REQUEST, E_INVALID_FIELD_IN_CDB, sam_stat);
		return SAM_STAT_CHECK_CONDITION;
	}

	MHVTL_DBG(1, "%s tape (%ld) **", (load) ? "Loading" : "Unloading",
						(long)cmd->dbuf_p->serialNo);

	switch (lu_priv->tapeLoaded) {
	case TAPE_UNLOADED:
		if (load)
			rewind_tape(sam_stat);
		else {
			mkSenseBuf(NOT_READY, E_MEDIUM_NOT_PRESENT, sam_stat);
			return SAM_STAT_CHECK_CONDITION;
		}
		break;

	case TAPE_LOADED:
		if (!load)
			unloadTape(sam_stat);
		break;

	default:
		mkSenseBuf(NOT_READY, E_MEDIUM_FMT_CORRUPT, sam_stat);
		return SAM_STAT_CHECK_CONDITION;
		break;
	}
	return SAM_STAT_GOOD;
}
コード例 #5
0
ファイル: tcopy.c プロジェクト: 2asoft/freebsd
int
main(int argc, char *argv[])
{
	int lastnread, nread, nw, inp, outp;
	enum {READ, VERIFY, COPY, COPYVERIFY} op = READ;
	sig_t oldsig;
	int ch, needeof;
	char *buff;
	const char *inf;

	msg = stdout;
	guesslen = 1;
	outp = -1;
	while ((ch = getopt(argc, argv, "cs:vx")) != -1)
		switch((char)ch) {
		case 'c':
			op = COPYVERIFY;
			break;
		case 's':
			maxblk = atoi(optarg);
			if (maxblk <= 0) {
				warnx("illegal block size");
				usage();
			}
			guesslen = 0;
			break;
		case 'v':
			op = VERIFY;
			break;
		case 'x':
			msg = stderr;
			break;
		case '?':
		default:
			usage();
		}
	argc -= optind;
	argv += optind;

	switch(argc) {
	case 0:
		if (op != READ)
			usage();
		inf = _PATH_DEFTAPE;
		break;
	case 1:
		if (op != READ)
			usage();
		inf = argv[0];
		break;
	case 2:
		if (op == READ)
			op = COPY;
		inf = argv[0];
		if ((outp = open(argv[1], op == VERIFY ? O_RDONLY :
		    op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0)
			err(3, "%s", argv[1]);
		break;
	default:
		usage();
	}

	if ((inp = open(inf, O_RDONLY, 0)) < 0)
		err(1, "%s", inf);

	buff = getspace(maxblk);

	if (op == VERIFY) {
		verify(inp, outp, buff);
		exit(0);
	}

	if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN)
		(void) signal(SIGINT, intr);

	needeof = 0;
	for (lastnread = NOCOUNT;;) {
		if ((nread = read(inp, buff, maxblk)) == -1) {
			while (errno == EINVAL && (maxblk -= 1024)) {
				nread = read(inp, buff, maxblk);
				if (nread >= 0)
					goto r1;
			}
			err(1, "read error, file %d, record %ju", filen, (intmax_t)record);
		} else if (nread != lastnread) {
			if (lastnread != 0 && lastnread != NOCOUNT) {
				if (lastrec == 0 && nread == 0)
					fprintf(msg, "%ju records\n", (intmax_t)record);
				else if (record - lastrec > 1)
					fprintf(msg, "records %ju to %ju\n",
					    (intmax_t)lastrec, (intmax_t)record);
				else
					fprintf(msg, "record %ju\n", (intmax_t)lastrec);
			}
			if (nread != 0)
				fprintf(msg, "file %d: block size %d: ",
				    filen, nread);
			(void) fflush(stdout);
			lastrec = record;
		}
r1:		guesslen = 0;
		if (nread > 0) {
			if (op == COPY || op == COPYVERIFY) {
				if (needeof) {
					writeop(outp, MTWEOF);
					needeof = 0;
				}
				nw = write(outp, buff, nread);
				if (nw != nread) {
					if (nw == -1) {
						warn("write error, file %d, record %ju", filen,
						    (intmax_t)record);
					} else {
						warnx("write error, file %d, record %ju", filen,
						    (intmax_t)record);
						warnx("write (%d) != read (%d)", nw, nread);
					}
					errx(5, "copy aborted");
				}
			}
			size += nread;
			record++;
		} else {
			if (lastnread <= 0 && lastnread != NOCOUNT) {
				fprintf(msg, "eot\n");
				break;
			}
			fprintf(msg,
			    "file %d: eof after %ju records: %ju bytes\n",
			    filen, (intmax_t)record, (intmax_t)size);
			needeof = 1;
			filen++;
			tsize += size;
			size = record = lastrec = 0;
			lastnread = 0;
		}
		lastnread = nread;
	}
	fprintf(msg, "total length: %ju bytes\n", (intmax_t)tsize);
	(void)signal(SIGINT, oldsig);
	if (op == COPY || op == COPYVERIFY) {
		writeop(outp, MTWEOF);
		writeop(outp, MTWEOF);
		if (op == COPYVERIFY) {
			rewind_tape(outp);
			rewind_tape(inp);
			verify(inp, outp, buff);
		}
	}
	exit(0);
}
コード例 #6
0
ファイル: menus.c プロジェクト: Oibaf66/fbzx-wii
void taps_menu() {

	unsigned char *fbuffer,fin;
	int ancho=screen->w;

	fbuffer=screen->pixels;
	
	fin=1;
	do {
		clean_screen();

		print_string(fbuffer,"TAP/TZX files",-1,20,15,0,ancho);

		print_string(fbuffer,"1:",14,60,12,0,ancho);
		print_string(fbuffer,"select a TAP/TZX file",62,60,15,0,ancho);


		print_string(fbuffer,"2:",14,100,12,0,ancho);
		print_string(fbuffer,"rewind TAP/TZX file",62,100,15,0,ancho);

		print_string(fbuffer,"3:",14,140,12,0,ancho);
		print_string(fbuffer,"instant/normal load",62,140,15,0,ancho);

		print_string(fbuffer,"4:",14,180,12,0,ancho);
		print_string(fbuffer,"write protection",62,180,15,0,ancho);
		
		print_string(fbuffer,"5:",14,220,12,0,ancho);
		print_string(fbuffer,"create TAP file",62,220,15,0,ancho);
				
		print_string(fbuffer,"ESC:",14,260,12,0,ancho);
		print_string(fbuffer,"return emulator",78,260,15,0,ancho);

		print_string(fbuffer,"Current TAP/TZX file is:",-1,310,12,0,ancho);
		print_string(fbuffer,ordenador.current_tap,-1,330,12,0,ancho);

		//print_copy(fbuffer,ancho);

		if(ordenador.tape_fast_load)
			print_string(fbuffer,"Fast load enabled	",10,420,14,0,ancho);
		else
			print_string(fbuffer,"Fast load disabled ",10,420,14,0,ancho);
		
		if(ordenador.tape_write)
			print_string(fbuffer,"Write enabled",390,420,14,0,ancho);
		else
			print_string(fbuffer,"Write disabled",390,420,14,0,ancho);

		switch(wait_key()) {
		case SDLK_ESCAPE: // to exit the help
			fin=0;
		break;
		case SDLK_1: //select tape
			ordenador.tape_stop=1;
			ordenador.tape_stop_fast = 1;
			ordenador.tape_start_countdwn=0;
			select_tapfile();
		break;
		case SDLK_2: //rewind tape
			fin=0;
			ordenador.tape_stop=1;
			ordenador.tape_stop_fast = 1;
			ordenador.tape_start_countdwn=0;
			if(ordenador.tap_file!=NULL) {
				ordenador.tape_current_mode=TAP_TRASH;
				rewind_tape(ordenador.tap_file,1);		
			}
			sprintf(ordenador.osd_text,"Tape rewound");
			ordenador.osd_time=50;			
		break;
		case SDLK_3: //Instant load settings
			ordenador.tape_stop=1;
			ordenador.tape_stop_fast = 1;
			ordenador.tape_start_countdwn=0;
			ordenador.tape_fast_load=1-ordenador.tape_fast_load;
			if(ordenador.tap_file!=NULL) {
				ordenador.tape_current_mode=TAP_TRASH;
				rewind_tape(ordenador.tap_file,1);
			}
		break;
		case SDLK_4:
			ordenador.tape_write=1-ordenador.tape_write;
		break;
		case SDLK_5:
			create_tapfile();
		break;
		default:
		break;
		}

	} while(fin);

	clean_screen();
}
コード例 #7
0
ファイル: proc_rule.c プロジェクト: antonblanchard/HTX
int
proc_rule(struct htx_data *phtx_info, struct ruleinfo *prule_info,
          char *wbuf, char *rbuf, struct blk_num_typ *pblk_num)
{
  int            dlen, loop, rc;                   
  char           msg[220], path[100];
  unsigned short seed[3];

  rc = 0;
  init_seed(seed);            /* initialize seed for random number generator */
  dlen = prule_info->num_blks * BLK_SIZE;       /* initialize length of data */
                                           /*-------------------------------*/
                                           /* initialize the write buffer   */
                                           /*-------------------------------*/
  if ( (prule_info->pattern_id[0] != '#') && 
       (prule_info->pattern_id[0] != 0) ) {
	 path[0] ='\0';	  
     if ( (int) htx_strlen((char *) htx_strcpy(path, getenv("HTXPATTERNS"))) == 0 )
        htx_strcpy(path, "../pattern/");         /* default ONLY */
     htx_strcat (path, prule_info->pattern_id);
     rc = hxfpat(path, wbuf, dlen);
     if ( rc == 1 ) {
        sprintf(msg, "cannot open pattern file - %s\n", path);
        hxfmsg(phtx_info, 0, SYSERR, msg);
        return(1);
     } 
     if ( rc == 2 ) {
        sprintf(msg, "cannot read pattern file - %s\n", path);
        hxfmsg(phtx_info, 0, SYSERR, msg);
        return(1);
     } 
  } else if ( prule_info->pattern_id[0] == '#' )
     bldbuf((unsigned short*)wbuf, dlen, prule_info->pattern_id, pblk_num);
  pblk_num->in_rule = 0;      /* initialize block number within current rule */
  rc = 0;
  tape_error_code = 0;
  for ( loop = 1; loop <= prule_info->num_oper; loop++ ) {
     if ( strcmp(prule_info->oper, "R") == 0 ) {     
        rc = read_tape(phtx_info, prule_info, loop, pblk_num, rbuf);
     } else if ( strcmp(prule_info->oper, "W") == 0 ) {
        rc = write_tape(phtx_info, prule_info, loop, pblk_num, wbuf);
     } else if ( strcmp(prule_info->oper, "RC") == 0 ) {   
        rc = read_tape(phtx_info, prule_info, loop, pblk_num, rbuf);
        if ( rc >= 0 )     
           rc = cmpbuf(phtx_info, prule_info, loop, pblk_num, wbuf, rbuf);
     } else if ( strcmp(prule_info->oper, "RW") == 0 ) {
        rc = rewind_tape(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "WEOF") == 0 ) { 
        rc = weof_tape(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "SF") == 0 ) {  
        rc = search_file(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "SR") == 0 ) {  
        rc = search_rec(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "D") == 0 ) { 
        rc = diag_tape(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "E") == 0 ) { 
        rc = erase_tape(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "S") == 0 ) { 
        rc = do_sleep(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "CO") == 0 ) { 
        rc = close_open(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "C") == 0 ) { 
        rc = tclose(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "O") == 0 ) {  
        rc = topen(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "WEOT") == 0 ) {
        rc = write_eot(phtx_info, prule_info,loop, pblk_num, wbuf);
     } else if ( strcmp(prule_info->oper, "RCEOT") == 0 ) {
        rc = read_eot(phtx_info, prule_info, loop,pblk_num, wbuf, rbuf);
     } else if ( strcmp(prule_info->oper, "REOT") == 0 ) {  
        rc = read_teot(phtx_info, prule_info, loop, pblk_num, wbuf, rbuf);
     } else if ( strcmp(prule_info->oper, "RS") == 0 ) {  
        rc = prt_req_sense(phtx_info, prule_info, loop, pblk_num);
	 }
#ifndef __HTX_LINUX__		
     else if ( strcmp(prule_info->oper, "ML") == 0 ) { 
        rc = medium_load(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "MUL") == 0 ) {   
        rc = medium_unload(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "RES") == 0 ) {   
        rc = read_status(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "IE") == 0 ) {   
        rc = init_element(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "RP") == 0 ) {  
        rc = read_posit(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "LB") == 0 ) {   
        rc = loc_block(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "ASF") == 0 ) { 
        rc = asearch_file(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "ASR") == 0 ) { 
        rc = asearch_rec(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "ADUL") == 0 ) {  
        rc = write_unload(phtx_info, prule_info, loop, pblk_num, wbuf);
     } else if ( strcmp(prule_info->oper, "TWIE") == 0 ) {  
        rc = twin_tape(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "TWPE") == 0 ) {   
        rc = twps_tape(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "TWRE") == 0 ) {  
        rc = twrd_stat(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "TWMM") == 0 ) { 
        rc = twmv_tape(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "TWUL") == 0 ) {  
        rc = unload_write(phtx_info, prule_info, loop, pblk_num, wbuf);
     } else if ( strcmp(prule_info->oper, "WUL") == 0 ) {   
        rc = tape_unload(phtx_info, prule_info, loop, pblk_num, wbuf);
     } else if ( strcmp(prule_info->oper, "CDRE") == 0 ) {
        rc = cdrd_stat(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "CDMM") == 0 ) {  
        rc = cdmv_tape(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "HUNL") == 0 ) {
        rc = himove(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "HINI") == 0 ) {
        rc = hiinit(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "HREL") == 0 ) {
        rc = hielem(phtx_info, prule_info, loop, pblk_num);
     } else if ( strcmp(prule_info->oper, "HWUN") == 0 ) {
        rc = hidal_unload(phtx_info, prule_info, loop, pblk_num, wbuf);
     } else if ( strcmp(prule_info->oper, "DBUG") == 0 ) {  
       rc = set_dbug(phtx_info, prule_info, pblk_num);
     } 
#endif
	 else if ( strcmp(prule_info->oper, "XCMD") == 0 ) {
       rc = do_cmd(phtx_info, prule_info, pblk_num);
     } else {
        ;
     }
     hxfupdate(UPDATE, phtx_info);
     if ( phtx_info->run_type[0] == 'O' ) {
        info_msg(phtx_info, prule_info, loop, pblk_num, msg);
        hxfmsg(phtx_info, 0, INFO, msg);
     } 
     if ( rc != 0 )
        break;
  } 
  return(rc);
} 
コード例 #8
0
int main(int argc, char ** argv) {
	static char * buffer[32];
	static char buffer_size[16];
	const char * device = DEFAULT_DEVICE;
	ssize_t size = DEFAULT_SIZE;
	bool no_rewind = false;
	bool rewind = false;

	ssize_t max_buffer_size = MAX_BUFFER_SIZE;
	ssize_t min_buffer_size = MIN_BUFFER_SIZE;
	ssize_t tmp_size = 0;

	enum {
		OPT_DEVICE     = 'd',
		OPT_HELP       = 'h',
		OPT_MAX_BUFFER = 'M',
		OPT_MIN_BUFFER = 'm',
		OPT_NO_REWIND  = 'r',
		OPT_REWIND     = 'R',
		OPT_SIZE       = 's',
		OPT_VERSION    = 'V',
	};

	static struct option op[] = {
		{ "device",          1, 0, OPT_DEVICE },
		{ "help",            0, 0, OPT_HELP },
		{ "max-buffer-size", 1, 0, OPT_MAX_BUFFER },
		{ "min-buffer-size", 1, 0, OPT_MIN_BUFFER },
		{ "no-rewind",       0, 0, OPT_NO_REWIND },
		{ "size",            1, 0, OPT_SIZE },
		{ "rewind-at-start", 0, 0, OPT_REWIND },
		{ "version",         0, 0, OPT_VERSION },

		{ 0, 0, 0, 0 },
	};

	static int lo;
	for (;;) {
		int c = getopt_long(argc, argv, "d:hm:M:s:rRV?", op, &lo);

		if (c == -1)
			break;

		switch (c) {
			case OPT_DEVICE:
				device = optarg;
				break;

			case OPT_HELP:
			case '?':
				printf("tape-benchmark (" TAPEBENCHMARK_VERSION ")\n");
				printf("  -d, --device=DEV           : use this device DEV instead of \"" DEFAULT_DEVICE "\"\n");
				printf("  -h, --help                 : show this and quit\n");
				convert_size(buffer_size, 16, MAX_BUFFER_SIZE);
				printf("  -M, --max-buffer-size=SIZE : maximum buffer size (instead of %s)\n", buffer_size);
				convert_size(buffer_size, 16, MIN_BUFFER_SIZE);
				printf("  -m, --min-buffer-size=SIZE : minimum buffer size (instead of %s)\n", buffer_size);
				convert_size(buffer_size, 16, DEFAULT_SIZE);
				printf("  -s, --size=SIZE            : size of file (default: %s)\n", buffer_size);
				printf("  -r, --no-rewind            : no rewind tape between step (default: rewind between step)\n");
				printf("  -R, --rewind-at-start      : rewind tape before writing on tape, (default: no rewind at start)\n\n");

				printf("SIZE can be specified with (BKGT)\n");
				printf("  1B => 1 byte, 1K => 1024B, 1M => 1024K, 1G => 1024M, 1T => 1024G\n");
				printf("Another way to set the size is by specifying an integer which will be interpreted as a power of two.\n");
				printf("  10 => 2^10 bytes (= 1K), 16 => 2^16 bytes (= 64K), 24 => 2^24 bytes (= 16M), and so on\n");
				printf("Constraint: min-buffer-size and max-buffer-size should be a power of two\n\n");

				printf("Note: this programme will allocate 32 buffers of max-buffer-size\n");

				return 0;

			case OPT_MAX_BUFFER:
				tmp_size = parse_size(optarg);
				if (check_size(tmp_size)) {
					max_buffer_size = tmp_size;
				} else {
					printf("Error: max-buffer-size should be a power of two\n");
					return 1;
				}
				break;

			case OPT_MIN_BUFFER:
				tmp_size = parse_size(optarg);
				if (check_size(tmp_size)) {
					min_buffer_size = tmp_size;
				} else {
					printf("Error: min-buffer-size should be a power of two\n");
					return 1;
				}
				break;

			case OPT_NO_REWIND:
				no_rewind = true;
				break;

			case OPT_SIZE:
				size = parse_size(optarg);
				break;

			case OPT_REWIND:
				rewind = true;
				break;

			case OPT_VERSION:
				printf("tape-benchmark (" TAPEBENCHMARK_VERSION ", date and time : " __DATE__ " " __TIME__ ")\n");
				printf("checksum of source code: " TAPEBENCHMARK_SRCSUM "\n");
				printf("git commit: " TAPEBENCHMARK_GIT_COMMIT "\n");
				return 0;
		}
	}

	print_time();
	print_flush("Openning \"%s\"... ", device);
	int fd_tape = open(device, O_RDONLY);
	if (fd_tape < 0) {
		printf("failed!!!, because %m\n");
		return 2;
	}

	struct mtget mt;
	int failed = ioctl(fd_tape, MTIOCGET, &mt);
	if (failed != 0) {
		close(fd_tape);
		printf("Oops: seem not to be a valid tape device\n");
		return 2;
	}

	if (GMT_WR_PROT(mt.mt_gstat)) {
		close(fd_tape);
		printf("Oops: Write lock enabled\n");
		return 2;
	}

	failed = close(fd_tape);

	fd_tape = open(device, O_WRONLY);
	if (fd_tape < 0) {
		printf("failed!!!, because %m\n");
		return 2;
	} else {
		printf("fd: %d\n", fd_tape);
	}

	if (rewind && !rewind_tape(fd_tape))
		return 2;

	ssize_t current_block_size = (mt.mt_dsreg & MT_ST_BLKSIZE_MASK) >> MT_ST_BLKSIZE_SHIFT;

	print_time();
	print_flush("Generate random data from \"/dev/urandom\"... ");
	int fd_ran = open("/dev/urandom", O_RDONLY);
	if (fd_ran < 0) {
		printf("Failed to open because %m\n");
		close(fd_tape);
		return 2;
	}

	int j;
	for (j = 0; j < 32; j++) {
		buffer[j] = malloc(max_buffer_size);
		if (buffer[j] == NULL) {
			printf("Error: failed to allocated memory (size: %zd) because %m\n", max_buffer_size);
			close(fd_tape);
			close(fd_ran);
			return 3;
		}

		ssize_t nb_read = read(fd_ran, buffer[j], max_buffer_size);
		if (nb_read < 0)
			printf("\nWarning: failed to read from \"/dev/urandom\" because %m\n");
		else if (nb_read < max_buffer_size)
			printf("\nWarning: read less than expected, %zd instead of %zd\n", nb_read, max_buffer_size);
	}
	close(fd_ran);
	printf("done\n");

	static char clean_line[64];
	memset(clean_line, ' ', 64);

	ssize_t write_size;
	for (write_size = min_buffer_size; write_size <= max_buffer_size; write_size <<= 1) {
		if (current_block_size > 0) {
			write_size = current_block_size;
			printf("Warning: block size is defined to %zd instead of %zd\n", current_block_size, write_size);
		}

		struct pollfd plfd = { fd_tape, POLLOUT, 0 };

		int pll_rslt = poll(&plfd, 1, 100);
		int poll_retry = 0;

		while (pll_rslt < 1) {
			if (poll_retry == 0)
				printf("Device is no ready, so we wait until");
			else
				printf(".");
			fflush(stdout);
			poll_retry++;

			pll_rslt = poll(&plfd, 1, 6000);

			if (pll_rslt > 0)
				printf("\n");
		}

		struct timeval time_start;
		gettimeofday(&time_start, NULL);

		ssize_t nb_loop = size / write_size;
		convert_size(buffer_size, 16, write_size);

		print_time();
		printf("Starting, nb loop: %zd, block size: %s\n", nb_loop, buffer_size);

		struct timespec start, last, current;
		clock_gettime(CLOCK_MONOTONIC, &start);
		last = start;

		int write_error = 0;
		long long int i;
		static int last_width = 64;
		for (i = 0; i < nb_loop; i++) {
			ssize_t nb_write = write(fd_tape, buffer[i & 0x1F], write_size);
			if (nb_write < 0) {
				if (last_width > 0)
					printf("\r%*s\r", last_width, clean_line);

				switch (errno) {
					case EINVAL:
						convert_size(buffer_size, 16, write_size >> 1);
						printf("It seems that you cannot use a block size greater than %s\n", buffer_size);
						break;

					case EBUSY:
						printf("rDevice is busy, so we wait a few seconds before restarting\n");
						sleep(8);

						print_time();
						printf("Restarting, nb loop: %zd, block size: %s\n", nb_loop, buffer_size);
						i = -1;

						clock_gettime(CLOCK_MONOTONIC, &start);
						break;

					default:
						printf("Oops: an error occured => (%d) %m\n", errno);
						printf("fd: %d, buffer: %p, count: %zd\n", fd_tape, buffer[i & 0x1F], write_size);
						break;
				}
				write_error = 1;
				break;
			}

			clock_gettime(CLOCK_MONOTONIC, &current);

			if (last.tv_sec + 5 <= current.tv_sec) {
				float pct = 100 * i;
				double time_spent = difftime(current.tv_sec, start.tv_sec);
				double speed = i * write_size;
				speed /= time_spent;
				convert_size(buffer_size, 16, speed);

				printf("\r%*s\r", last_width, clean_line);
				printf("loop: %lld, current speed %s, done: %.2f%%%n", i, buffer_size, pct / nb_loop, &last_width);
				fflush(stdout);

				last = current;
			}
		}

		printf("\r%*s\r", last_width, clean_line);

		struct timeval end;
		gettimeofday(&end, 0);

		clock_gettime(CLOCK_MONOTONIC, &current);

		double time_spent = difftime(current.tv_sec, start.tv_sec);
		double speed = i * write_size;
		speed /= time_spent;
		convert_size(buffer_size, 16, speed);

		print_time();
		printf("Finished, current speed %s\n", buffer_size);

		struct mtget mt2;
		failed = ioctl(fd_tape, MTIOCGET, &mt2);
		if (failed != 0) {
			printf("MTIOCGET failed => %m\n");
			break;
		}

		struct mtop eof = { MTWEOF, 1 };
		failed = ioctl(fd_tape, MTIOCTOP, &eof);
		if (failed != 0) {
			printf("Weof failed => %m\n");
			break;
		}

		struct mtop nop = { MTNOP, 1 };
		failed = ioctl(fd_tape, MTIOCTOP, &nop);
		if (failed != 0) {
			printf("Nop failed => %m\n");
			break;
		}

		failed = ioctl(fd_tape, MTIOCGET, &mt2);
		if (failed != 0) {
			printf("MTIOCGET failed => %m\n");
			break;
		}

		if (!no_rewind) {
			if (mt.mt_fileno < 2) {
				rewind_tape(fd_tape);
			} else {
				print_time();
				print_flush("Moving backward space 1 file... ");

				static struct mtop rewind = { MTBSFM, 2 };
				failed = ioctl(fd_tape, MTIOCTOP, &rewind);
				if (failed != 0)
					printf("Failed => %m\n");
				else
					printf("done\n");
			}
		}

		failed = ioctl(fd_tape, MTIOCGET, &mt2);
		if (failed)
			printf("MTIOCGET failed => %m\n");

		if (current_block_size > 0 || write_error)
			break;
	}

	close(fd_tape);

	for (j = 0; j < 32; j++)
		free(buffer[j]);

	return 0;
}