File indexing completed on 2024-04-28 07:42:26
0001 /* 0002 SPDX-License-Identifier: LGPL-2.0-or-later 0003 SPDX-FileCopyrightText: 2021 Harald Sitter <sitter@kde.org> 0004 */ 0005 0006 #include "metadata_p.h" 0007 0008 #include <QByteArray> 0009 #include <cerrno> 0010 0011 #ifdef Q_OS_LINUX 0012 #include <cstring> 0013 #include <fcntl.h> 0014 #include <span> 0015 #include <sys/stat.h> 0016 #include <sys/types.h> 0017 #include <unistd.h> 0018 #endif 0019 0020 namespace KCrash 0021 { 0022 #ifdef Q_OS_LINUX 0023 MetadataINIWriter::MetadataINIWriter(const QByteArray &path) 0024 { 0025 if (path.isEmpty()) { 0026 return; 0027 } 0028 0029 fd = ::open(path.constData(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, S_IRUSR | S_IWUSR); 0030 if (fd == -1) { 0031 fprintf(stderr, "Failed to open metadata file: %s\n", strerror(errno)); 0032 } else if (fd >= 0) { 0033 writable = true; 0034 const char *header = "[KCrash]\n"; 0035 write(fd, header, strlen(header)); 0036 } else { 0037 fprintf(stderr, "MetadataINIWriter: Unexpected fd %d\n", fd); 0038 Q_UNREACHABLE(); 0039 } 0040 } 0041 0042 void MetadataINIWriter::close() 0043 { 0044 if (fd >= 0 && ::close(fd) == -1) { 0045 fprintf(stderr, "Failed to close metadata file: %s\n", strerror(errno)); 0046 } 0047 writable = false; 0048 } 0049 0050 void MetadataINIWriter::add(const char *key, const char *value, BoolValue boolValue) 0051 { 0052 Q_ASSERT(key); 0053 Q_ASSERT(value); 0054 Q_ASSERT(key[0] == '-' && key[1] == '-'); // well-formed '--' prefix. This is important. MetadataWriter presume this 0055 Q_UNUSED(boolValue); // value is a bool string but we don't care, we always write the value anyway 0056 0057 if (fd < 0) { 0058 return; 0059 } 0060 0061 const auto valueSpan = std::span{value, strlen(value)}; 0062 0063 write(fd, key + 2, strlen(key + 2)); 0064 write(fd, "=", 1); 0065 if (strstr(value, "\n")) { // if it contains \n then write literally \n (2 characters) 0066 // Could appear in the exception what() string. KConfig knows what to do with this. 0067 for (const auto &character : valueSpan) { 0068 if (character == '\n') { 0069 write(fd, "\\n", 2); 0070 } else { 0071 write(fd, &character, 1); 0072 } 0073 } 0074 } else { // fast write entire string in one go since it contains no newlines 0075 write(fd, valueSpan.data(), valueSpan.size()); 0076 } 0077 write(fd, "\n", 1); 0078 } 0079 0080 bool MetadataINIWriter::isWritable() const 0081 { 0082 return writable; 0083 } 0084 #endif 0085 0086 Metadata::Metadata(const char *cmd) 0087 { 0088 // NB: cmd may be null! Just because we create metadata doesn't mean we'll execute drkonqi (we may only need the 0089 // backing writers) 0090 Q_ASSERT(argc == 0); 0091 argv.at(argc++) = cmd; 0092 } 0093 0094 void Metadata::setAdditionalWriter(MetadataWriter *writer) 0095 { 0096 // Once set the writer oughtn't be reset as we have no use case for this and should we get one in the future 0097 // it'll need at least review of the existing code to handle writer switching correctly. 0098 Q_ASSERT(m_writer == nullptr); 0099 Q_ASSERT(writer != nullptr); 0100 m_writer = writer; 0101 } 0102 0103 void Metadata::add(const char *key, const char *value) 0104 { 0105 add(key, value, BoolValue::No); 0106 } 0107 0108 void Metadata::addBool(const char *key) 0109 { 0110 add(key, "true", BoolValue::Yes); 0111 } 0112 0113 void Metadata::close() 0114 { 0115 // NULL terminated list 0116 argv.at(argc) = nullptr; 0117 0118 if (m_writer) { 0119 m_writer->close(); 0120 } 0121 } 0122 0123 void Metadata::add(const char *key, const char *value, BoolValue boolValue) 0124 { 0125 Q_ASSERT(key); 0126 Q_ASSERT(value); 0127 Q_ASSERT(key[0] == '-' && key[1] == '-'); // well-formed '--' prefix. This is important. MetadataWriter presume this 0128 Q_ASSERT(argc < argv.max_size()); // argv has a static max size. guard against exhaustion 0129 0130 argv.at(argc++) = key; 0131 if (!boolValue) { 0132 argv.at(argc++) = value; 0133 } 0134 0135 if (m_writer) { 0136 m_writer->add(key, value, boolValue); 0137 } 0138 } 0139 0140 } // namespace KCrash