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, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #pragma ident   "%Z%%M% %I%     %E% SMI"
  28 
  29 #include <stdio.h>
  30 #include <stdlib.h>
  31 #include <string.h>
  32 #include <stdarg.h>
  33 #include <libintl.h>
  34 #include <sys/types.h>
  35 #include <sys/ioctl.h>
  36 #include <kstat.h>
  37 #include <locale.h>
  38 #include <sys/fs/cachefs_log.h>
  39 #include "stats.h"
  40 
  41 void usage(char *);
  42 void pr_err(char *, ...);
  43 
  44 static int hflag = 0;
  45 static char *fpath = NULL;
  46 static int vflag = 0;
  47 char *prog;
  48 
  49 static void log_show(char *, char *);
  50 
  51 int
  52 main(int argc, char **argv)
  53 {
  54         int rc = 0, c;
  55         int errflg = 0;
  56         stats_cookie_t *fs = NULL;
  57         char *logfile;
  58 
  59         (void) setlocale(LC_ALL, "");
  60 #if !defined(TEXT_DOMAIN)
  61 #define TEXT_DOMAIN "SYS_TEST"
  62 #endif /* TEXT_DOMAIN */
  63         (void) textdomain(TEXT_DOMAIN);
  64 
  65         if (prog = strrchr(argv[0], '/'))
  66                 ++prog;
  67         else
  68                 prog = argv[0];
  69 
  70         while ((c = getopt(argc, argv, "hf:v")) != EOF)
  71                 switch (c) {
  72                 case 'h':
  73                         if (fpath != NULL)
  74                                 ++errflg;
  75                         else
  76                                 ++hflag;
  77                         break;
  78 
  79                 case 'f':
  80                         if (hflag)
  81                                 ++errflg;
  82                         else
  83                                 fpath = optarg;
  84                         break;
  85 
  86                 case 'v':
  87                         ++vflag;
  88                         break;
  89 
  90                 case '?':
  91                 default:
  92                         ++errflg;
  93                         break;
  94                 }
  95 
  96         if ((errflg) || (optind != (argc - 1))) {
  97                 usage(NULL);
  98                 rc = -1;
  99                 goto out;
 100         }
 101 
 102         fs = stats_create_mountpath(argv[optind], prog);
 103         if (fs == NULL) {
 104                 pr_err(gettext("Cannot initialize cachefs library\n"));
 105                 rc = 1;
 106                 goto out;
 107         }
 108 
 109         if (! stats_good(fs)) {
 110                 pr_err(stats_errorstr(fs));
 111                 rc = stats_errno(fs);
 112                 goto out;
 113         }
 114 
 115         if ((logfile = stats_log_kernel_getname(fs)) == NULL) {
 116                 pr_err(stats_errorstr(fs));
 117                 rc = stats_errno(fs);
 118                 goto out;
 119         }
 120         if ((logfile[0] == '\0') && (hflag) && (! vflag)) {
 121                 log_show(argv[optind], logfile);
 122                 goto out;
 123         }
 124 
 125         if (fpath != NULL) {
 126                 if ((stats_log_kernel_setname(fs, fpath) != 0) ||
 127                     (stats_log_which(fs, CACHEFS_LOG_MOUNT, 1) != 0) ||
 128                     (stats_log_which(fs, CACHEFS_LOG_UMOUNT, 1) != 0) ||
 129                     (stats_log_which(fs, CACHEFS_LOG_REMOVE, 1) != 0) ||
 130                     (stats_log_which(fs, CACHEFS_LOG_RMDIR, 1) != 0) ||
 131                     (stats_log_which(fs, CACHEFS_LOG_TRUNCATE, 1) != 0) ||
 132                     (stats_log_which(fs, CACHEFS_LOG_CREATE, 1) != 0) ||
 133                     (stats_log_which(fs, CACHEFS_LOG_MKDIR, 1) != 0) ||
 134                     (stats_log_which(fs, CACHEFS_LOG_RENAME, 1) != 0) ||
 135                     (stats_log_which(fs, CACHEFS_LOG_SYMLINK, 1) != 0) ||
 136                     (stats_log_which(fs, CACHEFS_LOG_UALLOC, 1) != 0) ||
 137                     (stats_log_which(fs, CACHEFS_LOG_CSYMLINK, 1) != 0) ||
 138                     (stats_log_which(fs, CACHEFS_LOG_FILLDIR, 1) != 0) ||
 139                     (stats_log_which(fs, CACHEFS_LOG_MDCREATE, 1) != 0) ||
 140                     (stats_log_which(fs, CACHEFS_LOG_NOCACHE, 1) != 0) ||
 141                     (stats_log_which(fs, CACHEFS_LOG_CALLOC, 1) != 0) ||
 142                     (stats_log_which(fs, CACHEFS_LOG_RFDIR, 1) != 0)) {
 143                         pr_err(stats_errorstr(fs));
 144                         rc = stats_errno(fs);
 145                         goto out;
 146                 }
 147         } else if (hflag) {
 148                 if (stats_log_kernel_setname(fs, NULL) != 0) {
 149                         pr_err(stats_errorstr(fs));
 150                         rc = stats_errno(fs);
 151                         goto out;
 152                 }
 153         }
 154 
 155         if ((logfile = stats_log_kernel_getname(fs)) == NULL) {
 156                 pr_err(stats_errorstr(fs));
 157                 rc = stats_errno(fs);
 158                 goto out;
 159         }
 160 
 161         log_show(argv[optind], logfile);
 162 
 163         /*
 164          * if they're changing state, inform them of other filesystems
 165          * that they're changing state for by way of sharing the
 166          * cache.
 167          *
 168          * or, if they're verbose (-v flag), tell them about the
 169          * others.
 170          */
 171 
 172         if (((fpath) || (hflag) || (vflag)) && (! stats_inerror(fs))) {
 173                 cachefs_kstat_key_t *k, *origk;
 174                 stats_cookie_t *sc;
 175                 int before = 0;
 176 
 177                 origk = stats_getkey(fs);
 178                 sc = stats_create_unbound(prog);
 179                 if (sc == NULL) {
 180                         pr_err(gettext("Cannot create stats object"));
 181                         rc = 1;
 182                         goto out;
 183                 }
 184 
 185                 while ((k = stats_next(sc)) != NULL) {
 186                         if (! k->ks_mounted) {
 187                                 free(k);
 188                                 continue;
 189                         }
 190                         if (strcmp((char *)(uintptr_t)origk->ks_cachedir,
 191                                 (char *)(uintptr_t)k->ks_cachedir) != 0) {
 192                                 free(k);
 193                                 continue;
 194                         }
 195                         if (origk->ks_id == k->ks_id) {
 196                                 free(k);
 197                                 continue;
 198                         }
 199                         if (! before)
 200                                 printf("\n");
 201                         before = 1;
 202                         log_show((char *)(uintptr_t)k->ks_mountpoint, logfile);
 203                         free(k);
 204                 }
 205                 free(origk);
 206                 stats_destroy(sc);
 207         }
 208 
 209         if (stats_inerror(fs)) {
 210                 pr_err(stats_errorstr(fs));
 211                 rc = stats_errno(fs);
 212         }
 213 
 214 out:
 215         stats_destroy(fs);
 216         return (rc);
 217 }
 218 
 219 static void
 220 log_show(char *mount, char *logfile)
 221 {
 222         if (logfile[0] == '\0')
 223                 logfile = gettext("not logged");
 224         printf("%s: %s\n", logfile, mount);
 225 }
 226 
 227 /*
 228  *
 229  *                      usage
 230  *
 231  * Description:
 232  *      Prints a short usage message.
 233  * Arguments:
 234  *      msgp    message to include with the usage message
 235  * Returns:
 236  * Preconditions:
 237  */
 238 
 239 void
 240 usage(char *msgp)
 241 {
 242         if (msgp) {
 243                 pr_err("%s", msgp);
 244         }
 245 
 246         fprintf(stderr,
 247             gettext("Usage: "
 248             "cachefslog [ -v ] [-h | -f <logfile>] mountpoint\n"));
 249 }
 250 
 251 /*
 252  *
 253  *                      pr_err
 254  *
 255  * Description:
 256  *      Prints an error message to stderr.
 257  * Arguments:
 258  *      fmt     printf style format
 259  *      ...     arguments for fmt
 260  * Returns:
 261  * Preconditions:
 262  *      precond(fmt)
 263  */
 264 
 265 void
 266 pr_err(char *fmt, ...)
 267 {
 268         va_list ap;
 269 
 270         va_start(ap, fmt);
 271         (void) fprintf(stderr, gettext("cachefslog: "));
 272         (void) vfprintf(stderr, fmt, ap);
 273         (void) fprintf(stderr, "\n");
 274         va_end(ap);
 275 }