| /* | |
| * Copyright (c) 2004-2012 Douglas Gilbert. | |
| * All rights reserved. | |
| * Use of this source code is governed by a BSD-style | |
| * license that can be found in the BSD_LICENSE file. | |
| */ | |
| #include <unistd.h> | |
| #include <fcntl.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <getopt.h> | |
| #include "sg_lib.h" | |
| #include "sg_cmds_basic.h" | |
| /* A utility program for the Linux OS SCSI subsystem. | |
| * | |
| * | |
| * This program issues the SCSI command SYNCHRONIZE CACHE(10) to the given | |
| * device. This command is defined for SCSI "direct access" devices | |
| * (e.g. disks). | |
| */ | |
| static char * version_str = "1.09 20120217"; | |
| static struct option long_options[] = { | |
| {"count", 1, 0, 'c'}, | |
| {"group", 1, 0, 'g'}, | |
| {"help", 0, 0, 'h'}, | |
| {"immed", 0, 0, 'i'}, | |
| {"lba", 1, 0, 'l'}, | |
| {"sync-nv", 0, 0, 's'}, | |
| {"verbose", 0, 0, 'v'}, | |
| {"version", 0, 0, 'V'}, | |
| {0, 0, 0, 0}, | |
| }; | |
| static void usage() | |
| { | |
| fprintf(stderr, "Usage: " | |
| "sg_sync [--count=COUNT] [--group=GN] [--help] [--immed]\n" | |
| " [--lba=LBA] [--sync-nv] [--verbose] [--version] " | |
| "DEVICE\n" | |
| " where:\n" | |
| " --count=COUNT|-c COUNT number of blocks to sync (def: 0 " | |
| "which implies\n" | |
| " rest of device)\n" | |
| " --group=GN|-g GN set group number field to GN (def: 0)\n" | |
| " --help|-h print out usage message\n" | |
| " --immed|-i command returns immediately when set " | |
| "else wait\n" | |
| " for 'sync' to complete\n" | |
| " --lba=LBA|-l LBA logical block address to start sync " | |
| "operation\n" | |
| " from (def: 0)\n" | |
| " --sync-nv|-s synchronize to non-volatile storage " | |
| "(if distinct\n" | |
| " from medium)\n" | |
| " --verbose|-v increase verbosity\n" | |
| " --version|-V print version string and exit\n\n" | |
| "Performs a SCSI SYNCHRONIZE CACHE(10) command\n" | |
| ); | |
| } | |
| int main(int argc, char * argv[]) | |
| { | |
| int sg_fd, res, c; | |
| int64_t count = 0; | |
| int group = 0; | |
| int64_t lba = 0; | |
| int immed = 0; | |
| int sync_nv = 0; | |
| int verbose = 0; | |
| const char * device_name = NULL; | |
| int ret = 0; | |
| while (1) { | |
| int option_index = 0; | |
| c = getopt_long(argc, argv, "c:g:hil:svV", long_options, | |
| &option_index); | |
| if (c == -1) | |
| break; | |
| switch (c) { | |
| case 'c': | |
| count = sg_get_llnum(optarg); | |
| if (count < 0) { | |
| fprintf(stderr, "bad argument to '--count'\n"); | |
| return SG_LIB_SYNTAX_ERROR; | |
| } | |
| break; | |
| case 'g': | |
| group = sg_get_num(optarg); | |
| if ((group < 0) || (group > 31)) { | |
| fprintf(stderr, "bad argument to '--group'\n"); | |
| return SG_LIB_SYNTAX_ERROR; | |
| } | |
| break; | |
| case 'h': | |
| case '?': | |
| usage(); | |
| return 0; | |
| case 'i': | |
| immed = 1; | |
| break; | |
| case 'l': | |
| lba = sg_get_llnum(optarg); | |
| if (lba < 0) { | |
| fprintf(stderr, "bad argument to '--lba'\n"); | |
| return SG_LIB_SYNTAX_ERROR; | |
| } | |
| break; | |
| case 's': | |
| sync_nv = 1; | |
| break; | |
| case 'v': | |
| ++verbose; | |
| break; | |
| case 'V': | |
| fprintf(stderr, "version: %s\n", version_str); | |
| return 0; | |
| default: | |
| fprintf(stderr, "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) | |
| fprintf(stderr, "Unexpected extra argument: %s\n", | |
| argv[optind]); | |
| usage(); | |
| return SG_LIB_SYNTAX_ERROR; | |
| } | |
| } | |
| if (NULL == device_name) { | |
| fprintf(stderr, "missing device name!\n"); | |
| usage(); | |
| return SG_LIB_SYNTAX_ERROR; | |
| } | |
| sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose); | |
| if (sg_fd < 0) { | |
| fprintf(stderr, "open error: %s: %s\n", device_name, | |
| safe_strerror(-sg_fd)); | |
| return SG_LIB_FILE_ERROR; | |
| } | |
| res = sg_ll_sync_cache_10(sg_fd, sync_nv, immed, group, | |
| (unsigned int)lba, (unsigned int)count, | |
| 1, verbose); | |
| ret = res; | |
| if (0 == res) | |
| ; | |
| else if (SG_LIB_CAT_NOT_READY == res) | |
| fprintf(stderr, "Synchronize cache failed, device not ready\n"); | |
| else if (SG_LIB_CAT_UNIT_ATTENTION == res) | |
| fprintf(stderr, "Synchronize cache, unit attention\n"); | |
| else if (SG_LIB_CAT_ABORTED_COMMAND == res) | |
| fprintf(stderr, "Synchronize cache, aborted command\n"); | |
| else if (SG_LIB_CAT_INVALID_OP == res) | |
| fprintf(stderr, "Synchronize cache command not supported\n"); | |
| else if (SG_LIB_CAT_ILLEGAL_REQ == res) | |
| fprintf(stderr, "bad field in Synchronize cache command\n"); | |
| else | |
| fprintf(stderr, "Synchronize cache failed\n"); | |
| res = sg_cmds_close_device(sg_fd); | |
| if (res < 0) { | |
| fprintf(stderr, "close error: %s\n", safe_strerror(-res)); | |
| if (0 == ret) | |
| return SG_LIB_FILE_ERROR; | |
| } | |
| return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; | |
| } |