-
-
Save sjorge/c3e438b00cc73543e25aa049423cbfe8 to your computer and use it in GitHub Desktop.
/* | |
* HD Set Parm | |
* ---------------------------- | |
* Based on setapm and setaam from: | |
* http://solaris.kuehnke.de/archives/23-Set-APM-and-AAM-feature-configuration \ | |
* -attributes-for-disks-on-Solaris.html | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <fcntl.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <limits.h> | |
#include <sys/ioctl.h> | |
#include <sys/scsi/impl/uscsi.h> | |
uchar_t sf_enable_apm_cdb[12] = { 0xa1, 0x06, 0x0c, 0x05, 0x24, 0x00, | |
0x00, 0x00, 0x00, 0xef, 0x00, 0x00 }; | |
uchar_t sf_enable_aam_cdb[12] = { 0xa1, 0x06, 0x0c, 0x42, 0xd0, 0x00, | |
0x00, 0x00, 0x00, 0xef, 0x00, 0x00 }; | |
static void | |
usage(int argc, char *argv[]) | |
{ | |
fprintf(stderr, "Usage: %s <device> <APM|AAM> <Level>\n", argv[0]); | |
fprintf(stderr, " where Level = [0..254] (0=Disable APM/AAM)\n"); | |
exit(EXIT_FAILURE); | |
} | |
int | |
main(int argc, char *argv[]) | |
{ | |
int i; | |
int disk_fd; | |
int plevel; | |
char pname[4]; | |
char disk_path[PATH_MAX]; | |
uchar_t sf_enable_axm_cdb[12]; | |
struct uscsi_cmd scsi_cmd; | |
/* | |
* validate input | |
*/ | |
if (argc != 4) { | |
/* incorrect argument count */ | |
usage(argc, argv); | |
} | |
if (argv[1][0] != '/') { | |
/* we have a bare disk name */ | |
snprintf(disk_path, sizeof (disk_path), | |
"/dev/rdsk/%s", argv[1]); | |
} else { | |
/* we have an absolute disk name */ | |
if (strlcpy(disk_path, argv[1], sizeof (disk_path)) >= | |
sizeof (disk_path)) { | |
perror("device path is to long!"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
if ((disk_fd = open(disk_path, O_RDWR | O_NDELAY)) < 0) { | |
/* unable to open device, does it exists? */ | |
perror("Failed to open device"); | |
exit(EXIT_FAILURE); | |
} | |
if (strlen(argv[2]) != 3) { | |
/* pname is not 3 long */ | |
usage(argc, argv); | |
} | |
strlcpy(pname, argv[2], sizeof (pname)); | |
if ((strncasecmp(pname, "APM", 3) != 0) && | |
(strncasecmp(pname, "AAM", 3) != 0)) { | |
usage(argc, argv); | |
} | |
for (i = 0; i < strlen(pname); i++) { | |
/* make the str pname to be upper case */ | |
/* FIXME: can this be cleaned up ? */ | |
pname[i] = toupper(pname[i]); | |
} | |
if (sscanf(argv[3], "%d", &plevel) != 1) { /* failed to read plevel */ | |
usage(argc, argv); | |
} | |
if (plevel < 0 || plevel > 254) { | |
/* plevel not in acceptable range */ | |
usage(argc, argv); | |
} | |
/* print notice */ | |
fprintf(stdout, "Setting %s to %d for disk %s ...\n", | |
pname, plevel, disk_path); | |
/* copy correct template */ | |
if (strncasecmp(pname, "APM", 3) == 0) { | |
memcpy(sf_enable_axm_cdb, sf_enable_apm_cdb, \ | |
sizeof (sf_enable_axm_cdb)); | |
} else { | |
memcpy(sf_enable_axm_cdb, sf_enable_aam_cdb, \ | |
sizeof (sf_enable_axm_cdb)); | |
} | |
/* insert plevel */ | |
sf_enable_axm_cdb[4] = (unsigned char)plevel; | |
if (plevel == 0) { | |
sf_enable_axm_cdb[3] = 0x85; | |
} | |
/* prepare scsi command */ | |
memset(&scsi_cmd, 0, sizeof (scsi_cmd)); | |
scsi_cmd.uscsi_cdblen = 12; | |
scsi_cmd.uscsi_timeout = 30; | |
scsi_cmd.uscsi_flags = USCSI_READ | USCSI_SILENT | USCSI_ISOLATE; | |
scsi_cmd.uscsi_cdb = (caddr_t)sf_enable_axm_cdb; | |
scsi_cmd.uscsi_rqbuf = NULL; | |
scsi_cmd.uscsi_rqlen = 0; | |
/* send scsi command */ | |
if (ioctl(disk_fd, USCSICMD, &scsi_cmd) < 0) { | |
close(disk_fd); | |
perror("USCSICMD ioctl failed"); | |
exit(EXIT_FAILURE); | |
} | |
/* cleanup */ | |
close(disk_fd); | |
fprintf(stdout, "Success.\n"); | |
return (EXIT_SUCCESS); | |
} | |
/* vim: set tabstop=8 noexpandtab shiftwidth=8 softtabstop=8 : */ |
sjorge
commented
Jan 5, 2018
•
Nice work for a C beginner. Some people start with helloworld.c. You... :)
Here are some comments that I would give to anyone else looking to integrate into illumos. I'm not sure if that is your intent or not. Aside from C style issues, most of the comments are related to string handling. This is particularly tricky in C.
- Block comments start with /* on one line, end with */ on the last line, and have a * at column 2. All the *'s align.
- Always indent with 8 character tabs. If you find your code is getting scrunched to the right half of 80 characters, that's a sign you probably should be splitting something out into a functions or you should be rethinking the algorithm.
- Use /* */ rather than //. No, I don't have a good reason for this, just the way things are.
- At line 42, there's no need to need check the length of argv[1]. The strlen() will read the first character, just as the comparison to '/' does later. Instead, just compare argv[1][0] to '/'.
- Line 43 does not initialize disk_path[10]. If it happens to not be '\0', the strcat that follows will append at a different spot. That different spot may be outside of the allocated buffer. Use strcpy() instead - it will copy the 10 characters and terminate the string with '\0'.
- Line 49 has a similar problem to 43. I have seen maybe one occurrence of strcpy(dst, src, strlen(src)) that wasn't a bug. In that case, dst was pre-initialized to contain all '\0' characters.
- In a program like this, you aren't really worried about putting a KB or two on the stack. Rather than dynamically allocating memory, you could just declare disk_path[PATH_MAX].
- Rather than the strcpy + strcat combination, I would typically use snprintf().
- Line 64, split into two lines.
Here's a C style guide - there's probably a newer one somewhere. :) If you were to build this as part of an illumos build, the cstyle command run during the build would have complained about the style issues I mentioned and probably a few others.
@mgerdts thanks for the feedback, I think I fixed most of the issues you brought up.
I'm not sure how to fix line 53 though?
Is there a way to run the cstyle command standalone?
random notes: strxxx vs strnxxx, the n will usually operate to the '\n' termination
e.g. strlen("abc") will be 3, strnlen("abc") will be 4... because "abc" is actually char ['a', 'b', 'c', '\n']
@mgerdts is sys/ioctl.h and unistd.h needed? Compiles and seems to run fine without those, but IIRC close () is provided by unistd.h? And I thought the ioctl command came from ioctl.h?