1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * SMB root file system support 4 * 5 * Copyright (c) 2019 Paulo Alcantara <palcantara@suse.de> 6 */ 7 #include <linux/init.h> 8 #include <linux/fs.h> 9 #include <linux/types.h> 10 #include <linux/ctype.h> 11 #include <linux/string.h> 12 #include <linux/root_dev.h> 13 #include <linux/kernel.h> 14 #include <linux/in.h> 15 #include <linux/inet.h> 16 #include <net/ipconfig.h> 17 18 #define DEFAULT_MNT_OPTS \ 19 "vers=1.0,cifsacl,mfsymlinks,rsize=1048576,wsize=65536,uid=0,gid=0," \ 20 "hard,rootfs" 21 22 static char root_dev[2048] __initdata = ""; 23 static char root_opts[1024] __initdata = DEFAULT_MNT_OPTS; 24 25 static __be32 __init parse_srvaddr(char *start, char *end) 26 { 27 /* TODO: ipv6 support */ 28 char addr[sizeof("aaa.bbb.ccc.ddd")]; 29 int i = 0; 30 31 while (start < end && i < sizeof(addr) - 1) { 32 if (isdigit(*start) || *start == '.') 33 addr[i++] = *start; 34 start++; 35 } 36 addr[i] = '\0'; 37 return in_aton(addr); 38 } 39 40 /* cifsroot=//<server-ip>/<share>[,options] */ 41 static int __init cifs_root_setup(char *line) 42 { 43 char *s; 44 int len; 45 __be32 srvaddr = htonl(INADDR_NONE); 46 47 ROOT_DEV = Root_CIFS; 48 49 if (strlen(line) > 3 && line[0] == '/' && line[1] == '/') { 50 s = strchr(&line[2], '/'); 51 if (!s || s[1] == '\0') 52 return 1; 53 54 /* make s point to ',' or '\0' at end of line */ 55 s = strchrnul(s, ','); 56 /* len is strlen(unc) + '\0' */ 57 len = s - line + 1; 58 if (len > sizeof(root_dev)) { 59 pr_err("Root-CIFS: UNC path too long\n"); 60 return 1; 61 } 62 strscpy(root_dev, line, len); 63 srvaddr = parse_srvaddr(&line[2], s); 64 if (*s) { 65 int n = snprintf(root_opts, 66 sizeof(root_opts), "%s,%s", 67 DEFAULT_MNT_OPTS, s + 1); 68 if (n >= sizeof(root_opts)) { 69 pr_err("Root-CIFS: mount options string too long\n"); 70 root_opts[sizeof(root_opts)-1] = '\0'; 71 return 1; 72 } 73 } 74 } 75 76 root_server_addr = srvaddr; 77 78 return 1; 79 } 80 81 __setup("cifsroot=", cifs_root_setup); 82 83 int __init cifs_root_data(char **dev, char **opts) 84 { 85 if (!root_dev[0] || root_server_addr == htonl(INADDR_NONE)) { 86 pr_err("Root-CIFS: no SMB server address\n"); 87 return -1; 88 } 89 90 *dev = root_dev; 91 *opts = root_opts; 92 93 return 0; 94 } 95