int main(int argc, char * argv[]) { int sg_fd, res, c; int do_origin = 0; int do_set = 0; int do_srep = 0; int do_raw = 0; int readonly = 0; bool secs_given = false; int verbose = 0; uint64_t secs = 0; uint64_t msecs = 0; int64_t ll; const char * device_name = NULL; const char * cmd_name; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hm:orRs:SvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': usage(); return 0; case 'm': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument to '--milliseconds=MS'\n"); return SG_LIB_SYNTAX_ERROR; } msecs = (uint64_t)ll; ++do_set; break; case 'o': ++do_origin; break; case 'r': ++do_raw; break; case 'R': ++readonly; break; case 's': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument to '--seconds=SEC'\n"); return SG_LIB_SYNTAX_ERROR; } secs = (uint64_t)ll; ++do_set; secs_given = true; break; case 'S': ++do_srep; break; case 'v': ++verbose; break; case 'V': pr2serr("version: %s\n", version_str); return 0; default: pr2serr("unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { device_name = argv[optind]; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } if (do_set > 1) { pr2serr("either --milliseconds=MS or --seconds=SEC may be given, " "not both\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, readonly, verbose); if (sg_fd < 0) { pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } memset(d_buff, 0, 12); if (do_set) { cmd_name = "Set timestamp"; sg_put_unaligned_be48(secs_given ? (secs * 1000) : msecs, d_buff + 4); res = sg_ll_set_timestamp(sg_fd, d_buff, 12, 1, verbose); } else { cmd_name = "Report timestamp"; res = sg_ll_rep_timestamp(sg_fd, d_buff, 12, NULL, 1, verbose); if (0 == res) { if (do_raw) dStrRaw((const char *)d_buff, 12); else { int len = sg_get_unaligned_be16(d_buff + 0); if (len < 8) pr2serr("timestamp parameter data length too short, " "expect >= 10, got %d\n", len + 2); else { if (do_origin) printf("Device clock %s\n", ts_origin_arr[0x7 & d_buff[2]]); msecs = sg_get_unaligned_be48(d_buff + 4); printf("%" PRIu64 "\n", do_srep ? (msecs / 1000) : msecs); } } } } ret = res; if (res) { if (SG_LIB_CAT_INVALID_OP == res) pr2serr("%s command not supported\n", cmd_name); else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("%s command: %s\n", cmd_name, b); } } res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
static void helper_full_attr(const unsigned char * alp, int len, int id, const struct attr_name_info_t * anip, const struct opts_t * op) { int k; const unsigned char * bp; if (op->verbose) printf("[r%c] ", (0x80 & alp[2]) ? 'o' : 'w'); if (op->verbose > 3) pr2serr("%s: id=0x%x, len=%d, anip->format=%d, anip->len=%d\n", __func__, id, len, anip->format, anip->len); switch (id) { case 0x224: /* logical position of first encrypted block */ k = all_ffs_or_last_fe(alp + 5, len - 5); if (1 == k) printf("<unknown> [ff]\n"); else if (2 == k) printf("<unknown [fe]>\n"); else { if ((len - 5) <= 8) printf("%" PRIx64, sg_get_unaligned_be(len - 5, alp + 5)); else { printf("\n"); dStrHex((const char *)(alp + 5), len - 5, 0); } } break; case 0x225: /* logical position of first unencrypted block * after first encrypted block */ k = all_ffs_or_last_fe(alp + 5, len - 5); if (1 == k) printf("<unknown> [ff]\n"); else if (2 == k) printf("<unknown [fe]>\n"); else { if ((len - 5) <= 8) printf("%" PRIx64, sg_get_unaligned_be(len - 5, alp + 5)); else { printf("\n"); dStrHex((const char *)(alp + 5), len - 5, 0); } } break; case 0x340: /* Medium Usage history */ bp = alp + 5; printf("\n"); if ((len - 5) < 90) { pr2serr("%s: expected 90 bytes, got %d\n", __func__, len - 5); break; } printf(" Current amount of data written [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 0)); printf(" Current write retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 6)); printf(" Current amount of data read [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 12)); printf(" Current read retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 18)); printf(" Previous amount of data written [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 24)); printf(" Previous write retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 30)); printf(" Previous amount of data read [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 36)); printf(" Previous read retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 42)); printf(" Total amount of data written [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 48)); printf(" Total write retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 54)); printf(" Total amount of data read [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 60)); printf(" Total read retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 66)); printf(" Load count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 72)); printf(" Total change partition count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 78)); printf(" Total partition initialization count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 84)); break; case 0x341: /* Partition Usage history */ bp = alp + 5; printf("\n"); if ((len - 5) < 60) { pr2serr("%s: expected 60 bytes, got %d\n", __func__, len - 5); break; } printf(" Current amount of data written [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 0)); printf(" Current write retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 4)); printf(" Current amount of data read [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 8)); printf(" Current read retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 12)); printf(" Previous amount of data written [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 16)); printf(" Previous write retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 20)); printf(" Previous amount of data read [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 24)); printf(" Previous read retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 28)); printf(" Total amount of data written [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 32)); printf(" Total write retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 36)); printf(" Total amount of data read [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 40)); printf(" Total read retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 44)); printf(" Load count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 48)); printf(" change partition count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 52)); printf(" partition initialization count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 56)); break; default: pr2serr("%s: unknown attribute id: 0x%x\n", __func__, id); printf(" In hex:\n"); dStrHex((const char *)alp, len, 0); break; } }