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 = NULL;
 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 }