1/*-
2 * Copyright (c) 2016 Andriy Gapon <avg@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <sys/cdefs.h>
27__FBSDID("$FreeBSD$");
28
29#include <sys/types.h>
30#include <errno.h>
31#include <limits.h>
32#include <inttypes.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <kenv.h>
37
38#include <libzfs.h>
39
40/* Keep in sync with zfsboot.c. */
41#define MAX_COMMAND_LEN	512
42
43int main(int argc, const char * const *argv)
44{
45	char buf[32];
46	libzfs_handle_t *hdl;
47	uint64_t pool_guid;
48	uint64_t vdev_guid;
49	int zfs_fd;
50	int len;
51
52	if (argc != 2) {
53		fprintf(stderr, "usage: zfsbootcfg <boot.config(5) options>\n");
54		return (1);
55	}
56
57	len = strlen(argv[1]);
58	if (len >= MAX_COMMAND_LEN) {
59		fprintf(stderr, "options string is too long\n");
60		return (1);
61	}
62
63	if (kenv(KENV_GET, "vfs.zfs.boot.primary_pool", buf, sizeof(buf)) <= 0) {
64		perror("can't get vfs.zfs.boot.primary_pool");
65		return (1);
66	}
67	pool_guid = strtoumax(buf, NULL, 10);
68	if (pool_guid == 0) {
69		perror("can't parse vfs.zfs.boot.primary_pool");
70		return (1);
71	}
72
73	if (kenv(KENV_GET, "vfs.zfs.boot.primary_vdev", buf, sizeof(buf)) <= 0) {
74		perror("can't get vfs.zfs.boot.primary_vdev");
75		return (1);
76	}
77	vdev_guid = strtoumax(buf, NULL, 10);
78	if (vdev_guid == 0) {
79		perror("can't parse vfs.zfs.boot.primary_vdev");
80		return (1);
81	}
82
83	if ((hdl = libzfs_init()) == NULL) {
84		(void) fprintf(stderr, "internal error: failed to "
85		    "initialize ZFS library\n");
86		return (1);
87	}
88
89	if (zpool_nextboot(hdl, pool_guid, vdev_guid, argv[1]) != 0) {
90		perror("ZFS_IOC_NEXTBOOT failed");
91		libzfs_fini(hdl);
92		return (1);
93	}
94
95	libzfs_fini(hdl);
96	printf("zfs next boot options are successfully written\n");
97	return (0);
98}
99