dlogutil/
lib.rs

1use dlog::{BufferId, Priority};
2use dlog_sys::{log_id_t, log_priority};
3use dlogutil_sys::*;
4use libc::timespec;
5use std::ffi::CStr;
6use std::io::{Error, ErrorKind, Result};
7use std::ptr::{null, null_mut};
8use std::time::Duration;
9
10/// Enumeration for timestamp-based log sorting orderings.
11///
12/// For more detailed information on the timestamp documentation,
13/// refer to the C library documentation.
14#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
15pub enum SortingOrder {
16    /// Monotonic timestamp applied by the sender.
17    SentMono,
18    /// Real-time timestamp applied by the sender.
19    SentReal,
20    /// Monotonic timestamp applied by the receiver.
21    RecvMono,
22    /// Real-time timestamp applied by the receiver.
23    RecvReal,
24    /// The default timestamp of the buffer. See [`buffer_get_default_ts_type`].
25    Default,
26}
27
28impl From<dlogutil_sorting_order> for SortingOrder {
29    fn from(c_enum: dlogutil_sorting_order) -> Self {
30        match c_enum {
31            dlogutil_sorting_order::DLOGUTIL_SORT_SENT_MONO => SortingOrder::SentMono,
32            dlogutil_sorting_order::DLOGUTIL_SORT_SENT_REAL => SortingOrder::SentReal,
33            dlogutil_sorting_order::DLOGUTIL_SORT_RECV_MONO => SortingOrder::RecvMono,
34            dlogutil_sorting_order::DLOGUTIL_SORT_RECV_REAL => SortingOrder::RecvReal,
35            dlogutil_sorting_order::DLOGUTIL_SORT_DEFAULT => SortingOrder::Default,
36        }
37    }
38}
39
40impl From<SortingOrder> for dlogutil_sorting_order {
41    fn from(rust_enum: SortingOrder) -> Self {
42        match rust_enum {
43            SortingOrder::SentMono => dlogutil_sorting_order::DLOGUTIL_SORT_SENT_MONO,
44            SortingOrder::SentReal => dlogutil_sorting_order::DLOGUTIL_SORT_SENT_REAL,
45            SortingOrder::RecvMono => dlogutil_sorting_order::DLOGUTIL_SORT_RECV_MONO,
46            SortingOrder::RecvReal => dlogutil_sorting_order::DLOGUTIL_SORT_RECV_REAL,
47            SortingOrder::Default => dlogutil_sorting_order::DLOGUTIL_SORT_DEFAULT,
48        }
49    }
50}
51
52/// A struct containing libdlogutil initialisation configuration.
53pub struct DlogutilConfig {
54    config: *mut dlogutil_config,
55}
56
57// SAFETY: it is ok to use the this object from different threads if only one thread
58// is using the memory at the time.
59unsafe impl Send for DlogutilConfig {}
60
61// SAFETY: the operations that do not modify the memory at all are ok to be used from
62// different threads at once, and those who do are marked as &mut.
63unsafe impl Sync for DlogutilConfig {}
64
65/// A struct containing the state of a log handling request.
66pub struct DlogutilState {
67    state: *mut dlogutil_state,
68}
69
70// SAFETY: it is ok to use the this object from different threads if only one thread
71// is using the memory at the time.
72unsafe impl Send for DlogutilState {}
73
74// SAFETY: the operations that do not modify the memory at all are ok to be used from
75// different threads at once, and those who do are marked as &mut.
76unsafe impl Sync for DlogutilState {}
77
78/// A struct containing the metadata and contents for a single dlog entry.
79pub struct DlogutilEntry {
80    entry: *mut dlogutil_entry,
81}
82
83// SAFETY: it is ok to use the this object from different threads if only one thread
84// is using the memory at the time.
85unsafe impl Send for DlogutilEntry {}
86
87// SAFETY: the operations that do not modify the memory at all are ok to be used from
88// different threads at once, and those who do are marked as &mut.
89unsafe impl Sync for DlogutilEntry {}
90
91impl Drop for DlogutilConfig {
92    fn drop(&mut self) {
93        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
94        // Since the function takes &mut, no other references can exist.
95        unsafe {
96            dlogutil_config_destroy(self.config);
97        }
98    }
99}
100
101impl Drop for DlogutilState {
102    fn drop(&mut self) {
103        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
104        // Since the function takes &mut, no other references can exist.
105        unsafe {
106            dlogutil_state_destroy(self.state);
107        }
108    }
109}
110
111impl Drop for DlogutilEntry {
112    fn drop(&mut self) {
113        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
114        // Since the function takes &mut, no other references can exist.
115        unsafe {
116            dlogutil_entry_destroy(self.entry);
117        }
118    }
119}
120
121impl DlogutilConfig {
122    /// Creates a new [`DlogutilConfig`] struct to be filled with configuration.
123    ///
124    /// Useful for dumping the logs of a specific thread in a multithreaded process.
125    ///
126    /// # Returns
127    ///
128    /// * `Ok(Self)` - A handle to the config struct.
129    /// * `Err(std::io::Error)` - An error.
130    ///
131    /// # Errors
132    ///
133    /// * [`std::io::ErrorKind::OutOfMemory`] - Out of memory.
134    pub fn create() -> Result<Self> {
135        // SAFETY: the function is safe by itself. It returns either a valid pointer,
136        // in which case we return Ok, or NULL, in which case we return Err, which
137        // means that if Self is created, the inner pointer is guaranteed to be correct.
138        let config = unsafe { dlogutil_config_create() };
139        if config.is_null() {
140            return Err(Error::from(ErrorKind::OutOfMemory));
141        }
142        Ok(DlogutilConfig { config })
143    }
144
145    /// Enables retrieving only those logs that are logged by the thread with
146    /// the given TID.
147    ///
148    /// Useful for dumping the logs of a specific thread in a multithreaded process.
149    ///
150    /// # Errors
151    ///
152    /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
153    /// * [`std::io::ErrorKind::OutOfMemory`] - Out of memory.
154    pub fn filter_tid(&mut self, tid: i32) -> Result<()> {
155        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
156        // Since the function takes &mut, no other references can exist.
157        match unsafe { dlogutil_config_filter_tid(self.config, tid) } {
158            0 => Ok(()),
159            e => Err(Error::from_raw_os_error(-e)),
160        }
161    }
162
163    /// Enables retrieving only those logs that are logged by the process with
164    /// the given PID.
165    ///
166    /// Useful for dumping the logs of a specific process.
167    ///
168    /// # Errors
169    ///
170    /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
171    /// * [`std::io::ErrorKind::OutOfMemory`] - Out of memory.
172    pub fn filter_pid(&mut self, pid: i32) -> Result<()> {
173        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
174        // Since the function takes &mut, no other references can exist.
175        match unsafe { dlogutil_config_filter_pid(self.config, pid) } {
176            0 => Ok(()),
177            e => Err(Error::from_raw_os_error(-e)),
178        }
179    }
180
181    /// Enables retrieving only those logs that match a given filter.
182    ///
183    /// # Arguments
184    ///
185    /// * `query` - The filter query. For syntax, see dlogutil's --help.
186    ///
187    /// # Errors
188    ///
189    /// * [`std::io::ErrorKind::InvalidInput`] - Invalid syntax of the filterspec.
190    /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
191    /// * [`std::io::ErrorKind::OutOfMemory`] - Out of memory.
192    pub fn filter_filterspec(&mut self, query: &str) -> Result<()> {
193        let query = format!("{}\0", query);
194        let query_c =
195            CStr::from_bytes_with_nul(query.as_bytes()).map_err(|_| ErrorKind::InvalidInput)?;
196        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
197        // The string is defined in a verified way above.
198        // Since the function takes &mut, no other references can exist.
199        match unsafe { dlogutil_config_filter_filterspec(self.config, query_c.as_ptr()) } {
200            0 => Ok(()),
201            e => Err(Error::from_raw_os_error(-e)),
202        }
203    }
204
205    /// Disables log sorting for given log retrieval request.
206    ///
207    /// Logs are still received in some order that is usually largely sorted,
208    /// but if sorting is disabled logutil-side there may be cases where a log
209    /// with a later timestamp is in front of a log with an earlier one.
210    /// The use case here is performance, since the failure case above is rare.
211    ///
212    /// # Errors
213    ///
214    /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
215    pub fn sorting_disable(&mut self) -> Result<()> {
216        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
217        // Since the function takes &mut, no other references can exist.
218        match unsafe { dlogutil_config_sorting_disable(self.config) } {
219            0 => Ok(()),
220            e => Err(Error::from_raw_os_error(-e)),
221        }
222    }
223
224    /// Enables log sorting for given log retrieval request.
225    ///
226    /// This is the default and generally makes sure that logs are in order,
227    /// but has a modest performance cost.
228    ///
229    /// # Errors
230    ///
231    /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
232    pub fn sorting_enable(&mut self) -> Result<()> {
233        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
234        // Since the function takes &mut, no other references can exist.
235        match unsafe { dlogutil_config_sorting_enable(self.config) } {
236            0 => Ok(()),
237            e => Err(Error::from_raw_os_error(-e)),
238        }
239    }
240
241    /// Enables sorting, choosing the sort buffer size manually.
242    ///
243    /// The count parameter influences the quality of sorting, but also memory usage.
244    /// This version is a somewhat lower level version of [`sorting_enable`].
245    /// For more information on sorting quality, refer to the C library documentation.
246    ///
247    /// [`sorting_enable`]: DlogutilConfig::sorting_enable
248    ///
249    /// # Arguments
250    ///
251    /// * `entry_count` - How many logs to keep at a given time. At least 1.
252    ///
253    /// # Errors
254    ///
255    /// * [`std::io::ErrorKind::InvalidInput`] - Zero size.
256    /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
257    pub fn sorting_enable_with_size(&mut self, entry_count: u32) -> Result<()> {
258        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
259        // Since the function takes &mut, no other references can exist.
260        match unsafe { dlogutil_config_sorting_enable_with_size(self.config, entry_count) } {
261            0 => Ok(()),
262            e => Err(Error::from_raw_os_error(-e)),
263        }
264    }
265
266    /// Chooses a timestamp type by which returned logs are sorted by.
267    ///
268    /// If the chosen timestamp is missing in the logs, currently they will not
269    /// be sorted at all. This should, however, still become a reasonable order,
270    /// since logs are usually stored sorted by one of timestamps. If only some
271    /// logs are missing the chosen timestamp, ordering of the logs is undefined.
272    /// See [`buffer_get_default_ts_type`] for the default.
273    ///
274    /// # Errors
275    ///
276    /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
277    pub fn order_set(&mut self, sort_by: SortingOrder) -> Result<()> {
278        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
279        // Since the function takes &mut, no other references can exist.
280        match unsafe { dlogutil_config_order_set(self.config, sort_by.into()) } {
281            0 => Ok(()),
282            e => Err(Error::from_raw_os_error(-e)),
283        }
284    }
285
286    /// Adds a buffer whence logs will be taken to a request.
287    ///
288    /// # Errors
289    ///
290    /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
291    pub fn buffer_add(&mut self, buf: BufferId) -> Result<()> {
292        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
293        // Since the function takes &mut, no other references can exist.
294        match unsafe { dlogutil_config_buffer_add(self.config, buf.into()) } {
295            0 => Ok(()),
296            e => Err(Error::from_raw_os_error(-e)),
297        }
298    }
299
300    /// Set log retrieval mode to retrieving all the logs since the start of
301    /// the system without an end.
302    ///
303    /// This is similar to `dlogutil` in a default mode.
304    ///
305    /// # Errors
306    ///
307    /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
308    pub fn mode_set_continuous(&mut self) -> Result<()> {
309        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
310        // Since the function takes &mut, no other references can exist.
311        match unsafe { dlogutil_config_mode_set_continuous(self.config) } {
312            0 => Ok(()),
313            e => Err(Error::from_raw_os_error(-e)),
314        }
315    }
316
317    /// Set log retrieval mode to retrieving all the logs since the call
318    /// without an end.
319    ///
320    /// This is similar to `dlogutil -m`.
321    ///
322    /// # Errors
323    ///
324    /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
325    pub fn mode_set_monitor(&mut self) -> Result<()> {
326        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
327        // Since the function takes &mut, no other references can exist.
328        match unsafe { dlogutil_config_mode_set_monitor(self.config) } {
329            0 => Ok(()),
330            e => Err(Error::from_raw_os_error(-e)),
331        }
332    }
333
334    /// Set log retrieval mode to dumping all the logs since the start of the
335    /// system until the call (possibly a specified amount of the most recent
336    /// of them instead).
337    ///
338    /// This is similar to `dlogutil -d`. After dumping all the logs,
339    /// [`get_log`] will signal this by returning `TIZEN_ERROR_NO_DATA`.
340    ///
341    /// [`get_log`]: DlogutilState::get_log
342    ///
343    /// # Arguments
344    ///
345    /// * `entry_count` - Number of logs to be returned. It can be
346    ///   `DLOGUTIL_MAX_DUMP_SIZE`, in which case all the logs will be dumped.
347    ///
348    /// # Errors
349    ///
350    /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
351    pub fn mode_set_dump(&mut self, entry_count: u32) -> Result<()> {
352        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
353        // Since the function takes &mut, no other references can exist.
354        match unsafe { dlogutil_config_mode_set_dump(self.config, entry_count) } {
355            0 => Ok(()),
356            e => Err(Error::from_raw_os_error(-e)),
357        }
358    }
359
360    /// Set log retrieval mode to dumping compressed historical logs.
361    ///
362    /// This is similar to `cat /var/log/dlog/xyz`. After dumping all the logs,
363    /// [`get_log`] will signal this by returning `TIZEN_ERROR_NO_DATA`.
364    ///
365    /// [`get_log`]: DlogutilState::get_log
366    ///
367    /// # Arguments
368    ///
369    /// * `compress_buffer` - The name of the compression storage entry.
370    ///
371    /// # Errors
372    ///
373    /// * [`std::io::ErrorKind::OutOfMemory`] - Not enough memory. Parameters left unchanged.
374    /// * [`std::io::ErrorKind::InvalidInput`] - The pointer was NULL.
375    pub fn mode_set_compressed_memory_dump(&mut self, compress_buffer: &str) -> Result<()> {
376        let compress_buffer = format!("{}\0", compress_buffer);
377        let compress_buffer_c = CStr::from_bytes_with_nul(compress_buffer.as_bytes())
378            .map_err(|_| ErrorKind::InvalidInput)?;
379        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
380        // The string is defined in a verified way above.
381        // Since the function takes &mut, no other references can exist.
382        match unsafe {
383            dlogutil_config_mode_set_compressed_memory_dump(self.config, compress_buffer_c.as_ptr())
384        } {
385            0 => Ok(()),
386            e => Err(Error::from_raw_os_error(-e)),
387        }
388    }
389}
390
391impl DlogutilState {
392    /// Finalizes the config into a state struct by connecting to buffers.
393    ///
394    /// An application having platform privilege level can read platform log
395    /// data by declaring <http://tizen.org/privilege/log>.
396    ///
397    /// # Returns
398    ///
399    /// * `Ok(Self)` - A handle to the state struct.
400    /// * `Err(std::io::Error)` - An error.
401    ///
402    /// # Errors
403    ///
404    /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
405    /// * [`std::io::ErrorKind::InvalidInput`] - No buffers selected.
406    /// * [`std::io::ErrorKind::Uncategorized`] - Unsupported buffer set (KMSG + non-KMSG).
407    /// * [`std::io::ErrorKind::Uncategorized`] - Unsupported backend (zero-copy).
408    /// * [`std::io::ErrorKind::Uncategorized`] - No buffers were opened (incl. due to null backend).
409    /// * [`std::io::ErrorKind::Uncategorized`] - Couldn't read config file.
410    /// * [`std::io::ErrorKind::Uncategorized`] - Couldn't contact log backend.
411    /// * [`std::io::ErrorKind::OutOfMemory`] - There's not enough memory.
412    pub fn create(config: DlogutilConfig) -> Result<Self> {
413        let mut state = DlogutilState { state: null_mut() };
414        // SAFETY: the config pointer is guaranteed to be correct by the way it's created.
415        // Otherwise, the function is safe by itself. It returns either a valid pointer,
416        // in which case we return Ok, or NULL, in which case we return Err, which
417        // means that if Self is created, the inner pointer is guaranteed to be correct.
418        match unsafe { dlogutil_config_connect(config.config, &mut state.state) } {
419            0 => Ok(state),
420            e => Err(Error::from_raw_os_error(-e)),
421        }
422    }
423
424    /// Retrieves a single log according to a dump request.
425    ///
426    /// Returns a returned log as a [`DlogutilEntry`] struct.
427    ///
428    /// If the calling process doesn't have `CAP_SYSLOG` and is not in the
429    /// log group, you will only get some of the logs.
430    /// Also, you must set the mode (`DlogutilConfig::mode_set_*`).
431    ///
432    /// [`DlogutilEntry`]: DlogutilEntry
433    ///
434    /// # Arguments
435    ///
436    /// * `timeout` - How many miliseconds to wait for the log.
437    ///   The actual runtime of the call can obviously be slightly longer than
438    ///   this argument. 0 means don't wait, None means wait indefinitely.
439    ///
440    /// # Returns
441    ///
442    /// * `Ok(DlogutilEntry)` - A returned log.
443    /// * `Err(std::io::Error)` - An error.
444    ///
445    /// # Errors
446    ///
447    /// * [`std::io::ErrorKind::Uncategorized`] - Timeout exceeded.
448    /// * [`std::io::ErrorKind::Uncategorized`] - In dump mode, no more logs remaining.
449    /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
450    /// * [`std::io::ErrorKind::InvalidInput`] - State not in log-getting mode.
451    /// * [`std::io::ErrorKind::OutOfMemory`] - There's not enough memory.
452    /// * [`std::io::ErrorKind::Uncategorized`] - Couldn't fulfill request.
453    pub fn get_log(&mut self, timeout: Option<Duration>) -> Result<DlogutilEntry> {
454        let mut entry_out = DlogutilEntry { entry: null_mut() };
455        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
456        // The C function passes the ownership of the entry to the pointer iff the
457        // return value is nonzero, which is exactly the case in which we return
458        // the struct in an Ok. Since the function takes &mut, no other references can exist.
459        match unsafe {
460            dlogutil_get_log(
461                self.state,
462                timeout.map_or(-1, |t| t.as_millis() as i32),
463                &mut entry_out.entry,
464            )
465        } {
466            0 => Ok(entry_out),
467            e => Err(Error::from_raw_os_error(-e)),
468        }
469    }
470
471    /// Irreversibly clears a log buffer from any logs inside.
472    ///
473    /// Either `CAP_SYSLOG` or being in the log group is required.
474    /// Also, you can't use one of the log-getting modes
475    /// (`DlogutilConfig::mode_set_*`).
476    ///
477    /// # Errors
478    ///
479    /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
480    /// * [`std::io::ErrorKind::Uncategorized`] - Couldn't fulfill request.
481    pub fn buffer_clear(&mut self, buffer: BufferId) -> Result<()> {
482        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
483        // Since the function takes &mut, no other references can exist.
484        match unsafe { dlogutil_buffer_clear(self.state, buffer.into()) } {
485            0 => Ok(()),
486            e => Err(Error::from_raw_os_error(-e)),
487        }
488    }
489
490    /// Gets the data storage capacity of a log buffer in bytes.
491    ///
492    /// Either `CAP_SYSLOG` or being in the log group is required.
493    /// Also, you can't use one of the log-getting modes
494    /// (`DlogutilConfig::mode_set_*`).
495    ///
496    /// # Returns
497    ///
498    /// * `Ok(u32)` - The buffer's maximum capacity in bytes.
499    /// * `Err(std::io::Error)` - An error.
500    ///
501    /// # Errors
502    ///
503    /// * [`std::io::ErrorKind::InvalidInput`] - State in log-getting mode.
504    /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
505    /// * [`std::io::ErrorKind::Uncategorized`] - Couldn't fulfill request.
506    pub fn buffer_get_capacity(&mut self, buffer: BufferId) -> Result<u32> {
507        let mut capacity = 0;
508        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
509        // Note that it is not correct for this function to take a shared reference, as in case of
510        // the pipe backend, the function will write to a pipe and expect to read an answer
511        // immediately.
512        match unsafe { dlogutil_buffer_get_capacity(self.state, buffer.into(), &mut capacity) } {
513            0 => Ok(capacity),
514            e => Err(Error::from_raw_os_error(-e)),
515        }
516    }
517
518    /// Gets the storage data usage of a log buffer in bytes.
519    ///
520    /// Either `CAP_SYSLOG` or being in the log group is required.
521    /// Also, you can't use one of the log-getting modes
522    /// (`DlogutilConfig::mode_set_*`).
523    ///
524    /// # Returns
525    ///
526    /// * `Ok(u32)` - Buffer's current usage in bytes.
527    /// * `Err(std::io::Error)` - An error.
528    ///
529    /// # Errors
530    ///
531    /// * [`std::io::ErrorKind::InvalidInput`] - State in log-getting mode.
532    /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
533    /// * [`std::io::ErrorKind::Uncategorized`] - Couldn't fulfill request.
534    pub fn buffer_get_usage(&mut self, buffer: BufferId) -> Result<u32> {
535        let mut usage = 0;
536        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
537        // Note that it is not correct for this function to take a shared reference, as in case of
538        // the pipe backend, the function will write to a pipe and expect to read an answer
539        // immediately.
540        match unsafe { dlogutil_buffer_get_usage(self.state, buffer.into(), &mut usage) } {
541            0 => Ok(usage),
542            e => Err(Error::from_raw_os_error(-e)),
543        }
544    }
545
546    /// Gets the buffer aliasing (same storage) information.
547    ///
548    /// Sometimes, multiple buffers will be backed by a single log storage
549    /// (for example, by the same kernel device). In such cases, the storage
550    /// will only be opened once.
551    /// This function allows you to see whether this is the case.
552    ///
553    /// # Returns
554    ///
555    /// * `Ok(BufferId)` - Buffer aliasing information.
556    /// * `Err(std::io::Error)` - An error.
557    ///
558    /// # Errors
559    ///
560    /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
561    pub fn buffer_get_alias(&self, buffer: BufferId) -> Result<BufferId> {
562        let mut real_buffer = log_id_t::LOG_ID_MAIN;
563        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
564        // This method only reads from the memory of the object, so it is ok for it to take
565        // a shared reference.
566        match unsafe { dlogutil_buffer_get_alias(self.state, buffer.into(), &mut real_buffer) } {
567            0 => Ok(real_buffer.into()),
568            e => Err(Error::from_raw_os_error(-e)),
569        }
570    }
571}
572
573impl DlogutilEntry {
574    /// Retrieves the timestamp of given type from the log entry.
575    ///
576    /// The information about timestamp availability can be retrieved using the
577    /// [`buffer_check_ts_type_available`] function.
578    ///
579    /// # Returns
580    ///
581    /// * `Ok(Duration)` - Timestamp of the entry as a [`Duration`] struct.
582    /// * `Err(std::io::Error)` - An error.
583    ///
584    /// [`Duration`]: std::time::Duration
585    ///
586    /// # Errors
587    ///
588    /// * [`std::io::ErrorKind::InvalidInput`] - Invalid value of order.
589    /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
590    /// * [`std::io::ErrorKind::Uncategorized`] - The timestamp is missing.
591    pub fn get_timestamp(&self, stamp_type: SortingOrder) -> Result<Duration> {
592        let mut ts = timespec {
593            tv_sec: 0,
594            tv_nsec: 0,
595        };
596        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
597        // This method only reads from the memory of the object, so it is ok for it to take
598        // a shared reference.
599        match unsafe { dlogutil_entry_get_timestamp(self.entry, stamp_type.into(), &mut ts) } {
600            0 => Ok(Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32)),
601            e => Err(Error::from_raw_os_error(-e)),
602        }
603    }
604
605    /// Retrieves the TID (thread identificator) of the log sender.
606    ///
607    /// If [`LogIdKmsg`] is used as the buffer, this function will always return
608    /// `TIZEN_ERROR_NO_DATA`.
609    /// This is because the KMSG buffer contains no TID information.
610    ///
611    /// [`LogIdKmsg`]: BufferId::LogIdKmsg
612    ///
613    /// # Returns
614    ///
615    /// * `Ok(i32)` - TID of the log sender.
616    /// * `Err(std::io::Error)` - An error.
617    ///
618    /// # Errors
619    ///
620    /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
621    /// * [`std::io::ErrorKind::Uncategorized`] - TID is missing or not applicable.
622    pub fn get_tid(&self) -> Result<i32> {
623        let mut tid = 0;
624        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
625        // This method only reads from the memory of the object, so it is ok for it to take
626        // a shared reference.
627        match unsafe { dlogutil_entry_get_tid(self.entry, &mut tid) } {
628            0 => Ok(tid),
629            e => Err(Error::from_raw_os_error(-e)),
630        }
631    }
632
633    /// Retrieves the PID (process identificator) of the log sender.
634    ///
635    /// If [`LogIdKmsg`] is used as the buffer, this function will always return
636    /// `TIZEN_ERROR_NO_DATA`.
637    /// This is because the KMSG buffer contains no PID information.
638    ///
639    /// [`LogIdKmsg`]: BufferId::LogIdKmsg
640    ///
641    /// # Returns
642    ///
643    /// * `Ok(i32)` - PID of the log sender.
644    /// * `Err(std::io::Error)` - An error.
645    ///
646    /// # Errors
647    ///
648    /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
649    /// * [`std::io::ErrorKind::Uncategorized`] - PID is missing or not applicable.
650    pub fn get_pid(&self) -> Result<i32> {
651        let mut pid = 0;
652        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
653        // This method only reads from the memory of the object, so it is ok for it to take
654        // a shared reference.
655        match unsafe { dlogutil_entry_get_pid(self.entry, &mut pid) } {
656            0 => Ok(pid),
657            e => Err(Error::from_raw_os_error(-e)),
658        }
659    }
660
661    /// Retrieves the priority level metadata of the log entry.
662    ///
663    /// # Returns
664    ///
665    /// * `Ok(Priority)` - Log priority.
666    /// * `Err(std::io::Error)` - An error.
667    ///
668    /// # Errors
669    ///
670    /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
671    /// * [`std::io::ErrorKind::Uncategorized`] - The priority is missing.
672    pub fn get_priority(&self) -> Result<Priority> {
673        let mut prio = log_priority::DLOG_UNKNOWN;
674        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
675        // This method only reads from the memory of the object, so it is ok for it to take
676        // a shared reference.
677        match unsafe { dlogutil_entry_get_priority(self.entry, &mut prio) } {
678            0 => Ok(prio.into()),
679            e => Err(Error::from_raw_os_error(-e)),
680        }
681    }
682
683    /// Retrieves the tag (arbitrary label) of the log entry.
684    ///
685    /// In some rare cases the entry may be malformed and the tag
686    /// may turn out to be unavailable.
687    ///
688    /// In such cases, an empty string may be returned instead.
689    ///
690    /// # Returns
691    ///
692    /// * `Ok(&str)` - Log tag.
693    /// * `Err(std::io::Error)` - An error.
694    ///
695    /// # Errors
696    ///
697    /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
698    /// * [`std::io::ErrorKind::Uncategorized`] - The tag is missing.
699    pub fn get_tag(&self) -> Result<&str> {
700        let mut tag_ptr = null();
701        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
702        // The function returns either NULL, in which case we return Err,
703        // or a string with same lifetime as self.entry, in which case we can safely
704        // call CStr::from_ptr and return it in an Ok.
705        // This method only reads from the memory of the object, so it is ok for it to take
706        // a shared reference.
707        unsafe {
708            match dlogutil_entry_get_tag(self.entry, &mut tag_ptr) {
709                0 => Ok(CStr::from_ptr(tag_ptr).to_str().unwrap()),
710                e => Err(Error::from_raw_os_error(-e)),
711            }
712        }
713    }
714
715    /// Retrieves the message (without any metadata) of the log entry.
716    ///
717    /// In some rare cases the entry may be malformed and the message
718    /// may turn out to be unavailable.
719    ///
720    /// In such cases, an empty string may be returned instead.
721    ///
722    /// # Returns
723    ///
724    /// * `Ok(&str)` - Log message.
725    /// * `Err(std::io::Error)` - An error.
726    ///
727    /// # Errors
728    ///
729    /// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
730    /// * [`std::io::ErrorKind::Uncategorized`] - The message is missing.
731    pub fn get_message(&self) -> Result<&str> {
732        let mut msg_ptr = null();
733        // SAFETY: the pointer is guaranteed to be correct by the way it's created.
734        // The function returns either NULL, in which case we return Err,
735        // or a string with same lifetime as self.entry, in which case we can safely
736        // call CStr::from_ptr and return it in an Ok.
737        // This method only reads from the memory of the object, so it is ok for it to take
738        // a shared reference.
739        unsafe {
740            match dlogutil_entry_get_message(self.entry, &mut msg_ptr) {
741                0 => Ok(CStr::from_ptr(msg_ptr).to_str().unwrap()),
742                e => Err(Error::from_raw_os_error(-e)),
743            }
744        }
745    }
746}
747
748/// Gets the human-readable, constant name of a buffer.
749///
750/// # Returns
751///
752/// * `Ok(&str)` - The name of the passed buffer.
753/// * `Err(std::io::Error)` - An error.
754///
755/// # Errors
756///
757/// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
758pub fn buffer_get_name(buffer: BufferId) -> Result<&'static str> {
759    let mut name_ptr = null();
760    // SAFETY: the function is safe by itself provided the target is a valid pointer.
761    // The function returns either NULL, in which case we return Err,
762    // or a string with static lifetime, in which case we can safely call
763    // CStr::from_ptr and return it in an Ok.
764    unsafe {
765        match dlogutil_buffer_get_name(buffer.into(), &mut name_ptr) {
766            0 => Ok(CStr::from_ptr(name_ptr).to_str().unwrap()),
767            e => Err(Error::from_raw_os_error(-e)),
768        }
769    }
770}
771
772/// Gets the default sorting timestamp type of a buffer.
773///
774/// This is the timestamp type that will be used for sorting by default.
775/// We assume that it is always available and the input is sorted by it.
776///
777/// # Returns
778///
779/// * `Ok(SortingOrder)` - The default timestamp type of the passed buffer.
780/// * `Err(std::io::Error)` - An error.
781///
782/// # Errors
783///
784/// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
785/// * [`std::io::ErrorKind::Uncategorized`] - Couldn't read config file.
786pub fn buffer_get_default_ts_type(buffer: BufferId) -> Result<SortingOrder> {
787    let mut typ = dlogutil_sorting_order::DLOGUTIL_SORT_SENT_MONO;
788    // SAFETY: the function is safe by itself provided the target is a valid pointer.
789    match unsafe { dlogutil_buffer_get_default_ts_type(buffer.into(), &mut typ) } {
790        0 => Ok(typ.into()),
791        e => Err(Error::from_raw_os_error(-e)),
792    }
793}
794
795/// Checks if a buffer contains timestamps of a given type.
796///
797/// If false is returned, the timestamp may still be available in some of the logs.
798/// However, if true is returned, the timestamp will always be available.
799/// You can check the timestamp availability per log using the [`get_timestamp`]
800/// function.
801///
802/// [`get_timestamp`]: DlogutilEntry::get_timestamp
803///
804/// # Returns
805///
806/// * `Ok(bool)` - Whether the given timestamp type is guaranteed to be available.
807/// * `Err(std::io::Error)` - An error.
808///
809/// # Errors
810///
811/// * [`std::io::ErrorKind::InvalidInput`] - More than one buffer.
812/// * [`std::io::ErrorKind::InvalidInput`] - One of the pointers was NULL.
813/// * [`std::io::ErrorKind::Uncategorized`] - Couldn't read config file.
814pub fn buffer_check_ts_type_available(buffer: BufferId, stamp_type: SortingOrder) -> Result<bool> {
815    let mut available = false;
816    // SAFETY: the function is safe by itself provided the target is a valid pointer.
817    match unsafe {
818        dlogutil_buffer_check_ts_type_available(buffer.into(), stamp_type.into(), &mut available)
819    } {
820        0 => Ok(available),
821        e => Err(Error::from_raw_os_error(-e)),
822    }
823}