1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2012, Joyent, Inc. All rights reserved.
24 */
25
26 /*
27 * This is a simple test program to exercise the hyprlofs ioctls. This is
28 * not designed as a full featured CLI and only does minimal error checking
29 * and reporting.
30 */
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <libgen.h>
38 #include <strings.h>
39 #include <sys/errno.h>
40 #include <sys/fs/hyprlofs.h>
41
42 extern int errno;
43
44 char *usage = "usage: <fs path> add [<file name> <alias>]+\n"
45 " <fs path> addl [<file name>]+\n"
46 " <fs path> rm [<alias>]+\n"
47 " <fs path> clear"
48 " <fs path> get";
49
50 typedef enum {
51 CMD_ADD,
52 CMD_RM,
53 CMD_CLR,
54 CMD_ADDL,
55 CMD_GET
56 } cmd_t;
57
58 static int
59 get_entries(int fd)
60 {
61 int err;
62 int i;
63 hyprlofs_curr_entries_t e;
64 hyprlofs_curr_entry_t *ep;
65
66 e.hce_cnt = 0;
67 e.hce_entries = NULL;
68
69 err = ioctl(fd, HYPRLOFS_GET_ENTRIES, &e);
70 if (err != 0 && errno != E2BIG) {
71 perror("ioctl");
72 return (1);
73 }
74
75 if (err == 0) {
76 (void) printf("success, but no entries\n");
77 return (0);
78 }
79
80 /*
81 * E2BIG is what we expect when there are existing mappings
82 * since the current cnt is still returned in that case.
83 */
84 (void) printf("cnt: %d\n", e.hce_cnt);
85
86 /* alloc array and call again, then print array */
87 if ((ep = (hyprlofs_curr_entry_t *)
88 malloc(sizeof (hyprlofs_curr_entry_t) * e.hce_cnt)) == NULL) {
89 (void) fprintf(stderr, "out of memory\n");
90 exit(1);
91 }
92
93 e.hce_entries = ep;
94 errno = 0;
95 if (ioctl(fd, HYPRLOFS_GET_ENTRIES, &e) != 0) {
96 /*
97 * Not handling an increase here. We would need to free and
98 * start over to do that, but ok for a test program.
99 */
100 perror("ioctl");
101 free(ep);
102 return (1);
103 }
104 for (i = 0; i < e.hce_cnt; i++)
105 (void) printf("%s %s\n", ep[i].hce_path, ep[i].hce_name);
106
107 free(ep);
108 return (0);
109 }
110
111 int
112 main(int argc, char **argv)
113 {
114 int i, ap;
115 cmd_t cmd;
116 int cnt = 0;
117 int fd;
118 int rv = 0;
119 hyprlofs_entry_t *e;
120 hyprlofs_entries_t ents;
121
122 if (argc < 3) {
123 (void) fprintf(stderr, "%s\n", usage);
124 exit(1);
125 }
126
127 if ((fd = open(argv[1], O_RDONLY)) < 0) {
128 perror("can't open hyprlofs mount");
129 exit(1);
130 }
131
132 if (strcmp(argv[2], "add") == 0) {
133 cmd = CMD_ADD;
134 } else if (strcmp(argv[2], "rm") == 0) {
135 cmd = CMD_RM;
136 } else if (strcmp(argv[2], "clear") == 0) {
137 cmd = CMD_CLR;
138 } else if (strcmp(argv[2], "addl") == 0) {
139 cmd = CMD_ADDL;
140 } else if (strcmp(argv[2], "get") == 0) {
141 cmd = CMD_GET;
142 } else {
143 (void) fprintf(stderr, "%s\n", usage);
144 exit(1);
145 }
146
147 /* Count up the number of parameters. The arg format varies w/ cmd */
148 switch (cmd) {
149 case CMD_ADD:
150 for (i = 3; i < argc; i++) {
151 /* argv[i] is the file path */
152
153 /* The next arg is the alias */
154 if (++i >= argc) {
155 (void) fprintf(stderr, "missing alias for %s\n",
156 argv[i - 1]);
157 exit(1);
158 }
159
160 cnt++;
161 }
162 break;
163 case CMD_ADDL:
164 cnt = argc - 3;
165 break;
166 case CMD_RM:
167 cnt = argc - 3;
168 break;
169 case CMD_CLR: /*FALLTHRU*/
170 case CMD_GET:
171 if (argc > 3) {
172 (void) fprintf(stderr, "%s\n", usage);
173 exit(1);
174 }
175 break;
176 }
177
178 if (cnt > 0) {
179 if ((e = (hyprlofs_entry_t *)malloc(sizeof (hyprlofs_entry_t) *
180 cnt)) == NULL) {
181 (void) fprintf(stderr, "out of memory\n");
182 exit(1);
183 }
184 }
185
186 /*
187 * Format up the args.
188 * We only setup the path member for the add cmd.
189 * We won't run this loop for the clear cmd.
190 * The addl command is special since we use basename to get the alias.
191 */
192 for (i = 0, ap = 3; i < cnt; i++, ap++) {
193 if (cmd == CMD_ADDL) {
194 e[i].hle_path = argv[ap];
195 e[i].hle_plen = strlen(e[i].hle_path);
196
197 e[i].hle_name = basename(argv[ap]);
198 e[i].hle_nlen = strlen(e[i].hle_name);
199
200 continue;
201 }
202
203 if (cmd == CMD_ADD) {
204 e[i].hle_path = argv[ap++];
205 e[i].hle_plen = strlen(e[i].hle_path);
206 }
207
208 e[i].hle_name = argv[ap];
209 e[i].hle_nlen = strlen(e[i].hle_name);
210 }
211
212 ents.hle_entries = e;
213 ents.hle_len = cnt;
214
215 switch (cmd) {
216 case CMD_ADD: /*FALLTHRU*/
217 case CMD_ADDL:
218 if (ioctl(fd, HYPRLOFS_ADD_ENTRIES, &ents) < 0) {
219 perror("ioctl");
220 rv = 1;
221 }
222 break;
223 case CMD_RM:
224 if (ioctl(fd, HYPRLOFS_RM_ENTRIES, &ents) < 0) {
225 perror("ioctl");
226 rv = 1;
227 }
228 break;
229 case CMD_CLR:
230 if (ioctl(fd, HYPRLOFS_RM_ALL) < 0) {
231 perror("ioctl");
232 rv = 1;
233 }
234 break;
235 case CMD_GET:
236 rv = get_entries(fd);
237 break;
238 }
239
240 (void) close(fd);
241 if (cnt > 0)
242 free(e);
243 return (rv);
244 }