xref: /kernel/linux/linux-5.10/fs/cifs/cifsroot.c (revision 8c2ecf20)
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