Print this page
3484 enhance and document tail follow support
Reviewed by: Joshua M. Clulow <jmc@joyent.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/tail/forward.c
          +++ new/usr/src/cmd/tail/forward.c
↓ open down ↓ 23 lines elided ↑ open up ↑
  24   24   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25   25   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26   26   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27   27   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28   28   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29   29   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30   30   * SUCH DAMAGE.
  31   31   */
  32   32  
  33   33  /*
  34      - * Solaris porting notes:  the original FreeBSD version made use of the
  35      - *                         BSD kqueue event notification framework; this
  36      - *                         was changed to use usleep()
       34 + * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  37   35   */
  38   36  
  39   37  #include <sys/param.h>
  40   38  #include <sys/mount.h>
  41   39  #include <sys/types.h>
  42   40  #include <sys/stat.h>
  43   41  #include <sys/statfs.h>
  44   42  #include <sys/statvfs.h>
  45   43  #include <sys/time.h>
  46   44  #include <sys/mman.h>
  47   45  #include <sys/poll.h>
  48   46  #include <port.h>
  49   47  #include <err.h>
  50   48  #include <errno.h>
  51   49  #include <fcntl.h>
  52   50  #include <limits.h>
  53   51  #include <stdio.h>
  54   52  #include <stdlib.h>
  55   53  #include <string.h>
       54 +#include <strings.h>
  56   55  #include <unistd.h>
  57   56  
  58   57  #include "extern.h"
  59   58  
  60   59  static void rlines(FILE *, const char *fn, off_t, struct stat *);
  61   60  static int show(file_info_t *);
  62   61  static void set_events(file_info_t *files);
  63   62  
  64   63  /* defines for inner loop actions */
  65   64  #define USE_SLEEP       0
       65 +#define USE_PORT        1
  66   66  #define ADD_EVENTS      2
  67   67  
  68      -int action = USE_SLEEP;
       68 +int port;
       69 +int action = USE_PORT;
  69   70  
  70   71  static const file_info_t *last;
  71   72  
  72   73  /*
  73   74   * forward -- display the file, from an offset, forward.
  74   75   *
  75   76   * There are eight separate cases for this -- regular and non-regular
  76   77   * files, by bytes or lines and from the beginning or end of the file.
  77   78   *
  78   79   * FBYTES       byte offset from the beginning of the file
↓ open down ↓ 175 lines elided ↑ open up ↑
 254  255                  (void) fclose(file->fp);
 255  256                  file->fp = NULL;
 256  257                  ierr(file->file_name);
 257  258                  return (0);
 258  259          }
 259  260          clearerr(file->fp);
 260  261          return (1);
 261  262  }
 262  263  
 263  264  static void
      265 +associate(file_info_t *file, boolean_t assoc)
      266 +{
      267 +        char buf[64];
      268 +
      269 +        if (action != USE_PORT || file->fp == NULL)
      270 +                return;
      271 +
      272 +        if (!S_ISREG(file->st.st_mode)) {
      273 +                /*
      274 +                 * For FIFOs, we use PORT_SOURCE_FD as our port event source.
      275 +                 */
      276 +                if (assoc) {
      277 +                        (void) port_associate(port, PORT_SOURCE_FD,
      278 +                            fileno(file->fp), POLLIN, file);
      279 +                } else {
      280 +                        (void) port_dissociate(port, PORT_SOURCE_FD,
      281 +                            fileno(file->fp));
      282 +                }
      283 +
      284 +                return;
      285 +        }
      286 +
      287 +        bzero(&file->fobj, sizeof (file->fobj));
      288 +
      289 +        /*
      290 +         * We pull a bit of a stunt here.  PORT_SOURCE_FILE only allows us to
      291 +         * specify a file name -- not a file descriptor.  If we were to specify
      292 +         * the name of the file to port_associate() and that file were moved
      293 +         * aside, we would not be able to reassociate an event because we would
      294 +         * not know a name that would resolve to the new file (indeed, there
      295 +         * might not be such a name -- the file may have been unlinked).  But
      296 +         * there _is_ a name that we know maps to the file and doesn't change:
      297 +         * the name of the representation of the open file descriptor in /proc.
      298 +         * We therefore associate with this name (and the underlying file),
      299 +         * not the name of the file as specified at the command line.
      300 +         */
      301 +        (void) snprintf(buf,
      302 +            sizeof (buf), "/proc/self/fd/%d", fileno(file->fp));
      303 +
      304 +        /*
      305 +         * Note that portfs uses the address of the specified file_obj_t to
      306 +         * tag an association; if one creates a different association with a
      307 +         * (different) file_ob_t that happens to be at the same address,
      308 +         * the first association will be implicitly removed.  To assure that
      309 +         * each file has a disjoint file_obj_t, we allocate the memory for it
      310 +         * in the file_info, not on the stack.
      311 +         */
      312 +        file->fobj.fo_name = buf;
      313 +
      314 +        if (assoc) {
      315 +                (void) port_associate(port, PORT_SOURCE_FILE,
      316 +                    (uintptr_t)&file->fobj, FILE_MODIFIED | FILE_TRUNC, file);
      317 +        } else {
      318 +                (void) port_dissociate(port, PORT_SOURCE_FILE,
      319 +                    (uintptr_t)&file->fobj);
      320 +        }
      321 +}
      322 +
      323 +static void
 264  324  set_events(file_info_t *files)
 265  325  {
 266  326          int i;
 267  327          file_info_t *file;
 268  328  
 269  329          for (i = 0, file = files; i < no_files; i++, file++) {
 270  330                  if (! file->fp)
 271  331                          continue;
 272  332  
 273  333                  (void) fstat(fileno(file->fp), &file->st);
      334 +
      335 +                associate(file, B_TRUE);
 274  336          }
 275  337  }
 276  338  
 277  339  /*
 278  340   * follow -- display the file, from an offset, forward.
 279  341   *
 280  342   */
 281  343  void
 282  344  follow(file_info_t *files, enum STYLE style, off_t off)
 283  345  {
 284  346          int active, ev_change, i, n = -1;
 285  347          struct stat sb2;
 286  348          file_info_t *file;
      349 +        struct timespec ts;
      350 +        port_event_t ev;
 287  351  
 288  352          /* Position each of the files */
 289  353  
 290  354          file = files;
 291  355          active = 0;
 292  356          n = 0;
 293  357          for (i = 0; i < no_files; i++, file++) {
 294  358                  if (file->fp) {
 295  359                          active = 1;
 296  360                          n++;
↓ open down ↓ 3 lines elided ↑ open up ↑
 300  364                          forward(file->fp, file->file_name, style, off,
 301  365                              &file->st);
 302  366                          if (Fflag && fileno(file->fp) != STDIN_FILENO)
 303  367                                  n++;
 304  368                  }
 305  369          }
 306  370          if (!Fflag && !active)
 307  371                  return;
 308  372  
 309  373          last = --file;
      374 +
      375 +        if (action == USE_PORT &&
      376 +            (stat("/proc/self/fd", &sb2) == -1 || !S_ISDIR(sb2.st_mode) ||
      377 +            (port = port_create()) == -1))
      378 +                action = USE_SLEEP;
      379 +
 310  380          set_events(files);
 311  381  
 312  382          for (;;) {
 313  383                  ev_change = 0;
 314  384                  if (Fflag) {
 315  385                          for (i = 0, file = files; i < no_files; i++, file++) {
 316  386                                  if (!file->fp) {
 317  387                                          file->fp = fopen(file->file_name, "r");
 318  388                                          if (file->fp != NULL &&
 319  389                                              fstat(fileno(file->fp), &file->st)
↓ open down ↓ 14 lines elided ↑ open up ↑
 334  404                                          (void) fclose(file->fp);
 335  405                                          file->fp = NULL;
 336  406                                          ev_change++;
 337  407                                          continue;
 338  408                                  }
 339  409  
 340  410                                  if (sb2.st_ino != file->st.st_ino ||
 341  411                                      sb2.st_dev != file->st.st_dev ||
 342  412                                      sb2.st_nlink == 0) {
 343  413                                          (void) show(file);
      414 +                                        associate(file, B_FALSE);
 344  415                                          file->fp = freopen(file->file_name, "r",
 345  416                                              file->fp);
 346      -                                        if (file->fp != NULL)
      417 +                                        if (file->fp != NULL) {
 347  418                                                  (void) memcpy(&file->st, &sb2,
 348  419                                                      sizeof (struct stat));
 349      -                                        else if (errno != ENOENT)
      420 +                                        } else if (errno != ENOENT)
 350  421                                                  ierr(file->file_name);
 351  422                                          ev_change++;
 352  423                                  }
 353  424                          }
 354  425                  }
 355  426  
 356  427                  for (i = 0, file = files; i < no_files; i++, file++)
 357  428                          if (file->fp && !show(file))
 358  429                                  ev_change++;
 359  430  
 360  431                  if (ev_change)
 361  432                          set_events(files);
 362  433  
 363  434                  switch (action) {
      435 +                case USE_PORT:
      436 +                        ts.tv_sec = 1;
      437 +                        ts.tv_nsec = 0;
      438 +
      439 +                        /*
      440 +                         * In the -F case we set a timeout to ensure that
      441 +                         * we re-stat the file at least once every second.
      442 +                         */
      443 +                        n = port_get(port, &ev, Fflag ? &ts : NULL);
      444 +
      445 +                        if (n == 0) {
      446 +                                file = (file_info_t *)ev.portev_user;
      447 +                                associate(file, B_TRUE);
      448 +
      449 +                                if (ev.portev_events & FILE_TRUNC)
      450 +                                        (void) fseek(file->fp, 0, SEEK_SET);
      451 +                        }
      452 +
      453 +                        break;
      454 +
 364  455                  case USE_SLEEP:
 365  456                          (void) usleep(250000);
 366  457                          break;
 367  458                  }
 368  459          }
 369  460  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX