18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * SMB root file system support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2019 Paulo Alcantara <palcantara@suse.de> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/init.h> 88c2ecf20Sopenharmony_ci#include <linux/fs.h> 98c2ecf20Sopenharmony_ci#include <linux/types.h> 108c2ecf20Sopenharmony_ci#include <linux/ctype.h> 118c2ecf20Sopenharmony_ci#include <linux/string.h> 128c2ecf20Sopenharmony_ci#include <linux/root_dev.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/in.h> 158c2ecf20Sopenharmony_ci#include <linux/inet.h> 168c2ecf20Sopenharmony_ci#include <net/ipconfig.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define DEFAULT_MNT_OPTS \ 198c2ecf20Sopenharmony_ci "vers=1.0,cifsacl,mfsymlinks,rsize=1048576,wsize=65536,uid=0,gid=0," \ 208c2ecf20Sopenharmony_ci "hard,rootfs" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic char root_dev[2048] __initdata = ""; 238c2ecf20Sopenharmony_cistatic char root_opts[1024] __initdata = DEFAULT_MNT_OPTS; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic __be32 __init parse_srvaddr(char *start, char *end) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci /* TODO: ipv6 support */ 288c2ecf20Sopenharmony_ci char addr[sizeof("aaa.bbb.ccc.ddd")]; 298c2ecf20Sopenharmony_ci int i = 0; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci while (start < end && i < sizeof(addr) - 1) { 328c2ecf20Sopenharmony_ci if (isdigit(*start) || *start == '.') 338c2ecf20Sopenharmony_ci addr[i++] = *start; 348c2ecf20Sopenharmony_ci start++; 358c2ecf20Sopenharmony_ci } 368c2ecf20Sopenharmony_ci addr[i] = '\0'; 378c2ecf20Sopenharmony_ci return in_aton(addr); 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* cifsroot=//<server-ip>/<share>[,options] */ 418c2ecf20Sopenharmony_cistatic int __init cifs_root_setup(char *line) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci char *s; 448c2ecf20Sopenharmony_ci int len; 458c2ecf20Sopenharmony_ci __be32 srvaddr = htonl(INADDR_NONE); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci ROOT_DEV = Root_CIFS; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (strlen(line) > 3 && line[0] == '/' && line[1] == '/') { 508c2ecf20Sopenharmony_ci s = strchr(&line[2], '/'); 518c2ecf20Sopenharmony_ci if (!s || s[1] == '\0') 528c2ecf20Sopenharmony_ci return 1; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci /* make s point to ',' or '\0' at end of line */ 558c2ecf20Sopenharmony_ci s = strchrnul(s, ','); 568c2ecf20Sopenharmony_ci /* len is strlen(unc) + '\0' */ 578c2ecf20Sopenharmony_ci len = s - line + 1; 588c2ecf20Sopenharmony_ci if (len > sizeof(root_dev)) { 598c2ecf20Sopenharmony_ci pr_err("Root-CIFS: UNC path too long\n"); 608c2ecf20Sopenharmony_ci return 1; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci strlcpy(root_dev, line, len); 638c2ecf20Sopenharmony_ci srvaddr = parse_srvaddr(&line[2], s); 648c2ecf20Sopenharmony_ci if (*s) { 658c2ecf20Sopenharmony_ci int n = snprintf(root_opts, 668c2ecf20Sopenharmony_ci sizeof(root_opts), "%s,%s", 678c2ecf20Sopenharmony_ci DEFAULT_MNT_OPTS, s + 1); 688c2ecf20Sopenharmony_ci if (n >= sizeof(root_opts)) { 698c2ecf20Sopenharmony_ci pr_err("Root-CIFS: mount options string too long\n"); 708c2ecf20Sopenharmony_ci root_opts[sizeof(root_opts)-1] = '\0'; 718c2ecf20Sopenharmony_ci return 1; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci root_server_addr = srvaddr; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return 1; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci__setup("cifsroot=", cifs_root_setup); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ciint __init cifs_root_data(char **dev, char **opts) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci if (!root_dev[0] || root_server_addr == htonl(INADDR_NONE)) { 868c2ecf20Sopenharmony_ci pr_err("Root-CIFS: no SMB server address\n"); 878c2ecf20Sopenharmony_ci return -1; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci *dev = root_dev; 918c2ecf20Sopenharmony_ci *opts = root_opts; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return 0; 948c2ecf20Sopenharmony_ci} 95