diff options
author | Jeff Layton <jlayton@redhat.com> | 2012-12-10 06:10:46 -0500 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2012-12-11 12:48:50 -0500 |
commit | d387a5c50bca619d56f276a69627c2e1c6e5c548 (patch) | |
tree | 86bc043af2734f67fabc1a3a1031a69e8ac31eaa /fs/cifs | |
parent | 839db3d10a5ba792d6533b8bb3380f52ac877344 (diff) |
cifs: parse the device name into UNC and prepath
This should fix a regression that was introduced when the new mount
option parser went in. Also, when the unc= and prefixpath= options
are provided, check their values against the ones we parsed from
the device string. If they differ, then throw a warning that tells
the user that we're using the values from the unc= option for now,
but that that will change in 3.10.
Pavel Shilovsky <piastry@etersoft.ru>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/connect.c | 95 |
1 files changed, 88 insertions, 7 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 94c4484c9ea3..7635b5db26a7 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -1096,6 +1096,52 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol) | |||
1096 | return 0; | 1096 | return 0; |
1097 | } | 1097 | } |
1098 | 1098 | ||
1099 | /* | ||
1100 | * Parse a devname into substrings and populate the vol->UNC and vol->prepath | ||
1101 | * fields with the result. Returns 0 on success and an error otherwise. | ||
1102 | */ | ||
1103 | static int | ||
1104 | cifs_parse_devname(const char *devname, struct smb_vol *vol) | ||
1105 | { | ||
1106 | char *pos; | ||
1107 | const char *delims = "/\\"; | ||
1108 | size_t len; | ||
1109 | |||
1110 | /* make sure we have a valid UNC double delimiter prefix */ | ||
1111 | len = strspn(devname, delims); | ||
1112 | if (len != 2) | ||
1113 | return -EINVAL; | ||
1114 | |||
1115 | /* find delimiter between host and sharename */ | ||
1116 | pos = strpbrk(devname + 2, delims); | ||
1117 | if (!pos) | ||
1118 | return -EINVAL; | ||
1119 | |||
1120 | /* skip past delimiter */ | ||
1121 | ++pos; | ||
1122 | |||
1123 | /* now go until next delimiter or end of string */ | ||
1124 | len = strcspn(pos, delims); | ||
1125 | |||
1126 | /* move "pos" up to delimiter or NULL */ | ||
1127 | pos += len; | ||
1128 | vol->UNC = kstrndup(devname, pos - devname, GFP_KERNEL); | ||
1129 | if (!vol->UNC) | ||
1130 | return -ENOMEM; | ||
1131 | |||
1132 | convert_delimiter(vol->UNC, '\\'); | ||
1133 | |||
1134 | /* If pos is NULL, or is a bogus trailing delimiter then no prepath */ | ||
1135 | if (!*pos++ || !*pos) | ||
1136 | return 0; | ||
1137 | |||
1138 | vol->prepath = kstrdup(pos, GFP_KERNEL); | ||
1139 | if (!vol->prepath) | ||
1140 | return -ENOMEM; | ||
1141 | |||
1142 | return 0; | ||
1143 | } | ||
1144 | |||
1099 | static int | 1145 | static int |
1100 | cifs_parse_mount_options(const char *mountdata, const char *devname, | 1146 | cifs_parse_mount_options(const char *mountdata, const char *devname, |
1101 | struct smb_vol *vol) | 1147 | struct smb_vol *vol) |
@@ -1181,6 +1227,16 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1181 | vol->backupuid_specified = false; /* no backup intent for a user */ | 1227 | vol->backupuid_specified = false; /* no backup intent for a user */ |
1182 | vol->backupgid_specified = false; /* no backup intent for a group */ | 1228 | vol->backupgid_specified = false; /* no backup intent for a group */ |
1183 | 1229 | ||
1230 | /* | ||
1231 | * For now, we ignore -EINVAL errors under the assumption that the | ||
1232 | * unc= and prefixpath= options will be usable. | ||
1233 | */ | ||
1234 | if (cifs_parse_devname(devname, vol) == -ENOMEM) { | ||
1235 | printk(KERN_ERR "CIFS: Unable to allocate memory to parse " | ||
1236 | "device string.\n"); | ||
1237 | goto out_nomem; | ||
1238 | } | ||
1239 | |||
1184 | while ((data = strsep(&options, separator)) != NULL) { | 1240 | while ((data = strsep(&options, separator)) != NULL) { |
1185 | substring_t args[MAX_OPT_ARGS]; | 1241 | substring_t args[MAX_OPT_ARGS]; |
1186 | unsigned long option; | 1242 | unsigned long option; |
@@ -1566,18 +1622,31 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1566 | got_ip = true; | 1622 | got_ip = true; |
1567 | break; | 1623 | break; |
1568 | case Opt_unc: | 1624 | case Opt_unc: |
1569 | kfree(vol->UNC); | 1625 | string = vol->UNC; |
1570 | vol->UNC = match_strdup(args); | 1626 | vol->UNC = match_strdup(args); |
1571 | if (vol->UNC == NULL) | 1627 | if (vol->UNC == NULL) { |
1628 | kfree(string); | ||
1572 | goto out_nomem; | 1629 | goto out_nomem; |
1630 | } | ||
1573 | 1631 | ||
1574 | convert_delimiter(vol->UNC, '\\'); | 1632 | convert_delimiter(vol->UNC, '\\'); |
1575 | if (vol->UNC[0] != '\\' || vol->UNC[1] != '\\') { | 1633 | if (vol->UNC[0] != '\\' || vol->UNC[1] != '\\') { |
1576 | printk(KERN_WARNING "CIFS: UNC Path does not " | 1634 | kfree(string); |
1635 | printk(KERN_ERR "CIFS: UNC Path does not " | ||
1577 | "begin with // or \\\\\n"); | 1636 | "begin with // or \\\\\n"); |
1578 | goto cifs_parse_mount_err; | 1637 | goto cifs_parse_mount_err; |
1579 | } | 1638 | } |
1580 | 1639 | ||
1640 | /* Compare old unc= option to new one */ | ||
1641 | if (!string || strcmp(string, vol->UNC)) | ||
1642 | printk(KERN_WARNING "CIFS: the value of the " | ||
1643 | "unc= mount option does not match the " | ||
1644 | "device string. Using the unc= option " | ||
1645 | "for now. In 3.10, that option will " | ||
1646 | "be ignored and the contents of the " | ||
1647 | "device string will be used " | ||
1648 | "instead. (%s != %s)\n", string, | ||
1649 | vol->UNC); | ||
1581 | break; | 1650 | break; |
1582 | case Opt_domain: | 1651 | case Opt_domain: |
1583 | string = match_strdup(args); | 1652 | string = match_strdup(args); |
@@ -1616,10 +1685,22 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1616 | if (*args[0].from == '/' || *args[0].from == '\\') | 1685 | if (*args[0].from == '/' || *args[0].from == '\\') |
1617 | args[0].from++; | 1686 | args[0].from++; |
1618 | 1687 | ||
1619 | kfree(vol->prepath); | 1688 | string = vol->prepath; |
1620 | vol->prepath = match_strdup(args); | 1689 | vol->prepath = match_strdup(args); |
1621 | if (vol->prepath == NULL) | 1690 | if (vol->prepath == NULL) { |
1691 | kfree(string); | ||
1622 | goto out_nomem; | 1692 | goto out_nomem; |
1693 | } | ||
1694 | /* Compare old prefixpath= option to new one */ | ||
1695 | if (!string || strcmp(string, vol->prepath)) | ||
1696 | printk(KERN_WARNING "CIFS: the value of the " | ||
1697 | "prefixpath= mount option does not " | ||
1698 | "match the device string. Using the " | ||
1699 | "prefixpath= option for now. In 3.10, " | ||
1700 | "that option will be ignored and the " | ||
1701 | "contents of the device string will be " | ||
1702 | "used instead.(%s != %s)\n", string, | ||
1703 | vol->prepath); | ||
1623 | break; | 1704 | break; |
1624 | case Opt_iocharset: | 1705 | case Opt_iocharset: |
1625 | string = match_strdup(args); | 1706 | string = match_strdup(args); |
@@ -1777,8 +1858,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1777 | } | 1858 | } |
1778 | #endif | 1859 | #endif |
1779 | if (!vol->UNC) { | 1860 | if (!vol->UNC) { |
1780 | cERROR(1, "CIFS mount error: No UNC path (e.g. -o " | 1861 | cERROR(1, "CIFS mount error: No usable UNC path provided in " |
1781 | "unc=\\\\192.168.1.100\\public) specified"); | 1862 | "device string or in unc= option!"); |
1782 | goto cifs_parse_mount_err; | 1863 | goto cifs_parse_mount_err; |
1783 | } | 1864 | } |
1784 | 1865 | ||