0d11ec45c7d19e7d86e7ce3548aa17473b9ae828
[platform/upstream/libzypp.git] / zypp / base / Sysconfig.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/base/Sysconfig.cc
10  *
11 */
12
13 #include <iostream>
14 #include <fstream>
15
16 #include "zypp/base/Logger.h"
17 #include "zypp/base/String.h"
18 #include "zypp/base/StrMatcher.h"
19 #include "zypp/base/IOStream.h"
20 #include "zypp/base/InputStream.h"
21 #include "zypp/Pathname.h"
22 #include "zypp/PathInfo.h"
23 #include "zypp/TmpPath.h"
24
25 #include "zypp/base/Sysconfig.h"
26
27 using namespace std;
28 using namespace zypp::base;
29
30 namespace zypp {
31   namespace base {
32     namespace sysconfig {
33
34       map<string,string> read( const Pathname & _path )
35       {
36         DBG << "Load '" << _path << "'" << endl;
37         map<string,string> ret;
38
39         string line;
40         ifstream in( _path.asString().c_str() );
41         if ( in.fail() ) {
42           WAR << "Unable to load '" << _path << "'" << endl;
43           return ret;
44         }
45
46         while( getline( in, line ) ) {
47           if ( *line.begin() != '#' ) {
48
49             string::size_type pos = line.find( '=', 0 );
50
51             if ( pos != string::npos ) {
52
53               string key = str::trim( line.substr( 0, pos ) );
54               string value = str::trim( line.substr( pos + 1, line.length() - pos - 1 ) );
55
56               if ( value.length() >= 2
57                    && *(value.begin()) == '"'
58                    && *(value.rbegin()) == '"' )
59               {
60                 value = value.substr( 1, value.length() - 2 );
61               }
62               if ( value.length() >= 2
63                    && *(value.begin()) == '\''
64                    && *(value.rbegin()) == '\'' )
65               {
66                 value = value.substr( 1, value.length() - 2 );
67               }
68               XXX << "KEY: '" << key << "' VALUE: '" << value << "'" << endl;
69               ret[key] = value;
70
71             } // '=' found
72
73           } // not comment
74
75         } // while getline
76         MIL << "done reading '" << _path << "'" << endl;
77         return ret;
78       }
79
80       bool write( const Pathname & path_r, const std::string & key_r, const std::string & val_r, const std::string & newcomment_r )
81       {
82         if ( key_r.empty() )
83         {
84           WAR << "Empty key in write " << path_r << endl;
85           return false;
86         }
87
88         PathInfo pi( path_r );
89         if ( ! pi.isFile() )
90           ZYPP_THROW( Exception( str::Str() << path_r << ": " << Errno(ENOENT) ) );
91         if ( ! pi.userMayRW() )
92           ZYPP_THROW( Exception( str::Str() << path_r << ": " << Errno(EACCES) ) );
93
94         bool found = false;
95         filesystem::TmpFile tmpf( filesystem::TmpFile::makeSibling( path_r ) );
96         {
97           StrMatcher matches( "^[ \t]*"+key_r+"[ \t]*=", Match::REGEX );
98           std::ofstream o( tmpf.path().c_str() );
99           iostr::forEachLine( InputStream( path_r ),
100                               [&]( int num_r, std::string line_r )->bool
101                               {
102                                 if ( !found && matches( line_r ) )
103                                 {
104                                   o << key_r << '=' << val_r << endl;
105                                   found = true;
106                                   MIL << path_r << ": " << key_r << '=' << val_r << " changed on line " << num_r << endl;
107                                 }
108                                 else
109                                   o << line_r << endl;
110                                 return true;
111                               } );
112           if ( !found )
113           {
114             if ( newcomment_r.empty() )
115             {
116               WAR << path_r << ": " << key_r << '=' << val_r << " can not be added (no comment provided)." << endl;
117             }
118             else
119             {
120               std::vector<std::string> lines;
121               str::split( newcomment_r, std::back_inserter(lines), "\r\n" );
122               o << endl;
123               for ( auto line : lines )
124               {
125                 if ( line[0] != '#' )
126                   o << "# ";
127                 o << line << endl;
128               }
129               o << key_r << '=' << val_r << endl;
130               found = true;
131               MIL << path_r << ": " << key_r << '=' << val_r << " appended. " << endl;
132             }
133           }
134
135           if ( ! o )
136             ZYPP_THROW( Exception( str::Str() << tmpf.path() << ": " << Errno(EIO) ) );
137         }
138
139         // If everything is fine, exchange the files:
140         int res = exchange( tmpf.path(), path_r );
141         if ( res )
142         {
143           ZYPP_THROW( Exception( str::Str() << tmpf.path() << ": " << Errno(res) ) );
144         }
145         return found;
146       }
147
148       bool writeStringVal( const Pathname & path_r, const std::string & key_r, const std::string & val_r, const std::string & newcomment_r )
149       {
150         return write( path_r, key_r, str::Str() << '"' << str::escape( val_r, '"' )<< '"', newcomment_r );
151       }
152
153     } // namespace sysconfig
154   } // namespace base
155 } // namespace zypp