+
+int
+oslogopen(__unused dev_t dev, __unused int flags, __unused int mode, struct proc *p)
+{
+ LOG_LOCK();
+ if (oslog_open) {
+ LOG_UNLOCK();
+ return(EBUSY);
+ }
+ oslogsoftc.sc_pgid = p->p_pid; /* signal process only */
+ oslog_open = 1;
+
+ LOG_UNLOCK();
+ return (0);
+}
+
+int
+oslogclose(__unused dev_t dev, __unused int flag, __unused int devtype, __unused struct proc *p)
+{
+ LOG_LOCK();
+ oslogsoftc.sc_state &= ~(LOG_NBIO | LOG_ASYNC);
+ selwakeup(&oslogsoftc.sc_selp);
+ selthreadclear(&oslogsoftc.sc_selp);
+ oslog_open = 0;
+ LOG_UNLOCK();
+ return (0);
+}
+
+int
+oslog_streamopen(__unused dev_t dev, __unused int flags, __unused int mode, struct proc *p)
+{
+ char *oslog_stream_msg_bufc = NULL;
+ oslog_stream_buf_entry_t entries = NULL;
+
+ lck_spin_lock(&oslog_stream_lock);
+ if (oslog_stream_open) {
+ lck_spin_unlock(&oslog_stream_lock);
+ return EBUSY;
+ }
+ lck_spin_unlock(&oslog_stream_lock);
+
+ // Allocate the stream buffer
+ oslog_stream_msg_bufc = kalloc(oslog_stream_buf_size);
+ if (!oslog_stream_msg_bufc) {
+ return ENOMEM;
+ }
+
+ /* entries to support kernel logging in stream mode */
+ entries = kalloc(oslog_stream_num_entries * sizeof(struct oslog_stream_buf_entry_s));
+ if (!entries) {
+ kfree(oslog_stream_msg_bufc, oslog_stream_buf_size);
+ return ENOMEM;
+ }
+
+ lck_spin_lock(&oslog_stream_lock);
+ if (oslog_stream_open) {
+ lck_spin_unlock(&oslog_stream_lock);
+ kfree(oslog_stream_msg_bufc, oslog_stream_buf_size);
+ kfree(entries, oslog_stream_num_entries * sizeof(struct oslog_stream_buf_entry_s));
+ return EBUSY;
+ }
+
+ assert(oslog_streambufp->msg_bufc == NULL);
+ oslog_streambufp->msg_bufc = oslog_stream_msg_bufc;
+ oslog_streambufp->msg_size = oslog_stream_buf_size;
+
+ oslog_stream_buf_entries = entries;
+
+ STAILQ_INIT(&oslog_stream_free_head);
+ STAILQ_INIT(&oslog_stream_buf_head);
+
+ for (int i = 0; i < oslog_stream_num_entries; i++) {
+ oslog_stream_buf_entries[i].type = oslog_stream_link_type_log;
+ oslog_stream_buf_entries[i].offset = 0;
+ oslog_stream_buf_entries[i].size = 0;
+ oslog_stream_buf_entries[i].timestamp = 0;
+ STAILQ_INSERT_TAIL(&oslog_stream_free_head, &oslog_stream_buf_entries[i], buf_entries);
+ }
+
+ /* there should be no pending entries in the stream */
+ assert(STAILQ_EMPTY(&oslog_stream_buf_head));
+ assert(oslog_streambufp->msg_bufx == 0);
+ assert(oslog_streambufp->msg_bufr == 0);
+
+ oslog_streambufp->msg_bufx = 0;
+ oslog_streambufp->msg_bufr = 0;
+ oslog_streamsoftc.sc_pgid = p->p_pid; /* signal process only */
+ oslog_stream_open = 1;
+ lck_spin_unlock(&oslog_stream_lock);
+
+ return 0;
+}
+
+int
+oslog_streamclose(__unused dev_t dev, __unused int flag, __unused int devtype, __unused struct proc *p)
+{
+ oslog_stream_buf_entry_t next_entry = NULL;
+ char *oslog_stream_msg_bufc = NULL;
+ oslog_stream_buf_entry_t entries = NULL;
+
+ lck_spin_lock(&oslog_stream_lock);
+
+ if (oslog_stream_open == 0) {
+ lck_spin_unlock(&oslog_stream_lock);
+ return EBADF;
+ }
+
+ // Consume all log lines
+ while (!STAILQ_EMPTY(&oslog_stream_buf_head)) {
+ next_entry = STAILQ_FIRST(&oslog_stream_buf_head);
+ STAILQ_REMOVE_HEAD(&oslog_stream_buf_head, buf_entries);
+ }
+ oslog_streamwakeup_locked();
+ oslog_streamsoftc.sc_state &= ~(LOG_NBIO | LOG_ASYNC);
+ selwakeup(&oslog_streamsoftc.sc_selp);
+ selthreadclear(&oslog_streamsoftc.sc_selp);
+ oslog_stream_open = 0;
+ oslog_streambufp->msg_bufr = 0;
+ oslog_streambufp->msg_bufx = 0;
+ oslog_stream_msg_bufc = oslog_streambufp->msg_bufc;
+ oslog_streambufp->msg_bufc = NULL;
+ entries = oslog_stream_buf_entries;
+ oslog_stream_buf_entries = NULL;
+ oslog_streambufp->msg_size = 0;
+
+ lck_spin_unlock(&oslog_stream_lock);
+
+ // Free the stream buffer
+ kfree(oslog_stream_msg_bufc, oslog_stream_buf_size);
+ // Free the list entries
+ kfree(entries, oslog_stream_num_entries * sizeof(struct oslog_stream_buf_entry_s));
+
+ return 0;
+}
+