2323#include "ch_domain.h"
2424#include "datatypes.h"
2525#include "domain_driver.h"
26+ #include "virfile.h"
2627#include "viralloc.h"
2728#include "virlog.h"
2829#include "virtime.h"
2930#include "virsystemd.h"
31+ #include "virutil.h"
32+
33+ #include <fcntl.h>
3034
3135#define VIR_FROM_THIS VIR_FROM_CH
3236
@@ -40,6 +44,41 @@ VIR_ENUM_IMPL(virCHDomainJob,
4044
4145VIR_LOG_INIT ("ch.ch_domain" );
4246
47+ struct _chDomainLogContext {
48+ GObject parent ;
49+
50+ int writefd ;
51+ int readfd ; /* Only used if manager == NULL */
52+ off_t pos ;
53+ ino_t inode ; /* Only used if manager != NULL */
54+ char * path ;
55+ virLogManagerPtr manager ;
56+ };
57+ static void chDomainLogContextFinalize (GObject * obj );
58+ static void ch_domain_log_context_init (chDomainLogContext * logctxt G_GNUC_UNUSED )
59+ {
60+ }
61+ static void ch_domain_log_context_class_init (chDomainLogContextClass * klass )
62+ {
63+ GObjectClass * obj = G_OBJECT_CLASS (klass );
64+
65+ obj -> finalize = chDomainLogContextFinalize ;
66+ }
67+
68+ G_DEFINE_TYPE (chDomainLogContext , ch_domain_log_context , G_TYPE_OBJECT );
69+
70+ static void
71+ chDomainLogContextFinalize (GObject * object )
72+ {
73+ chDomainLogContextPtr ctxt = CH_DOMAIN_LOG_CONTEXT (object );
74+ VIR_DEBUG ("ctxt=%p" , ctxt );
75+
76+ virLogManagerFree (ctxt -> manager );
77+ g_free (ctxt -> path );
78+ VIR_FORCE_CLOSE (ctxt -> writefd );
79+ VIR_FORCE_CLOSE (ctxt -> readfd );
80+ G_OBJECT_CLASS (ch_domain_log_context_parent_class )-> finalize (object );
81+ }
4382static int
4483virCHDomainObjInitJob (virCHDomainObjPrivatePtr priv )
4584{
@@ -485,3 +524,146 @@ virCHDomainObjFromDomain(virDomainPtr domain)
485524
486525 return vm ;
487526}
527+
528+
529+ chDomainLogContextPtr chDomainLogContextNew (virCHDriverPtr driver ,
530+ virDomainObjPtr vm ,
531+ chDomainLogContextMode mode )
532+ {
533+ g_autoptr (virCHDriverConfig ) cfg = virCHDriverGetConfig (driver );
534+ chDomainLogContextPtr ctxt = CH_DOMAIN_LOG_CONTEXT (g_object_new (CH_TYPE_DOMAIN_LOG_CONTEXT , NULL ));
535+
536+ VIR_DEBUG ("Context new %p stdioLogD=%d" , ctxt , cfg -> stdioLogD );
537+ ctxt -> writefd = -1 ;
538+ ctxt -> readfd = -1 ;
539+
540+ ctxt -> path = g_strdup_printf ("%s/%s.log" , cfg -> logDir , vm -> def -> name );
541+
542+ if (cfg -> stdioLogD ) {
543+ ctxt -> manager = virLogManagerNew (driver -> privileged );
544+ if (!ctxt -> manager )
545+ goto error ;
546+
547+ ctxt -> writefd = virLogManagerDomainOpenLogFile (ctxt -> manager ,
548+ "ch" ,
549+ vm -> def -> uuid ,
550+ vm -> def -> name ,
551+ ctxt -> path ,
552+ 0 ,
553+ & ctxt -> inode ,
554+ & ctxt -> pos );
555+ if (ctxt -> writefd < 0 )
556+ goto error ;
557+ } else {
558+ if ((ctxt -> writefd = open (ctxt -> path , O_WRONLY | O_CREAT | O_APPEND , S_IRUSR | S_IWUSR )) < 0 ) {
559+ virReportSystemError (errno , _ ("failed to create logfile %s" ),
560+ ctxt -> path );
561+ goto error ;
562+ }
563+ if (virSetCloseExec (ctxt -> writefd ) < 0 ) {
564+ virReportSystemError (errno , _ ("failed to set close-on-exec flag on %s" ),
565+ ctxt -> path );
566+ goto error ;
567+ }
568+
569+ /* For unprivileged startup we must truncate the file since
570+ * we can't rely on logrotate. We don't use O_TRUNC since
571+ * it is better for SELinux policy if we truncate afterwards */
572+ if (mode == CH_DOMAIN_LOG_CONTEXT_MODE_START &&
573+ !driver -> privileged &&
574+ ftruncate (ctxt -> writefd , 0 ) < 0 ) {
575+ virReportSystemError (errno , _ ("failed to truncate %s" ),
576+ ctxt -> path );
577+ goto error ;
578+ }
579+
580+ if (mode == CH_DOMAIN_LOG_CONTEXT_MODE_START ) {
581+ if ((ctxt -> readfd = open (ctxt -> path , O_RDONLY , S_IRUSR | S_IWUSR )) < 0 ) {
582+ virReportSystemError (errno , _ ("failed to open logfile %s" ),
583+ ctxt -> path );
584+ goto error ;
585+ }
586+ if (virSetCloseExec (ctxt -> readfd ) < 0 ) {
587+ virReportSystemError (errno , _ ("failed to set close-on-exec flag on %s" ),
588+ ctxt -> path );
589+ goto error ;
590+ }
591+ }
592+
593+ if ((ctxt -> pos = lseek (ctxt -> writefd , 0 , SEEK_END )) < 0 ) {
594+ virReportSystemError (errno , _ ("failed to seek in log file %s" ),
595+ ctxt -> path );
596+ goto error ;
597+ }
598+ }
599+
600+ return ctxt ;
601+
602+ error :
603+ g_clear_object (& ctxt );
604+ return NULL ;
605+ }
606+
607+ /**
608+ * chDomainLogAppendMessage:
609+ *
610+ * This is a best-effort attempt to add a log message to the ch log file
611+ * either by using virtlogd or the legacy approach */
612+ int
613+ chDomainLogAppendMessage (virCHDriverPtr driver ,
614+ virDomainObjPtr vm ,
615+ const char * fmt ,
616+ ...)
617+ {
618+ g_autoptr (virCHDriverConfig ) cfg = virCHDriverGetConfig (driver );
619+ virLogManagerPtr manager = NULL ;
620+ va_list ap ;
621+ g_autofree char * path = NULL ;
622+ int writefd = -1 ;
623+ g_autofree char * message = NULL ;
624+ int ret = -1 ;
625+
626+ va_start (ap , fmt );
627+
628+ message = g_strdup_vprintf (fmt , ap );
629+
630+ VIR_DEBUG ("Append log message (vm='%s' message='%s) stdioLogD=%d" ,
631+ vm -> def -> name , message , cfg -> stdioLogD );
632+
633+ path = g_strdup_printf ("%s/%s.log" , cfg -> logDir , vm -> def -> name );
634+
635+ if (cfg -> stdioLogD ) {
636+ if (!(manager = virLogManagerNew (driver -> privileged )))
637+ goto cleanup ;
638+
639+ if (virLogManagerDomainAppendMessage (manager , "ch" , vm -> def -> uuid ,
640+ vm -> def -> name , path , message , 0 ) < 0 )
641+ goto cleanup ;
642+ } else {
643+ if ((writefd = open (path , O_WRONLY | O_CREAT | O_APPEND , S_IRUSR | S_IWUSR )) < 0 ) {
644+ virReportSystemError (errno , _ ("failed to create logfile %s" ),
645+ path );
646+ goto cleanup ;
647+ }
648+
649+ if (safewrite (writefd , message , strlen (message )) < 0 )
650+ goto cleanup ;
651+ }
652+
653+ ret = 0 ;
654+
655+ cleanup :
656+ va_end (ap );
657+ VIR_FORCE_CLOSE (writefd );
658+ virLogManagerFree (manager );
659+
660+ return ret ;
661+ }
662+
663+
664+ int chDomainLogContextGetWriteFD (chDomainLogContextPtr ctxt )
665+ {
666+ return ctxt -> writefd ;
667+ }
668+
669+
0 commit comments