/* * will get the mode page only i.e. will strip off the header. */ int get_mode_page(int fd, int page_no, int pc, int buf_len, uchar_t *buffer) { int ret; uchar_t byte2, *buf; uint_t header_len, page_len, copy_cnt; byte2 = (uchar_t)(((pc << 6) & 0xC0) | (page_no & 0x3f)); buf = (uchar_t *)my_zalloc(256); /* Ask 254 bytes only to make our IDE driver happy */ ret = mode_sense(fd, byte2, 1, 254, buf); if (ret == 0) { free(buf); return (0); } header_len = 8 + read_scsi16(&buf[6]); page_len = buf[header_len + 1] + 2; copy_cnt = (page_len > buf_len) ? buf_len : page_len; (void) memcpy(buffer, &buf[header_len], copy_cnt); free(buf); return (1); }
bstreamhandle open_file_read_stream(char *file) { bstreamhandle h; int fd; struct stat st; str_errno = 0; if (stat(file, &st) < 0) return (NULL); if ((st.st_mode & S_IFMT) == S_IFDIR) { str_errno = STR_ERR_NO_REG_FILE; return (NULL); } fd = open(file, O_RDONLY); if (fd < 0) return (NULL); h = (bstreamhandle)my_zalloc(sizeof (*h)); h->bstr_fd = fd; h->bstr_read = file_stream_read; h->bstr_close = file_stream_close; h->bstr_size = file_stream_size; h->bstr_rewind = file_stream_rewind; return (h); }
/* * Find out media capacity. */ uint32_t get_last_possible_lba(cd_device *dev) { uchar_t *di; uint32_t cap; di = (uchar_t *)my_zalloc(DISC_INFO_BLOCK_SIZE); if (!read_disc_info(dev->d_fd, di)) { free(di); return (0); } /* * If we have a DVD+R this field is an LBA. If the media is * a CD-R/W the field is MSF formatted. Otherwise this field * is not valid and will be zero. */ if (device_type == DVD_PLUS) { if (read_scsi32(&di[20]) != 0xffffffff) { cap = read_scsi32(&di[20]); } else { cap = 0; } } else { if ((di[21] != 0) && (di[21] != 0xff)) { cap = MSF2LBA(di[21], di[22], di[23]); } else { cap = 0; } } free(di); return (cap); }
bstreamhandle open_stdin_read_stream(void) { bstreamhandle h; int mode; str_errno = 0; if ((mode = fcntl(0, F_GETFD, NULL)) < 0) { str_errno = STR_ERR_NO_READ_STDIN; return (NULL); } mode &= 3; if ((mode != O_RDONLY) && (mode != O_RDWR)) { str_errno = STR_ERR_NO_READ_STDIN; return (NULL); } h = (bstreamhandle)my_zalloc(sizeof (*h)); h->bstr_fd = 0; h->bstr_read = file_stream_read; h->bstr_close = stdin_stream_close; h->bstr_size = file_stream_size; h->bstr_rewind = stdin_stream_rewind; return (h); }
char * get_tmp_name(void) { char *t; char *envptr; t = (char *)my_zalloc(PATH_MAX); /* * generate temp directory path based on this order: * user specified (-m option), temp env variable, * and finally /tmp if nothing is found. */ if (alt_tmp_dir) { /* copy and leave room for temp filename */ (void) strlcpy(t, alt_tmp_dir, PATH_MAX - 10); } else { envptr = getenv("TMPDIR"); if (envptr != NULL) { (void) strlcpy(t, envptr, PATH_MAX - 10); } else { (void) strlcpy(t, "/tmp", 5); } } /* * no need to check if path is valid. statvfs will catch * it later and fail with a proper error message. */ return (t); }
bstreamhandle open_temp_file_stream(void) { bstreamhandle h; char *t; int fd; str_errno = 0; t = (char *)get_tmp_name(); if (strlcat(t, "/cdXXXXXX", PATH_MAX) >= PATH_MAX) return (NULL); fd = mkstemp(t); if (debug) (void) printf("temp is: %s length: %d\n", t, strlen(t)); if (fd < 0) return (NULL); (void) unlink(t); h = (bstreamhandle)my_zalloc(sizeof (*h)); h->bstr_fd = fd; h->bstr_read = file_stream_read; h->bstr_write = file_stream_write; h->bstr_close = file_stream_close; h->bstr_size = file_stream_size; h->bstr_rewind = file_stream_rewind; return (h); }
bstreamhandle open_wav_write_stream(char *fname) { bstreamhandle h; int esav, fd; uchar_t head[] = PRE_DEF_WAV_HDR; str_errno = 0; fd = -1; fd = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666); if (fd < 0) goto open_wav_write_stream_failed; if (write(fd, head, PRE_DEF_WAV_HDR_LEN) != PRE_DEF_WAV_HDR_LEN) { goto open_wav_write_stream_failed; } h = (bstreamhandle)my_zalloc(sizeof (*h)); h->bstr_fd = fd; h->bstr_write = file_stream_write; h->bstr_close = wav_write_stream_close; return (h); open_wav_write_stream_failed: esav = errno; if (fd != -1) (void) close(fd); errno = esav; return (NULL); }
/* * Manage sending of SET STREAMING command using the specified * read_speed and write_speed. * * This function allocates and initializes a Performance * Descriptor, which is sent as part of the SET STREAMING * command. The descriptor is deallocated before function * exit. */ static int do_set_streaming(cd_device *dev, uint_t read_speed, uint_t write_speed) { int ret; uchar_t *str; /* Allocate and initialize the Performance Descriptor */ str = (uchar_t *)my_zalloc(SET_STREAM_DATA_LEN); /* Read Time (in milliseconds) */ load_scsi32(&str[16], 1000); /* Write Time (in milliseconds) */ load_scsi32(&str[24], 1000); /* Read Speed */ load_scsi32(&str[12], (uint32_t)read_speed); /* Write Speed */ load_scsi32(&str[20], (uint32_t)write_speed); /* issue SET STREAMING command */ ret = set_streaming(dev->d_fd, str); free(str); return (ret); }
/* * will take care of adding mode header and any extra bytes at the end. */ int set_mode_page(int fd, uchar_t *buffer) { int ret; uchar_t *buf; uint_t total, p_len; p_len = buffer[1] + 2; total = p_len + 8; buf = (uchar_t *)my_zalloc(total); (void) memcpy(&buf[8], buffer, p_len); if (debug) { int i; (void) printf("MODE: ["); for (i = 0; i < p_len; i++) { (void) printf("0x%02x ", (uchar_t)buffer[i]); } (void) printf("]\n"); } ret = mode_select(fd, total, buf); free(buf); return (ret); }
uchar_t get_data_mode(int fd, uint32_t lba) { int ret; uchar_t *buf; uchar_t mode; buf = (uchar_t *)my_zalloc(8); ret = read_header(fd, lba, buf); if (ret == 0) mode = 0xff; else mode = buf[0]; free(buf); return (mode); }
bstreamhandle open_file_write_stream(char *fname) { bstreamhandle h; int fd; str_errno = 0; fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666); if (fd < 0) return (NULL); h = (bstreamhandle)my_zalloc(sizeof (*h)); h->bstr_fd = fd; h->bstr_write = file_stream_write; h->bstr_close = file_stream_close; return (h); }
/* * Find out media capacity. */ int get_last_possible_lba(cd_device *dev) { uchar_t *di; int cap; di = (uchar_t *)my_zalloc(DISC_INFO_BLOCK_SIZE); if (!read_disc_info(dev->d_fd, di)) { free(di); return (0); } if ((di[21] != 0) && (di[21] != 0xff)) { cap = ((di[21] * 60) + di[22]) * 75; } else { cap = 0; } free(di); return (cap); }
/* * Get current Read or Write Speed from Mode Page 0x2a. * * Use the size of the Page to determine which Multimedia Command * set (MMC) is present. Based on the MMC version, get the * specified Read/Write Speed. * * Note that some MMC versions do not necessarily support a * (current) Read or Write Speed. As a result, this function * _can_ return a value of zero. * * The newer standards (reserve and) mark the field(s) as Obsolete, * yet many vendors populate the Obsolete fields with valid values * (assumedly for backward compatibility). This is important, as * a command like GET PERFORMANCE cannot return _the_ speed; it can * only return a Logical-Block-Address-dependent (LBA) speed. Such * values can vary widely between the innermost and outermost Track. * Mode Page 0x2a is the best solution identifying "the current * (nominal) speed". */ static uint16_t cd_speed_get(cd_device *dev, int cmd) { uchar_t *mp2a; uint16_t rate = 0; int offset; uint_t buflen = 254; /* * Allocate a buffer acceptably larger than any nominal * Page for Page Code 0x2A. */ mp2a = (uchar_t *)my_zalloc(buflen); if (get_mode_page(dev->d_fd, 0x2A, 0, buflen, mp2a) == 0) goto end; /* Determine MMC version based on 'Page Length' field */ switch (mp2a[1]) { case 0x14: /* MMC-1 */ if (debug) (void) printf("Mode Page 2A: MMC-1\n"); offset = (cmd == GET_READ_SPEED) ? 14 : 20; rate = read_scsi16(&mp2a[offset]); break; case 0x18: /* MMC-2 */ if (debug) (void) printf("Mode Page 2A: MMC-2;" " Read and Write Speeds are " "obsolete\n"); /* see if "Obsolete" values are valid: */ offset = (cmd == GET_READ_SPEED) ? 14 : 20; rate = read_scsi16(&mp2a[offset]); break; default: /* MMC-3 or newer */ if (debug) (void) printf("Mode Page 2A: MMC-3 or" " newer; Read Speed is obsolete.\n"); if (cmd == GET_READ_SPEED) { /* this is Obsolete, but try it */ offset = 14; rate = read_scsi16(&mp2a[offset]); } else { /* Write Speed is not obsolete */ offset = 28; rate = read_scsi16(&mp2a[offset]); if (rate == 0) { /* * then try an Obsolete field * (but this shouldn't happen!) */ offset = 20; rate = read_scsi16(&mp2a[offset]); } } break; } end: free(mp2a); if (debug) (void) printf("cd_speed_get: %s Speed is " "%uX\n", (cmd == GET_READ_SPEED) ? "Read" : "Write", cdrw_bandwidth_to_x(rate)); return (rate); }
/* * Close session. This will write TOC. */ int finalize(cd_device *dev) { uchar_t *di; int count, ret, err; int immediate; int finalize_max; /* * For ATAPI devices we will use the immediate mode and will * poll the command for completion so that this command may * not hog the channel. But for SCSI, we will use the treditional * way of issuing the command with a large enough timeout. This * is done because immediate mode was designed for ATAPI and some * SCSI RW drives might not be even tested with it. */ if ((dev->d_inq[2] & 7) != 0) { /* SCSI device */ immediate = 0; } else { /* non-SCSI (e.g ATAPI) device */ immediate = 1; } /* We need to close track before close session */ if (device_type == DVD_PLUS) { if (!close_track(dev->d_fd, 0, 0, immediate)) return (0); } if (!close_track(dev->d_fd, 0, 1, immediate)) { /* * For DAO mode which we use for DVD-RW, the latest MMC * specification does not mention close_track. Some * newer drives will return an ILLEGAL INSTRUCTION * which we will ignore. We have also found a Panasonic * drive which will return a MEDIA ERROR. It is safe * to ignore both errors as this is not needed for * these drives. * This is kept for older drives which had needed * us to issue close_track to flush the cache fully. * once we are certain these drives have cleared the * market, this can be removed. */ if (device_type == DVD_MINUS) { return (0); } } else { if (!immediate) return (1); } if (immediate) { (void) sleep(10); di = (uchar_t *)my_zalloc(DISC_INFO_BLOCK_SIZE); err = 0; if (device_type == CD_RW) { /* Finalization should not take more than 6 minutes */ finalize_max = FINALIZE_TIMEOUT; } else { /* some DVD-RW drives take longer than 6 minutes */ finalize_max = FINALIZE_TIMEOUT*2; } for (count = 0; count < finalize_max; count++) { ret = read_disc_info(dev->d_fd, di); if (ret != 0) break; if (uscsi_status != 2) err = 1; if (SENSE_KEY(rqbuf) == 2) { /* not ready but not becoming ready */ if (ASC(rqbuf) != 4) err = 1; } else if (SENSE_KEY(rqbuf) == 5) { /* illegal mode for this track */ if (ASC(rqbuf) != 0x64) err = 1; } else { err = 1; } if (err == 1) { if (debug) { (void) printf("Finalization failed\n"); (void) printf("%x %x %x %x\n", uscsi_status, SENSE_KEY(rqbuf), ASC(rqbuf), ASCQ(rqbuf)); } free(di); return (0); } if (uscsi_status == 2) { int i; /* illegal field in command packet */ if (ASC(rqbuf) == 0x24) { /* print it out! */ (void) printf("\n"); for (i = 0; i < 18; i++) (void) printf("%x ", (unsigned)(rqbuf[i])); (void) printf("\n"); } } (void) sleep(5); } free(di); } return (ret); }
/* * Set page code 5 for TAO mode. */ int prepare_for_write(cd_device *dev, int track_mode, int test_write, int keep_disc_open) { uchar_t *buf; int no_err; int reset_device; if ((write_mode == DAO_MODE) && keep_disc_open) { (void) printf(gettext( "Multi-session is not supported on DVD media\n")); exit(1); } if ((write_mode == DAO_MODE) && debug) { (void) printf("Preparing to write in DAO\n"); } (void) start_stop(dev->d_fd, 1); /* Some drives do not support this command but still do it */ (void) rezero_unit(dev->d_fd); buf = (uchar_t *)my_zalloc(64); no_err = get_mode_page(dev->d_fd, 5, 0, 64, buf); if (no_err) no_err = ((buf[1] + 2) > 64) ? 0 : 1; /* * If the device is already in simulation mode and again a * simulation is requested, then set the device in non-simulation * 1st and then take it to simulation mode. This will flush any * previous fake state in the drive. */ if (no_err && test_write && (buf[2] & 0x10)) { reset_device = 1; } else { reset_device = 0; } if (no_err != 0) { buf[0] &= 0x3f; /* set TAO or DAO writing mode */ buf[2] = (write_mode == TAO_MODE)?1:2; /* set simulation flag */ if (test_write && (!reset_device)) { buf[2] |= 0x10; } else { buf[2] &= ~0x10; } /* Turn on HW buffer underrun protection (BUFE) */ if (!test_write) { buf[2] |= 0x40; } /* set track mode type */ if (device_type == CD_RW) { buf[3] = track_mode & 0x0f; /* ctrl nibble */ } else { buf[3] = 5; /* always 5 for DVD */ } if (keep_disc_open) { buf[3] |= 0xc0; /* Allow more sessions */ } /* Select track type (audio or data) */ if (track_mode == TRACK_MODE_DATA) { buf[4] = 8; /* 2048 byte sector */ } else { buf[4] = 0; /* 2352 byte sector */ } buf[7] = buf[8] = 0; /* Need to clear these fields for setting into DAO */ if (write_mode == DAO_MODE) buf[5] = buf[15] = 0; /* print out mode for detailed log */ if (debug && verbose) { int i; (void) printf("setting = [ "); for (i = 0; i < 15; i++) (void) printf("0x%x ", buf[i]); (void) printf("]\n"); } no_err = set_mode_page(dev->d_fd, buf); if (no_err && reset_device) { /* Turn the test write bit back on */ buf[2] |= 0x10; no_err = set_mode_page(dev->d_fd, buf); } /* * Since BUFE is the only optional flag we are * setting we will try to turn it off if the command * fails. */ if (!no_err) { /* * Some old drives may not support HW * buffer underrun protection, try again * after turning it off. */ if (debug) (void) printf("Turning off BUFE\n"); buf[2] &= ~0x40; no_err = set_mode_page(dev->d_fd, buf); } } free(buf); return (no_err); }
/* * Builds track information database for track trackno. If trackno is * -1, builds the database for next blank track. */ int build_track_info(cd_device *dev, int trackno, struct track_info *t_info) { uchar_t *ti; uchar_t toc[20]; /* 2 entries + 4 byte header */ int ret; (void) memset(t_info, 0, sizeof (*t_info)); /* 1st try READ TRACK INFORMATION */ ti = (uchar_t *)my_zalloc(TRACK_INFO_SIZE); t_info->ti_track_no = trackno; /* Gererate faked information for writing to DVD */ if (device_type != CD_RW) { uint_t bsize; t_info->ti_flags = 0x3000; t_info->ti_track_no = 1; t_info->ti_session_no = 1; t_info->ti_track_mode = 0x4; t_info->ti_data_mode = 1; t_info->ti_start_address = 0; /* only 1 track on DVD make it max size */ t_info->ti_track_size = read_format_capacity(target->d_fd, &bsize); if (t_info->ti_track_size < MAX_CD_BLKS) { t_info->ti_track_size = MAX_DVD_BLKS; } t_info->ti_nwa = 0; t_info->ti_lra = 0; t_info->ti_packet_size = 0x10; t_info->ti_free_blocks = 0; } if (read_track_info(dev->d_fd, trackno, ti)) { if (debug) (void) printf("using read_track_info for TOC \n"); t_info->ti_track_no = ti[2]; t_info->ti_session_no = ti[3]; t_info->ti_flags = (ti[6] >> 4) & 0xf; t_info->ti_flags |= (uint32_t)(ti[5] & 0xf0); t_info->ti_flags |= (uint32_t)(ti[7]) << 8; t_info->ti_flags |= TI_SESSION_NO_VALID | TI_FREE_BLOCKS_VALID; t_info->ti_track_mode = ti[5] & 0xf; if ((ti[6] & 0xf) == 0xf) t_info->ti_data_mode = 0xff; else t_info->ti_data_mode = ti[6] & 0xf; t_info->ti_start_address = read_scsi32(&ti[8]); t_info->ti_nwa = read_scsi32(&ti[12]); t_info->ti_free_blocks = read_scsi32(&ti[16]); t_info->ti_packet_size = read_scsi32(&ti[20]); t_info->ti_track_size = read_scsi32(&ti[24]); t_info->ti_lra = read_scsi32(&ti[28]); free(ti); return (1); } /* READ TRACK INFORMATION not supported, try other options */ free(ti); /* * We can get info for next blank track if READ TRACK INFO is not * supported. */ if (trackno == -1) return (0); if (debug) (void) printf("using READ_TOC for TOC\n"); /* Try Read TOC */ if (!read_toc(dev->d_fd, 0, trackno, 20, toc)) { return (0); } t_info->ti_start_address = read_scsi32(&toc[8]); t_info->ti_track_mode = toc[5] & 0xf; t_info->ti_track_size = read_scsi32(&toc[16]) - read_scsi32(&toc[8]); t_info->ti_data_mode = get_data_mode(dev->d_fd, read_scsi32(&toc[8])); /* Numbers for audio tracks are always in 2K chunks */ if ((dev->d_blksize == 512) && ((t_info->ti_track_mode & 4) == 0)) { t_info->ti_start_address /= 4; t_info->ti_track_size /= 4; } /* Now find out the session thing */ ret = read_toc(dev->d_fd, 1, trackno, 12, toc); /* * Make sure that the call succeeds and returns the requested * TOC size correctly. */ if ((ret == 0) || (toc[1] != 0x0a)) { /* For ATAPI drives or old Toshiba drives */ ret = read_toc_as_per_8020(dev->d_fd, 1, trackno, 12, toc); } /* If this goes through well TOC length will always be 0x0a */ if (ret && (toc[1] == 0x0a)) { if (trackno >= toc[6]) { t_info->ti_session_no = toc[3]; t_info->ti_flags |= TI_SESSION_NO_VALID; } /* * This might be the last track of this session. If so, * exclude the leadout and next lead in. */ if (trackno == (toc[6] - 1)) { /* * 1.5 Min leadout + 1 min. leadin + 2 sec. pre-gap. * For 2nd+ leadout it will be 0.5 min. But currently * there is no direct way. And it will not happen * for any normal case. * * 75 frames/sec, 60 sec/min, so leadin gap is * ((1.5 +1)*60 + 2)*75 = 11400 frames (blocks) */ t_info->ti_track_size -= 11400; } } return (1); }
bstreamhandle open_wav_read_stream(char *fname) { bstreamhandle h; int fd, sav; Wave_filehdr *wav; struct stat st; uint32_t data_size; wav = NULL; str_errno = 0; fd = open(fname, O_RDONLY); if (fd < 0) return (NULL); if (fstat(fd, &st) < 0) { goto wav_open_failed; } if ((st.st_mode & S_IFMT) != S_IFREG) { str_errno = STR_ERR_NO_REG_FILE; goto wav_open_failed; } wav = (Wave_filehdr *)my_zalloc(sizeof (*wav)); if (read(fd, wav, sizeof (*wav)) != sizeof (*wav)) { str_errno = STR_ERR_WAV_READ_ERR; goto wav_open_failed; } if ((strncmp(wav->riff, "RIFF", 4) != 0) || (strncmp(wav->wave, "WAVE", 4) != 0)) { str_errno = STR_ERR_WAV_BAD_HEADER; goto wav_open_failed; } if (((CPU_TO_LE32(wav->total_chunk_size) + 8) != st.st_size) || (strncmp(wav->fmt, "fmt ", 4) != 0) || (CPU_TO_LE16(wav->fmt_tag) != 1) || (CPU_TO_LE16(wav->n_channels) != 2) || (CPU_TO_LE32(wav->sample_rate) != 44100) || (CPU_TO_LE16(wav->bits_per_sample) != 16) || (strncmp(wav->data, "data", 4) != 0) || ((CPU_TO_LE32(wav->data_size) + 44) != st.st_size)) { str_errno = STR_ERR_WAV_UNSUPPORTED_FORMAT; goto wav_open_failed; } data_size = CPU_TO_LE32(wav->data_size); if (lseek(fd, sizeof (*wav), SEEK_SET) < 0) { goto wav_open_failed; } free(wav); h = (bstreamhandle)my_zalloc(sizeof (*h)); h->bstr_fd = fd; h->bstr_read = file_stream_read; h->bstr_close = file_stream_close; h->bstr_size = audio_stream_size; h->bstr_rewind = wav_stream_rewind; h->bstr_private = (void *)data_size; return (h); wav_open_failed: sav = errno; (void) close(fd); if (wav != NULL) free(wav); errno = sav; return (NULL); }
/* * The size of the last track in one of the first N - 1 sessions of an * N-session (N > 1) disc is reported incorrectly by some drives and calculated * incorrectly for others, because a pre-gap/lead-out/lead-in section that ends * a session is erroneously considered part of that track. This function checks * for this corner case, and adjusts the track size if necessary. */ static int check_track_size(cd_device *dev, int trk_num, struct track_info *tip) { size_t raw_toc_len; uchar_t *raw_toc; rtoc_hdr_t hdr; uint32_t sess_leadout_lba; int sess_last_trk_num; int trk_sess_num; uint32_t trk_size; /* Request Raw TOC Header for session count. */ if (read_toc(dev->d_fd, FORMAT_RAW_TOC, 1, sizeof (rtoc_hdr_t), (uchar_t *)&hdr) != 1) return (0); /* Is this a multi-session medium? */ if (hdr.rh_last_sess_num > hdr.rh_first_sess_num) { /* Yes; request entire Raw TOC. */ raw_toc_len = read_scsi16(&hdr.rh_data_len1) + RTOC_DATA_LEN_SZ; raw_toc = (uchar_t *)my_zalloc(raw_toc_len); if (read_toc(dev->d_fd, FORMAT_RAW_TOC, 1, raw_toc_len, raw_toc) != 1) goto fail; if (rtoc_get_trk_sess_num(raw_toc, raw_toc_len, trk_num, &trk_sess_num) != 1) goto fail; tip->ti_session_no = trk_sess_num; tip->ti_flags |= TI_SESSION_NO_VALID; /* Is the track in one of the first N - 1 sessions? */ if (trk_sess_num < hdr.rh_last_sess_num) { if (rtoc_get_sess_last_trk_num(raw_toc, raw_toc_len, trk_sess_num, &sess_last_trk_num) != 1) goto fail; /* Is the track the last track in the session? */ if (trk_num == sess_last_trk_num) { if (rtoc_get_sess_leadout_lba(raw_toc, raw_toc_len, trk_sess_num, &sess_leadout_lba) != 1) goto fail; trk_size = sess_leadout_lba - tip->ti_start_address; /* Fix track size if it was too big. */ if (tip->ti_track_size > trk_size) tip->ti_track_size = trk_size; } } free(raw_toc); } return (1); fail: free(raw_toc); return (0); }
void info(void) { uchar_t *toc, *p, *conf; int ret, toc_size; uint_t bsize; size_t cap = 0; char *msg; struct track_info *ti; msg = gettext("Cannot read Table of contents\n"); get_media_type(target->d_fd); (void) printf(gettext("\nDevice : %.8s %.16s\n"), &target->d_inq[8], &target->d_inq[16]); (void) printf(gettext("Firmware : Rev. %.4s (%.12s)\n"), &target->d_inq[32], &target->d_inq[36]); if (check_device(target, CHECK_DEVICE_NOT_READY)) { (void) check_device(target, CHECK_NO_MEDIA | EXIT_IF_CHECK_FAILED); (void) check_device(target, CHECK_DEVICE_NOT_READY | EXIT_IF_CHECK_FAILED); } if (verbose != 0) { /* * Determine the media type by reading the active profile * from the profile list. */ (void) printf(gettext("Media Type : ")); conf = (uchar_t *)my_zalloc(MMC_FTR_HDR_LEN); if (get_configuration(target->d_fd, MMC_FTR_PRFL_LIST, MMC_FTR_HDR_LEN, conf)) print_profile_name(read_scsi16(&conf[6]), 0, 1); else (void) printf(gettext("UNKNOWN\n")); free(conf); /* * Get the start address of the last possible lead out. */ cap = get_last_possible_lba(target); /* * The start address of the last possible leadout will only * be zero if the disc is full or this drive does not support * this method of determining capacity. */ if (cap == 0) cap = read_format_capacity(target->d_fd, &bsize); /* * Since both methods of determining the capacity of the * media count the correct number of blocks, just multiply * the capacity by the block size. */ cap *= target->d_blksize; if (device_type == CD_RW) { (void) printf(gettext("Media Capacity : %.2f MB "), ((double)cap/ONE_MB_BASE2)); } else { /* * For DVD's make sure we print out "Formatted Media * Capacity". Don't do this for CD-RWs as only * DVDs are formatted. */ (void) printf(gettext("Formatted Media Capacity : " "%.2f GB "), ((double)cap/ONE_GB_BASE10)); } cap /= target->d_blksize; (void) printf(gettext("(%u blocks)\n"), (uint_t)cap); } if (!check_device(target, CHECK_MEDIA_IS_NOT_BLANK)) { (void) printf(gettext("Media is blank\n")); exit(0); } /* Find out the number of entries in the toc */ toc = (uchar_t *)my_zalloc(12); if (!read_toc(target->d_fd, 0, 1, 4, toc)) { err_msg(msg); } else { toc_size = 256*toc[0] + toc[1] + 2; free(toc); /* allocate enough space for each track entry */ toc = (uchar_t *)my_zalloc(toc_size); if (!read_toc(target->d_fd, 0, 1, toc_size, toc)) { err_msg(msg); exit(1); } (void) printf("\n"); /* l10n_NOTE : Preserve column numbers of '|' character */ (void) printf(gettext("Track No. |Type |Start address\n")); (void) printf("----------+--------+-------------\n"); /* look at each track and display it's type. */ for (p = &toc[4]; p < (toc + toc_size); p += 8) { if (p[2] != 0xAA) (void) printf(" %-3d |", p[2]); else (void) printf("Leadout |"); (void) printf("%s |", (p[1] & 4) ? gettext("Data ") : gettext("Audio")); (void) printf("%u\n", read_scsi32(&p[4])); } } (void) printf("\n"); ret = read_toc(target->d_fd, 1, 0, 12, toc); if ((ret == 0) || (toc[1] != 0x0a)) /* For ATAPI drives or old Toshiba drives */ ret = read_toc_as_per_8020(target->d_fd, 1, 0, 12, toc); if (ret && (toc[1] == 0x0a)) { (void) printf(gettext("Last session start address: %u\n"), read_scsi32(&toc[8])); } free(toc); ti = (struct track_info *)my_zalloc(sizeof (struct track_info)); if (build_track_info(target, -1, ti) && (ti->ti_flags & TI_NWA_VALID)) { (void) printf(gettext("Next writable address: %u\n"), ti->ti_nwa); } free(ti); exit(0); }
bstreamhandle open_au_read_stream(char *fname) { bstreamhandle h; int fd, sav; au_filehdr_t *au; struct stat st; uint32_t data_size; au = NULL; str_errno = 0; fd = open(fname, O_RDONLY); if (fd < 0) return (NULL); if (fstat(fd, &st) < 0) { goto au_open_failed; } if ((st.st_mode & S_IFMT) != S_IFREG) { str_errno = STR_ERR_NO_REG_FILE; goto au_open_failed; } au = (au_filehdr_t *)my_zalloc(sizeof (*au)); if (read(fd, au, sizeof (*au)) != sizeof (*au)) { str_errno = STR_ERR_AU_READ_ERR; goto au_open_failed; } au->au_magic = BE32_TO_CPU(au->au_magic); au->au_offset = BE32_TO_CPU(au->au_offset); au->au_data_size = BE32_TO_CPU(au->au_data_size); au->au_encoding = BE32_TO_CPU(au->au_encoding); au->au_sample_rate = BE32_TO_CPU(au->au_sample_rate); au->au_channels = BE32_TO_CPU(au->au_channels); if (au->au_magic != AUDIO_AU_FILE_MAGIC) { str_errno = STR_ERR_AU_BAD_HEADER; goto au_open_failed; } if ((au->au_encoding != AUDIO_AU_ENCODING_LINEAR_16) || (au->au_sample_rate != 44100) || (au->au_channels != 2)) { str_errno = STR_ERR_AU_UNSUPPORTED_FORMAT; goto au_open_failed; } if (au->au_data_size != AUDIO_AU_UNKNOWN_SIZE) { if ((au->au_offset + au->au_data_size) != st.st_size) { str_errno = STR_ERR_AU_BAD_HEADER; goto au_open_failed; } data_size = au->au_data_size; } else { data_size = st.st_size - au->au_offset; } if (data_size == 0) { str_errno = STR_ERR_AU_UNSUPPORTED_FORMAT; goto au_open_failed; } if (lseek(fd, au->au_offset, SEEK_SET) < 0) { goto au_open_failed; } free(au); h = (bstreamhandle)my_zalloc(sizeof (*h)); h->bstr_fd = fd; h->bstr_read = file_stream_read_wrbo; h->bstr_close = file_stream_close; h->bstr_size = audio_stream_size; h->bstr_rewind = au_stream_rewind; h->bstr_private = (void *)data_size; return (h); au_open_failed: sav = errno; (void) close(fd); if (au != NULL) free(au); errno = sav; return (NULL); }