...

Source file src/github.com/coreos/go-systemd/v22/sdjournal/journal.go

Documentation: github.com/coreos/go-systemd/v22/sdjournal

     1  // Copyright 2015 RedHat, Inc.
     2  // Copyright 2015 CoreOS, Inc.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  // Package sdjournal provides a low-level Go interface to the
    17  // systemd journal wrapped around the sd-journal C API.
    18  //
    19  // All public read methods map closely to the sd-journal API functions. See the
    20  // sd-journal.h documentation[1] for information about each function.
    21  //
    22  // To write to the journal, see the pure-Go "journal" package
    23  //
    24  // [1] http://www.freedesktop.org/software/systemd/man/sd-journal.html
    25  package sdjournal
    26  
    27  // #include <systemd/sd-journal.h>
    28  // #include <systemd/sd-id128.h>
    29  // #include <stdlib.h>
    30  // #include <syslog.h>
    31  //
    32  // int
    33  // my_sd_journal_open(void *f, sd_journal **ret, int flags)
    34  // {
    35  //   int (*sd_journal_open)(sd_journal **, int);
    36  //
    37  //   sd_journal_open = f;
    38  //   return sd_journal_open(ret, flags);
    39  // }
    40  //
    41  // int
    42  // my_sd_journal_open_directory(void *f, sd_journal **ret, const char *path, int flags)
    43  // {
    44  //   int (*sd_journal_open_directory)(sd_journal **, const char *, int);
    45  //
    46  //   sd_journal_open_directory = f;
    47  //   return sd_journal_open_directory(ret, path, flags);
    48  // }
    49  //
    50  // int
    51  // my_sd_journal_open_files(void *f, sd_journal **ret, const char **paths, int flags)
    52  // {
    53  //   int (*sd_journal_open_files)(sd_journal **, const char **, int);
    54  //
    55  //   sd_journal_open_files = f;
    56  //   return sd_journal_open_files(ret, paths, flags);
    57  // }
    58  //
    59  // void
    60  // my_sd_journal_close(void *f, sd_journal *j)
    61  // {
    62  //   int (*sd_journal_close)(sd_journal *);
    63  //
    64  //   sd_journal_close = f;
    65  //   sd_journal_close(j);
    66  // }
    67  //
    68  // int
    69  // my_sd_journal_get_usage(void *f, sd_journal *j, uint64_t *bytes)
    70  // {
    71  //   int (*sd_journal_get_usage)(sd_journal *, uint64_t *);
    72  //
    73  //   sd_journal_get_usage = f;
    74  //   return sd_journal_get_usage(j, bytes);
    75  // }
    76  //
    77  // int
    78  // my_sd_journal_add_match(void *f, sd_journal *j, const void *data, size_t size)
    79  // {
    80  //   int (*sd_journal_add_match)(sd_journal *, const void *, size_t);
    81  //
    82  //   sd_journal_add_match = f;
    83  //   return sd_journal_add_match(j, data, size);
    84  // }
    85  //
    86  // int
    87  // my_sd_journal_add_disjunction(void *f, sd_journal *j)
    88  // {
    89  //   int (*sd_journal_add_disjunction)(sd_journal *);
    90  //
    91  //   sd_journal_add_disjunction = f;
    92  //   return sd_journal_add_disjunction(j);
    93  // }
    94  //
    95  // int
    96  // my_sd_journal_add_conjunction(void *f, sd_journal *j)
    97  // {
    98  //   int (*sd_journal_add_conjunction)(sd_journal *);
    99  //
   100  //   sd_journal_add_conjunction = f;
   101  //   return sd_journal_add_conjunction(j);
   102  // }
   103  //
   104  // void
   105  // my_sd_journal_flush_matches(void *f, sd_journal *j)
   106  // {
   107  //   int (*sd_journal_flush_matches)(sd_journal *);
   108  //
   109  //   sd_journal_flush_matches = f;
   110  //   sd_journal_flush_matches(j);
   111  // }
   112  //
   113  // int
   114  // my_sd_journal_next(void *f, sd_journal *j)
   115  // {
   116  //   int (*sd_journal_next)(sd_journal *);
   117  //
   118  //   sd_journal_next = f;
   119  //   return sd_journal_next(j);
   120  // }
   121  //
   122  // int
   123  // my_sd_journal_next_skip(void *f, sd_journal *j, uint64_t skip)
   124  // {
   125  //   int (*sd_journal_next_skip)(sd_journal *, uint64_t);
   126  //
   127  //   sd_journal_next_skip = f;
   128  //   return sd_journal_next_skip(j, skip);
   129  // }
   130  //
   131  // int
   132  // my_sd_journal_previous(void *f, sd_journal *j)
   133  // {
   134  //   int (*sd_journal_previous)(sd_journal *);
   135  //
   136  //   sd_journal_previous = f;
   137  //   return sd_journal_previous(j);
   138  // }
   139  //
   140  // int
   141  // my_sd_journal_previous_skip(void *f, sd_journal *j, uint64_t skip)
   142  // {
   143  //   int (*sd_journal_previous_skip)(sd_journal *, uint64_t);
   144  //
   145  //   sd_journal_previous_skip = f;
   146  //   return sd_journal_previous_skip(j, skip);
   147  // }
   148  //
   149  // int
   150  // my_sd_journal_get_data(void *f, sd_journal *j, const char *field, const void **data, size_t *length)
   151  // {
   152  //   int (*sd_journal_get_data)(sd_journal *, const char *, const void **, size_t *);
   153  //
   154  //   sd_journal_get_data = f;
   155  //   return sd_journal_get_data(j, field, data, length);
   156  // }
   157  //
   158  // int
   159  // my_sd_journal_set_data_threshold(void *f, sd_journal *j, size_t sz)
   160  // {
   161  //   int (*sd_journal_set_data_threshold)(sd_journal *, size_t);
   162  //
   163  //   sd_journal_set_data_threshold = f;
   164  //   return sd_journal_set_data_threshold(j, sz);
   165  // }
   166  //
   167  // int
   168  // my_sd_journal_get_cursor(void *f, sd_journal *j, char **cursor)
   169  // {
   170  //   int (*sd_journal_get_cursor)(sd_journal *, char **);
   171  //
   172  //   sd_journal_get_cursor = f;
   173  //   return sd_journal_get_cursor(j, cursor);
   174  // }
   175  //
   176  // int
   177  // my_sd_journal_test_cursor(void *f, sd_journal *j, const char *cursor)
   178  // {
   179  //   int (*sd_journal_test_cursor)(sd_journal *, const char *);
   180  //
   181  //   sd_journal_test_cursor = f;
   182  //   return sd_journal_test_cursor(j, cursor);
   183  // }
   184  //
   185  // int
   186  // my_sd_journal_get_realtime_usec(void *f, sd_journal *j, uint64_t *usec)
   187  // {
   188  //   int (*sd_journal_get_realtime_usec)(sd_journal *, uint64_t *);
   189  //
   190  //   sd_journal_get_realtime_usec = f;
   191  //   return sd_journal_get_realtime_usec(j, usec);
   192  // }
   193  //
   194  // int
   195  // my_sd_journal_get_monotonic_usec(void *f, sd_journal *j, uint64_t *usec, sd_id128_t *boot_id)
   196  // {
   197  //   int (*sd_journal_get_monotonic_usec)(sd_journal *, uint64_t *, sd_id128_t *);
   198  //
   199  //   sd_journal_get_monotonic_usec = f;
   200  //   return sd_journal_get_monotonic_usec(j, usec, boot_id);
   201  // }
   202  //
   203  // int
   204  // my_sd_journal_seek_head(void *f, sd_journal *j)
   205  // {
   206  //   int (*sd_journal_seek_head)(sd_journal *);
   207  //
   208  //   sd_journal_seek_head = f;
   209  //   return sd_journal_seek_head(j);
   210  // }
   211  //
   212  // int
   213  // my_sd_journal_seek_tail(void *f, sd_journal *j)
   214  // {
   215  //   int (*sd_journal_seek_tail)(sd_journal *);
   216  //
   217  //   sd_journal_seek_tail = f;
   218  //   return sd_journal_seek_tail(j);
   219  // }
   220  //
   221  //
   222  // int
   223  // my_sd_journal_seek_cursor(void *f, sd_journal *j, const char *cursor)
   224  // {
   225  //   int (*sd_journal_seek_cursor)(sd_journal *, const char *);
   226  //
   227  //   sd_journal_seek_cursor = f;
   228  //   return sd_journal_seek_cursor(j, cursor);
   229  // }
   230  //
   231  // int
   232  // my_sd_journal_seek_realtime_usec(void *f, sd_journal *j, uint64_t usec)
   233  // {
   234  //   int (*sd_journal_seek_realtime_usec)(sd_journal *, uint64_t);
   235  //
   236  //   sd_journal_seek_realtime_usec = f;
   237  //   return sd_journal_seek_realtime_usec(j, usec);
   238  // }
   239  //
   240  // int
   241  // my_sd_journal_wait(void *f, sd_journal *j, uint64_t timeout_usec)
   242  // {
   243  //   int (*sd_journal_wait)(sd_journal *, uint64_t);
   244  //
   245  //   sd_journal_wait = f;
   246  //   return sd_journal_wait(j, timeout_usec);
   247  // }
   248  //
   249  // void
   250  // my_sd_journal_restart_data(void *f, sd_journal *j)
   251  // {
   252  //   void (*sd_journal_restart_data)(sd_journal *);
   253  //
   254  //   sd_journal_restart_data = f;
   255  //   sd_journal_restart_data(j);
   256  // }
   257  //
   258  // int
   259  // my_sd_journal_enumerate_data(void *f, sd_journal *j, const void **data, size_t *length)
   260  // {
   261  //   int (*sd_journal_enumerate_data)(sd_journal *, const void **, size_t *);
   262  //
   263  //   sd_journal_enumerate_data = f;
   264  //   return sd_journal_enumerate_data(j, data, length);
   265  // }
   266  //
   267  // int
   268  // my_sd_journal_query_unique(void *f, sd_journal *j, const char *field)
   269  // {
   270  //   int(*sd_journal_query_unique)(sd_journal *, const char *);
   271  //
   272  //   sd_journal_query_unique = f;
   273  //   return sd_journal_query_unique(j, field);
   274  // }
   275  //
   276  // int
   277  // my_sd_journal_enumerate_unique(void *f, sd_journal *j, const void **data, size_t *length)
   278  // {
   279  //   int(*sd_journal_enumerate_unique)(sd_journal *, const void **, size_t *);
   280  //
   281  //   sd_journal_enumerate_unique = f;
   282  //   return sd_journal_enumerate_unique(j, data, length);
   283  // }
   284  //
   285  // void
   286  // my_sd_journal_restart_unique(void *f, sd_journal *j)
   287  // {
   288  //   void(*sd_journal_restart_unique)(sd_journal *);
   289  //
   290  //   sd_journal_restart_unique = f;
   291  //   sd_journal_restart_unique(j);
   292  // }
   293  //
   294  // int
   295  // my_sd_journal_get_catalog(void *f, sd_journal *j, char **ret)
   296  // {
   297  //   int(*sd_journal_get_catalog)(sd_journal *, char **);
   298  //
   299  //   sd_journal_get_catalog = f;
   300  //   return sd_journal_get_catalog(j, ret);
   301  // }
   302  //
   303  // int
   304  // my_sd_id128_get_boot(void *f, sd_id128_t *boot_id)
   305  // {
   306  //   int(*sd_id128_get_boot)(sd_id128_t *);
   307  //
   308  //   sd_id128_get_boot = f;
   309  //   return sd_id128_get_boot(boot_id);
   310  // }
   311  //
   312  // char *
   313  // my_sd_id128_to_string(void *f, sd_id128_t boot_id, char s[SD_ID128_STRING_MAX])
   314  // {
   315  //   char *(*sd_id128_to_string)(sd_id128_t, char *);
   316  //
   317  //   sd_id128_to_string = f;
   318  //   return sd_id128_to_string(boot_id, s);
   319  // }
   320  //
   321  import "C"
   322  import (
   323  	"bytes"
   324  	"errors"
   325  	"fmt"
   326  	"strings"
   327  	"sync"
   328  	"syscall"
   329  	"time"
   330  	"unsafe"
   331  )
   332  
   333  // Journal entry field strings which correspond to:
   334  // http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html
   335  const (
   336  	// User Journal Fields
   337  	SD_JOURNAL_FIELD_MESSAGE           = "MESSAGE"
   338  	SD_JOURNAL_FIELD_MESSAGE_ID        = "MESSAGE_ID"
   339  	SD_JOURNAL_FIELD_PRIORITY          = "PRIORITY"
   340  	SD_JOURNAL_FIELD_CODE_FILE         = "CODE_FILE"
   341  	SD_JOURNAL_FIELD_CODE_LINE         = "CODE_LINE"
   342  	SD_JOURNAL_FIELD_CODE_FUNC         = "CODE_FUNC"
   343  	SD_JOURNAL_FIELD_ERRNO             = "ERRNO"
   344  	SD_JOURNAL_FIELD_SYSLOG_FACILITY   = "SYSLOG_FACILITY"
   345  	SD_JOURNAL_FIELD_SYSLOG_IDENTIFIER = "SYSLOG_IDENTIFIER"
   346  	SD_JOURNAL_FIELD_SYSLOG_PID        = "SYSLOG_PID"
   347  
   348  	// Trusted Journal Fields
   349  	SD_JOURNAL_FIELD_PID                       = "_PID"
   350  	SD_JOURNAL_FIELD_UID                       = "_UID"
   351  	SD_JOURNAL_FIELD_GID                       = "_GID"
   352  	SD_JOURNAL_FIELD_COMM                      = "_COMM"
   353  	SD_JOURNAL_FIELD_EXE                       = "_EXE"
   354  	SD_JOURNAL_FIELD_CMDLINE                   = "_CMDLINE"
   355  	SD_JOURNAL_FIELD_CAP_EFFECTIVE             = "_CAP_EFFECTIVE"
   356  	SD_JOURNAL_FIELD_AUDIT_SESSION             = "_AUDIT_SESSION"
   357  	SD_JOURNAL_FIELD_AUDIT_LOGINUID            = "_AUDIT_LOGINUID"
   358  	SD_JOURNAL_FIELD_SYSTEMD_CGROUP            = "_SYSTEMD_CGROUP"
   359  	SD_JOURNAL_FIELD_SYSTEMD_SESSION           = "_SYSTEMD_SESSION"
   360  	SD_JOURNAL_FIELD_SYSTEMD_UNIT              = "_SYSTEMD_UNIT"
   361  	SD_JOURNAL_FIELD_SYSTEMD_USER_UNIT         = "_SYSTEMD_USER_UNIT"
   362  	SD_JOURNAL_FIELD_SYSTEMD_OWNER_UID         = "_SYSTEMD_OWNER_UID"
   363  	SD_JOURNAL_FIELD_SYSTEMD_SLICE             = "_SYSTEMD_SLICE"
   364  	SD_JOURNAL_FIELD_SELINUX_CONTEXT           = "_SELINUX_CONTEXT"
   365  	SD_JOURNAL_FIELD_SOURCE_REALTIME_TIMESTAMP = "_SOURCE_REALTIME_TIMESTAMP"
   366  	SD_JOURNAL_FIELD_BOOT_ID                   = "_BOOT_ID"
   367  	SD_JOURNAL_FIELD_MACHINE_ID                = "_MACHINE_ID"
   368  	SD_JOURNAL_FIELD_HOSTNAME                  = "_HOSTNAME"
   369  	SD_JOURNAL_FIELD_TRANSPORT                 = "_TRANSPORT"
   370  
   371  	// Address Fields
   372  	SD_JOURNAL_FIELD_CURSOR              = "__CURSOR"
   373  	SD_JOURNAL_FIELD_REALTIME_TIMESTAMP  = "__REALTIME_TIMESTAMP"
   374  	SD_JOURNAL_FIELD_MONOTONIC_TIMESTAMP = "__MONOTONIC_TIMESTAMP"
   375  )
   376  
   377  // Journal event constants
   378  const (
   379  	SD_JOURNAL_NOP        = int(C.SD_JOURNAL_NOP)
   380  	SD_JOURNAL_APPEND     = int(C.SD_JOURNAL_APPEND)
   381  	SD_JOURNAL_INVALIDATE = int(C.SD_JOURNAL_INVALIDATE)
   382  )
   383  
   384  const (
   385  	// IndefiniteWait is a sentinel value that can be passed to
   386  	// sdjournal.Wait() to signal an indefinite wait for new journal
   387  	// events. It is implemented as the maximum value for a time.Duration:
   388  	// https://github.com/golang/go/blob/e4dcf5c8c22d98ac9eac7b9b226596229624cb1d/src/time/time.go#L434
   389  	IndefiniteWait time.Duration = 1<<63 - 1
   390  )
   391  
   392  var (
   393  	// ErrNoTestCursor gets returned when using TestCursor function and cursor
   394  	// parameter is not the same as the current cursor position.
   395  	ErrNoTestCursor = errors.New("Cursor parameter is not the same as current position")
   396  )
   397  
   398  // Journal is a Go wrapper of an sd_journal structure.
   399  type Journal struct {
   400  	cjournal *C.sd_journal
   401  	mu       sync.Mutex
   402  }
   403  
   404  // JournalEntry represents all fields of a journal entry plus address fields.
   405  type JournalEntry struct {
   406  	Fields             map[string]string
   407  	Cursor             string
   408  	RealtimeTimestamp  uint64
   409  	MonotonicTimestamp uint64
   410  }
   411  
   412  // Match is a convenience wrapper to describe filters supplied to AddMatch.
   413  type Match struct {
   414  	Field string
   415  	Value string
   416  }
   417  
   418  // String returns a string representation of a Match suitable for use with AddMatch.
   419  func (m *Match) String() string {
   420  	return m.Field + "=" + m.Value
   421  }
   422  
   423  // NewJournal returns a new Journal instance pointing to the local journal
   424  func NewJournal() (j *Journal, err error) {
   425  	j = &Journal{}
   426  
   427  	sd_journal_open, err := getFunction("sd_journal_open")
   428  	if err != nil {
   429  		return nil, err
   430  	}
   431  
   432  	r := C.my_sd_journal_open(sd_journal_open, &j.cjournal, C.SD_JOURNAL_LOCAL_ONLY)
   433  
   434  	if r < 0 {
   435  		return nil, fmt.Errorf("failed to open journal: %s", syscall.Errno(-r).Error())
   436  	}
   437  
   438  	return j, nil
   439  }
   440  
   441  // NewJournalFromDir returns a new Journal instance pointing to a journal residing
   442  // in a given directory.
   443  func NewJournalFromDir(path string) (j *Journal, err error) {
   444  	j = &Journal{}
   445  
   446  	sd_journal_open_directory, err := getFunction("sd_journal_open_directory")
   447  	if err != nil {
   448  		return nil, err
   449  	}
   450  
   451  	p := C.CString(path)
   452  	defer C.free(unsafe.Pointer(p))
   453  
   454  	r := C.my_sd_journal_open_directory(sd_journal_open_directory, &j.cjournal, p, 0)
   455  	if r < 0 {
   456  		return nil, fmt.Errorf("failed to open journal in directory %q: %s", path, syscall.Errno(-r).Error())
   457  	}
   458  
   459  	return j, nil
   460  }
   461  
   462  // NewJournalFromFiles returns a new Journal instance pointing to a journals residing
   463  // in a given files.
   464  func NewJournalFromFiles(paths ...string) (j *Journal, err error) {
   465  	j = &Journal{}
   466  
   467  	sd_journal_open_files, err := getFunction("sd_journal_open_files")
   468  	if err != nil {
   469  		return nil, err
   470  	}
   471  
   472  	// by making the slice 1 elem too long, we guarantee it'll be null-terminated
   473  	cPaths := make([]*C.char, len(paths)+1)
   474  	for idx, path := range paths {
   475  		p := C.CString(path)
   476  		cPaths[idx] = p
   477  		defer C.free(unsafe.Pointer(p))
   478  	}
   479  
   480  	r := C.my_sd_journal_open_files(sd_journal_open_files, &j.cjournal, &cPaths[0], 0)
   481  	if r < 0 {
   482  		return nil, fmt.Errorf("failed to open journals in paths %q: %s", paths, syscall.Errno(-r).Error())
   483  	}
   484  
   485  	return j, nil
   486  }
   487  
   488  // Close closes a journal opened with NewJournal.
   489  func (j *Journal) Close() error {
   490  	sd_journal_close, err := getFunction("sd_journal_close")
   491  	if err != nil {
   492  		return err
   493  	}
   494  
   495  	j.mu.Lock()
   496  	C.my_sd_journal_close(sd_journal_close, j.cjournal)
   497  	j.mu.Unlock()
   498  
   499  	return nil
   500  }
   501  
   502  // AddMatch adds a match by which to filter the entries of the journal.
   503  func (j *Journal) AddMatch(match string) error {
   504  	sd_journal_add_match, err := getFunction("sd_journal_add_match")
   505  	if err != nil {
   506  		return err
   507  	}
   508  
   509  	m := C.CString(match)
   510  	defer C.free(unsafe.Pointer(m))
   511  
   512  	j.mu.Lock()
   513  	r := C.my_sd_journal_add_match(sd_journal_add_match, j.cjournal, unsafe.Pointer(m), C.size_t(len(match)))
   514  	j.mu.Unlock()
   515  
   516  	if r < 0 {
   517  		return fmt.Errorf("failed to add match: %s", syscall.Errno(-r).Error())
   518  	}
   519  
   520  	return nil
   521  }
   522  
   523  // AddDisjunction inserts a logical OR in the match list.
   524  func (j *Journal) AddDisjunction() error {
   525  	sd_journal_add_disjunction, err := getFunction("sd_journal_add_disjunction")
   526  	if err != nil {
   527  		return err
   528  	}
   529  
   530  	j.mu.Lock()
   531  	r := C.my_sd_journal_add_disjunction(sd_journal_add_disjunction, j.cjournal)
   532  	j.mu.Unlock()
   533  
   534  	if r < 0 {
   535  		return fmt.Errorf("failed to add a disjunction in the match list: %s", syscall.Errno(-r).Error())
   536  	}
   537  
   538  	return nil
   539  }
   540  
   541  // AddConjunction inserts a logical AND in the match list.
   542  func (j *Journal) AddConjunction() error {
   543  	sd_journal_add_conjunction, err := getFunction("sd_journal_add_conjunction")
   544  	if err != nil {
   545  		return err
   546  	}
   547  
   548  	j.mu.Lock()
   549  	r := C.my_sd_journal_add_conjunction(sd_journal_add_conjunction, j.cjournal)
   550  	j.mu.Unlock()
   551  
   552  	if r < 0 {
   553  		return fmt.Errorf("failed to add a conjunction in the match list: %s", syscall.Errno(-r).Error())
   554  	}
   555  
   556  	return nil
   557  }
   558  
   559  // FlushMatches flushes all matches, disjunctions and conjunctions.
   560  func (j *Journal) FlushMatches() {
   561  	sd_journal_flush_matches, err := getFunction("sd_journal_flush_matches")
   562  	if err != nil {
   563  		return
   564  	}
   565  
   566  	j.mu.Lock()
   567  	C.my_sd_journal_flush_matches(sd_journal_flush_matches, j.cjournal)
   568  	j.mu.Unlock()
   569  }
   570  
   571  // Next advances the read pointer into the journal by one entry.
   572  func (j *Journal) Next() (uint64, error) {
   573  	sd_journal_next, err := getFunction("sd_journal_next")
   574  	if err != nil {
   575  		return 0, err
   576  	}
   577  
   578  	j.mu.Lock()
   579  	r := C.my_sd_journal_next(sd_journal_next, j.cjournal)
   580  	j.mu.Unlock()
   581  
   582  	if r < 0 {
   583  		return 0, fmt.Errorf("failed to iterate journal: %s", syscall.Errno(-r).Error())
   584  	}
   585  
   586  	return uint64(r), nil
   587  }
   588  
   589  // NextSkip advances the read pointer by multiple entries at once,
   590  // as specified by the skip parameter.
   591  func (j *Journal) NextSkip(skip uint64) (uint64, error) {
   592  	sd_journal_next_skip, err := getFunction("sd_journal_next_skip")
   593  	if err != nil {
   594  		return 0, err
   595  	}
   596  
   597  	j.mu.Lock()
   598  	r := C.my_sd_journal_next_skip(sd_journal_next_skip, j.cjournal, C.uint64_t(skip))
   599  	j.mu.Unlock()
   600  
   601  	if r < 0 {
   602  		return 0, fmt.Errorf("failed to iterate journal: %s", syscall.Errno(-r).Error())
   603  	}
   604  
   605  	return uint64(r), nil
   606  }
   607  
   608  // Previous sets the read pointer into the journal back by one entry.
   609  func (j *Journal) Previous() (uint64, error) {
   610  	sd_journal_previous, err := getFunction("sd_journal_previous")
   611  	if err != nil {
   612  		return 0, err
   613  	}
   614  
   615  	j.mu.Lock()
   616  	r := C.my_sd_journal_previous(sd_journal_previous, j.cjournal)
   617  	j.mu.Unlock()
   618  
   619  	if r < 0 {
   620  		return 0, fmt.Errorf("failed to iterate journal: %s", syscall.Errno(-r).Error())
   621  	}
   622  
   623  	return uint64(r), nil
   624  }
   625  
   626  // PreviousSkip sets back the read pointer by multiple entries at once,
   627  // as specified by the skip parameter.
   628  func (j *Journal) PreviousSkip(skip uint64) (uint64, error) {
   629  	sd_journal_previous_skip, err := getFunction("sd_journal_previous_skip")
   630  	if err != nil {
   631  		return 0, err
   632  	}
   633  
   634  	j.mu.Lock()
   635  	r := C.my_sd_journal_previous_skip(sd_journal_previous_skip, j.cjournal, C.uint64_t(skip))
   636  	j.mu.Unlock()
   637  
   638  	if r < 0 {
   639  		return 0, fmt.Errorf("failed to iterate journal: %s", syscall.Errno(-r).Error())
   640  	}
   641  
   642  	return uint64(r), nil
   643  }
   644  
   645  func (j *Journal) getData(field string) (unsafe.Pointer, C.int, error) {
   646  	sd_journal_get_data, err := getFunction("sd_journal_get_data")
   647  	if err != nil {
   648  		return nil, 0, err
   649  	}
   650  
   651  	f := C.CString(field)
   652  	defer C.free(unsafe.Pointer(f))
   653  
   654  	var d unsafe.Pointer
   655  	var l C.size_t
   656  
   657  	j.mu.Lock()
   658  	r := C.my_sd_journal_get_data(sd_journal_get_data, j.cjournal, f, &d, &l)
   659  	j.mu.Unlock()
   660  
   661  	if r < 0 {
   662  		return nil, 0, fmt.Errorf("failed to read message: %s", syscall.Errno(-r).Error())
   663  	}
   664  
   665  	return d, C.int(l), nil
   666  }
   667  
   668  // GetData gets the data object associated with a specific field from the
   669  // the journal entry referenced by the last completed Next/Previous function
   670  // call. To call GetData, you must have first called one of these functions.
   671  func (j *Journal) GetData(field string) (string, error) {
   672  	d, l, err := j.getData(field)
   673  	if err != nil {
   674  		return "", err
   675  	}
   676  
   677  	return C.GoStringN((*C.char)(d), l), nil
   678  }
   679  
   680  // GetDataValue gets the data object associated with a specific field from the
   681  // journal entry referenced by the last completed Next/Previous function call,
   682  // returning only the value of the object. To call GetDataValue, you must first
   683  // have called one of the Next/Previous functions.
   684  func (j *Journal) GetDataValue(field string) (string, error) {
   685  	val, err := j.GetData(field)
   686  	if err != nil {
   687  		return "", err
   688  	}
   689  
   690  	return strings.SplitN(val, "=", 2)[1], nil
   691  }
   692  
   693  // GetDataBytes gets the data object associated with a specific field from the
   694  // journal entry referenced by the last completed Next/Previous function call.
   695  // To call GetDataBytes, you must first have called one of these functions.
   696  func (j *Journal) GetDataBytes(field string) ([]byte, error) {
   697  	d, l, err := j.getData(field)
   698  	if err != nil {
   699  		return nil, err
   700  	}
   701  
   702  	return C.GoBytes(d, l), nil
   703  }
   704  
   705  // GetDataValueBytes gets the data object associated with a specific field from the
   706  // journal entry referenced by the last completed Next/Previous function call,
   707  // returning only the value of the object. To call GetDataValueBytes, you must first
   708  // have called one of the Next/Previous functions.
   709  func (j *Journal) GetDataValueBytes(field string) ([]byte, error) {
   710  	val, err := j.GetDataBytes(field)
   711  	if err != nil {
   712  		return nil, err
   713  	}
   714  
   715  	return bytes.SplitN(val, []byte("="), 2)[1], nil
   716  }
   717  
   718  // GetEntry returns a full representation of the journal entry referenced by the
   719  // last completed Next/Previous function call, with all key-value pairs of data
   720  // as well as address fields (cursor, realtime timestamp and monotonic timestamp).
   721  // To call GetEntry, you must first have called one of the Next/Previous functions.
   722  func (j *Journal) GetEntry() (*JournalEntry, error) {
   723  	sd_journal_get_realtime_usec, err := getFunction("sd_journal_get_realtime_usec")
   724  	if err != nil {
   725  		return nil, err
   726  	}
   727  
   728  	sd_journal_get_monotonic_usec, err := getFunction("sd_journal_get_monotonic_usec")
   729  	if err != nil {
   730  		return nil, err
   731  	}
   732  
   733  	sd_journal_get_cursor, err := getFunction("sd_journal_get_cursor")
   734  	if err != nil {
   735  		return nil, err
   736  	}
   737  
   738  	sd_journal_restart_data, err := getFunction("sd_journal_restart_data")
   739  	if err != nil {
   740  		return nil, err
   741  	}
   742  
   743  	sd_journal_enumerate_data, err := getFunction("sd_journal_enumerate_data")
   744  	if err != nil {
   745  		return nil, err
   746  	}
   747  
   748  	j.mu.Lock()
   749  	defer j.mu.Unlock()
   750  
   751  	var r C.int
   752  	entry := &JournalEntry{Fields: make(map[string]string)}
   753  
   754  	var realtimeUsec C.uint64_t
   755  	r = C.my_sd_journal_get_realtime_usec(sd_journal_get_realtime_usec, j.cjournal, &realtimeUsec)
   756  	if r < 0 {
   757  		return nil, fmt.Errorf("failed to get realtime timestamp: %s", syscall.Errno(-r).Error())
   758  	}
   759  
   760  	entry.RealtimeTimestamp = uint64(realtimeUsec)
   761  
   762  	var monotonicUsec C.uint64_t
   763  	var boot_id C.sd_id128_t
   764  
   765  	r = C.my_sd_journal_get_monotonic_usec(sd_journal_get_monotonic_usec, j.cjournal, &monotonicUsec, &boot_id)
   766  	if r < 0 {
   767  		return nil, fmt.Errorf("failed to get monotonic timestamp: %s", syscall.Errno(-r).Error())
   768  	}
   769  
   770  	entry.MonotonicTimestamp = uint64(monotonicUsec)
   771  
   772  	var c *C.char
   773  	// since the pointer is mutated by sd_journal_get_cursor, need to wait
   774  	// until after the call to free the memory
   775  	r = C.my_sd_journal_get_cursor(sd_journal_get_cursor, j.cjournal, &c)
   776  	defer C.free(unsafe.Pointer(c))
   777  	if r < 0 {
   778  		return nil, fmt.Errorf("failed to get cursor: %s", syscall.Errno(-r).Error())
   779  	}
   780  
   781  	entry.Cursor = C.GoString(c)
   782  
   783  	// Implements the JOURNAL_FOREACH_DATA_RETVAL macro from journal-internal.h
   784  	var d unsafe.Pointer
   785  	var l C.size_t
   786  	C.my_sd_journal_restart_data(sd_journal_restart_data, j.cjournal)
   787  	for {
   788  		r = C.my_sd_journal_enumerate_data(sd_journal_enumerate_data, j.cjournal, &d, &l)
   789  		if r == 0 {
   790  			break
   791  		}
   792  
   793  		if r < 0 {
   794  			return nil, fmt.Errorf("failed to read message field: %s", syscall.Errno(-r).Error())
   795  		}
   796  
   797  		msg := C.GoStringN((*C.char)(d), C.int(l))
   798  		kv := strings.SplitN(msg, "=", 2)
   799  		if len(kv) < 2 {
   800  			return nil, fmt.Errorf("failed to parse field")
   801  		}
   802  
   803  		entry.Fields[kv[0]] = kv[1]
   804  	}
   805  
   806  	return entry, nil
   807  }
   808  
   809  // SetDataThreshold sets the data field size threshold for data returned by
   810  // GetData. To retrieve the complete data fields this threshold should be
   811  // turned off by setting it to 0, so that the library always returns the
   812  // complete data objects.
   813  func (j *Journal) SetDataThreshold(threshold uint64) error {
   814  	sd_journal_set_data_threshold, err := getFunction("sd_journal_set_data_threshold")
   815  	if err != nil {
   816  		return err
   817  	}
   818  
   819  	j.mu.Lock()
   820  	r := C.my_sd_journal_set_data_threshold(sd_journal_set_data_threshold, j.cjournal, C.size_t(threshold))
   821  	j.mu.Unlock()
   822  
   823  	if r < 0 {
   824  		return fmt.Errorf("failed to set data threshold: %s", syscall.Errno(-r).Error())
   825  	}
   826  
   827  	return nil
   828  }
   829  
   830  // GetRealtimeUsec gets the realtime (wallclock) timestamp of the journal
   831  // entry referenced by the last completed Next/Previous function call. To
   832  // call GetRealtimeUsec, you must first have called one of the Next/Previous
   833  // functions.
   834  func (j *Journal) GetRealtimeUsec() (uint64, error) {
   835  	var usec C.uint64_t
   836  
   837  	sd_journal_get_realtime_usec, err := getFunction("sd_journal_get_realtime_usec")
   838  	if err != nil {
   839  		return 0, err
   840  	}
   841  
   842  	j.mu.Lock()
   843  	r := C.my_sd_journal_get_realtime_usec(sd_journal_get_realtime_usec, j.cjournal, &usec)
   844  	j.mu.Unlock()
   845  
   846  	if r < 0 {
   847  		return 0, fmt.Errorf("failed to get realtime timestamp: %s", syscall.Errno(-r).Error())
   848  	}
   849  
   850  	return uint64(usec), nil
   851  }
   852  
   853  // GetMonotonicUsec gets the monotonic timestamp of the journal entry
   854  // referenced by the last completed Next/Previous function call. To call
   855  // GetMonotonicUsec, you must first have called one of the Next/Previous
   856  // functions.
   857  func (j *Journal) GetMonotonicUsec() (uint64, error) {
   858  	var usec C.uint64_t
   859  	var boot_id C.sd_id128_t
   860  
   861  	sd_journal_get_monotonic_usec, err := getFunction("sd_journal_get_monotonic_usec")
   862  	if err != nil {
   863  		return 0, err
   864  	}
   865  
   866  	j.mu.Lock()
   867  	r := C.my_sd_journal_get_monotonic_usec(sd_journal_get_monotonic_usec, j.cjournal, &usec, &boot_id)
   868  	j.mu.Unlock()
   869  
   870  	if r < 0 {
   871  		return 0, fmt.Errorf("failed to get monotonic timestamp: %s", syscall.Errno(-r).Error())
   872  	}
   873  
   874  	return uint64(usec), nil
   875  }
   876  
   877  // GetCursor gets the cursor of the last journal entry reeferenced by the
   878  // last completed Next/Previous function call. To call GetCursor, you must
   879  // first have called one of the Next/Previous functions.
   880  func (j *Journal) GetCursor() (string, error) {
   881  	sd_journal_get_cursor, err := getFunction("sd_journal_get_cursor")
   882  	if err != nil {
   883  		return "", err
   884  	}
   885  
   886  	var d *C.char
   887  	// since the pointer is mutated by sd_journal_get_cursor, need to wait
   888  	// until after the call to free the memory
   889  
   890  	j.mu.Lock()
   891  	r := C.my_sd_journal_get_cursor(sd_journal_get_cursor, j.cjournal, &d)
   892  	j.mu.Unlock()
   893  	defer C.free(unsafe.Pointer(d))
   894  
   895  	if r < 0 {
   896  		return "", fmt.Errorf("failed to get cursor: %s", syscall.Errno(-r).Error())
   897  	}
   898  
   899  	cursor := C.GoString(d)
   900  
   901  	return cursor, nil
   902  }
   903  
   904  // TestCursor checks whether the current position in the journal matches the
   905  // specified cursor
   906  func (j *Journal) TestCursor(cursor string) error {
   907  	sd_journal_test_cursor, err := getFunction("sd_journal_test_cursor")
   908  	if err != nil {
   909  		return err
   910  	}
   911  
   912  	c := C.CString(cursor)
   913  	defer C.free(unsafe.Pointer(c))
   914  
   915  	j.mu.Lock()
   916  	r := C.my_sd_journal_test_cursor(sd_journal_test_cursor, j.cjournal, c)
   917  	j.mu.Unlock()
   918  
   919  	if r < 0 {
   920  		return fmt.Errorf("failed to test to cursor %q: %s", cursor, syscall.Errno(-r).Error())
   921  	} else if r == 0 {
   922  		return ErrNoTestCursor
   923  	}
   924  
   925  	return nil
   926  }
   927  
   928  // SeekHead seeks to the beginning of the journal, i.e. the oldest available
   929  // entry. This call must be followed by a call to Next before any call to
   930  // Get* will return data about the first element.
   931  func (j *Journal) SeekHead() error {
   932  	sd_journal_seek_head, err := getFunction("sd_journal_seek_head")
   933  	if err != nil {
   934  		return err
   935  	}
   936  
   937  	j.mu.Lock()
   938  	r := C.my_sd_journal_seek_head(sd_journal_seek_head, j.cjournal)
   939  	j.mu.Unlock()
   940  
   941  	if r < 0 {
   942  		return fmt.Errorf("failed to seek to head of journal: %s", syscall.Errno(-r).Error())
   943  	}
   944  
   945  	return nil
   946  }
   947  
   948  // SeekTail may be used to seek to the end of the journal, i.e. the most recent
   949  // available entry. This call must be followed by a call to Previous before any
   950  // call to Get* will return data about the last element.
   951  func (j *Journal) SeekTail() error {
   952  	sd_journal_seek_tail, err := getFunction("sd_journal_seek_tail")
   953  	if err != nil {
   954  		return err
   955  	}
   956  
   957  	j.mu.Lock()
   958  	r := C.my_sd_journal_seek_tail(sd_journal_seek_tail, j.cjournal)
   959  	j.mu.Unlock()
   960  
   961  	if r < 0 {
   962  		return fmt.Errorf("failed to seek to tail of journal: %s", syscall.Errno(-r).Error())
   963  	}
   964  
   965  	return nil
   966  }
   967  
   968  // SeekRealtimeUsec seeks to the entry with the specified realtime (wallclock)
   969  // timestamp, i.e. CLOCK_REALTIME. This call must be followed by a call to
   970  // Next/Previous before any call to Get* will return data about the sought entry.
   971  func (j *Journal) SeekRealtimeUsec(usec uint64) error {
   972  	sd_journal_seek_realtime_usec, err := getFunction("sd_journal_seek_realtime_usec")
   973  	if err != nil {
   974  		return err
   975  	}
   976  
   977  	j.mu.Lock()
   978  	r := C.my_sd_journal_seek_realtime_usec(sd_journal_seek_realtime_usec, j.cjournal, C.uint64_t(usec))
   979  	j.mu.Unlock()
   980  
   981  	if r < 0 {
   982  		return fmt.Errorf("failed to seek to %d: %s", usec, syscall.Errno(-r).Error())
   983  	}
   984  
   985  	return nil
   986  }
   987  
   988  // SeekCursor seeks to a concrete journal cursor. This call must be
   989  // followed by a call to Next/Previous before any call to Get* will return
   990  // data about the sought entry.
   991  func (j *Journal) SeekCursor(cursor string) error {
   992  	sd_journal_seek_cursor, err := getFunction("sd_journal_seek_cursor")
   993  	if err != nil {
   994  		return err
   995  	}
   996  
   997  	c := C.CString(cursor)
   998  	defer C.free(unsafe.Pointer(c))
   999  
  1000  	j.mu.Lock()
  1001  	r := C.my_sd_journal_seek_cursor(sd_journal_seek_cursor, j.cjournal, c)
  1002  	j.mu.Unlock()
  1003  
  1004  	if r < 0 {
  1005  		return fmt.Errorf("failed to seek to cursor %q: %s", cursor, syscall.Errno(-r).Error())
  1006  	}
  1007  
  1008  	return nil
  1009  }
  1010  
  1011  // Wait will synchronously wait until the journal gets changed. The maximum time
  1012  // this call sleeps may be controlled with the timeout parameter.  If
  1013  // sdjournal.IndefiniteWait is passed as the timeout parameter, Wait will
  1014  // wait indefinitely for a journal change.
  1015  func (j *Journal) Wait(timeout time.Duration) int {
  1016  	var to uint64
  1017  
  1018  	sd_journal_wait, err := getFunction("sd_journal_wait")
  1019  	if err != nil {
  1020  		return -1
  1021  	}
  1022  
  1023  	if timeout == IndefiniteWait {
  1024  		// sd_journal_wait(3) calls for a (uint64_t) -1 to be passed to signify
  1025  		// indefinite wait, but using a -1 overflows our C.uint64_t, so we use an
  1026  		// equivalent hex value.
  1027  		to = 0xffffffffffffffff
  1028  	} else {
  1029  		to = uint64(timeout / time.Microsecond)
  1030  	}
  1031  	j.mu.Lock()
  1032  	r := C.my_sd_journal_wait(sd_journal_wait, j.cjournal, C.uint64_t(to))
  1033  	j.mu.Unlock()
  1034  
  1035  	return int(r)
  1036  }
  1037  
  1038  // GetUsage returns the journal disk space usage, in bytes.
  1039  func (j *Journal) GetUsage() (uint64, error) {
  1040  	var out C.uint64_t
  1041  
  1042  	sd_journal_get_usage, err := getFunction("sd_journal_get_usage")
  1043  	if err != nil {
  1044  		return 0, err
  1045  	}
  1046  
  1047  	j.mu.Lock()
  1048  	r := C.my_sd_journal_get_usage(sd_journal_get_usage, j.cjournal, &out)
  1049  	j.mu.Unlock()
  1050  
  1051  	if r < 0 {
  1052  		return 0, fmt.Errorf("failed to get journal disk space usage: %s", syscall.Errno(-r).Error())
  1053  	}
  1054  
  1055  	return uint64(out), nil
  1056  }
  1057  
  1058  // GetUniqueValues returns all unique values for a given field.
  1059  func (j *Journal) GetUniqueValues(field string) ([]string, error) {
  1060  	var result []string
  1061  
  1062  	sd_journal_query_unique, err := getFunction("sd_journal_query_unique")
  1063  	if err != nil {
  1064  		return nil, err
  1065  	}
  1066  
  1067  	sd_journal_enumerate_unique, err := getFunction("sd_journal_enumerate_unique")
  1068  	if err != nil {
  1069  		return nil, err
  1070  	}
  1071  
  1072  	sd_journal_restart_unique, err := getFunction("sd_journal_restart_unique")
  1073  	if err != nil {
  1074  		return nil, err
  1075  	}
  1076  
  1077  	j.mu.Lock()
  1078  	defer j.mu.Unlock()
  1079  
  1080  	f := C.CString(field)
  1081  	defer C.free(unsafe.Pointer(f))
  1082  
  1083  	r := C.my_sd_journal_query_unique(sd_journal_query_unique, j.cjournal, f)
  1084  
  1085  	if r < 0 {
  1086  		return nil, fmt.Errorf("failed to query journal: %s", syscall.Errno(-r).Error())
  1087  	}
  1088  
  1089  	// Implements the SD_JOURNAL_FOREACH_UNIQUE macro from sd-journal.h
  1090  	var d unsafe.Pointer
  1091  	var l C.size_t
  1092  	C.my_sd_journal_restart_unique(sd_journal_restart_unique, j.cjournal)
  1093  	for {
  1094  		r = C.my_sd_journal_enumerate_unique(sd_journal_enumerate_unique, j.cjournal, &d, &l)
  1095  		if r == 0 {
  1096  			break
  1097  		}
  1098  
  1099  		if r < 0 {
  1100  			return nil, fmt.Errorf("failed to read message field: %s", syscall.Errno(-r).Error())
  1101  		}
  1102  
  1103  		msg := C.GoStringN((*C.char)(d), C.int(l))
  1104  		kv := strings.SplitN(msg, "=", 2)
  1105  		if len(kv) < 2 {
  1106  			return nil, fmt.Errorf("failed to parse field")
  1107  		}
  1108  
  1109  		result = append(result, kv[1])
  1110  	}
  1111  
  1112  	return result, nil
  1113  }
  1114  
  1115  // GetCatalog retrieves a message catalog entry for the journal entry referenced
  1116  // by the last completed Next/Previous function call. To call GetCatalog, you
  1117  // must first have called one of these functions.
  1118  func (j *Journal) GetCatalog() (string, error) {
  1119  	sd_journal_get_catalog, err := getFunction("sd_journal_get_catalog")
  1120  	if err != nil {
  1121  		return "", err
  1122  	}
  1123  
  1124  	var c *C.char
  1125  
  1126  	j.mu.Lock()
  1127  	r := C.my_sd_journal_get_catalog(sd_journal_get_catalog, j.cjournal, &c)
  1128  	j.mu.Unlock()
  1129  	defer C.free(unsafe.Pointer(c))
  1130  
  1131  	if r < 0 {
  1132  		return "", fmt.Errorf("failed to retrieve catalog entry for current journal entry: %s", syscall.Errno(-r).Error())
  1133  	}
  1134  
  1135  	catalog := C.GoString(c)
  1136  
  1137  	return catalog, nil
  1138  }
  1139  
  1140  // GetBootID get systemd boot id
  1141  func (j *Journal) GetBootID() (string, error) {
  1142  	sd_id128_get_boot, err := getFunction("sd_id128_get_boot")
  1143  	if err != nil {
  1144  		return "", err
  1145  	}
  1146  
  1147  	var boot_id C.sd_id128_t
  1148  	r := C.my_sd_id128_get_boot(sd_id128_get_boot, &boot_id)
  1149  	if r < 0 {
  1150  		return "", fmt.Errorf("failed to get boot id: %s", syscall.Errno(-r).Error())
  1151  	}
  1152  
  1153  	sd_id128_to_string, err := getFunction("sd_id128_to_string")
  1154  	if err != nil {
  1155  		return "", err
  1156  	}
  1157  
  1158  	id128StringMax := C.size_t(C.SD_ID128_STRING_MAX)
  1159  	c := (*C.char)(C.malloc(id128StringMax))
  1160  	defer C.free(unsafe.Pointer(c))
  1161  	C.my_sd_id128_to_string(sd_id128_to_string, boot_id, c)
  1162  
  1163  	bootID := C.GoString(c)
  1164  	if len(bootID) <= 0 {
  1165  		return "", fmt.Errorf("get boot id %s is not valid", bootID)
  1166  	}
  1167  
  1168  	return bootID, nil
  1169  }
  1170  

View as plain text