Skip to content

Commit dab147d

Browse files
jgottulatonyhutter
authored andcommitted
Use substantially more robust program exit status logic in zvol_id
Currently, there are several places in zvol_id where the program logic returns particular errno values, or even particular ioctl return values, as the program exit status, rather than a straightforward system of explicit zero on success and explicit nonzero value(s) on failure. This is problematic for multiple reasons. One particularly interesting problem that can arise, is that if any of these values happens to have all 8 least significant bits unset (i.e., it is a positive or negative multiple of 256), then although the C program sees a nonzero int value (presumed to be a failure exit status), the actual exit status as seen by the system is only the bottom 8 bits of that integer: zero. This can happen in practice, and I have encountered it myself. In a particularly weird situation, the zvol_open code in the zfs kernel module was behaving in such a manner that it caused the open() syscall to fail and for errno to be set to a kernel-private value (ERESTARTSYS, which happens to be defined as 512). It turns out that 512 is evenly divisible by 256; or, in other words, its least significant 8 bits are all-zero. So even though zvol_id believed it was returning a nonzero (failure) exit status of 512, the system modulo'd that value by 256, resulting in the actual exit status visible by other programs being 0! This actually-zero (non-failure) exit status caused problems: udev believed that the program was operating successfully, when in fact it was attempting to indicate failure via a nonzero exit status integer. Combined with another problem, this led to the creation of nonsense symlinks for zvol dev nodes by udev. Let's get rid of all this problematic logic, and simply return EXIT_SUCCESS (0) is everything went fine, and EXIT_FAILURE (1) if anything went wrong. Additionally, let's clarify some of the variable names (error is similar to errno, etc) and clean up the overall program flow a bit. Reviewed-by: Brian Behlendorf <[email protected]> Reviewed-by: Pavel Zakharov <[email protected]> Signed-off-by: Justin Gottula <[email protected]> Closes openzfs#12302
1 parent 7138fe7 commit dab147d

File tree

1 file changed

+27
-23
lines changed

1 file changed

+27
-23
lines changed

cmd/zvol_id/zvol_id_main.c

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -38,40 +38,39 @@
3838
static int
3939
ioctl_get_msg(char *var, int fd)
4040
{
41-
int error = 0;
41+
int ret;
4242
char msg[ZFS_MAX_DATASET_NAME_LEN];
4343

44-
error = ioctl(fd, BLKZNAME, msg);
45-
if (error < 0) {
46-
return (error);
44+
ret = ioctl(fd, BLKZNAME, msg);
45+
if (ret < 0) {
46+
return (ret);
4747
}
4848

4949
snprintf(var, ZFS_MAX_DATASET_NAME_LEN, "%s", msg);
50-
return (error);
50+
return (ret);
5151
}
5252

5353
int
5454
main(int argc, char **argv)
5555
{
56-
int fd, error = 0;
56+
int fd = -1, ret = 0, status = EXIT_FAILURE;
5757
char zvol_name[ZFS_MAX_DATASET_NAME_LEN];
5858
char *zvol_name_part = NULL;
5959
char *dev_name;
6060
struct stat64 statbuf;
6161
int dev_minor, dev_part;
6262
int i;
63-
int rc;
6463

6564
if (argc < 2) {
6665
fprintf(stderr, "Usage: %s /dev/zvol_device_node\n", argv[0]);
67-
return (EINVAL);
66+
goto fail;
6867
}
6968

7069
dev_name = argv[1];
71-
error = stat64(dev_name, &statbuf);
72-
if (error != 0) {
70+
ret = stat64(dev_name, &statbuf);
71+
if (ret != 0) {
7372
fprintf(stderr, "Unable to access device file: %s\n", dev_name);
74-
return (errno);
73+
goto fail;
7574
}
7675

7776
dev_minor = minor(statbuf.st_rdev);
@@ -80,31 +79,36 @@ main(int argc, char **argv)
8079
fd = open(dev_name, O_RDONLY);
8180
if (fd < 0) {
8281
fprintf(stderr, "Unable to open device file: %s\n", dev_name);
83-
return (errno);
82+
goto fail;
8483
}
8584

86-
error = ioctl_get_msg(zvol_name, fd);
87-
if (error < 0) {
85+
ret = ioctl_get_msg(zvol_name, fd);
86+
if (ret < 0) {
8887
fprintf(stderr, "ioctl_get_msg failed: %s\n", strerror(errno));
89-
return (errno);
88+
goto fail;
9089
}
9190
if (dev_part > 0)
92-
rc = asprintf(&zvol_name_part, "%s-part%d", zvol_name,
91+
ret = asprintf(&zvol_name_part, "%s-part%d", zvol_name,
9392
dev_part);
9493
else
95-
rc = asprintf(&zvol_name_part, "%s", zvol_name);
94+
ret = asprintf(&zvol_name_part, "%s", zvol_name);
9695

97-
if (rc == -1 || zvol_name_part == NULL)
98-
goto error;
96+
if (ret == -1 || zvol_name_part == NULL)
97+
goto fail;
9998

10099
for (i = 0; i < strlen(zvol_name_part); i++) {
101100
if (isblank(zvol_name_part[i]))
102101
zvol_name_part[i] = '+';
103102
}
104103

105104
printf("%s\n", zvol_name_part);
106-
free(zvol_name_part);
107-
error:
108-
close(fd);
109-
return (error);
105+
status = EXIT_SUCCESS;
106+
107+
fail:
108+
if (zvol_name_part)
109+
free(zvol_name_part);
110+
if (fd >= 0)
111+
close(fd);
112+
113+
return (status);
110114
}

0 commit comments

Comments
 (0)