Initial commit
This commit is contained in:
commit
87325b96bc
|
@ -0,0 +1,74 @@
|
|||
*.lo
|
||||
*.o
|
||||
*.cache
|
||||
*.la
|
||||
*.pc
|
||||
*.gcda
|
||||
*.gcno
|
||||
*.gir
|
||||
*.pyc
|
||||
*.typelib
|
||||
*~
|
||||
.deps/
|
||||
.libs/
|
||||
Makefile
|
||||
Makefile.in
|
||||
/stamp-h1
|
||||
missing
|
||||
/libtool
|
||||
ltmain.sh
|
||||
install-sh
|
||||
/mkinstalldirs
|
||||
/gtk-doc.make
|
||||
/config.h
|
||||
/config.h.in
|
||||
/aclocal.m4
|
||||
config.guess
|
||||
/config.log
|
||||
/config.status
|
||||
config.sub
|
||||
/configure
|
||||
depcomp
|
||||
/.sass-cache
|
||||
/lang/da.json
|
||||
/lang/de.json
|
||||
/com.redhat.Cockpit.conf
|
||||
/com.redhat.Cockpit.service
|
||||
/cockpit-generated.c
|
||||
/cockpit-generated.h
|
||||
/cockpit-generated-doc-com.redhat.*.xml
|
||||
/cockpit-ws
|
||||
/cockpit-ws.8
|
||||
/cockpit-ws.service
|
||||
/cockpit.conf.5
|
||||
/cockpit.js
|
||||
/cockpit.service
|
||||
/cockpitd
|
||||
/cockpitd.8
|
||||
/cockpitenumtypes.c
|
||||
/cockpitenumtypes.h
|
||||
/cockpitwsenumtypes.c
|
||||
/cockpitwsenumtypes.h
|
||||
/src/daemon/data/lang/da.json
|
||||
/src/daemon/data/lang/de.json
|
||||
/src/web/lib/jquery.mobile.adwaita-1.3.0.css
|
||||
/src/web/lib/jquery.mobile.theme-1.3.0.scss
|
||||
/test-server
|
||||
/test-server-generated.c
|
||||
/test-server-generated.h
|
||||
/test/mock
|
||||
/test/test-machine
|
||||
/test/testlib.pyc
|
||||
/test/*.rpm
|
||||
/test/run
|
||||
/cockpit-session
|
||||
/test-session
|
||||
/cockpit-agent
|
||||
/cockpit-ws-notls.service
|
||||
/test-agent
|
||||
/tools/*.m4
|
||||
/tools/coverage
|
||||
/tools/coverage.info
|
||||
/test-*
|
||||
/frob-*
|
||||
/mock-*
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "src/libgsystem"]
|
||||
path = src/libgsystem
|
||||
url = git://git.gnome.org/libgsystem
|
|
@ -0,0 +1,6 @@
|
|||
David Zeuthen
|
||||
Colin Walters
|
||||
Stef Walter
|
||||
Andreas Nilsson
|
||||
Patrick Uiterwijk
|
||||
Marius Vollmer
|
|
@ -0,0 +1,502 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
|
@ -0,0 +1,63 @@
|
|||
NULL =
|
||||
man_MANS =
|
||||
BUILT_SOURCES =
|
||||
EXTRA_DIST =
|
||||
CLEANFILES =
|
||||
noinst_SCRIPTS =
|
||||
libexec_PROGRAMS =
|
||||
noinst_PROGRAMS =
|
||||
noinst_LTLIBRARIES =
|
||||
privlibdir = $(pkglibdir)
|
||||
privlib_LTLIBRARIES =
|
||||
TESTS =
|
||||
|
||||
ACLOCAL_AMFLAGS = -I tools ${ACLOCAL_FLAGS}
|
||||
|
||||
SUBDIRS = doc po
|
||||
|
||||
DISTCHECK_CONFIGURE_FLAGS= \
|
||||
--disable-introspection \
|
||||
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir) \
|
||||
$(NULL)
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-DSRCDIR=\"$(abs_srcdir)\" \
|
||||
-DBUILDDIR=\"$(abs_builddir)\" \
|
||||
$(NULL)
|
||||
|
||||
cockpit_cppflags_common = \
|
||||
-I$(top_builddir) \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_builddir)/src \
|
||||
-I$(top_srcdir)/src \
|
||||
-DPACKAGE_LIBEXEC_DIR=\""$(libexecdir)"\" \
|
||||
-DPACKAGE_SYSCONF_DIR=\""$(sysconfdir)"\" \
|
||||
-DPACKAGE_DATA_DIR=\""$(datadir)"\" \
|
||||
-DPACKAGE_BIN_DIR=\""$(bindir)"\" \
|
||||
-DPACKAGE_LOCALSTATE_DIR=\""$(localstatedir)"\" \
|
||||
-DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \
|
||||
-DPACKAGE_LIB_DIR=\""$(libdir)"\" \
|
||||
-D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT \
|
||||
-DCOCKPIT_COMPILATION \
|
||||
$(NULL)
|
||||
|
||||
cockpit_cppflags_glib_version = \
|
||||
-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_34 \
|
||||
-DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_34 \
|
||||
$(NULL)
|
||||
|
||||
include doc/man/Makefile-man.am
|
||||
include data/Makefile-data.am
|
||||
include src/cockpit/Makefile-libcockpit.am
|
||||
include src/websocket/Makefile-websocket.am
|
||||
include tools/Makefile-tools.am
|
||||
|
||||
libgsystem_srcpath := src/libgsystem
|
||||
libgsystem_cflags := -Isrc/libgsystem $(GIO_CFLAGS)
|
||||
libgsystem_libs := $(GIO_LIBS)
|
||||
include src/libgsystem/Makefile-libgsystem.am
|
||||
noinst_LTLIBRARIES += libgsystem.la
|
||||
|
||||
include src/ws/Makefile-ws.am
|
||||
include src/daemon/Makefile-daemon.am
|
||||
include src/web/Makefile-web.am
|
|
@ -0,0 +1,20 @@
|
|||
Cockpit, a remote manager for GNU/Linux servers
|
||||
===============================================
|
||||
|
||||
Cockpit runs in a browser and can manage your network of GNU/Linux
|
||||
machines.
|
||||
|
||||
CAVEAT:
|
||||
|
||||
This is pre-release software. Only install it in a system that
|
||||
you are ready to lose. It is a good idea to make a virtual
|
||||
machine (or three) to play around with Cockpit.
|
||||
|
||||
NOTE:
|
||||
|
||||
We are just ramping up, and things are a bit rough around the
|
||||
edges. Even compiling and running this code is quite involved, as
|
||||
it depends on a few external packages that aren't released yet.
|
||||
|
||||
Running ./configure should give you some hints as to what you are
|
||||
missing and where to get it from.
|
|
@ -0,0 +1,28 @@
|
|||
#! /bin/sh
|
||||
|
||||
set -e -x
|
||||
|
||||
IFCONFIG=/sbin/ifconfig
|
||||
|
||||
silent()
|
||||
{
|
||||
"$@" > /dev/null 2> /dev/null
|
||||
return $?
|
||||
}
|
||||
|
||||
cd test
|
||||
|
||||
if ! silent $IFCONFIG cockpit0; then
|
||||
sudo ./vm-prep
|
||||
fi
|
||||
rpms=$(EXTRA_FLAGS="CFLAGS='-O2 -Wall -Werror'" ./make-rpms)
|
||||
if [ -z "$rpms" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
./vm-create
|
||||
./vm-install $rpms
|
||||
|
||||
./check-verify
|
||||
|
||||
rm -rf test-machine
|
|
@ -0,0 +1,67 @@
|
|||
#!/bin/sh
|
||||
# This file is part of Cockpit.
|
||||
#
|
||||
# Copyright (C) 2013 Red Hat, Inc.
|
||||
#
|
||||
# Cockpit is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Cockpit is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Run this to generate all the initial makefiles, etc.
|
||||
|
||||
set -eux
|
||||
|
||||
srcdir=`dirname $0`
|
||||
test -z "$srcdir" && srcdir=.
|
||||
|
||||
PKG_NAME="Cockpit"
|
||||
|
||||
(test -f $srcdir/data/cockpit) || {
|
||||
echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
|
||||
echo " top-level $PKG_NAME directory"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Fetch submodules if needed
|
||||
if test ! -f src/libgsystem/README;
|
||||
then
|
||||
echo "+ Setting up submodules"
|
||||
git submodule init
|
||||
git submodule update
|
||||
fi
|
||||
|
||||
rm -rf autom4te.cache
|
||||
|
||||
autoreconf -f -i
|
||||
|
||||
intltoolize --force --copy || exit $?
|
||||
|
||||
set +x
|
||||
|
||||
# NOCONFIGURE is used by gnome-common; support both
|
||||
if ! test -z "${AUTOGEN_SUBDIR_MODE:-}"; then
|
||||
NOCONFIGURE=1
|
||||
fi
|
||||
|
||||
if test -z "${NOCONFIGURE:-}"; then
|
||||
if test -z "$*"; then
|
||||
echo "I am going to run ./configure with no arguments - if you wish "
|
||||
echo "to pass any to it, please specify them on the $0 command line."
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "${NOCONFIGURE:-}"; then
|
||||
$srcdir/configure --enable-maintainer-mode ${AUTOGEN_CONFIGURE_ARGS:-} "$@" || exit $?
|
||||
|
||||
echo
|
||||
echo "Now type 'make' to compile $PKG_NAME."
|
||||
fi
|
|
@ -0,0 +1,228 @@
|
|||
# This file is part of Cockpit.
|
||||
#
|
||||
# Copyright (C) 2013 Red Hat, Inc.
|
||||
#
|
||||
# Cockpit is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Cockpit is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
AC_INIT([Cockpit],[0.2],[devel@lists.cockpit-project.org],[cockpit],[http://www.cockpit-project.org/])
|
||||
|
||||
AC_CONFIG_SRCDIR([src])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_AUX_DIR([tools])
|
||||
AC_CONFIG_MACRO_DIR([tools])
|
||||
|
||||
AM_INIT_AUTOMAKE([1.9 foreign dist-bzip2 no-dist-gzip serial-tests])
|
||||
AM_MAINTAINER_MODE([enable])
|
||||
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_CC_C99
|
||||
AC_ISC_POSIX
|
||||
AC_HEADER_STDC
|
||||
AC_PROG_LIBTOOL
|
||||
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
|
||||
# Initialization
|
||||
#
|
||||
|
||||
AC_PATH_PROG([XSLTPROC], [xsltproc])
|
||||
if test -z "$XSLTPROC"; then
|
||||
AC_MSG_ERROR([xsltproc is needed])
|
||||
fi
|
||||
|
||||
AC_PATH_PROG([JSL], [jsl])
|
||||
if test -z "$JSL"; then
|
||||
AC_MSG_WARN([jsl is needed to run js-lint])
|
||||
fi
|
||||
|
||||
AC_PATH_PROG([SASS], [pyscss])
|
||||
if test -z "$SASS"; then
|
||||
AC_MSG_ERROR([pyscss is needed])
|
||||
fi
|
||||
|
||||
GTK_DOC_CHECK([1.3])
|
||||
|
||||
GOBJECT_INTROSPECTION_CHECK([0.6.2])
|
||||
|
||||
GIO_REQUIREMENT="gio-unix-2.0 >= 2.34"
|
||||
SYSTEMD_REQUIREMENT="libsystemd-journal >= 187 libsystemd-daemon"
|
||||
JSON_GLIB_REQUIREMENT="json-glib-1.0 >= 0.14.0"
|
||||
LIBSSH_REQUIREMENT="libssh_rc >= 0.6.0"
|
||||
|
||||
dnl Used for anything that just needs gio
|
||||
PKG_CHECK_MODULES(GIO, [gio-unix-2.0 >= 2.34.0])
|
||||
AC_SUBST(GIO_CFLAGS)
|
||||
AC_SUBST(GIO_LIBS)
|
||||
|
||||
dnl Our two main binaries
|
||||
PKG_CHECK_MODULES(COCKPIT_WS, [$GIO_REQUIREMENT
|
||||
$SYSTEMD_REQUIREMENT
|
||||
$JSON_GLIB_REQUIREMENT
|
||||
$LIBSSH_REQUIREMENT])
|
||||
|
||||
PKG_CHECK_MODULES(COCKPIT_AGENT, [$GIO_REQUIREMENT
|
||||
$SYSTEMD_REQUIREMENT
|
||||
$JSON_GLIB_REQUIREMENT])
|
||||
|
||||
PKG_CHECK_MODULES(COCKPIT_DAEMON, [$GIO_REQUIREMENT
|
||||
$SYSTEMD_REQUIREMENT
|
||||
$JSON_GLIB_REQUIREMENT
|
||||
gudev-1.0 >= 165
|
||||
udisks2 >= 2.0.91
|
||||
libnm-glib >= 0.9.7.0 libnm-util
|
||||
accountsservice >= 0.6.35])
|
||||
|
||||
old_CFLAGS=$CFLAGS
|
||||
old_LIBS=$LIBS
|
||||
CFLAGS=$COCKPIT_DAEMON_CFLAGS
|
||||
LIBS=$COCKPIT_DAEMON_LIBS
|
||||
|
||||
AC_CHECK_FUNC(act_user_get_groups, [], AC_MSG_ERROR([
|
||||
The accountsservice package needs a patch. See
|
||||
|
||||
https://bugs.freedesktop.org/attachment.cgi?id=81059&action=edit]))
|
||||
|
||||
AC_CHECK_FUNC(udisks_volume_group_get_name, [], AC_MSG_ERROR([
|
||||
The udisks2 package needs a patch. See
|
||||
|
||||
https://bugs.freedesktop.org/attachment.cgi?id=84713&action=edit]))
|
||||
|
||||
CFLAGS=$old_CFLAGS
|
||||
LIBS=$old_LIBS
|
||||
|
||||
# systemd
|
||||
AC_ARG_WITH([systemdsystemunitdir],
|
||||
AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]),
|
||||
[],
|
||||
[with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)])
|
||||
if test "x$with_systemdsystemunitdir" != "xno"; then
|
||||
AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$systemdsystemunitdir"])
|
||||
|
||||
# Internationalization
|
||||
|
||||
IT_PROG_INTLTOOL([$INTLTOOL_REQUIRED])
|
||||
|
||||
GETTEXT_PACKAGE=cockpit
|
||||
AC_SUBST([GETTEXT_PACKAGE])
|
||||
AM_GLIB_GNU_GETTEXT
|
||||
AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE],["$GETTEXT_PACKAGE"],[gettext domain])
|
||||
|
||||
# For po2json
|
||||
|
||||
for mod in JSON Locale::PO; do
|
||||
AC_MSG_CHECKING([for CPAN perl module $mod])
|
||||
if perl -e "use $mod;"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_ERROR([The CPAN perl module $mod is required])
|
||||
fi
|
||||
done
|
||||
|
||||
# Config
|
||||
|
||||
AC_DEFINE_UNQUOTED([COCKPIT_CONFIG_FILE],["$sysconfdir/cockpit/config"],[Configuration file])
|
||||
|
||||
changequote(,)dnl
|
||||
if test "x$GCC" = "xyes"; then
|
||||
CFLAGS="-Wall \
|
||||
-Werror=strict-prototypes -Werror=missing-prototypes \
|
||||
-Werror=implicit-function-declaration \
|
||||
-Werror=pointer-arith -Werror=init-self \
|
||||
-Werror=format-security \
|
||||
-Werror=missing-include-dirs -Werror=aggregate-return $CFLAGS"
|
||||
fi
|
||||
changequote([,])dnl
|
||||
|
||||
# Debug
|
||||
|
||||
AC_MSG_CHECKING([for debug mode])
|
||||
AC_ARG_ENABLE(debug,
|
||||
AC_HELP_STRING([--enable-debug=no/default/yes],
|
||||
[Turn on or off debugging])
|
||||
)
|
||||
|
||||
if test "$enable_debug" != "no"; then
|
||||
AC_DEFINE_UNQUOTED(WITH_DEBUG, 1, [Print debug output])
|
||||
AC_DEFINE_UNQUOTED(_DEBUG, 1, [In debug mode])
|
||||
CFLAGS="$CFLAGS -g"
|
||||
fi
|
||||
if test "$enable_debug" = "yes"; then
|
||||
debug_status="yes"
|
||||
CFLAGS="$CFLAGS -O0"
|
||||
elif test "$enable_debug" = "no"; then
|
||||
debug_status="no"
|
||||
CFLAGS="$CFLAGS -O2"
|
||||
AC_DEFINE_UNQUOTED(G_DISABLE_ASSERT, 1, [Disable glib assertions])
|
||||
else
|
||||
debug_status="default"
|
||||
fi
|
||||
AC_MSG_RESULT($debug_status)
|
||||
|
||||
# Coverage
|
||||
|
||||
AC_MSG_CHECKING([whether to build with coverage])
|
||||
AC_ARG_ENABLE([coverage],
|
||||
[AS_HELP_STRING([--enable-coverage], [Whether to enable coverage testing])],
|
||||
[],
|
||||
[enable_coverage=no])
|
||||
|
||||
if test "$enable_coverage" = "yes"; then
|
||||
if test "$GCC" != "yes"; then
|
||||
AC_MSG_ERROR(Coverage testing requires GCC)
|
||||
fi
|
||||
|
||||
CFLAGS="$CFLAGS -O0 -g --coverage"
|
||||
LDFLAGS="$LDFLAGS --coverage"
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([WITH_COVERAGE], [test "$enable_coverage" = "yes"])
|
||||
AC_MSG_RESULT([$enable_coverage])
|
||||
|
||||
# Generate
|
||||
#
|
||||
|
||||
AC_OUTPUT([
|
||||
Makefile
|
||||
doc/Makefile
|
||||
po/Makefile.in
|
||||
])
|
||||
|
||||
dnl ==========================================================================
|
||||
echo "
|
||||
Cockpit $VERSION
|
||||
================
|
||||
|
||||
prefix: ${prefix}
|
||||
libdir: ${libdir}
|
||||
libexecdir: ${libexecdir}
|
||||
bindir: ${bindir}
|
||||
sbindir: ${sbindir}
|
||||
datadir: ${datadir}
|
||||
sysconfdir: ${sysconfdir}
|
||||
localstatedir: ${localstatedir}
|
||||
introspection: ${found_introspection}
|
||||
systemdsystemunitdir: ${systemdsystemunitdir}
|
||||
|
||||
compiler: ${CC}
|
||||
cflags: ${CFLAGS}
|
||||
cppflags: ${CPPFLAGS}
|
||||
|
||||
Maintainer mode: ${USE_MAINTAINER_MODE}
|
||||
Building api docs: ${enable_gtk_doc}
|
||||
Debug mode: ${debug_status}
|
||||
With coverage: ${enable_coverage}
|
||||
"
|
|
@ -0,0 +1,4 @@
|
|||
/cockpit.service
|
||||
/cockpit-ws.service
|
||||
/com.redhat.Cockpit.conf
|
||||
/com.redhat.Cockpit.service
|
|
@ -0,0 +1,48 @@
|
|||
dbusservicedir = $(datadir)/dbus-1/system-services
|
||||
dbusservice_DATA = com.redhat.Cockpit.service
|
||||
|
||||
com.redhat.Cockpit.service: data/com.redhat.Cockpit.service.in Makefile
|
||||
@sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@
|
||||
|
||||
dbusconfdir = $(sysconfdir)/dbus-1/system.d
|
||||
dbusconf_DATA = com.redhat.Cockpit.conf \
|
||||
data/com.redhat.Cockpit.DBusTests.Test.conf
|
||||
|
||||
com.redhat.Cockpit.conf: data/com.redhat.Cockpit.conf.in Makefile
|
||||
cp $< $@
|
||||
|
||||
if HAVE_SYSTEMD
|
||||
systemdunitdir = $(systemdsystemunitdir)
|
||||
dist_systemdunit_DATA = data/cockpit-ws.socket data/cockpit-ws-notls.socket data/test-server.socket
|
||||
nodist_systemdunit_DATA =
|
||||
|
||||
cockpit.service : data/cockpit.service.in Makefile
|
||||
@sed -e "s|\@libexecdir\@|$(libexecdir)|;s|\@datadir\@|$(datadir)|" $< > $@
|
||||
nodist_systemdunit_DATA += cockpit.service
|
||||
|
||||
cockpit-ws.service : data/cockpit-ws.service.in Makefile
|
||||
@sed -e "s|\@libexecdir\@|$(libexecdir)|;s|\@datadir\@|$(datadir)|" $< > $@
|
||||
nodist_systemdunit_DATA += cockpit-ws.service
|
||||
|
||||
cockpit-ws-notls.service : data/cockpit-ws-notls.service.in Makefile
|
||||
@sed -e "s|\@libexecdir\@|$(libexecdir)|;s|\@datadir\@|$(datadir)|" $< > $@
|
||||
nodist_systemdunit_DATA += cockpit-ws-notls.service
|
||||
|
||||
test-server.service : data/test-server.service.in Makefile
|
||||
@sed -e "s|\@libexecdir\@|$(libexecdir)|;s|\@datadir\@|$(datadir)|" $< > $@
|
||||
nodist_systemdunit_DATA += test-server.service
|
||||
|
||||
endif
|
||||
EXTRA_DIST += \
|
||||
data/com.redhat.Cockpit.xml \
|
||||
data/cockpit.service.in data/cockpit-ws.service.in \
|
||||
data/test-server.service.in \
|
||||
data/com.redhat.Cockpit.service.in \
|
||||
data/com.redhat.Cockpit.conf.in \
|
||||
$(NULL)
|
||||
|
||||
pamdir = $(sysconfdir)/pam.d
|
||||
dist_pam_DATA = data/cockpit
|
||||
|
||||
cockpitconfdir = $(sysconfdir)/cockpit
|
||||
cockpitconf_DATA = data/config
|
|
@ -0,0 +1,15 @@
|
|||
#%PAM-1.0
|
||||
auth required pam_sepermit.so
|
||||
auth substack password-auth
|
||||
auth include postlogin
|
||||
account required pam_nologin.so
|
||||
account include password-auth
|
||||
password include password-auth
|
||||
# pam_selinux.so close should be the first session rule
|
||||
session required pam_selinux.so close
|
||||
session required pam_loginuid.so
|
||||
# pam_selinux.so open should only be followed by sessions to be executed in the user context
|
||||
session required pam_selinux.so open env_params
|
||||
session optional pam_keyinit.so force revoke
|
||||
session include password-auth
|
||||
session include postlogin
|
|
@ -0,0 +1,8 @@
|
|||
[Unit]
|
||||
Description=Cockpit Web Server (No TLS)
|
||||
Documentation=man:cockpit-ws(8)
|
||||
Requires=cockpit-ws-notls.socket
|
||||
Conflicts=cockpit-ws.service
|
||||
|
||||
[Service]
|
||||
ExecStart=@libexecdir@/cockpit-ws --no-tls
|
|
@ -0,0 +1,10 @@
|
|||
[Unit]
|
||||
Description=Cockpit Web Server Socket (No TLS)
|
||||
Documentation=man:cockpit-ws(8)
|
||||
Conflicts=cockpit-ws.socket
|
||||
|
||||
[Socket]
|
||||
ListenStream=21064
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
|
@ -0,0 +1,7 @@
|
|||
[Unit]
|
||||
Description=Cockpit Web Server
|
||||
Documentation=man:cockpit-ws(8)
|
||||
Requires=cockpit-ws.socket
|
||||
|
||||
[Service]
|
||||
ExecStart=@libexecdir@/cockpit-ws
|
|
@ -0,0 +1,9 @@
|
|||
[Unit]
|
||||
Description=Cockpit Web Server Socket
|
||||
Documentation=man:cockpit-ws(8)
|
||||
|
||||
[Socket]
|
||||
ListenStream=21064
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
|
@ -0,0 +1,11 @@
|
|||
[Unit]
|
||||
Description=Cockpit
|
||||
Documentation=man:cockpitd(8)
|
||||
|
||||
[Service]
|
||||
BusName=com.redhat.Cockpit
|
||||
ExecStart=@libexecdir@/cockpitd
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Also=cockpit-ws.socket
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!DOCTYPE busconfig PUBLIC
|
||||
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||
<busconfig>
|
||||
<policy user="root">
|
||||
<allow own="com.redhat.Cockpit.DBusTests.Test"/>
|
||||
</policy>
|
||||
|
||||
<policy context="default">
|
||||
<allow send_destination="com.redhat.Cockpit.DBusTests.Test"/>
|
||||
</policy>
|
||||
</busconfig>
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!DOCTYPE busconfig PUBLIC
|
||||
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||
<busconfig>
|
||||
<!-- Only root can own the service -->
|
||||
<policy user="root">
|
||||
<allow own="com.redhat.Cockpit"/>
|
||||
</policy>
|
||||
|
||||
<!-- Anyone can send messages to the owner of org.freedesktop.UDisks2 -->
|
||||
<policy context="default">
|
||||
<allow send_destination="com.redhat.Cockpit"/>
|
||||
</policy>
|
||||
</busconfig>
|
|
@ -0,0 +1,5 @@
|
|||
[D-BUS Service]
|
||||
Name=com.redhat.Cockpit
|
||||
Exec=@libexecdir@/cockpitd --no-debug
|
||||
User=root
|
||||
SystemdService=cockpit.service
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,2 @@
|
|||
# Cockpit configuration file.
|
||||
# Use "man cockpit.conf" for documentation.
|
|
@ -0,0 +1,6 @@
|
|||
[Unit]
|
||||
Description=Test Server
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=@datadir@/cockpit-test-assets
|
||||
ExecStart=@datadir@/cockpit-test-assets/test-server
|
|
@ -0,0 +1,5 @@
|
|||
[Unit]
|
||||
Description=Test Server Socket
|
||||
|
||||
[Socket]
|
||||
ListenStream=8765
|
|
@ -0,0 +1,13 @@
|
|||
NULL =
|
||||
|
||||
EXTRA_DIST = \
|
||||
cockpit-transport.svg \
|
||||
cockpit-transport.png \
|
||||
$(NULL)
|
||||
|
||||
render-images: cockpit-transport.png
|
||||
|
||||
cockpit-transport.png: cockpit-transport.svg
|
||||
inkscape --without-gui --export-area-page \
|
||||
--export-width=1280 --export-height=960 \
|
||||
--export-png=$@ $<
|
Binary file not shown.
After Width: | Height: | Size: 333 KiB |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 413 KiB |
|
@ -0,0 +1,23 @@
|
|||
man_MANS += \
|
||||
cockpitd.8 \
|
||||
cockpit-ws.8 \
|
||||
cockpit.conf.5 \
|
||||
$(NULL)
|
||||
|
||||
cockpitd.8 : doc/man/cockpitd.xml
|
||||
$(XSLTPROC) -nonet http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
|
||||
|
||||
cockpit-ws.8 : doc/man/cockpit-ws.xml
|
||||
$(XSLTPROC) -nonet http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
|
||||
|
||||
cockpit.conf.5 : doc/man/cockpit.conf.xml
|
||||
$(XSLTPROC) -nonet http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
|
||||
|
||||
EXTRA_DIST += \
|
||||
doc/man/cockpitd.xml \
|
||||
doc/man/cockpit-ws.xml \
|
||||
doc/man/cockpit.conf.xml \
|
||||
$(NULL)
|
||||
|
||||
CLEANFILES += \
|
||||
$(man_MANS)
|
|
@ -0,0 +1,158 @@
|
|||
<refentry id="cockpit-ws.8">
|
||||
|
||||
<!--
|
||||
This file is part of Cockpit.
|
||||
|
||||
Copyright (C) 2013 Red Hat, Inc.
|
||||
|
||||
Cockpit is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Cockpit is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<refentryinfo>
|
||||
<title>cockpit-ws</title>
|
||||
<date>February 2012</date>
|
||||
<productname>cockpit</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>cockpit-ws</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
<refmiscinfo class="version"></refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>cockpit-ws</refname>
|
||||
<refpurpose>Cockpit web server</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>cockpit-ws</command>
|
||||
<arg><option>--help</option></arg>
|
||||
<arg><option>--port</option> <replaceable>PORT</replaceable></arg>
|
||||
<arg><option>--no-tls</option></arg>
|
||||
<arg><option>--no-auth</option></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
|
||||
<refsect1><title>DESCRIPTION</title>
|
||||
<para>
|
||||
The <command>cockpit-ws</command> program is the web server
|
||||
component used for communication between the browser application
|
||||
and
|
||||
<citerefentry>
|
||||
<refentrytitle>cockpitd</refentrytitle><manvolnum>8</manvolnum>
|
||||
</citerefentry>.
|
||||
</para>
|
||||
<para>
|
||||
Users or administrators should never need to start this program
|
||||
as it automatically started by
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
on bootup.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>AUTHENTICATION</title>
|
||||
<para>
|
||||
Access to the <literal>com.redhat.Cockpit</literal> D-Bus service
|
||||
via the <filename>/socket</filename> URI requires authentication
|
||||
- this is implemented by asking for the root password. Static
|
||||
files from <filename>/usr/share/cockpit/content</filename> are
|
||||
served without requiring any authentication.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>TRANSPORT SECURITY</title>
|
||||
<para>
|
||||
To specify the TLS certificate the web server should use, simply
|
||||
drop a file with the extension <literal>.cert</literal> in the
|
||||
<filename>/etc/cockpit/ws-certs.d</filename> directory. If there are
|
||||
multiple files in this directory, then the highest priority one
|
||||
is chosen after sorting. If there is no TLS certificate, a
|
||||
self-signed certificate is automatically generated using the
|
||||
<command>/etc/pki/tls/certs/make-dummy-cert</command> command
|
||||
and stored in
|
||||
<filename>/var/lib/cockpit/temp-self-signed.cert</filename>.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>OPTIONS</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>--help</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Show help options.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--port</option> <replaceable>PORT</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Serve HTTP requests <replaceable>PORT</replaceable> instead of port 21064.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--no-tls</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Don't use TLS.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--no-auth</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Don't require authentication.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1><title>AUTHOR</title>
|
||||
<para>
|
||||
Written by David Zeuthen <email>zeuthen@gmail.com</email> with
|
||||
a lot of help from many others.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>BUGS</title>
|
||||
<para>
|
||||
Please send bug reports to either the distribution bug tracker
|
||||
or the upstream bug tracker at
|
||||
<ulink url="https://redhat.com/TODO"/>.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>SEE ALSO</title>
|
||||
<para>
|
||||
<citerefentry>
|
||||
<refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum>
|
||||
</citerefentry>
|
||||
<citerefentry>
|
||||
<refentrytitle>cockpitd</refentrytitle><manvolnum>8</manvolnum>
|
||||
</citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
|
@ -0,0 +1,83 @@
|
|||
<refentry id="cockpit.conf.5">
|
||||
|
||||
<!--
|
||||
This file is part of Cockpit.
|
||||
|
||||
Copyright (C) 2013 Red Hat, Inc.
|
||||
|
||||
Cockpit is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Cockpit is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<refentryinfo>
|
||||
<title>cockpit.conf</title>
|
||||
<productname>cockpit</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>cockpit.conf</refentrytitle>
|
||||
<manvolnum>5</manvolnum>
|
||||
<refmiscinfo class="version"></refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>cockpit.conf</refname>
|
||||
<refpurpose>Cockpit configuration file</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsect1><title>DESCRIPTION</title>
|
||||
<para>
|
||||
Cockpit can be configured via /etc/cockpit.conf. That file has a INI
|
||||
file syntax and thus contains key / value pairs, grouped into
|
||||
topical groups.
|
||||
|
||||
For example, to set the "group" key in the "login" group to the
|
||||
value "adm", place this into /etc/cockpit.conf:
|
||||
|
||||
<programlisting>
|
||||
[login]
|
||||
group = adm
|
||||
</programlisting>
|
||||
|
||||
No configuration options are defined at the moment. How
|
||||
disappointing.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1><title>AUTHOR</title>
|
||||
<para>
|
||||
Written by Marius Vollmer <email><marius.vollmer@redhat.com></email>.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>BUGS</title>
|
||||
<para>
|
||||
Please send bug reports to either the distribution bug tracker
|
||||
or the upstream bug tracker at
|
||||
<ulink url="https://redhat.com/TODO"/>.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>SEE ALSO</title>
|
||||
<para>
|
||||
<citerefentry>
|
||||
<refentrytitle>cockpitd</refentrytitle><manvolnum>8</manvolnum>
|
||||
</citerefentry>,
|
||||
<citerefentry>
|
||||
<refentrytitle>cockpit-ws</refentrytitle><manvolnum>8</manvolnum>
|
||||
</citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
|
@ -0,0 +1,137 @@
|
|||
<refentry id="cockpitd.8">
|
||||
|
||||
<!--
|
||||
This file is part of Cockpit.
|
||||
|
||||
Copyright (C) 2013 Red Hat, Inc.
|
||||
|
||||
Cockpit is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Cockpit is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<refentryinfo>
|
||||
<title>cockpitd</title>
|
||||
<date>February 2012</date>
|
||||
<productname>cockpit</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>cockpitd</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
<refmiscinfo class="version"></refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>cockpitd</refname>
|
||||
<refpurpose>Cockpit daemon</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>cockpitd</command>
|
||||
<arg><option>--help</option></arg>
|
||||
<arg><option>--replace</option></arg>
|
||||
<arg><option>--http-root</option> <replaceable>PATH</replaceable></arg>
|
||||
<arg><option>--no-debug</option></arg>
|
||||
<arg><option>--no-sigint</option></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
|
||||
<refsect1><title>DESCRIPTION</title>
|
||||
<para>
|
||||
The <command>cockpitd</command> program provides the
|
||||
<emphasis>com.redhat.Cockpit</emphasis> name on the system
|
||||
message bus. Users or administrators should never need to start
|
||||
this daemon as it automatically started by
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
on bootup.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>OPTIONS</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>--help</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Show help options.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>--replace</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Replace existing daemon.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--http-root</option> <replaceable>PATH</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Serve HTTP requests from <replaceable>PATH</replaceable> instead of <filename>/usr/share/cockpit/content</filename>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--no-debug</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Do not print debug or informational messages on stdout/stderr.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--no-sigint</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Do not handle SIGINT for controlled shutdown.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1><title>AUTHOR</title>
|
||||
<para>
|
||||
Written by David Zeuthen <email>zeuthen@gmail.com</email> with
|
||||
a lot of help from many others.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>BUGS</title>
|
||||
<para>
|
||||
Please send bug reports to either the distribution bug tracker
|
||||
or the upstream bug tracker at
|
||||
<ulink url="https://redhat.com/TODO"/>.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>SEE ALSO</title>
|
||||
<para>
|
||||
<citerefentry>
|
||||
<refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum>
|
||||
</citerefentry>,
|
||||
<citerefentry>
|
||||
<refentrytitle>cockpit-ws</refentrytitle><manvolnum>8</manvolnum>
|
||||
</citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
|
@ -0,0 +1,4 @@
|
|||
Makefile.in.in
|
||||
POTFILES
|
||||
*.gmo
|
||||
stamp-it
|
|
@ -0,0 +1,26 @@
|
|||
[encoding: UTF-8]
|
||||
# List of source files containing translatable strings.
|
||||
# Please keep this file sorted alphabetically.
|
||||
[type: gettext/glade] src/web/index.html
|
||||
src/web/cockpit-about.js
|
||||
src/web/cockpit-cpu-status.js
|
||||
src/web/cockpit-dashboard.js
|
||||
src/web/cockpit-disk-io-status.js
|
||||
src/web/cockpit-i18n.js
|
||||
src/web/cockpit-jobs.js
|
||||
src/web/cockpit-journal.js
|
||||
src/web/cockpit-language.js
|
||||
src/web/cockpit-login.js
|
||||
src/web/cockpit-main.js
|
||||
src/web/cockpit-memory-status.js
|
||||
src/web/cockpit-network-traffic-status.js
|
||||
src/web/cockpit-networking.js
|
||||
src/web/cockpit-page.js
|
||||
src/web/cockpit-plot.js
|
||||
src/web/cockpit-realms.js
|
||||
src/web/cockpit-services.js
|
||||
src/web/cockpit-shutdown.js
|
||||
src/web/cockpit-storage.js
|
||||
src/web/cockpit-system-information.js
|
||||
src/web/cockpit-util.js
|
||||
src/daemon/manager.c
|
|
@ -0,0 +1,2 @@
|
|||
# List of files where to skip translations.
|
||||
# Please keep this file sorted alphabetically.
|
|
@ -0,0 +1,5 @@
|
|||
/cockpit-generated-doc-*.xml
|
||||
/cockpit-generated.c
|
||||
/cockpit-generated.h
|
||||
/cockpitenumtypes.c
|
||||
/cockpitenumtypes.h
|
|
@ -0,0 +1,42 @@
|
|||
dbus_built_sources = cockpit-generated.h cockpit-generated.c
|
||||
|
||||
$(dbus_built_sources) : Makefile.am $(top_srcdir)/data/com.redhat.Cockpit.xml
|
||||
gdbus-codegen \
|
||||
--interface-prefix com.redhat.Cockpit. \
|
||||
--c-namespace Cockpit \
|
||||
--c-generate-object-manager \
|
||||
--generate-c-code cockpit-generated \
|
||||
--generate-docbook cockpit-generated-doc \
|
||||
$(top_srcdir)/data/com.redhat.Cockpit.xml \
|
||||
$(NULL)
|
||||
BUILT_SOURCES += $(dbus_built_sources)
|
||||
|
||||
cockpitenumtypes.h: src/cockpit/cockpitenums.h src/cockpit/cockpitenumtypes.h.template
|
||||
glib-mkenums --template $(top_srcdir)/src/cockpit/cockpitenumtypes.h.template $(top_srcdir)/src/cockpit/cockpitenums.h > $@.tmp && mv $@.tmp $@
|
||||
|
||||
cockpitenumtypes.c: src/cockpit/cockpitenums.h src/cockpit/cockpitenumtypes.c.template
|
||||
glib-mkenums --template $(top_srcdir)/src/cockpit/cockpitenumtypes.c.template $(top_srcdir)/src/cockpit/cockpitenums.h > $@.tmp && mv $@.tmp $@
|
||||
|
||||
BUILT_SOURCES += cockpitenumtypes.h cockpitenumtypes.c
|
||||
EXTRA_DIST += cockpitenumtypes.h.template cockpitenumtypes.c.template
|
||||
|
||||
privlib_LTLIBRARIES += libcockpit-1.0.la
|
||||
|
||||
libcockpit_1_0_la_SOURCES = cockpitenumtypes.h cockpitenumtypes.c \
|
||||
$(dbus_built_sources) \
|
||||
src/cockpit/cockpitenums.h \
|
||||
src/cockpit/cockpiterror.h src/cockpit/cockpiterror.c \
|
||||
src/cockpit/cockpitlog.h src/cockpit/cockpitlog.c \
|
||||
src/cockpit/cockpittypes.h \
|
||||
$(NULL)
|
||||
|
||||
libcockpit_1_0_la_CPPFLAGS = \
|
||||
$(cockpit_cppflags_common) \
|
||||
-DG_LOG_DOMAIN=\"libcockpit\" \
|
||||
$(GIO_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
libcockpit_1_0_la_LIBADD = \
|
||||
$(GIO_LIBS) \
|
||||
$(NULL)
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __COCKPIT_H__
|
||||
#define __COCKPIT_H__
|
||||
|
||||
#if !defined(COCKPIT_API_IS_SUBJECT_TO_CHANGE) && !defined(COCKPIT_COMPILATION)
|
||||
#error libcockpit is unstable API. You must define COCKPIT_API_IS_SUBJECT_TO_CHANGE before including cockpit/cockpit.h
|
||||
#endif
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define __COCKPIT_INSIDE_COCKPIT_H__
|
||||
#include <cockpit/cockpittypes.h>
|
||||
#include <cockpit/cockpitenums.h>
|
||||
#include <cockpit/cockpiterror.h>
|
||||
#include <cockpit/cockpitlog.h>
|
||||
#include <cockpitenumtypes.h>
|
||||
#include <cockpit-generated.h>
|
||||
#undef __COCKPIT_INSIDE_COCKPIT_H__
|
||||
|
||||
#endif /* __COCKPIT_H__ */
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (__COCKPIT_INSIDE_COCKPIT_H__) && !defined (COCKPIT_COMPILATION)
|
||||
#error "Only <cockpit/cockpit.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __COCKPIT_ENUMS_H__
|
||||
#define __COCKPIT_ENUMS_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* CockpitError:
|
||||
* @COCKPIT_ERROR_FAILED: The operation failed.
|
||||
*
|
||||
* Error codes for the #COCKPIT_ERROR error domain and the corresponding
|
||||
* D-Bus error names.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
COCKPIT_ERROR_NO_SUCH_REALM, /* com.redhat.Cockpit.Error.NoSuchRealm */
|
||||
COCKPIT_ERROR_AUTHENTICATION_FAILED, /* com.redhat.Cockpit.Error.AuthenticationFailed */
|
||||
COCKPIT_ERROR_CANCELLED, /* com.redhat.Cockpit.Error.Cancelled */
|
||||
COCKPIT_ERROR_FAILED, /* com.redhat.Cockpit.Error.Failed */
|
||||
} CockpitError;
|
||||
|
||||
#define COCKPIT_ERROR_NUM_ENTRIES (COCKPIT_ERROR_FAILED + 1)
|
||||
|
||||
/**
|
||||
* CockpitLogLevel:
|
||||
* @COCKPIT_LOG_LEVEL_DEBUG: Debug messages.
|
||||
* @COCKPIT_LOG_LEVEL_INFO: Informational messages.
|
||||
* @COCKPIT_LOG_LEVEL_NOTICE: Messages that the administrator should take notice of.
|
||||
* @COCKPIT_LOG_LEVEL_WARNING: Warning messages.
|
||||
* @COCKPIT_LOG_LEVEL_ERROR: Error messages.
|
||||
*
|
||||
* Logging levels. The level @COCKPIT_LOG_LEVEL_NOTICE and above goes to syslog.
|
||||
*
|
||||
* Unlike g_warning() and g_error(), none of these logging levels causes the program to ever terminate.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
COCKPIT_LOG_LEVEL_DEBUG,
|
||||
COCKPIT_LOG_LEVEL_INFO,
|
||||
COCKPIT_LOG_LEVEL_NOTICE,
|
||||
COCKPIT_LOG_LEVEL_WARNING,
|
||||
COCKPIT_LOG_LEVEL_ERROR
|
||||
} CockpitLogLevel;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __COCKPIT_ENUMS_H__ */
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*** BEGIN file-header ***/
|
||||
#include "cockpit/cockpitenums.h"
|
||||
#include "cockpitenumtypes.h"
|
||||
|
||||
/*** END file-header ***/
|
||||
|
||||
/*** BEGIN file-production ***/
|
||||
/* enumerations from "@filename@" */
|
||||
/*** END file-production ***/
|
||||
|
||||
/*** BEGIN value-header ***/
|
||||
GType
|
||||
@enum_name@_get_type (void)
|
||||
{
|
||||
static volatile gsize g_define_type_id__volatile = 0;
|
||||
|
||||
if (g_once_init_enter (&g_define_type_id__volatile))
|
||||
{
|
||||
static const G@Type@Value values[] = {
|
||||
/*** END value-header ***/
|
||||
|
||||
/*** BEGIN value-production ***/
|
||||
{ @VALUENAME@, "@VALUENAME@", "@valuenick@" },
|
||||
/*** END value-production ***/
|
||||
|
||||
/*** BEGIN value-tail ***/
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
GType g_define_type_id =
|
||||
g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
|
||||
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
|
||||
}
|
||||
|
||||
return g_define_type_id__volatile;
|
||||
}
|
||||
|
||||
/*** END value-tail ***/
|
||||
|
||||
/*** BEGIN file-tail ***/
|
||||
/*** END file-tail ***/
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*** BEGIN file-header ***/
|
||||
#ifndef __COCKPIT_ENUM_TYPES_H__
|
||||
#define __COCKPIT_ENUM_TYPES_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
/*** END file-header ***/
|
||||
|
||||
/*** BEGIN file-production ***/
|
||||
|
||||
/* enumerations from "@filename@" */
|
||||
/*** END file-production ***/
|
||||
|
||||
/*** BEGIN value-header ***/
|
||||
GType @enum_name@_get_type (void) G_GNUC_CONST;
|
||||
#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
|
||||
/*** END value-header ***/
|
||||
|
||||
/*** BEGIN file-tail ***/
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __COCKPIT_ENUM_TYPES_H__ */
|
||||
/*** END file-tail ***/
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "cockpiterror.h"
|
||||
|
||||
/**
|
||||
* SECTION:cockpiterror
|
||||
* @title: CockpitError
|
||||
* @short_description: Possible errors that can be returned
|
||||
*
|
||||
* Error codes and D-Bus errors.
|
||||
*/
|
||||
|
||||
static const GDBusErrorEntry dbus_error_entries[] =
|
||||
{
|
||||
{COCKPIT_ERROR_NO_SUCH_REALM, "com.redhat.Cockpit.Error.NoSuchRealm"},
|
||||
{COCKPIT_ERROR_AUTHENTICATION_FAILED, "com.redhat.Cockpit.Error.AuthenticationFailed"},
|
||||
{COCKPIT_ERROR_CANCELLED, "com.redhat.Cockpit.Error.Cancelled"},
|
||||
{COCKPIT_ERROR_FAILED, "com.redhat.Cockpit.Error.Failed"},
|
||||
};
|
||||
|
||||
GQuark
|
||||
cockpit_error_quark (void)
|
||||
{
|
||||
G_STATIC_ASSERT (G_N_ELEMENTS (dbus_error_entries) == COCKPIT_ERROR_NUM_ENTRIES);
|
||||
static volatile gsize quark_volatile = 0;
|
||||
g_dbus_error_register_error_domain ("cockpit-error-quark",
|
||||
&quark_volatile,
|
||||
dbus_error_entries,
|
||||
G_N_ELEMENTS (dbus_error_entries));
|
||||
return (GQuark) quark_volatile;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (__COCKPIT_INSIDE_COCKPIT_H__) && !defined (COCKPIT_COMPILATION)
|
||||
#error "Only <cockpit/cockpit.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __COCKPIT_ERROR_H__
|
||||
#define __COCKPIT_ERROR_H__
|
||||
|
||||
#include <cockpit/cockpittypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* COCKPIT_ERROR:
|
||||
*
|
||||
* Error domain for Cockpit. Errors in this domain will be form the
|
||||
* #CockpitError enumeration. See #GError for more information on error
|
||||
* domains.
|
||||
*/
|
||||
#define COCKPIT_ERROR (cockpit_error_quark ())
|
||||
|
||||
GQuark cockpit_error_quark (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __COCKPIT_ERROR_H__ */
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* We wrap journal logging, so this is useless */
|
||||
#define SD_JOURNAL_SUPPRESS_LOCATION 1
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "cockpitlog.h"
|
||||
|
||||
#include <systemd/sd-journal.h>
|
||||
|
||||
void
|
||||
cockpit_null_log_handler (const gchar *log_domain,
|
||||
GLogLevelFlags log_level,
|
||||
const gchar *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* who, me? */
|
||||
}
|
||||
|
||||
void
|
||||
cockpit_journal_log_handler (const gchar *log_domain,
|
||||
GLogLevelFlags log_level,
|
||||
const gchar *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
int priority;
|
||||
|
||||
/*
|
||||
* Note: we should not call GLib fucntions here.
|
||||
*
|
||||
* Mapping glib log levels to syslog priorities
|
||||
* is not at all obvious.
|
||||
*/
|
||||
|
||||
switch (log_level & G_LOG_LEVEL_MASK)
|
||||
{
|
||||
/*
|
||||
* In GLib this is always fatal, caller of this
|
||||
* function aborts()
|
||||
*/
|
||||
case G_LOG_LEVEL_ERROR:
|
||||
priority = LOG_CRIT;
|
||||
break;
|
||||
|
||||
/*
|
||||
* By convention in GLib applications, critical warnings
|
||||
* are usually internal programmer error (ie: precondition
|
||||
* failures). This maps well to LOG_CRIT.
|
||||
*/
|
||||
case G_LOG_LEVEL_CRITICAL:
|
||||
priority = LOG_CRIT;
|
||||
break;
|
||||
|
||||
/*
|
||||
* By convention in GLib apps, g_warning() is used for
|
||||
* non-fatal problems, but ones that should be corrected
|
||||
* or not be encountered in normal system behavior.
|
||||
*/
|
||||
case G_LOG_LEVEL_WARNING:
|
||||
priority = LOG_ERR;
|
||||
break;
|
||||
|
||||
/*
|
||||
* These are related to bad input, or other hosts behaving
|
||||
* badly. Map well to syslog warnings.
|
||||
*/
|
||||
case G_LOG_LEVEL_MESSAGE:
|
||||
default:
|
||||
priority = LOG_WARNING;
|
||||
break;
|
||||
|
||||
/* Informational messages, startup, shutdown etc. */
|
||||
case G_LOG_LEVEL_INFO:
|
||||
priority = LOG_INFO;
|
||||
break;
|
||||
|
||||
/* Never log internal debug/tracing messages to journal */
|
||||
case G_LOG_LEVEL_DEBUG:
|
||||
return;
|
||||
}
|
||||
|
||||
sd_journal_send ("MESSAGE=%s", message,
|
||||
"PRIORITY=%d", (int)priority,
|
||||
"COCKPIT_DOMAIN=%s", log_domain ? log_domain : "",
|
||||
NULL);
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (__COCKPIT_INSIDE_COCKPIT_H__) && !defined (COCKPIT_COMPILATION)
|
||||
#error "Only <cockpit/cockpit.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#ifndef __COCKPIT_LOG_H__
|
||||
#define __COCKPIT_LOG_H__
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void cockpit_null_log_handler (const gchar *log_domain,
|
||||
GLogLevelFlags log_level,
|
||||
const gchar *message,
|
||||
gpointer user_data);
|
||||
|
||||
void cockpit_journal_log_handler (const gchar *log_domain,
|
||||
GLogLevelFlags log_level,
|
||||
const gchar *message,
|
||||
gpointer user_data);
|
||||
|
||||
/*
|
||||
* GLib doesn't have g_info() yet:
|
||||
* https://bugzilla.gnome.org/show_bug.cgi?id=711103
|
||||
*/
|
||||
#ifndef g_info
|
||||
|
||||
#if defined(G_HAVE_ISO_VARARGS)
|
||||
|
||||
#define g_info(...) g_log (G_LOG_DOMAIN, \
|
||||
G_LOG_LEVEL_INFO, \
|
||||
__VA_ARGS__)
|
||||
|
||||
#elif defined (G_HAVE_GNUC_VARARGS)
|
||||
|
||||
#define g_info(format...) g_log (G_LOG_DOMAIN, \
|
||||
G_LOG_LEVEL_INFO, \
|
||||
format)
|
||||
|
||||
#else
|
||||
|
||||
static void
|
||||
g_info (const gchar *format,
|
||||
...)
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, format);
|
||||
g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format, args);
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
#endif /* no varargs */
|
||||
|
||||
#endif /* g_info */
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __COCKPIT_LOG_H__ */
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (__COCKPIT_INSIDE_COCKPIT_H__) && !defined (COCKPIT_COMPILATION)
|
||||
#error "Only <cockpit/cockpit.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __COCKPIT_TYPES_H__
|
||||
#define __COCKPIT_TYPES_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <cockpit/cockpitenums.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __COCKPIT_TYPES_H__ */
|
|
@ -0,0 +1 @@
|
|||
/cockpitd
|
|
@ -0,0 +1,75 @@
|
|||
COCKPIT_BUILD_INFO = "Built on $(shell date)"
|
||||
|
||||
libexec_PROGRAMS += cockpitd
|
||||
|
||||
cockpitd_SOURCES = \
|
||||
src/daemon/main.c \
|
||||
src/daemon/types.h \
|
||||
src/daemon/daemon.h \
|
||||
src/daemon/daemon.c \
|
||||
src/daemon/auth.h \
|
||||
src/daemon/auth.c \
|
||||
src/daemon/utils.h \
|
||||
src/daemon/utils.c \
|
||||
src/daemon/manager.h \
|
||||
src/daemon/manager.c \
|
||||
src/daemon/network.h \
|
||||
src/daemon/network.c \
|
||||
src/daemon/netinterface.h \
|
||||
src/daemon/netinterface.c \
|
||||
src/daemon/cpumonitor.h \
|
||||
src/daemon/cpumonitor.c \
|
||||
src/daemon/memorymonitor.h \
|
||||
src/daemon/memorymonitor.c \
|
||||
src/daemon/networkmonitor.h \
|
||||
src/daemon/networkmonitor.c \
|
||||
src/daemon/diskiomonitor.h \
|
||||
src/daemon/diskiomonitor.c \
|
||||
src/daemon/storagemanager.h \
|
||||
src/daemon/storagemanager.c \
|
||||
src/daemon/storageprovider.h \
|
||||
src/daemon/storageprovider.c \
|
||||
src/daemon/storageobject.h \
|
||||
src/daemon/storageobject.c \
|
||||
src/daemon/storageblock.h \
|
||||
src/daemon/storageblock.c \
|
||||
src/daemon/storagedrive.h \
|
||||
src/daemon/storagedrive.c \
|
||||
src/daemon/storagemdraid.h \
|
||||
src/daemon/storagemdraid.c \
|
||||
src/daemon/storagevolumegroup.h \
|
||||
src/daemon/storagevolumegroup.c \
|
||||
src/daemon/storagelogicalvolume.h \
|
||||
src/daemon/storagelogicalvolume.c \
|
||||
src/daemon/storagejob.h \
|
||||
src/daemon/storagejob.c \
|
||||
src/daemon/realms.h \
|
||||
src/daemon/realms.c \
|
||||
src/daemon/services.h \
|
||||
src/daemon/services.c \
|
||||
src/daemon/journal.h \
|
||||
src/daemon/journal.c \
|
||||
src/daemon/accounts.h \
|
||||
src/daemon/accounts.c \
|
||||
src/daemon/account.h \
|
||||
src/daemon/account.c \
|
||||
src/daemon/cgroup-show.h \
|
||||
src/daemon/cgroup-show.c \
|
||||
$(NULL)
|
||||
|
||||
cockpitd_CFLAGS = \
|
||||
$(cockpit_cppflags_common) \
|
||||
$(cockpit_cppflags_glib_version) \
|
||||
-I$(top_srcdir)/src/daemon \
|
||||
-I$(top_srcdir)/src/libgsystem \
|
||||
-DG_LOG_DOMAIN=\"cockpitd\" \
|
||||
-DCOCKPIT_BUILD_INFO=\"$(COCKPIT_BUILD_INFO)\" \
|
||||
$(COCKPIT_DAEMON_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
cockpitd_LDADD = \
|
||||
$(COCKPIT_DAEMON_LIBS) \
|
||||
libgsystem.la \
|
||||
libcockpit-1.0.la \
|
||||
-lm \
|
||||
$(NULL)
|
|
@ -0,0 +1,391 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <act/act.h>
|
||||
#include <glib.h>
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
#include "libgsystem.h"
|
||||
|
||||
#include "daemon.h"
|
||||
#include "auth.h"
|
||||
#include "account.h"
|
||||
|
||||
#include <cockpit/cockpit.h>
|
||||
|
||||
typedef struct _AccountClass AccountClass;
|
||||
|
||||
struct _Account
|
||||
{
|
||||
CockpitAccountSkeleton parent_instance;
|
||||
|
||||
ActUser *u;
|
||||
};
|
||||
|
||||
struct _AccountClass
|
||||
{
|
||||
CockpitAccountSkeletonClass parent_class;
|
||||
};
|
||||
|
||||
static void account_iface_init (CockpitAccountIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (Account, account, COCKPIT_TYPE_ACCOUNT_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (COCKPIT_TYPE_ACCOUNT, account_iface_init));
|
||||
|
||||
static void
|
||||
account_finalize (GObject *object)
|
||||
{
|
||||
if (G_OBJECT_CLASS (account_parent_class)->finalize != NULL)
|
||||
G_OBJECT_CLASS (account_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
account_init (Account *account)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
account_constructed (GObject *_object)
|
||||
{
|
||||
if (G_OBJECT_CLASS (account_parent_class)->constructed != NULL)
|
||||
G_OBJECT_CLASS (account_parent_class)->constructed (_object);
|
||||
}
|
||||
|
||||
static void
|
||||
account_class_init (AccountClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = account_finalize;
|
||||
gobject_class->constructed = account_constructed;
|
||||
}
|
||||
|
||||
CockpitAccount *
|
||||
account_new ()
|
||||
{
|
||||
return COCKPIT_ACCOUNT (g_object_new (TYPE_ACCOUNT, NULL));
|
||||
}
|
||||
|
||||
void
|
||||
account_update (Account *acc,
|
||||
ActUser *user)
|
||||
{
|
||||
acc->u = user;
|
||||
if (user)
|
||||
{
|
||||
cockpit_account_set_user_name (COCKPIT_ACCOUNT (acc), act_user_get_user_name (user));
|
||||
cockpit_account_set_real_name (COCKPIT_ACCOUNT (acc), act_user_get_real_name (user));
|
||||
cockpit_account_set_locked (COCKPIT_ACCOUNT (acc), act_user_get_locked (user));
|
||||
cockpit_account_set_last_login (COCKPIT_ACCOUNT (acc), act_user_get_login_time (user));
|
||||
cockpit_account_set_logged_in (COCKPIT_ACCOUNT (acc), act_user_is_logged_in_anywhere (user));
|
||||
cockpit_account_set_groups (COCKPIT_ACCOUNT (acc), act_user_get_groups (user));
|
||||
cockpit_account_emit_changed (COCKPIT_ACCOUNT (acc));
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
account_auth_check (CockpitAccount *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
Account *acc)
|
||||
{
|
||||
uid_t peer;
|
||||
if (!daemon_get_sender_uid (daemon_get (), invocation, &peer))
|
||||
return FALSE;
|
||||
if (acc->u && act_user_get_uid (acc->u) == peer)
|
||||
return TRUE;
|
||||
if (!auth_check_uid_role (invocation, peer, COCKPIT_ROLE_USER_ADMIN))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_get_icon_data_url (CockpitAccount *object,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
Account *acc = ACCOUNT (object);
|
||||
gs_free gchar *raw_data = NULL;
|
||||
gsize raw_size;
|
||||
gs_free gchar *base64_data = NULL;
|
||||
gs_free gchar *data = NULL;
|
||||
|
||||
if (acc->u == NULL)
|
||||
goto out;
|
||||
|
||||
const gchar *icon_file = act_user_get_icon_file (acc->u);
|
||||
if (icon_file == NULL)
|
||||
goto out;
|
||||
|
||||
if (!g_file_get_contents (icon_file, &raw_data, &raw_size, NULL))
|
||||
goto out;
|
||||
|
||||
base64_data = g_base64_encode ((guchar *)raw_data, raw_size);
|
||||
data = g_strdup_printf ("data:image/png;base64,%s", base64_data);
|
||||
|
||||
out:
|
||||
cockpit_account_complete_get_icon_data_url (object, invocation, data? data : "");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_set_icon_data_url (CockpitAccount *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_data)
|
||||
{
|
||||
GError *error = NULL;
|
||||
Account *acc = ACCOUNT (object);
|
||||
|
||||
if (!account_auth_check (object, invocation, acc))
|
||||
return TRUE;
|
||||
|
||||
if (acc->u)
|
||||
{
|
||||
const gchar *base64_data = strstr (arg_data, "base64,");
|
||||
if (base64_data == NULL)
|
||||
goto out;
|
||||
|
||||
base64_data += strlen ("base64,");
|
||||
|
||||
gsize raw_size;
|
||||
gs_free gchar *raw_data = (gchar *)g_base64_decode (base64_data, &raw_size);
|
||||
|
||||
gs_unref_object GFileIOStream *tmp_stream = NULL;
|
||||
gs_unref_object GFile *tmp_file = g_file_new_tmp ("cockpit-user-icon-XXXXXX", &tmp_stream, &error);
|
||||
|
||||
if (tmp_file == NULL)
|
||||
goto out;
|
||||
|
||||
GOutputStream *out = g_io_stream_get_output_stream (G_IO_STREAM (tmp_stream));
|
||||
if (!g_output_stream_write_all (out, raw_data, raw_size, NULL, NULL, &error))
|
||||
goto out;
|
||||
|
||||
if (!g_io_stream_close (G_IO_STREAM (tmp_stream), NULL, &error))
|
||||
goto out;
|
||||
|
||||
gs_free gchar *tmp_path = g_file_get_path (tmp_file);
|
||||
act_user_set_icon_file (acc->u, tmp_path);
|
||||
g_file_delete (tmp_file, NULL, NULL);
|
||||
}
|
||||
|
||||
out:
|
||||
if (error)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR, COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
else
|
||||
cockpit_account_complete_set_icon_data_url (object, invocation);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_set_real_name (CockpitAccount *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_value)
|
||||
{
|
||||
Account *acc = ACCOUNT (object);
|
||||
|
||||
if (!account_auth_check (object, invocation, acc))
|
||||
return TRUE;
|
||||
|
||||
if (acc->u)
|
||||
act_user_set_real_name (acc->u, arg_value);
|
||||
|
||||
cockpit_account_complete_set_real_name (object, invocation);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_set_password (CockpitAccount *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_password)
|
||||
{
|
||||
Account *acc = ACCOUNT (object);
|
||||
|
||||
if (!account_auth_check (object, invocation, acc))
|
||||
return TRUE;
|
||||
|
||||
if (acc->u)
|
||||
{
|
||||
act_user_set_password_mode (acc->u, ACT_USER_PASSWORD_MODE_REGULAR);
|
||||
act_user_set_password (acc->u, arg_password, "");
|
||||
}
|
||||
|
||||
cockpit_account_complete_set_password (object, invocation);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_set_locked (CockpitAccount *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gboolean arg_locked)
|
||||
{
|
||||
Account *acc = ACCOUNT (object);
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_USER_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
if (acc->u)
|
||||
act_user_set_locked (acc->u, arg_locked);
|
||||
|
||||
cockpit_account_complete_set_locked (object, invocation);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_change_groups (CockpitAccount *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *const *arg_add,
|
||||
const gchar *const *arg_remove)
|
||||
{
|
||||
Account *acc = ACCOUNT (object);
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_USER_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
if (acc->u)
|
||||
act_user_change_groups (acc->u, arg_add, arg_remove);
|
||||
|
||||
cockpit_account_complete_change_groups (object, invocation);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
CockpitAccount *object;
|
||||
GDBusMethodInvocation *invocation;
|
||||
} CallData;
|
||||
|
||||
static void
|
||||
delete_account_done (ActUserManager *manager,
|
||||
GAsyncResult *res,
|
||||
CallData *data)
|
||||
{
|
||||
CockpitAccount *object = data->object;
|
||||
GDBusMethodInvocation *invocation = data->invocation;
|
||||
g_free (data);
|
||||
|
||||
GError *error = NULL;
|
||||
gboolean success = act_user_manager_delete_user_finish (manager, res, &error);
|
||||
if (!success)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR, COCKPIT_ERROR_FAILED,
|
||||
"Failed to delete user account: %s", error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
cockpit_account_complete_delete (object, invocation);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_delete (CockpitAccount *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gboolean remove_files)
|
||||
{
|
||||
Account *acc = ACCOUNT (object);
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_USER_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
if (acc->u)
|
||||
{
|
||||
CallData *data = g_new0 (CallData, 1);
|
||||
data->object = object;
|
||||
data->invocation = invocation;
|
||||
|
||||
act_user_manager_delete_user_async (act_user_manager_get_default (),
|
||||
acc->u,
|
||||
remove_files,
|
||||
NULL,
|
||||
(GAsyncReadyCallback)delete_account_done,
|
||||
data);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cockpit_account_complete_delete (object, invocation);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_kill_sessions (CockpitAccount *object,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
Account *acc = ACCOUNT (object);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_USER_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
if (acc->u)
|
||||
{
|
||||
gs_unref_object GDBusConnection *bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM,
|
||||
NULL,
|
||||
&error);
|
||||
if (bus == NULL)
|
||||
goto out;
|
||||
|
||||
gs_unref_variant GVariant *result =
|
||||
g_dbus_connection_call_sync (bus,
|
||||
"org.freedesktop.login1",
|
||||
"/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
"KillUser",
|
||||
g_variant_new ("(ui)",
|
||||
act_user_get_uid (acc->u),
|
||||
SIGTERM),
|
||||
NULL,
|
||||
0,
|
||||
-1,
|
||||
NULL,
|
||||
&error);
|
||||
}
|
||||
|
||||
out:
|
||||
if (error)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR, COCKPIT_ERROR_FAILED,
|
||||
"Failed to kill sessions: %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
cockpit_account_complete_kill_sessions (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
account_iface_init (CockpitAccountIface *iface)
|
||||
{
|
||||
iface->handle_get_icon_data_url = handle_get_icon_data_url;
|
||||
iface->handle_set_icon_data_url = handle_set_icon_data_url;
|
||||
iface->handle_set_real_name = handle_set_real_name;
|
||||
iface->handle_set_password = handle_set_password;
|
||||
iface->handle_set_locked = handle_set_locked;
|
||||
iface->handle_change_groups = handle_change_groups;
|
||||
iface->handle_delete = handle_delete;
|
||||
iface->handle_kill_sessions = handle_kill_sessions;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __ACCOUNT_H__
|
||||
#define __ACCOUNT_H__
|
||||
|
||||
#include <act/act.h>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_ACCOUNT (account_get_type ())
|
||||
#define ACCOUNT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_ACCOUNT, Account))
|
||||
#define IS_ACCOUNT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_ACCOUNT))
|
||||
|
||||
GType account_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CockpitAccount * account_new (void);
|
||||
|
||||
void account_update (Account *acc,
|
||||
ActUser *user);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __ACCOUNTS_H__ */
|
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <act/act.h>
|
||||
|
||||
#include "libgsystem.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include "daemon.h"
|
||||
#include "auth.h"
|
||||
#include "accounts.h"
|
||||
#include "account.h"
|
||||
|
||||
#include <cockpit/cockpit.h>
|
||||
|
||||
typedef struct _AccountsClass AccountsClass;
|
||||
|
||||
struct _Accounts {
|
||||
CockpitAccountsSkeleton parent_instance;
|
||||
|
||||
ActUserManager *um;
|
||||
GHashTable *act_user_to_account;
|
||||
};
|
||||
|
||||
struct _AccountsClass {
|
||||
CockpitAccountsSkeletonClass parent_class;
|
||||
};
|
||||
|
||||
static void accounts_iface_init (CockpitAccountsIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (Accounts, accounts, COCKPIT_TYPE_ACCOUNTS_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (COCKPIT_TYPE_ACCOUNTS, accounts_iface_init));
|
||||
|
||||
static void
|
||||
user_added (ActUserManager *um,
|
||||
ActUser *user,
|
||||
Accounts *accounts)
|
||||
{
|
||||
if (act_user_is_system_account (user))
|
||||
return;
|
||||
|
||||
GDBusObjectManagerServer *object_manager_server = daemon_get_object_manager (daemon_get ());
|
||||
|
||||
CockpitAccount *acc = account_new ();
|
||||
account_update (ACCOUNT (acc), user);
|
||||
|
||||
gs_free gchar *path =
|
||||
utils_generate_object_path ("/com/redhat/Cockpit/Accounts",
|
||||
cockpit_account_get_user_name (acc));
|
||||
gs_unref_object CockpitObjectSkeleton *obj = cockpit_object_skeleton_new (path);
|
||||
cockpit_object_skeleton_set_account (obj, acc);
|
||||
g_dbus_object_manager_server_export_uniquely (object_manager_server,
|
||||
G_DBUS_OBJECT_SKELETON (obj));
|
||||
|
||||
g_hash_table_insert (accounts->act_user_to_account, user, ACCOUNT(acc));
|
||||
}
|
||||
|
||||
static void
|
||||
user_removed (ActUserManager *um,
|
||||
ActUser *user,
|
||||
Accounts *accounts)
|
||||
{
|
||||
GDBusObjectManagerServer *object_manager_server = daemon_get_object_manager (daemon_get ());
|
||||
|
||||
Account *acc = g_hash_table_lookup (accounts->act_user_to_account, user);
|
||||
if (acc)
|
||||
{
|
||||
account_update (acc, NULL);
|
||||
g_dbus_object_manager_server_unexport (object_manager_server,
|
||||
g_dbus_object_get_object_path (g_dbus_interface_get_object (G_DBUS_INTERFACE (acc))));
|
||||
g_hash_table_remove (accounts->act_user_to_account, user);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
user_changed (ActUserManager *um,
|
||||
ActUser *user,
|
||||
Accounts *accounts)
|
||||
{
|
||||
Account *acc = g_hash_table_lookup (accounts->act_user_to_account, user);
|
||||
if (acc)
|
||||
account_update (acc, user);
|
||||
}
|
||||
|
||||
static void
|
||||
users_loaded (ActUserManager *manager,
|
||||
GParamSpec *pspec,
|
||||
Accounts *accounts)
|
||||
{
|
||||
if (act_user_manager_no_service (manager))
|
||||
g_warning ("Can't contact accountsservice");
|
||||
|
||||
GSList *list = act_user_manager_list_users (accounts->um);
|
||||
|
||||
g_signal_connect (accounts->um, "user-changed", G_CALLBACK (user_changed), accounts);
|
||||
g_signal_connect (accounts->um, "user-is-logged-in-changed", G_CALLBACK (user_changed), accounts);
|
||||
g_signal_connect (accounts->um, "user-added", G_CALLBACK (user_added), accounts);
|
||||
g_signal_connect (accounts->um, "user-removed", G_CALLBACK (user_removed), accounts);
|
||||
|
||||
for (GSList *l = list; l; l = l->next)
|
||||
{
|
||||
ActUser *user = l->data;
|
||||
user_added (accounts->um, user, accounts);
|
||||
}
|
||||
g_slist_free (list);
|
||||
}
|
||||
|
||||
static void
|
||||
accounts_finalize (GObject *object)
|
||||
{
|
||||
Accounts *accounts = ACCOUNTS (object);
|
||||
g_hash_table_unref (accounts->act_user_to_account);
|
||||
|
||||
if (G_OBJECT_CLASS (accounts_parent_class)->finalize != NULL)
|
||||
G_OBJECT_CLASS (accounts_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
accounts_init (Accounts *accounts)
|
||||
{
|
||||
accounts->act_user_to_account = g_hash_table_new_full (g_direct_hash,
|
||||
g_direct_equal,
|
||||
NULL,
|
||||
g_object_unref);
|
||||
accounts->um = act_user_manager_get_default ();
|
||||
|
||||
gboolean loaded;
|
||||
g_object_get (accounts->um, "is-loaded", &loaded, NULL);
|
||||
if (loaded)
|
||||
users_loaded (accounts->um, NULL, accounts);
|
||||
else
|
||||
g_signal_connect (accounts->um, "notify::is-loaded", G_CALLBACK (users_loaded), accounts);
|
||||
|
||||
/* A "role" is a POSIX group plus localized descriptions.
|
||||
Eventually, this will be configurable by dropping files into a
|
||||
directory, but for now we just hard code some to get started.
|
||||
*/
|
||||
|
||||
GVariantBuilder roles_builder;
|
||||
g_variant_builder_init (&roles_builder, G_VARIANT_TYPE ("a(ss)"));
|
||||
g_variant_builder_add (&roles_builder, "(ss)",
|
||||
COCKPIT_ROLE_ADMIN, "Server Administrator");
|
||||
g_variant_builder_add (&roles_builder, "(ss)",
|
||||
COCKPIT_ROLE_USER_ADMIN, "User Account Administrator");
|
||||
g_variant_builder_add (&roles_builder, "(ss)",
|
||||
COCKPIT_ROLE_REALM_ADMIN, "Realm Administrator");
|
||||
g_variant_builder_add (&roles_builder, "(ss)",
|
||||
COCKPIT_ROLE_STORAGE_ADMIN, "Storage Administrator");
|
||||
cockpit_accounts_set_roles (COCKPIT_ACCOUNTS (accounts), g_variant_builder_end (&roles_builder));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
accounts_authorize_method (GDBusInterfaceSkeleton *interface,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
return daemon_authorize_method (daemon_get (), invocation);
|
||||
}
|
||||
|
||||
static void
|
||||
accounts_class_init (AccountsClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GDBusInterfaceSkeletonClass *skeleton_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = accounts_finalize;
|
||||
|
||||
skeleton_class = G_DBUS_INTERFACE_SKELETON_CLASS (klass);
|
||||
skeleton_class->g_authorize_method = accounts_authorize_method;
|
||||
}
|
||||
|
||||
CockpitAccounts *
|
||||
accounts_new (void)
|
||||
{
|
||||
return COCKPIT_ACCOUNTS (g_object_new (TYPE_ACCOUNTS, NULL));
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
CockpitAccounts *object;
|
||||
GDBusMethodInvocation *invocation;
|
||||
gchar *password;
|
||||
gboolean locked;
|
||||
} CallData;
|
||||
|
||||
static void
|
||||
create_account_done (ActUserManager *manager,
|
||||
GAsyncResult *res,
|
||||
CallData *data)
|
||||
{
|
||||
CockpitAccounts *object = data->object;
|
||||
GDBusMethodInvocation *invocation = data->invocation;
|
||||
gs_free gchar *password = data->password;
|
||||
gboolean locked = data->locked;
|
||||
g_free (data);
|
||||
|
||||
GError *error = NULL;
|
||||
ActUser *user = act_user_manager_create_user_finish (manager, res, &error);
|
||||
if (user == NULL)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR, COCKPIT_ERROR_FAILED,
|
||||
"Failed to create user account: %s", error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (password && *password)
|
||||
{
|
||||
act_user_set_password_mode (user, ACT_USER_PASSWORD_MODE_REGULAR);
|
||||
act_user_set_password (user, password, "");
|
||||
}
|
||||
|
||||
act_user_set_locked (user, locked);
|
||||
|
||||
cockpit_accounts_complete_create_account (object, invocation);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_create_account (CockpitAccounts *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_user_name,
|
||||
const gchar *arg_real_name,
|
||||
const gchar *arg_password,
|
||||
gboolean arg_locked)
|
||||
{
|
||||
Accounts *accounts = ACCOUNTS (object);
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_USER_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
CallData *data = g_new0 (CallData, 1);
|
||||
data->object = object;
|
||||
data->invocation = invocation;
|
||||
data->password = g_strdup (arg_password);
|
||||
data->locked = arg_locked;
|
||||
|
||||
act_user_manager_create_user_async (accounts->um,
|
||||
arg_user_name,
|
||||
arg_real_name,
|
||||
ACT_USER_ACCOUNT_TYPE_STANDARD,
|
||||
NULL,
|
||||
(GAsyncReadyCallback)create_account_done,
|
||||
data);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
accounts_iface_init (CockpitAccountsIface *iface)
|
||||
{
|
||||
iface->handle_create_account = handle_create_account;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __ACCOUNTS_H__
|
||||
#define __ACCOUNTS_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_ACCOUNTS (accounts_get_type ())
|
||||
#define ACCOUNTS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_ACCOUNTS, Accounts))
|
||||
#define IS_ACCOUNTS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_ACCOUNTS))
|
||||
|
||||
GType accounts_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CockpitAccounts * accounts_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __ACCOUNTS_H__ */
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include "libgsystem.h"
|
||||
#include "auth.h"
|
||||
#include "daemon.h"
|
||||
|
||||
static struct passwd *
|
||||
getpwuid_a (uid_t uid,
|
||||
int *errp)
|
||||
{
|
||||
int err;
|
||||
long bufsize = sysconf (_SC_GETPW_R_SIZE_MAX);
|
||||
struct passwd *buf, *ret;
|
||||
|
||||
buf = malloc (sizeof(struct passwd) + bufsize);
|
||||
if (buf == NULL)
|
||||
err = ENOMEM;
|
||||
else
|
||||
err = getpwuid_r (uid, buf, (char *)(buf + 1), bufsize, &ret);
|
||||
|
||||
if (ret == NULL)
|
||||
{
|
||||
free (buf);
|
||||
if (err == 0)
|
||||
err = ENOENT;
|
||||
}
|
||||
|
||||
if (errp)
|
||||
*errp = err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct group *
|
||||
getgrnam_a (const gchar *group,
|
||||
int *errp)
|
||||
{
|
||||
int err;
|
||||
long bufsize = sysconf (_SC_GETGR_R_SIZE_MAX);
|
||||
struct group *buf, *ret;
|
||||
|
||||
buf = malloc (sizeof(struct group) + bufsize);
|
||||
if (buf == NULL)
|
||||
err = ENOMEM;
|
||||
else
|
||||
err = getgrnam_r (group, buf, (char *)(buf + 1), bufsize, &ret);
|
||||
|
||||
if (ret == NULL)
|
||||
{
|
||||
free (buf);
|
||||
if (err == 0)
|
||||
err = ENOENT;
|
||||
}
|
||||
|
||||
if (errp)
|
||||
*errp = err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gid_t *
|
||||
getgrouplist_a (const char *user,
|
||||
int gid,
|
||||
int *n_groupsp,
|
||||
int *errp)
|
||||
{
|
||||
int err, n_groups;
|
||||
gid_t *buf;
|
||||
|
||||
n_groups = 200;
|
||||
buf = malloc ((n_groups + 1) * sizeof (gid_t));
|
||||
if (buf == NULL)
|
||||
err = ENOMEM;
|
||||
else
|
||||
{
|
||||
// Super paranoid: The user might have been added to more groups
|
||||
// since the last call and thus getgrouplist can fail more than
|
||||
// once because of insufficent space.
|
||||
|
||||
int tries = 0;
|
||||
err = 0;
|
||||
while (getgrouplist (user, gid, buf, &n_groups) == -1)
|
||||
{
|
||||
buf = realloc (buf, (n_groups + 1) * sizeof (gid_t));
|
||||
if (buf == NULL)
|
||||
{
|
||||
err = ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
tries += 1;
|
||||
if (tries > 5)
|
||||
{
|
||||
err = EIO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (err == 0)
|
||||
buf[n_groups] = (gid_t)-1;
|
||||
else
|
||||
{
|
||||
free (buf);
|
||||
buf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (errp)
|
||||
*errp = err;
|
||||
if (n_groupsp)
|
||||
*n_groupsp = n_groups;
|
||||
return buf;
|
||||
}
|
||||
|
||||
gboolean
|
||||
auth_uid_is_wheel (uid_t uid)
|
||||
{
|
||||
gs_free struct passwd *pw = getpwuid_a (uid, NULL);
|
||||
if (pw == NULL)
|
||||
return FALSE;
|
||||
|
||||
gs_free struct group *gr = getgrnam_a ("wheel", NULL);
|
||||
if (gr == NULL)
|
||||
return FALSE;
|
||||
|
||||
int n_groups;
|
||||
gs_free gid_t *gids = getgrouplist_a (pw->pw_name, pw->pw_gid, &n_groups, NULL);
|
||||
if (gids == NULL)
|
||||
return FALSE;
|
||||
|
||||
for (int i = 0; i < n_groups; i++)
|
||||
if (gids[i] == gr->gr_gid)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
auth_check_uid_role (GDBusMethodInvocation *invocation,
|
||||
uid_t uid,
|
||||
const gchar *role)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (uid == 0)
|
||||
return TRUE;
|
||||
|
||||
gs_free struct passwd *pw = getpwuid_a (uid, &err);
|
||||
if (pw == NULL)
|
||||
goto error;
|
||||
|
||||
gs_free struct group *wheel_gr = getgrnam_a ("wheel", NULL);
|
||||
gs_free struct group *role_gr = role ? getgrnam_a (role, NULL) : NULL;
|
||||
|
||||
int n_groups;
|
||||
gs_free gid_t *gids = getgrouplist_a (pw->pw_name, pw->pw_gid, &n_groups, &err);
|
||||
if (gids == NULL)
|
||||
goto error;
|
||||
|
||||
for (int i = 0; i < n_groups; i++)
|
||||
if ((wheel_gr && gids[i] == wheel_gr->gr_gid)
|
||||
|| (role_gr && gids[i] == role_gr->gr_gid))
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
if (err)
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR, COCKPIT_ERROR_FAILED,
|
||||
"%s", strerror(err));
|
||||
else
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED,
|
||||
"Method %s.%s needs role '%s'",
|
||||
g_dbus_method_invocation_get_interface_name (invocation),
|
||||
g_dbus_method_invocation_get_method_name (invocation),
|
||||
role ? role : "wheel");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
auth_check_sender_role (GDBusMethodInvocation *invocation,
|
||||
const gchar *role)
|
||||
{
|
||||
uid_t peer;
|
||||
if (!daemon_get_sender_uid (daemon_get (), invocation, &peer))
|
||||
return FALSE;
|
||||
if (!auth_check_uid_role (invocation, peer, role))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __AUTH_H__
|
||||
#define __AUTH_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define COCKPIT_ROLE_ADMIN "wheel"
|
||||
#define COCKPIT_ROLE_USER_ADMIN "cockpit-user-admin"
|
||||
#define COCKPIT_ROLE_REALM_ADMIN "cockpit-realm-admin"
|
||||
#define COCKPIT_ROLE_STORAGE_ADMIN "cockpit-storage-admin"
|
||||
|
||||
gboolean auth_uid_is_wheel (uid_t uid);
|
||||
|
||||
gboolean auth_check_uid_role (GDBusMethodInvocation *invocation,
|
||||
uid_t uid,
|
||||
const gchar *role);
|
||||
gboolean auth_check_sender_role (GDBusMethodInvocation *invocation,
|
||||
const gchar *role);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __DAEMON_H__ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,11 @@
|
|||
#ifndef CGROUP_SHOW_H
|
||||
#define CGROUP_SHOW_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
#include <glib.h>
|
||||
|
||||
GVariant *collect_cgroup_and_extra_by_spec(const char *spec, bool kernel_threads, bool all,
|
||||
const pid_t extra_pids[], unsigned n_extra_pids);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,425 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "cpumonitor.h"
|
||||
|
||||
/**
|
||||
* SECTION:cpumonitor
|
||||
* @title: CpuMonitor
|
||||
* @short_description: Implementation of #CockpitResourceMonitor for CPU usage
|
||||
*
|
||||
* This type provides an implementation of the #CockpitResourceMonitor interface for CPU usage.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gint64 timestamp;
|
||||
gint64 nice_value;
|
||||
gint64 user_value;
|
||||
gint64 system_value;
|
||||
gint64 iowait_value;
|
||||
gdouble nice_percentage;
|
||||
gdouble user_percentage;
|
||||
gdouble system_percentage;
|
||||
gdouble iowait_percentage;
|
||||
} Sample;
|
||||
|
||||
typedef struct _CpuMonitorClass CpuMonitorClass;
|
||||
|
||||
/**
|
||||
* CpuMonitor:
|
||||
*
|
||||
* The #CpuMonitor structure contains only private data and should
|
||||
* only be accessed using the provided API.
|
||||
*/
|
||||
struct _CpuMonitor
|
||||
{
|
||||
CockpitResourceMonitorSkeleton parent_instance;
|
||||
|
||||
Daemon *daemon;
|
||||
|
||||
guint user_hz;
|
||||
|
||||
guint samples_max;
|
||||
gint samples_prev;
|
||||
guint samples_next;
|
||||
|
||||
/* Arrays of samples_max Sample instances (nice, user, system, iowait) */
|
||||
Sample *samples;
|
||||
};
|
||||
|
||||
struct _CpuMonitorClass
|
||||
{
|
||||
CockpitResourceMonitorSkeletonClass parent_class;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DAEMON
|
||||
};
|
||||
|
||||
static void resource_monitor_iface_init (CockpitResourceMonitorIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (CpuMonitor, cpu_monitor, COCKPIT_TYPE_RESOURCE_MONITOR_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (COCKPIT_TYPE_RESOURCE_MONITOR, resource_monitor_iface_init));
|
||||
|
||||
static void on_tick (Daemon *daemon,
|
||||
guint64 delta_usec,
|
||||
gpointer user_data);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
cpu_monitor_init (CpuMonitor *monitor)
|
||||
{
|
||||
const gchar *legends[5] = {"Nice", "User", "Kernel", "I/O Wait", NULL}; /* TODO: i18n */
|
||||
|
||||
g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (monitor),
|
||||
G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
|
||||
|
||||
monitor->user_hz = sysconf (_SC_CLK_TCK);
|
||||
if (monitor->user_hz == -1 || monitor->user_hz == 0)
|
||||
{
|
||||
monitor->user_hz = 100;
|
||||
g_warning ("sysconf (_SC_CLK_TCK) returned %d - forcing user_hz to 100", monitor->user_hz);
|
||||
}
|
||||
|
||||
/* Assign legends */
|
||||
cockpit_resource_monitor_set_legends (COCKPIT_RESOURCE_MONITOR (monitor), legends);
|
||||
|
||||
monitor->samples_prev = -1;
|
||||
monitor->samples_max = 300;
|
||||
monitor->samples = g_new0 (Sample, monitor->samples_max);
|
||||
}
|
||||
|
||||
static void
|
||||
cpu_monitor_finalize (GObject *object)
|
||||
{
|
||||
CpuMonitor *monitor = CPU_MONITOR (object);
|
||||
|
||||
g_free (monitor->samples);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (monitor->daemon, G_CALLBACK (on_tick), monitor);
|
||||
|
||||
G_OBJECT_CLASS (cpu_monitor_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
cpu_monitor_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
CpuMonitor *monitor = CPU_MONITOR (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DAEMON:
|
||||
g_value_set_object (value, cpu_monitor_get_daemon (monitor));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cpu_monitor_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
CpuMonitor *monitor = CPU_MONITOR (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DAEMON:
|
||||
g_assert (monitor->daemon == NULL);
|
||||
/* we don't take a reference to the daemon */
|
||||
monitor->daemon = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void collect (CpuMonitor *monitor);
|
||||
|
||||
static void
|
||||
on_tick (Daemon *daemon,
|
||||
guint64 delta_usec,
|
||||
gpointer user_data)
|
||||
{
|
||||
CpuMonitor *monitor = CPU_MONITOR (user_data);
|
||||
collect (monitor);
|
||||
}
|
||||
|
||||
static void
|
||||
cpu_monitor_constructed (GObject *object)
|
||||
{
|
||||
CpuMonitor *monitor = CPU_MONITOR (object);
|
||||
|
||||
cockpit_resource_monitor_set_num_samples (COCKPIT_RESOURCE_MONITOR (monitor), monitor->samples_max);
|
||||
cockpit_resource_monitor_set_num_series (COCKPIT_RESOURCE_MONITOR (monitor), 4);
|
||||
|
||||
g_signal_connect (monitor->daemon, "tick", G_CALLBACK (on_tick), monitor);
|
||||
collect (monitor);
|
||||
|
||||
if (G_OBJECT_CLASS (cpu_monitor_parent_class)->constructed != NULL)
|
||||
G_OBJECT_CLASS (cpu_monitor_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
cpu_monitor_class_init (CpuMonitorClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = cpu_monitor_finalize;
|
||||
gobject_class->constructed = cpu_monitor_constructed;
|
||||
gobject_class->set_property = cpu_monitor_set_property;
|
||||
gobject_class->get_property = cpu_monitor_get_property;
|
||||
|
||||
/**
|
||||
* CpuMonitor:daemon:
|
||||
*
|
||||
* The #Daemon for the object.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_DAEMON,
|
||||
g_param_spec_object ("daemon",
|
||||
NULL,
|
||||
NULL,
|
||||
TYPE_DAEMON,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
/**
|
||||
* cpu_monitor_new:
|
||||
* @daemon: A #Daemon.
|
||||
*
|
||||
* Creates a new #CpuMonitor instance.
|
||||
*
|
||||
* Returns: A new #CpuMonitor. Free with g_object_unref().
|
||||
*/
|
||||
CockpitResourceMonitor *
|
||||
cpu_monitor_new (Daemon *daemon)
|
||||
{
|
||||
g_return_val_if_fail (IS_DAEMON (daemon), NULL);
|
||||
return COCKPIT_RESOURCE_MONITOR (g_object_new (TYPE_CPU_MONITOR,
|
||||
"daemon", daemon,
|
||||
NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* cpu_monitor_get_daemon:
|
||||
* @monitor: A #CpuMonitor.
|
||||
*
|
||||
* Gets the daemon used by @monitor.
|
||||
*
|
||||
* Returns: A #Daemon. Do not free, the object is owned by @monitor.
|
||||
*/
|
||||
Daemon *
|
||||
cpu_monitor_get_daemon (CpuMonitor *monitor)
|
||||
{
|
||||
g_return_val_if_fail (IS_CPU_MONITOR (monitor), NULL);
|
||||
return monitor->daemon;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gboolean
|
||||
calc_percentage (CpuMonitor *monitor,
|
||||
Sample *sample,
|
||||
Sample *last,
|
||||
gint64 sample_value,
|
||||
gint64 last_value)
|
||||
{
|
||||
gdouble ret;
|
||||
gdouble secs_usage_in_period;
|
||||
gdouble period;
|
||||
|
||||
secs_usage_in_period = (((gdouble) sample_value) - ((gdouble) last_value)) / monitor->user_hz;
|
||||
period = ((gdouble) (sample->timestamp - last->timestamp)) / ((gdouble) G_USEC_PER_SEC);
|
||||
ret = 100.0 * secs_usage_in_period / period;
|
||||
if (ret < 0.0)
|
||||
ret = 0.0;
|
||||
if (ret > 100.0)
|
||||
ret = 1.0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* TODO: this should be optimized so we don't allocate memory and call open()/close() all the time */
|
||||
static void
|
||||
collect (CpuMonitor *monitor)
|
||||
{
|
||||
gchar *contents = NULL;
|
||||
gsize len;
|
||||
GError *error;
|
||||
gchar **lines = NULL;
|
||||
guint n;
|
||||
gint64 now;
|
||||
GVariantBuilder builder;
|
||||
Sample *sample = NULL;
|
||||
|
||||
error = NULL;
|
||||
if (!g_file_get_contents ("/proc/stat",
|
||||
&contents,
|
||||
&len,
|
||||
&error))
|
||||
{
|
||||
g_warning ("Error loading contents /proc/stat: %s (%s, %d)",
|
||||
error->message, g_quark_to_string (error->domain), error->code);
|
||||
g_error_free (error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
now = g_get_real_time ();
|
||||
|
||||
/* see 'man proc' for the format of /proc/stat */
|
||||
|
||||
lines = g_strsplit (contents, "\n", -1);
|
||||
for (n = 0; lines != NULL && lines[n] != NULL; n++)
|
||||
{
|
||||
const gchar *line = lines[n];
|
||||
guint64 user;
|
||||
guint64 nice;
|
||||
guint64 system;
|
||||
guint64 idle;
|
||||
guint64 iowait;
|
||||
Sample *last;
|
||||
|
||||
if (!(g_str_has_prefix (line, "cpu ")))
|
||||
continue;
|
||||
|
||||
last = NULL;
|
||||
if (monitor->samples_prev != -1)
|
||||
last = &(monitor->samples[monitor->samples_prev]);
|
||||
sample = &(monitor->samples[monitor->samples_next]);
|
||||
|
||||
#define FMT64 "%" G_GUINT64_FORMAT " "
|
||||
if (sscanf (line + sizeof ("cpu ") - 1, FMT64 FMT64 FMT64 FMT64 FMT64,
|
||||
&user,
|
||||
&nice,
|
||||
&system,
|
||||
&idle,
|
||||
&iowait) != 5)
|
||||
{
|
||||
g_warning ("Error parsing line %d of /proc/stat with content `%s'", n, line);
|
||||
continue;
|
||||
}
|
||||
|
||||
sample->timestamp = now;
|
||||
sample->nice_value = nice;
|
||||
sample->user_value = user;
|
||||
sample->system_value = system;
|
||||
sample->iowait_value = iowait;
|
||||
|
||||
if (last != NULL)
|
||||
{
|
||||
sample->nice_percentage = calc_percentage (monitor, sample, last, sample->nice_value, last->nice_value);
|
||||
sample->user_percentage = calc_percentage (monitor, sample, last, sample->user_value, last->user_value);
|
||||
sample->system_percentage = calc_percentage (monitor, sample, last, sample->system_value, last->system_value);
|
||||
sample->iowait_percentage = calc_percentage (monitor, sample, last, sample->iowait_value, last->iowait_value);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
g_strfreev (lines);
|
||||
g_free (contents);
|
||||
|
||||
if (sample != NULL)
|
||||
{
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("ad"));
|
||||
g_variant_builder_add (&builder, "d", sample->nice_percentage);
|
||||
g_variant_builder_add (&builder, "d", sample->user_percentage);
|
||||
g_variant_builder_add (&builder, "d", sample->system_percentage);
|
||||
g_variant_builder_add (&builder, "d", sample->iowait_percentage);
|
||||
cockpit_resource_monitor_emit_new_sample (COCKPIT_RESOURCE_MONITOR (monitor),
|
||||
now, g_variant_builder_end (&builder));
|
||||
}
|
||||
|
||||
monitor->samples_prev = monitor->samples_next;
|
||||
monitor->samples_next += 1;
|
||||
if (monitor->samples_next == monitor->samples_max)
|
||||
monitor->samples_next = 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gboolean
|
||||
handle_get_samples (CockpitResourceMonitor *_monitor,
|
||||
GDBusMethodInvocation *invocation,
|
||||
GVariant *arg_options)
|
||||
{
|
||||
CpuMonitor *monitor = CPU_MONITOR (_monitor);
|
||||
GVariantBuilder builder;
|
||||
gint n;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(xad)"));
|
||||
for (n = 0; n < monitor->samples_max; n++)
|
||||
{
|
||||
gint pos;
|
||||
GVariantBuilder sample_builder;
|
||||
|
||||
pos = monitor->samples_next + n;
|
||||
if (pos > monitor->samples_max)
|
||||
pos -= monitor->samples_max;
|
||||
|
||||
if (monitor->samples[pos].timestamp == 0)
|
||||
continue;
|
||||
|
||||
g_variant_builder_init (&sample_builder, G_VARIANT_TYPE ("ad"));
|
||||
g_variant_builder_add (&sample_builder, "d", monitor->samples[pos].nice_percentage);
|
||||
g_variant_builder_add (&sample_builder, "d", monitor->samples[pos].user_percentage);
|
||||
g_variant_builder_add (&sample_builder, "d", monitor->samples[pos].system_percentage);
|
||||
g_variant_builder_add (&sample_builder, "d", monitor->samples[pos].iowait_percentage);
|
||||
|
||||
g_variant_builder_add (&builder, "(x@ad)",
|
||||
monitor->samples[pos].timestamp,
|
||||
g_variant_builder_end (&sample_builder));
|
||||
}
|
||||
cockpit_resource_monitor_complete_get_samples (_monitor, invocation,
|
||||
g_variant_builder_end (&builder));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
resource_monitor_iface_init (CockpitResourceMonitorIface *iface)
|
||||
{
|
||||
iface->handle_get_samples = handle_get_samples;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __CPU_MONITOR_H__
|
||||
#define __CPU_MONITOR_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_CPU_MONITOR (cpu_monitor_get_type ())
|
||||
#define CPU_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_CPU_MONITOR, CpuMonitor))
|
||||
#define IS_CPU_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_CPU_MONITOR))
|
||||
|
||||
GType cpu_monitor_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CockpitResourceMonitor * cpu_monitor_new (Daemon *daemon);
|
||||
|
||||
Daemon * cpu_monitor_get_daemon (CpuMonitor *monitor);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CPU_MONITOR_H__ */
|
|
@ -0,0 +1,570 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "libgsystem.h"
|
||||
|
||||
#include "daemon.h"
|
||||
#include "auth.h"
|
||||
#include "manager.h"
|
||||
#include "network.h"
|
||||
#include "cpumonitor.h"
|
||||
#include "memorymonitor.h"
|
||||
#include "networkmonitor.h"
|
||||
#include "diskiomonitor.h"
|
||||
#include "storageprovider.h"
|
||||
#include "storagemanager.h"
|
||||
#include "realms.h"
|
||||
#include "services.h"
|
||||
#include "journal.h"
|
||||
#include "accounts.h"
|
||||
|
||||
#include <cockpit/cockpit.h>
|
||||
|
||||
/**
|
||||
* SECTION:daemon
|
||||
* @title: Daemon
|
||||
* @short_description: Main daemon object
|
||||
*
|
||||
* Object holding all global state.
|
||||
*/
|
||||
|
||||
typedef struct _DaemonClass DaemonClass;
|
||||
|
||||
/**
|
||||
* Daemon:
|
||||
*
|
||||
* The #Daemon structure contains only private data and should only be
|
||||
* accessed using the provided API.
|
||||
*/
|
||||
struct _Daemon
|
||||
{
|
||||
GObject parent_instance;
|
||||
GDBusProxy *system_bus_proxy;
|
||||
GDBusConnection *connection;
|
||||
GDBusObjectManagerServer *object_manager;
|
||||
gchar *http_root;
|
||||
|
||||
StorageProvider *storage_provider;
|
||||
|
||||
guint tick_timeout_id;
|
||||
gint64 last_tick;
|
||||
};
|
||||
|
||||
struct _DaemonClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (*tick) (Daemon *daemon,
|
||||
guint64 delta_usec);
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_CONNECTION,
|
||||
PROP_OBJECT_MANAGER,
|
||||
PROP_HTTP_ROOT
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
TICK_SIGNAL,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(Daemon, daemon, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
daemon_finalize (GObject *object)
|
||||
{
|
||||
Daemon *daemon = DAEMON (object);
|
||||
|
||||
g_object_unref (daemon->storage_provider);
|
||||
g_object_unref (daemon->object_manager);
|
||||
g_object_unref (daemon->connection);
|
||||
g_object_unref (daemon->system_bus_proxy);
|
||||
|
||||
if (daemon->tick_timeout_id > 0)
|
||||
g_source_remove (daemon->tick_timeout_id);
|
||||
|
||||
g_free (daemon->http_root);
|
||||
|
||||
if (G_OBJECT_CLASS (daemon_parent_class)->finalize != NULL)
|
||||
G_OBJECT_CLASS (daemon_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
daemon_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
Daemon *daemon = DAEMON (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CONNECTION:
|
||||
g_value_set_object (value, daemon_get_connection (daemon));
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_MANAGER:
|
||||
g_value_set_object (value, daemon_get_object_manager (daemon));
|
||||
break;
|
||||
|
||||
case PROP_HTTP_ROOT:
|
||||
g_value_set_string (value, daemon_get_http_root (daemon));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
daemon_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
Daemon *daemon = DAEMON (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CONNECTION:
|
||||
g_assert (daemon->connection == NULL);
|
||||
daemon->connection = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
case PROP_HTTP_ROOT:
|
||||
g_assert (daemon->http_root == NULL);
|
||||
daemon->http_root = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
daemon_init (Daemon *daemon)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_timeout (gpointer user_data)
|
||||
{
|
||||
Daemon *daemon = DAEMON (user_data);
|
||||
guint64 delta_usec = 0;
|
||||
gint64 now;
|
||||
|
||||
now = g_get_monotonic_time ();
|
||||
if (daemon->last_tick != 0)
|
||||
delta_usec = now - daemon->last_tick;
|
||||
daemon->last_tick = now;
|
||||
|
||||
g_signal_emit (daemon, signals[TICK_SIGNAL], 0, delta_usec);
|
||||
|
||||
return TRUE; /* keep source around */
|
||||
}
|
||||
|
||||
static Daemon *_daemon_instance;
|
||||
|
||||
static void
|
||||
daemon_constructed (GObject *_object)
|
||||
{
|
||||
Daemon *daemon = DAEMON (_object);
|
||||
CockpitManager *manager;
|
||||
CockpitNetwork *network = NULL;
|
||||
CockpitResourceMonitor *monitor;
|
||||
CockpitRealms *realms;
|
||||
CockpitServices *services;
|
||||
CockpitJournal *journal;
|
||||
CockpitAccounts *accounts;
|
||||
CockpitStorageManager *storage_manager;
|
||||
CockpitObjectSkeleton *object = NULL;
|
||||
|
||||
g_assert (_daemon_instance == NULL);
|
||||
_daemon_instance = daemon;
|
||||
|
||||
daemon->system_bus_proxy = g_dbus_proxy_new_sync (daemon->connection, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
|
||||
NULL, "org.freedesktop.DBus",
|
||||
"/org/freedesktop/DBus",
|
||||
"org.freedesktop.DBus", NULL, NULL);
|
||||
g_assert (daemon->system_bus_proxy != NULL);
|
||||
|
||||
daemon->object_manager = g_dbus_object_manager_server_new ("/com/redhat/Cockpit");
|
||||
|
||||
/* /com/redhat/Cockpit/Manager */
|
||||
manager = manager_new (daemon);
|
||||
object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/Manager");
|
||||
cockpit_object_skeleton_set_manager (object, manager);
|
||||
g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
|
||||
g_object_unref (manager);
|
||||
g_object_unref (object);
|
||||
|
||||
/* /com/redhat/Cockpit/Network */
|
||||
network = network_new (daemon);
|
||||
object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/Network");
|
||||
cockpit_object_skeleton_set_network (object, network);
|
||||
g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
|
||||
g_clear_object (&network);
|
||||
g_clear_object (&object);
|
||||
|
||||
/* /com/redhat/Cockpit/CpuMonitor */
|
||||
monitor = cpu_monitor_new (daemon);
|
||||
object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/CpuMonitor");
|
||||
cockpit_object_skeleton_set_resource_monitor (object, monitor);
|
||||
g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
|
||||
g_object_unref (monitor);
|
||||
g_object_unref (object);
|
||||
|
||||
/* /com/redhat/Cockpit/MemoryMonitor */
|
||||
monitor = memory_monitor_new (daemon);
|
||||
object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/MemoryMonitor");
|
||||
cockpit_object_skeleton_set_resource_monitor (object, monitor);
|
||||
g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
|
||||
g_object_unref (monitor);
|
||||
g_object_unref (object);
|
||||
|
||||
/* /com/redhat/Cockpit/NetworkMonitor */
|
||||
monitor = network_monitor_new (daemon);
|
||||
object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/NetworkMonitor");
|
||||
cockpit_object_skeleton_set_resource_monitor (object, monitor);
|
||||
g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
|
||||
g_object_unref (monitor);
|
||||
g_object_unref (object);
|
||||
|
||||
/* /com/redhat/Cockpit/DiskIOMonitor */
|
||||
monitor = disk_io_monitor_new (daemon);
|
||||
object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/DiskIOMonitor");
|
||||
cockpit_object_skeleton_set_resource_monitor (object, monitor);
|
||||
g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
|
||||
g_object_unref (monitor);
|
||||
g_object_unref (object);
|
||||
|
||||
/* /com/redhat/Cockpit/Realms */
|
||||
realms = realms_new (daemon);
|
||||
object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/Realms");
|
||||
cockpit_object_skeleton_set_realms (object, realms);
|
||||
g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
|
||||
g_object_unref (realms);
|
||||
g_object_unref (object);
|
||||
|
||||
/* /com/redhat/Cockpit/Services */
|
||||
services = services_new (daemon);
|
||||
object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/Services");
|
||||
cockpit_object_skeleton_set_services (object, services);
|
||||
g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
|
||||
g_object_unref (services);
|
||||
g_object_unref (object);
|
||||
|
||||
/* /com/redhat/Cockpit/Journal */
|
||||
journal = journal_new ();
|
||||
object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/Journal");
|
||||
cockpit_object_skeleton_set_journal (object, journal);
|
||||
g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
|
||||
g_object_unref (journal);
|
||||
|
||||
/* /com/redhat/Cockpit/Accounts */
|
||||
accounts = accounts_new ();
|
||||
object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/Accounts");
|
||||
cockpit_object_skeleton_set_accounts (object, accounts);
|
||||
g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
|
||||
g_object_unref (accounts);
|
||||
|
||||
g_object_unref (object);
|
||||
|
||||
/* /com/redhat/Cockpit/Storage/Manager */
|
||||
storage_manager = storage_manager_new (daemon);
|
||||
object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/Storage/Manager");
|
||||
cockpit_object_skeleton_set_storage_manager (object, storage_manager);
|
||||
g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
|
||||
g_object_unref (storage_manager);
|
||||
g_object_unref (object);
|
||||
|
||||
daemon->storage_provider = storage_provider_new (daemon);
|
||||
|
||||
/* Export the ObjectManager */
|
||||
g_dbus_object_manager_server_set_connection (daemon->object_manager, daemon->connection);
|
||||
|
||||
daemon->tick_timeout_id = g_timeout_add_seconds (1, on_timeout, daemon);
|
||||
|
||||
if (G_OBJECT_CLASS (daemon_parent_class)->constructed != NULL)
|
||||
G_OBJECT_CLASS (daemon_parent_class)->constructed (_object);
|
||||
}
|
||||
|
||||
static void
|
||||
daemon_class_init (DaemonClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = daemon_finalize;
|
||||
gobject_class->constructed = daemon_constructed;
|
||||
gobject_class->set_property = daemon_set_property;
|
||||
gobject_class->get_property = daemon_get_property;
|
||||
|
||||
/**
|
||||
* Daemon:connection:
|
||||
*
|
||||
* The #GDBusConnection the daemon is for.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_CONNECTION,
|
||||
g_param_spec_object ("connection",
|
||||
"Connection",
|
||||
"The D-Bus connection the daemon is for",
|
||||
G_TYPE_DBUS_CONNECTION,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* Daemon:http-root:
|
||||
*
|
||||
* The path where to serve HTTP files from.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_HTTP_ROOT,
|
||||
g_param_spec_string ("http-root",
|
||||
"HTTP Root",
|
||||
"The path where to serve HTTP files from",
|
||||
PACKAGE_DATA_DIR "/cockpit/content",
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* Daemon:object-manager:
|
||||
*
|
||||
* The #GDBusObjectManager used by the daemon
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_OBJECT_MANAGER,
|
||||
g_param_spec_object ("object-manager",
|
||||
"Object Manager",
|
||||
"The D-Bus Object Manager server used by the daemon",
|
||||
G_TYPE_DBUS_OBJECT_MANAGER_SERVER,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* Daemon::tick
|
||||
* @daemon: A #Daemon.
|
||||
* @delta_usec: The number of micro-seconds since this was last emitted or 0 if the first time it's emitted.
|
||||
*
|
||||
* Emitted every second - subsystems should use this signal instead
|
||||
* of setting up their own timeout.
|
||||
*
|
||||
* This signal is emitted in the
|
||||
* <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
|
||||
* that @daemon was created in.
|
||||
*/
|
||||
signals[TICK_SIGNAL] = g_signal_new ("tick",
|
||||
G_OBJECT_CLASS_TYPE (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (DaemonClass, tick),
|
||||
NULL,
|
||||
NULL,
|
||||
g_cclosure_marshal_generic,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_UINT64);
|
||||
}
|
||||
|
||||
/**
|
||||
* daemon_new:
|
||||
* @connection: A #GDBusConnection.
|
||||
*
|
||||
* Create a new daemon object for exporting objects on @connection.
|
||||
*
|
||||
* Returns: A #Daemon object. Free with g_object_unref().
|
||||
*/
|
||||
Daemon *
|
||||
daemon_new (GDBusConnection *connection,
|
||||
const gchar *http_root)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
|
||||
return DAEMON (g_object_new (TYPE_DAEMON,
|
||||
"connection", connection,
|
||||
"http-root", http_root,
|
||||
NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* daemon_get:
|
||||
*
|
||||
* Returns: (transfer none): Th singleton #Daemon instance
|
||||
*/
|
||||
Daemon *
|
||||
daemon_get (void)
|
||||
{
|
||||
g_assert (_daemon_instance);
|
||||
return _daemon_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* daemon_get_connection:
|
||||
* @daemon: A #Daemon.
|
||||
*
|
||||
* Gets the D-Bus connection used by @daemon.
|
||||
*
|
||||
* Returns: A #GDBusConnection. Do not free, the object is owned by @daemon.
|
||||
*/
|
||||
GDBusConnection *
|
||||
daemon_get_connection (Daemon *daemon)
|
||||
{
|
||||
g_return_val_if_fail (IS_DAEMON (daemon), NULL);
|
||||
return daemon->connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* daemon_get_object_manager:
|
||||
* @daemon: A #Daemon.
|
||||
*
|
||||
* Gets the D-Bus object manager used by @daemon.
|
||||
*
|
||||
* Returns: A #GDBusObjectManagerServer. Do not free, the object is owned by @daemon.
|
||||
*/
|
||||
GDBusObjectManagerServer *
|
||||
daemon_get_object_manager (Daemon *daemon)
|
||||
{
|
||||
g_return_val_if_fail (IS_DAEMON (daemon), NULL);
|
||||
return daemon->object_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* daemon_get_http_root:
|
||||
* @daemon: A #Daemon.
|
||||
*
|
||||
* Gets the path where HTTP files are to be served from.
|
||||
*
|
||||
* Returns: A string owned by @daemon.
|
||||
*/
|
||||
const gchar *
|
||||
daemon_get_http_root (Daemon *daemon)
|
||||
{
|
||||
g_return_val_if_fail (IS_DAEMON (daemon), NULL);
|
||||
return daemon->http_root;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
authorize_method (Daemon *daemon,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gboolean *out_is_authorized,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
const char *sender = g_dbus_method_invocation_get_sender (invocation);
|
||||
gs_unref_variant GVariant *reply = NULL;
|
||||
guint32 uid = 42;
|
||||
|
||||
reply = g_dbus_proxy_call_sync (daemon->system_bus_proxy, "org.freedesktop.DBus.GetConnectionUnixUser",
|
||||
g_variant_new ("(s)", sender), 0, -1,
|
||||
cancellable, error);
|
||||
if (reply == NULL)
|
||||
return FALSE;
|
||||
|
||||
g_variant_get (reply, "(u)", &uid);
|
||||
|
||||
*out_is_authorized = (uid == 0 || auth_uid_is_wheel (uid));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* daemon_authorize_method:
|
||||
* @daemon: a #Daemon
|
||||
* @invocation: method invocation handle
|
||||
*
|
||||
* Global hook used to authorize DBus methods. We restrict them to
|
||||
* root at the moment (but this forces the bridge to run as root).
|
||||
*
|
||||
* Possibly a better long term fix is that the bridge actually starts
|
||||
* cockpitd as root, opens a private socketpair between them to speak
|
||||
* DBus, then drops privileges.
|
||||
*
|
||||
* Returns: %TRUE if call should be authorized, %FALSE otherwise
|
||||
*/
|
||||
gboolean
|
||||
daemon_authorize_method (Daemon *daemon,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
GError *error = NULL;
|
||||
gboolean is_authorized = FALSE;
|
||||
|
||||
if (!authorize_method (daemon, invocation, &is_authorized, NULL, &error))
|
||||
{
|
||||
g_warning ("Error while authorizing method %s.%s: %s",
|
||||
g_dbus_method_invocation_get_interface_name (invocation),
|
||||
g_dbus_method_invocation_get_method_name (invocation),
|
||||
error->message);
|
||||
g_clear_error (&error);
|
||||
return FALSE;
|
||||
}
|
||||
if (!is_authorized)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_ACCESS_DENIED,
|
||||
"Method %s.%s cannot be invoked by non-root",
|
||||
g_dbus_method_invocation_get_interface_name (invocation),
|
||||
g_dbus_method_invocation_get_method_name (invocation));
|
||||
}
|
||||
return is_authorized;
|
||||
}
|
||||
|
||||
gboolean
|
||||
daemon_get_sender_uid (Daemon *daemon,
|
||||
GDBusMethodInvocation *invocation,
|
||||
uid_t *uid)
|
||||
{
|
||||
GError *error = NULL;
|
||||
const char *sender = g_dbus_method_invocation_get_sender (invocation);
|
||||
gs_unref_variant GVariant *reply = NULL;
|
||||
|
||||
reply = g_dbus_proxy_call_sync (daemon->system_bus_proxy, "org.freedesktop.DBus.GetConnectionUnixUser",
|
||||
g_variant_new ("(s)", sender), 0, -1,
|
||||
NULL, &error);
|
||||
if (reply == NULL)
|
||||
{
|
||||
g_dbus_method_invocation_take_error (invocation, error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (g_variant_is_of_type (reply, G_VARIANT_TYPE("(u)")))
|
||||
g_variant_get (reply, "(u)", uid);
|
||||
else
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR, COCKPIT_ERROR_FAILED,
|
||||
"DBus is broken");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __DAEMON_H__
|
||||
#define __DAEMON_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_DAEMON (daemon_get_type ())
|
||||
#define DAEMON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_DAEMON, Daemon))
|
||||
#define IS_DAEMON(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_DAEMON))
|
||||
|
||||
GType daemon_get_type (void) G_GNUC_CONST;
|
||||
|
||||
Daemon * daemon_new (GDBusConnection *connection,
|
||||
const gchar *http_root);
|
||||
|
||||
Daemon * daemon_get (void);
|
||||
|
||||
GDBusConnection * daemon_get_connection (Daemon *daemon);
|
||||
|
||||
GDBusObjectManagerServer * daemon_get_object_manager (Daemon *daemon);
|
||||
|
||||
const gchar * daemon_get_http_root (Daemon *daemon);
|
||||
|
||||
gboolean daemon_authorize_method (Daemon *daemon,
|
||||
GDBusMethodInvocation *invocation);
|
||||
|
||||
gboolean daemon_get_sender_uid (Daemon *daemon,
|
||||
GDBusMethodInvocation *invocation,
|
||||
uid_t *uid);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __DAEMON_H__ */
|
|
@ -0,0 +1,458 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "diskiomonitor.h"
|
||||
|
||||
/**
|
||||
* SECTION:diskiomonitor
|
||||
* @title: DiskIOMonitor
|
||||
* @short_description: Implementation of #CockpitResourceMonitor for disk I/O usage
|
||||
*
|
||||
* This type provides an implementation of the #CockpitResourceMonitor interface for disk I/O usage.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gint64 timestamp;
|
||||
gint64 bytes_read;
|
||||
gint64 bytes_written;
|
||||
gint64 num_ops;
|
||||
gdouble bytes_read_per_sec;
|
||||
gdouble bytes_written_per_sec;
|
||||
gdouble io_operations_per_sec;
|
||||
} Sample;
|
||||
|
||||
typedef struct _DiskIOMonitorClass DiskIOMonitorClass;
|
||||
|
||||
/**
|
||||
* DiskIOMonitor:
|
||||
*
|
||||
* The #DiskIOMonitor structure contains only private data and should
|
||||
* only be accessed using the provided API.
|
||||
*/
|
||||
struct _DiskIOMonitor
|
||||
{
|
||||
CockpitResourceMonitorSkeleton parent_instance;
|
||||
|
||||
Daemon *daemon;
|
||||
|
||||
guint user_hz;
|
||||
|
||||
guint samples_max;
|
||||
gint samples_prev;
|
||||
guint samples_next;
|
||||
|
||||
/* Arrays of samples_max Sample instances */
|
||||
Sample *samples;
|
||||
};
|
||||
|
||||
struct _DiskIOMonitorClass
|
||||
{
|
||||
CockpitResourceMonitorSkeletonClass parent_class;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DAEMON
|
||||
};
|
||||
|
||||
static void resource_monitor_iface_init (CockpitResourceMonitorIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (DiskIOMonitor, disk_io_monitor, COCKPIT_TYPE_RESOURCE_MONITOR_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (COCKPIT_TYPE_RESOURCE_MONITOR, resource_monitor_iface_init));
|
||||
|
||||
static void on_tick (Daemon *daemon,
|
||||
guint64 delta_usec,
|
||||
gpointer user_data);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
disk_io_monitor_init (DiskIOMonitor *monitor)
|
||||
{
|
||||
const gchar *legends[4] = {"Disk Reads", "Disk Writes", "I/O Operations", NULL}; /* TODO: i18n */
|
||||
|
||||
g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (monitor),
|
||||
G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
|
||||
|
||||
/* Assign legends */
|
||||
cockpit_resource_monitor_set_legends (COCKPIT_RESOURCE_MONITOR (monitor), legends);
|
||||
|
||||
monitor->samples_prev = -1;
|
||||
monitor->samples_max = 300;
|
||||
monitor->samples = g_new0 (Sample, monitor->samples_max);
|
||||
}
|
||||
|
||||
static void
|
||||
disk_io_monitor_finalize (GObject *object)
|
||||
{
|
||||
DiskIOMonitor *monitor = DISK_IO_MONITOR (object);
|
||||
|
||||
g_free (monitor->samples);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (monitor->daemon, G_CALLBACK (on_tick), monitor);
|
||||
|
||||
G_OBJECT_CLASS (disk_io_monitor_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
disk_io_monitor_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
DiskIOMonitor *monitor = DISK_IO_MONITOR (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DAEMON:
|
||||
g_value_set_object (value, disk_io_monitor_get_daemon (monitor));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
disk_io_monitor_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
DiskIOMonitor *monitor = DISK_IO_MONITOR (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DAEMON:
|
||||
g_assert (monitor->daemon == NULL);
|
||||
/* we don't take a reference to the daemon */
|
||||
monitor->daemon = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void collect (DiskIOMonitor *monitor);
|
||||
|
||||
static void
|
||||
on_tick (Daemon *daemon,
|
||||
guint64 delta_usec,
|
||||
gpointer user_data)
|
||||
{
|
||||
DiskIOMonitor *monitor = DISK_IO_MONITOR (user_data);
|
||||
collect (monitor);
|
||||
}
|
||||
|
||||
static void
|
||||
disk_io_monitor_constructed (GObject *object)
|
||||
{
|
||||
DiskIOMonitor *monitor = DISK_IO_MONITOR (object);
|
||||
|
||||
cockpit_resource_monitor_set_num_samples (COCKPIT_RESOURCE_MONITOR (monitor), monitor->samples_max);
|
||||
cockpit_resource_monitor_set_num_series (COCKPIT_RESOURCE_MONITOR (monitor), 3);
|
||||
|
||||
g_signal_connect (monitor->daemon, "tick", G_CALLBACK (on_tick), monitor);
|
||||
collect (monitor);
|
||||
|
||||
if (G_OBJECT_CLASS (disk_io_monitor_parent_class)->constructed != NULL)
|
||||
G_OBJECT_CLASS (disk_io_monitor_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
disk_io_monitor_class_init (DiskIOMonitorClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = disk_io_monitor_finalize;
|
||||
gobject_class->constructed = disk_io_monitor_constructed;
|
||||
gobject_class->set_property = disk_io_monitor_set_property;
|
||||
gobject_class->get_property = disk_io_monitor_get_property;
|
||||
|
||||
/**
|
||||
* DiskIOMonitor:daemon:
|
||||
*
|
||||
* The #Daemon for the object.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_DAEMON,
|
||||
g_param_spec_object ("daemon",
|
||||
NULL,
|
||||
NULL,
|
||||
TYPE_DAEMON,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
/**
|
||||
* disk_io_monitor_new:
|
||||
* @daemon: A #Daemon.
|
||||
*
|
||||
* Creates a new #DiskIOMonitor instance.
|
||||
*
|
||||
* Returns: A new #DiskIOMonitor. Free with g_object_unref().
|
||||
*/
|
||||
CockpitResourceMonitor *
|
||||
disk_io_monitor_new (Daemon *daemon)
|
||||
{
|
||||
g_return_val_if_fail (IS_DAEMON (daemon), NULL);
|
||||
return COCKPIT_RESOURCE_MONITOR (g_object_new (TYPE_DISK_IO_MONITOR,
|
||||
"daemon", daemon,
|
||||
NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* disk_io_monitor_get_daemon:
|
||||
* @monitor: A #DiskIOMonitor.
|
||||
*
|
||||
* Gets the daemon used by @monitor.
|
||||
*
|
||||
* Returns: A #Daemon. Do not free, the object is owned by @monitor.
|
||||
*/
|
||||
Daemon *
|
||||
disk_io_monitor_get_daemon (DiskIOMonitor *monitor)
|
||||
{
|
||||
g_return_val_if_fail (IS_DISK_IO_MONITOR (monitor), NULL);
|
||||
return monitor->daemon;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gboolean
|
||||
calc_bandwidth (DiskIOMonitor *monitor,
|
||||
Sample *sample,
|
||||
Sample *last,
|
||||
gint64 sample_value,
|
||||
gint64 last_value)
|
||||
{
|
||||
gdouble ret;
|
||||
gdouble bytes_in_period;
|
||||
gdouble period;
|
||||
|
||||
bytes_in_period = sample_value - last_value;
|
||||
period = ((gdouble) (sample->timestamp - last->timestamp)) / ((gdouble) G_USEC_PER_SEC);
|
||||
ret = bytes_in_period / period;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* TODO: this should be optimized so we don't allocate network and call open()/close() all the time */
|
||||
static void
|
||||
collect (DiskIOMonitor *monitor)
|
||||
{
|
||||
gchar *contents = NULL;
|
||||
gsize len;
|
||||
GError *error;
|
||||
gchar **lines = NULL;
|
||||
guint n;
|
||||
gint64 now;
|
||||
Sample *sample = NULL;
|
||||
Sample *last = NULL;
|
||||
GVariantBuilder builder;
|
||||
|
||||
error = NULL;
|
||||
if (!g_file_get_contents ("/proc/diskstats",
|
||||
&contents,
|
||||
&len,
|
||||
&error))
|
||||
{
|
||||
g_warning ("Error loading contents /proc/vmstat: %s (%s, %d)",
|
||||
error->message, g_quark_to_string (error->domain), error->code);
|
||||
g_error_free (error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
now = g_get_real_time ();
|
||||
|
||||
sample = &(monitor->samples[monitor->samples_next]);
|
||||
sample->timestamp = now;
|
||||
sample->bytes_read = 0;
|
||||
sample->bytes_written = 0;
|
||||
sample->num_ops = 0;
|
||||
|
||||
if (monitor->samples_prev != -1)
|
||||
last = &(monitor->samples[monitor->samples_prev]);
|
||||
|
||||
lines = g_strsplit (contents, "\n", -1);
|
||||
for (n = 0; lines != NULL && lines[n] != NULL; n++)
|
||||
{
|
||||
const gchar *line = lines[n];
|
||||
guint num_parsed;
|
||||
gint dev_major, dev_minor;
|
||||
gchar dev_name[64]; /* TODO: big enough? */
|
||||
guint64 num_reads, num_reads_merged, num_sectors_read, num_msec_reading;
|
||||
guint64 num_writes, num_writes_merged, num_sectors_written, num_msec_writing;
|
||||
guint64 num_io_in_progress, num_msec_doing_io, weighted_num_msec_doing_io;
|
||||
|
||||
if (strlen (line) == 0)
|
||||
continue;
|
||||
|
||||
/* From http://www.kernel.org/doc/Documentation/iostats.txt
|
||||
*
|
||||
* Field 1 -- # of reads completed
|
||||
* This is the total number of reads completed successfully.
|
||||
* Field 2 -- # of reads merged, field 6 -- # of writes merged
|
||||
* Reads and writes which are adjacent to each other may be merged for
|
||||
* efficiency. Thus two 4K reads may become one 8K read before it is
|
||||
* ultimately handed to the disk, and so it will be counted (and queued)
|
||||
* as only one I/O. This field lets you know how often this was done.
|
||||
* Field 3 -- # of sectors read
|
||||
* This is the total number of sectors read successfully.
|
||||
* Field 4 -- # of milliseconds spent reading
|
||||
* This is the total number of milliseconds spent by all reads (as
|
||||
* measured from __make_request() to end_that_request_last()).
|
||||
* Field 5 -- # of writes completed
|
||||
* This is the total number of writes completed successfully.
|
||||
* Field 7 -- # of sectors written
|
||||
* This is the total number of sectors written successfully.
|
||||
* Field 8 -- # of milliseconds spent writing
|
||||
* This is the total number of milliseconds spent by all writes (as
|
||||
* measured from __make_request() to end_that_request_last()).
|
||||
* Field 9 -- # of I/Os currently in progress
|
||||
* The only field that should go to zero. Incremented as requests are
|
||||
* given to appropriate struct request_queue and decremented as they finish.
|
||||
* Field 10 -- # of milliseconds spent doing I/Os
|
||||
* This field increases so long as field 9 is nonzero.
|
||||
* Field 11 -- weighted # of milliseconds spent doing I/Os
|
||||
* This field is incremented at each I/O start, I/O completion, I/O
|
||||
* merge, or read of these stats by the number of I/Os in progress
|
||||
* (field 9) times the number of milliseconds spent doing I/O since the
|
||||
* last update of this field. This can provide an easy measure of both
|
||||
* I/O completion time and the backlog that may be accumulating.
|
||||
*/
|
||||
|
||||
num_parsed = sscanf (line,
|
||||
"%d %d %s"
|
||||
" %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT
|
||||
" %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT
|
||||
" %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT,
|
||||
&dev_major, &dev_minor, dev_name,
|
||||
&num_reads, &num_reads_merged, &num_sectors_read, &num_msec_reading,
|
||||
&num_writes, &num_writes_merged, &num_sectors_written, &num_msec_writing,
|
||||
&num_io_in_progress, &num_msec_doing_io, &weighted_num_msec_doing_io);
|
||||
if (num_parsed != 14)
|
||||
{
|
||||
g_warning ("Error parsing line %d of file /proc/diskstats (num_parsed=%d): `%s'", n, num_parsed, line);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip mapped devices and partitions... otherwise we'll count their
|
||||
* I/O more than once
|
||||
*
|
||||
* TODO: the way we identify dm devices and partitions is not
|
||||
* very elegant... we should consult sysfs via libgudev1
|
||||
* instead.
|
||||
*/
|
||||
if (dev_major == 253)
|
||||
continue;
|
||||
|
||||
if (g_str_has_prefix (dev_name, "sd") && g_ascii_isdigit (dev_name[strlen (dev_name) - 1]))
|
||||
continue;
|
||||
|
||||
sample->bytes_read += num_sectors_read * 512;
|
||||
sample->bytes_written += num_sectors_written * 512;
|
||||
sample->num_ops += num_reads_merged + num_writes_merged;
|
||||
}
|
||||
|
||||
if (last != NULL)
|
||||
{
|
||||
sample->bytes_read_per_sec = calc_bandwidth (monitor, sample, last, sample->bytes_read, last->bytes_read);
|
||||
sample->bytes_written_per_sec = calc_bandwidth (monitor, sample, last, sample->bytes_written, last->bytes_written);
|
||||
sample->io_operations_per_sec = calc_bandwidth (monitor, sample, last, sample->num_ops, last->num_ops);
|
||||
}
|
||||
|
||||
out:
|
||||
g_strfreev (lines);
|
||||
g_free (contents);
|
||||
if (sample != NULL)
|
||||
{
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("ad"));
|
||||
g_variant_builder_add (&builder, "d", sample->bytes_read_per_sec);
|
||||
g_variant_builder_add (&builder, "d", sample->bytes_written_per_sec);
|
||||
g_variant_builder_add (&builder, "d", sample->io_operations_per_sec);
|
||||
cockpit_resource_monitor_emit_new_sample (COCKPIT_RESOURCE_MONITOR(monitor),
|
||||
now, g_variant_builder_end (&builder));
|
||||
}
|
||||
|
||||
monitor->samples_prev = monitor->samples_next;
|
||||
monitor->samples_next += 1;
|
||||
if (monitor->samples_next == monitor->samples_max)
|
||||
monitor->samples_next = 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gboolean
|
||||
handle_get_samples (CockpitResourceMonitor *_monitor,
|
||||
GDBusMethodInvocation *invocation,
|
||||
GVariant *arg_options)
|
||||
{
|
||||
DiskIOMonitor *monitor = DISK_IO_MONITOR (_monitor);
|
||||
GVariantBuilder builder;
|
||||
gint n;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(xad)"));
|
||||
for (n = 0; n < monitor->samples_max; n++)
|
||||
{
|
||||
gint pos;
|
||||
GVariantBuilder sample_builder;
|
||||
|
||||
pos = monitor->samples_next + n;
|
||||
if (pos > monitor->samples_max)
|
||||
pos -= monitor->samples_max;
|
||||
|
||||
if (monitor->samples[pos].timestamp == 0)
|
||||
continue;
|
||||
|
||||
g_variant_builder_init (&sample_builder, G_VARIANT_TYPE ("ad"));
|
||||
g_variant_builder_add (&sample_builder, "d", monitor->samples[pos].bytes_read_per_sec);
|
||||
g_variant_builder_add (&sample_builder, "d", monitor->samples[pos].bytes_written_per_sec);
|
||||
g_variant_builder_add (&sample_builder, "d", monitor->samples[pos].io_operations_per_sec);
|
||||
|
||||
g_variant_builder_add (&builder, "(x@ad)",
|
||||
monitor->samples[pos].timestamp,
|
||||
g_variant_builder_end (&sample_builder));
|
||||
}
|
||||
cockpit_resource_monitor_complete_get_samples (_monitor, invocation,
|
||||
g_variant_builder_end (&builder));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
resource_monitor_iface_init (CockpitResourceMonitorIface *iface)
|
||||
{
|
||||
iface->handle_get_samples = handle_get_samples;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __DISK_IO_MONITOR_H__
|
||||
#define __DISK_IO_MONITOR_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_DISK_IO_MONITOR (disk_io_monitor_get_type ())
|
||||
#define DISK_IO_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_DISK_IO_MONITOR, DiskIOMonitor))
|
||||
#define IS_DISK_IO_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_DISK_IO_MONITOR))
|
||||
|
||||
GType disk_io_monitor_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CockpitResourceMonitor * disk_io_monitor_new (Daemon *daemon);
|
||||
|
||||
Daemon * disk_io_monitor_get_daemon (DiskIOMonitor *monitor);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __DISK_IO_MONITOR_H__ */
|
|
@ -0,0 +1,493 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <systemd/sd-journal.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "libgsystem.h"
|
||||
#include "daemon.h"
|
||||
#include "journal.h"
|
||||
#include "auth.h"
|
||||
|
||||
typedef struct _JournalClass JournalClass;
|
||||
|
||||
struct _Journal
|
||||
{
|
||||
CockpitJournalSkeleton parent_instance;
|
||||
};
|
||||
|
||||
struct _JournalClass
|
||||
{
|
||||
CockpitJournalSkeletonClass parent_class;
|
||||
};
|
||||
|
||||
static void journal_iface_init (CockpitJournalIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (Journal, journal, COCKPIT_TYPE_JOURNAL_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (COCKPIT_TYPE_JOURNAL, journal_iface_init));
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
journal_finalize (GObject *object)
|
||||
{
|
||||
G_OBJECT_CLASS (journal_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
journal_init (Journal *self)
|
||||
{
|
||||
g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (self),
|
||||
G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
|
||||
}
|
||||
|
||||
static void
|
||||
journal_class_init (JournalClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = journal_finalize;
|
||||
}
|
||||
|
||||
CockpitJournal *
|
||||
journal_new (void)
|
||||
{
|
||||
return COCKPIT_JOURNAL (g_object_new (TYPE_JOURNAL, NULL));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fail_with_errno (GDBusMethodInvocation *invocation,
|
||||
const char *message,
|
||||
int code)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR, COCKPIT_ERROR_FAILED,
|
||||
"%s: %s", message, strerror (code));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_journal (sd_journal **ptr)
|
||||
{
|
||||
if (*ptr)
|
||||
sd_journal_close (*ptr);
|
||||
}
|
||||
|
||||
static int
|
||||
seek_to_boot_id (sd_journal *j,
|
||||
const char *boot_id)
|
||||
{
|
||||
int ret;
|
||||
gs_free char *match_boot_id = NULL;
|
||||
|
||||
if (strcmp (boot_id, "current") == 0)
|
||||
{
|
||||
sd_id128_t id;
|
||||
ret = sd_id128_get_boot (&id);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
match_boot_id = g_strdup_printf ("_BOOT_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id));
|
||||
}
|
||||
else
|
||||
match_boot_id = g_strdup_printf ("_BOOT_ID=%s", boot_id);
|
||||
|
||||
__attribute__ ((cleanup (cleanup_journal))) sd_journal *jj = NULL;
|
||||
ret = sd_journal_open (&jj, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = sd_journal_add_match (jj, match_boot_id, strlen (match_boot_id));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = sd_journal_next (jj);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
gs_free char *cursor = NULL;
|
||||
ret = sd_journal_get_cursor (jj, &cursor);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sd_journal_seek_cursor (j, cursor);
|
||||
}
|
||||
|
||||
static void
|
||||
add_field (GVariantBuilder *fields,
|
||||
gint max_field_size,
|
||||
const void *data,
|
||||
size_t len)
|
||||
{
|
||||
if (len > max_field_size)
|
||||
len = max_field_size;
|
||||
|
||||
const gchar *last_valid;
|
||||
g_utf8_validate (data, len, &last_valid);
|
||||
size_t valid_len = (last_valid - (const gchar *)data);
|
||||
|
||||
// We allow up to 3 extra bytes, which might belong to
|
||||
// the next code point.
|
||||
if (valid_len + 3 >= len)
|
||||
{
|
||||
gs_free gchar *zero_terminated_data = g_strndup (data, valid_len);
|
||||
g_variant_builder_add (fields, "s", zero_terminated_data);
|
||||
}
|
||||
else
|
||||
g_variant_builder_add (fields, "s", "<binary>");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_query (CockpitJournal *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
GVariant *arg_match,
|
||||
const gchar *arg_filter_text,
|
||||
const gchar *arg_seek,
|
||||
gint arg_skip,
|
||||
gint arg_count,
|
||||
const gchar *const *arg_fields,
|
||||
gint arg_max_field_size,
|
||||
gboolean arg_wait)
|
||||
{
|
||||
__attribute__ ((cleanup (cleanup_journal))) sd_journal *j = NULL;
|
||||
int ret;
|
||||
gboolean eof = FALSE;
|
||||
gboolean backwards = FALSE;
|
||||
gboolean empty = FALSE;
|
||||
int extra_skip = 1;
|
||||
int n = 0;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
ret = sd_journal_open (&j, 0);
|
||||
if (ret < 0)
|
||||
return fail_with_errno (invocation, "Can't open journal", -ret);
|
||||
|
||||
GVariantIter match_iter;
|
||||
GVariantIter *clause_iter;
|
||||
gboolean need_disjunction = FALSE;
|
||||
g_variant_iter_init (&match_iter, arg_match);
|
||||
while (g_variant_iter_next (&match_iter, "as", &clause_iter))
|
||||
{
|
||||
if (need_disjunction)
|
||||
{
|
||||
ret = sd_journal_add_disjunction (j);
|
||||
if (ret < 0)
|
||||
return fail_with_errno (invocation, "Can't add disjunction", -ret);
|
||||
}
|
||||
|
||||
const gchar *clause;
|
||||
while (g_variant_iter_next (clause_iter, "&s", &clause))
|
||||
{
|
||||
ret = sd_journal_add_match (j, clause, strlen (clause));
|
||||
if (ret < 0)
|
||||
{
|
||||
g_variant_iter_free (clause_iter);
|
||||
return fail_with_errno (invocation, "Can't add match", -ret);
|
||||
}
|
||||
}
|
||||
|
||||
need_disjunction = TRUE;
|
||||
g_variant_iter_free (clause_iter);
|
||||
}
|
||||
|
||||
ret = sd_journal_set_data_threshold (j, arg_max_field_size);
|
||||
if (ret < 0)
|
||||
return fail_with_errno (invocation, "Can't set data limit", -ret);
|
||||
|
||||
if (arg_seek == NULL
|
||||
|| *arg_seek == '\0'
|
||||
|| strcmp (arg_seek, "head") == 0)
|
||||
{
|
||||
ret = sd_journal_seek_head (j);
|
||||
}
|
||||
else if (strcmp (arg_seek, "tail") == 0)
|
||||
{
|
||||
ret = sd_journal_seek_tail (j);
|
||||
}
|
||||
else if (g_str_has_prefix (arg_seek, "rel_usecs="))
|
||||
{
|
||||
uint64_t rel_usecs = strtoll (arg_seek + 10, NULL, 10);
|
||||
ret = sd_journal_seek_realtime_usec (j, g_get_real_time () + rel_usecs);
|
||||
}
|
||||
else if (g_str_has_prefix (arg_seek, "boot_id="))
|
||||
{
|
||||
const char *arg_boot_id = arg_seek + 8;
|
||||
ret = seek_to_boot_id (j, arg_boot_id);
|
||||
}
|
||||
else if (g_str_has_prefix (arg_seek, "exact_cursor="))
|
||||
{
|
||||
const char *cursor = arg_seek + 13;
|
||||
ret = sd_journal_seek_cursor (j, cursor);
|
||||
if (ret >= 0)
|
||||
ret = sd_journal_next (j);
|
||||
if (ret > 0)
|
||||
ret = sd_journal_test_cursor (j, cursor);
|
||||
if (ret == 0)
|
||||
ret = -ENOENT;
|
||||
extra_skip = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = sd_journal_seek_cursor (j, arg_seek);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
return fail_with_errno (invocation, "Can't seek", -ret);
|
||||
|
||||
/* When skipping backwards, we skip as far as we can and then return
|
||||
entries from there while staying within the window that was
|
||||
originally requested. We will never wait for more entries to
|
||||
appear.
|
||||
|
||||
When skipping forward, we need to skip by one more than asked
|
||||
because of the way the journal API works. We will also wait if
|
||||
necessary.
|
||||
*/
|
||||
if (arg_skip < 0)
|
||||
{
|
||||
backwards = TRUE;
|
||||
arg_skip = -arg_skip;
|
||||
|
||||
ret = sd_journal_previous_skip (j, arg_skip);
|
||||
if (ret < 0)
|
||||
return fail_with_errno (invocation, "Can't skip", -ret);
|
||||
|
||||
empty = (ret == 0);
|
||||
|
||||
if (ret < arg_skip)
|
||||
{
|
||||
eof = TRUE;
|
||||
if (arg_count > arg_skip)
|
||||
arg_count = arg_skip;
|
||||
arg_count -= arg_skip - ret;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
arg_skip += extra_skip;
|
||||
again:
|
||||
ret = sd_journal_next_skip (j, arg_skip);
|
||||
if (ret < 0)
|
||||
return fail_with_errno (invocation, "Can't skip", -ret);
|
||||
|
||||
arg_skip -= ret;
|
||||
if (arg_skip > 0)
|
||||
{
|
||||
if (arg_wait)
|
||||
{
|
||||
ret = sd_journal_wait (j, 10 * 1000 * 1000);
|
||||
if (ret < 0)
|
||||
return fail_with_errno (invocation, "Can't wait", -ret);
|
||||
if (ret != SD_JOURNAL_NOP)
|
||||
goto again;
|
||||
}
|
||||
eof = TRUE;
|
||||
arg_count = 0;
|
||||
empty = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
gs_free char *first_cursor = NULL;
|
||||
if (!empty)
|
||||
{
|
||||
ret = sd_journal_get_cursor (j, &first_cursor);
|
||||
if (ret < 0)
|
||||
return fail_with_errno (invocation, "Can't get first cursor", -ret);
|
||||
}
|
||||
else
|
||||
first_cursor = g_strdup ("");
|
||||
|
||||
GVariantBuilder entries;
|
||||
g_variant_builder_init (&entries, G_VARIANT_TYPE ("aas"));
|
||||
|
||||
while (n < arg_count)
|
||||
{
|
||||
gboolean include;
|
||||
|
||||
if (arg_filter_text && *arg_filter_text)
|
||||
{
|
||||
const void *data;
|
||||
size_t len;
|
||||
size_t text_len = strlen (arg_filter_text);
|
||||
|
||||
// Skip this entry if none of the fields contain the text.
|
||||
include = FALSE;
|
||||
while (sd_journal_enumerate_data (j, &data, &len) > 0 && !include)
|
||||
if (memmem (data, len, arg_filter_text, text_len))
|
||||
include = TRUE;
|
||||
}
|
||||
else
|
||||
include = TRUE;
|
||||
|
||||
if (include)
|
||||
{
|
||||
GVariantBuilder fields;
|
||||
g_variant_builder_init (&fields, G_VARIANT_TYPE ("as"));
|
||||
|
||||
for (int i = 0; arg_fields[i]; i++)
|
||||
{
|
||||
const void *data;
|
||||
size_t len;
|
||||
|
||||
if (strcmp (arg_fields[i], "*") == 0)
|
||||
{
|
||||
sd_journal_restart_data (j);
|
||||
while (sd_journal_enumerate_data (j, &data, &len) > 0)
|
||||
add_field (&fields, arg_max_field_size, data, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
gs_free char *cursor_buf = NULL;
|
||||
char usec_buf[40];
|
||||
|
||||
if (strcmp (arg_fields[i], "__REALTIME_TIMESTAMP") == 0)
|
||||
{
|
||||
uint64_t usec;
|
||||
ret = sd_journal_get_realtime_usec (j, &usec);
|
||||
if (ret >= 0)
|
||||
{
|
||||
snprintf (usec_buf, sizeof (usec_buf), "%" G_GUINT64_FORMAT, usec);
|
||||
data = usec_buf;
|
||||
len = strlen (usec_buf);
|
||||
}
|
||||
}
|
||||
else if (strcmp (arg_fields[i], "__CURSOR") == 0)
|
||||
{
|
||||
ret = sd_journal_get_cursor (j, &cursor_buf);
|
||||
if (ret >= 0)
|
||||
{
|
||||
data = cursor_buf;
|
||||
len = strlen (cursor_buf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = sd_journal_get_data (j, arg_fields[i], &data, &len);
|
||||
if (ret >= 0)
|
||||
{
|
||||
size_t p = strlen (arg_fields[i]) + 1;
|
||||
if (len >= p)
|
||||
{
|
||||
len -= p;
|
||||
data = ((const char *)data) + p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == -ENOENT)
|
||||
g_variant_builder_add (&fields, "s", "");
|
||||
else if (ret < 0)
|
||||
g_variant_builder_add (&fields, "s", strerror (-ret));
|
||||
else
|
||||
add_field (&fields, arg_max_field_size, data, len);
|
||||
}
|
||||
}
|
||||
|
||||
g_variant_builder_add (&entries, "as", &fields);
|
||||
}
|
||||
|
||||
n += 1;
|
||||
|
||||
if (n >= arg_count)
|
||||
break;
|
||||
|
||||
if (sd_journal_next (j) != 1)
|
||||
{
|
||||
if (!backwards)
|
||||
eof = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gs_free char *last_cursor = NULL;
|
||||
if (!empty)
|
||||
{
|
||||
ret = sd_journal_get_cursor (j, &last_cursor);
|
||||
if (ret < 0)
|
||||
return fail_with_errno (invocation, "Can't get last cursor", -ret);
|
||||
}
|
||||
else
|
||||
last_cursor = g_strdup ("");
|
||||
|
||||
cockpit_journal_complete_query (object, invocation,
|
||||
g_variant_builder_end (&entries),
|
||||
first_cursor,
|
||||
last_cursor,
|
||||
eof);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_query_unique (CockpitJournal *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_field,
|
||||
int arg_max_len)
|
||||
{
|
||||
__attribute__ ((cleanup (cleanup_journal))) sd_journal *j = NULL;
|
||||
int ret;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
ret = sd_journal_open (&j, 0);
|
||||
if (ret < 0)
|
||||
return fail_with_errno (invocation, "Can't open journal", -ret);
|
||||
|
||||
ret = sd_journal_set_data_threshold (j, arg_max_len);
|
||||
if (ret < 0)
|
||||
return fail_with_errno (invocation, "Can't set data limit", -ret);
|
||||
|
||||
ret = sd_journal_query_unique (j, arg_field);
|
||||
if (ret < 0)
|
||||
return fail_with_errno (invocation, "Can't query unique values", -ret);
|
||||
|
||||
GVariantBuilder values;
|
||||
g_variant_builder_init (&values, G_VARIANT_TYPE ("as"));
|
||||
|
||||
const void *data;
|
||||
size_t len, prefix_len = strlen (arg_field) + 1;
|
||||
while ((ret = sd_journal_enumerate_unique (j, &data, &len)) > 0)
|
||||
{
|
||||
if (len >= prefix_len)
|
||||
{
|
||||
len -= prefix_len;
|
||||
data = ((const char *)data) + prefix_len;
|
||||
}
|
||||
if (len <= arg_max_len)
|
||||
{
|
||||
gs_free gchar *utf8 = g_locale_to_utf8 (data, len, NULL, NULL, NULL);
|
||||
if (utf8)
|
||||
g_variant_builder_add (&values, "s", utf8);
|
||||
}
|
||||
}
|
||||
|
||||
cockpit_journal_complete_query_unique (object, invocation, g_variant_builder_end (&values));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
journal_iface_init (CockpitJournalIface *iface)
|
||||
{
|
||||
iface->handle_query = handle_query;
|
||||
iface->handle_query_unique = handle_query_unique;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __JOURNAL_H__
|
||||
#define __JOURNAL_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_JOURNAL (journal_get_type ())
|
||||
#define JOURNAL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_JOURNAL, Journal))
|
||||
#define IS_JOURNAL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_JOURNAL))
|
||||
|
||||
GType journal_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CockpitJournal * journal_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __JOURNAL_H__ */
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <glib-unix.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "daemon.h"
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static GMainLoop *loop = NULL;
|
||||
|
||||
static gchar *opt_http_root = NULL;
|
||||
static gboolean opt_replace = FALSE;
|
||||
static gboolean opt_no_sigint = FALSE;
|
||||
static gboolean opt_debug = FALSE;
|
||||
|
||||
static GOptionEntry opt_entries[] =
|
||||
{
|
||||
{"http-root", 0, 0, G_OPTION_ARG_FILENAME, &opt_http_root, "Path to serve HTTP GET requests from", NULL},
|
||||
{"replace", 'r', 0, G_OPTION_ARG_NONE, &opt_replace, "Replace existing daemon", NULL},
|
||||
{"no-sigint", 's', 0, G_OPTION_ARG_NONE, &opt_no_sigint, "Do not handle SIGINT for controlled shutdown", NULL},
|
||||
{"debug", 'd', 0, G_OPTION_ARG_NONE, &opt_debug, "Debug mode: log messages to output", NULL},
|
||||
{NULL }
|
||||
};
|
||||
|
||||
static Daemon *the_daemon = NULL;
|
||||
|
||||
static void
|
||||
on_bus_acquired (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
the_daemon = daemon_new (connection, opt_http_root);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_lost (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (the_daemon == NULL)
|
||||
{
|
||||
g_warning ("Failed to connect to the system message bus");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_message ("Lost (or failed to acquire) the name %s on the system message bus", name);
|
||||
}
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_acquired (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_sigint (gpointer user_data)
|
||||
{
|
||||
g_message ("Caught SIGINT. Initiating shutdown");
|
||||
g_main_loop_quit (loop);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
GError *error;
|
||||
GOptionContext *opt_context;
|
||||
gint ret;
|
||||
guint name_owner_id;
|
||||
guint sigint_id;
|
||||
|
||||
ret = 1;
|
||||
loop = NULL;
|
||||
opt_context = NULL;
|
||||
name_owner_id = 0;
|
||||
sigint_id = 0;
|
||||
|
||||
g_type_init ();
|
||||
|
||||
/* avoid gvfs (http://bugzilla.gnome.org/show_bug.cgi?id=526454) */
|
||||
if (!g_setenv ("GIO_USE_VFS", "local", TRUE))
|
||||
{
|
||||
g_printerr ("Error setting GIO_USE_GVFS\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
opt_context = g_option_context_new ("cockpit storage daemon");
|
||||
g_option_context_add_main_entries (opt_context, opt_entries, NULL);
|
||||
error = NULL;
|
||||
if (!g_option_context_parse (opt_context, &argc, &argv, &error))
|
||||
{
|
||||
g_printerr ("Error parsing options: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (g_getenv ("PATH") == NULL)
|
||||
g_setenv ("PATH", "/usr/bin:/bin:/usr/sbin:/sbin", TRUE);
|
||||
|
||||
if (!opt_debug)
|
||||
g_log_set_default_handler (cockpit_journal_log_handler, NULL);
|
||||
|
||||
if (opt_http_root == NULL)
|
||||
opt_http_root = g_strdup (PACKAGE_DATA_DIR "/cockpit/content");
|
||||
|
||||
g_info ("cockpit daemon version %s starting", PACKAGE_VERSION);
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
sigint_id = 0;
|
||||
if (!opt_no_sigint)
|
||||
{
|
||||
sigint_id = g_unix_signal_add_full (G_PRIORITY_DEFAULT,
|
||||
SIGINT,
|
||||
on_sigint,
|
||||
NULL, /* user_data */
|
||||
NULL); /* GDestroyNotify */
|
||||
}
|
||||
|
||||
name_owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
|
||||
"com.redhat.Cockpit",
|
||||
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
|
||||
(opt_replace ? G_BUS_NAME_OWNER_FLAGS_REPLACE : 0),
|
||||
on_bus_acquired,
|
||||
on_name_acquired,
|
||||
on_name_lost,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
g_free (opt_http_root);
|
||||
if (sigint_id > 0)
|
||||
g_source_remove (sigint_id);
|
||||
if (the_daemon != NULL)
|
||||
g_object_unref (the_daemon);
|
||||
if (name_owner_id != 0)
|
||||
g_bus_unown_name (name_owner_id);
|
||||
if (loop != NULL)
|
||||
g_main_loop_unref (loop);
|
||||
if (opt_context != NULL)
|
||||
g_option_context_free (opt_context);
|
||||
|
||||
g_info ("cockpit daemon version %s exiting", PACKAGE_VERSION);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,960 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gi18n-lib.h>
|
||||
|
||||
#include "libgsystem.h"
|
||||
|
||||
#include <gudev/gudev.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "auth.h"
|
||||
#include "manager.h"
|
||||
#include "utils.h"
|
||||
|
||||
/**
|
||||
* SECTION:manager
|
||||
* @title: Manager
|
||||
* @short_description: Implementation of #CockpitManager
|
||||
*
|
||||
* This type provides an implementation of the #CockpitManager interface.
|
||||
*/
|
||||
|
||||
typedef struct _ManagerClass ManagerClass;
|
||||
|
||||
/**
|
||||
* Manager:
|
||||
*
|
||||
* The #Manager structure contains only private data and should
|
||||
* only be accessed using the provided API.
|
||||
*/
|
||||
struct _Manager
|
||||
{
|
||||
CockpitManagerSkeleton parent_instance;
|
||||
|
||||
Daemon *daemon;
|
||||
|
||||
/* may be NULL */
|
||||
GDBusProxy *hostname1_proxy;
|
||||
|
||||
GFileMonitor *systemd_shutdown_schedule_monitor;
|
||||
|
||||
GFileMonitor *etc_os_release_monitor;
|
||||
};
|
||||
|
||||
struct _ManagerClass
|
||||
{
|
||||
CockpitManagerSkeletonClass parent_class;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DAEMON
|
||||
};
|
||||
|
||||
static void manager_iface_init (CockpitManagerIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (Manager, manager, COCKPIT_TYPE_MANAGER_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (COCKPIT_TYPE_MANAGER, manager_iface_init));
|
||||
|
||||
static void update_dmi (Manager *manager);
|
||||
|
||||
static void update_hostname1 (Manager *manager);
|
||||
static void on_hostname1_properties_changed (GDBusProxy *proxy,
|
||||
GVariant *changed_properties,
|
||||
const gchar *const *invalidated_properties,
|
||||
gpointer user_data);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
manager_finalize (GObject *object)
|
||||
{
|
||||
Manager *manager = MANAGER (object);
|
||||
|
||||
if (manager->hostname1_proxy != NULL)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (manager->hostname1_proxy,
|
||||
G_CALLBACK (on_hostname1_properties_changed),
|
||||
manager);
|
||||
g_object_unref (manager->hostname1_proxy);
|
||||
}
|
||||
|
||||
if (manager->systemd_shutdown_schedule_monitor)
|
||||
g_object_unref (manager->systemd_shutdown_schedule_monitor);
|
||||
|
||||
g_clear_object (&manager->etc_os_release_monitor);
|
||||
|
||||
G_OBJECT_CLASS (manager_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
manager_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
Manager *manager = MANAGER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DAEMON:
|
||||
g_value_set_object (value, manager_get_daemon (manager));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
manager_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
Manager *manager = MANAGER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DAEMON:
|
||||
g_assert (manager->daemon == NULL);
|
||||
/* we don't take a reference to the daemon */
|
||||
manager->daemon = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
manager_init (Manager *manager)
|
||||
{
|
||||
g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (manager),
|
||||
G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
|
||||
}
|
||||
|
||||
static void
|
||||
on_systemd_shutdown_scheduled_changed (GFileMonitor *monitor,
|
||||
GFile *file,
|
||||
GFile *other_file,
|
||||
GFileMonitorEvent event_type,
|
||||
gpointer user_data);
|
||||
|
||||
static void
|
||||
reread_os_release (Manager *manager)
|
||||
{
|
||||
gs_unref_object GFile *etc_os_release = g_file_new_for_path ("/etc/os-release");
|
||||
gs_free char *contents = NULL;
|
||||
const char *operating_system_value = NULL;
|
||||
char **lines = NULL;
|
||||
char **iter = NULL;
|
||||
GError *local_error = NULL;
|
||||
gs_unref_hashtable GHashTable *os_release_keys =
|
||||
g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
|
||||
contents = gs_file_load_contents_utf8 (etc_os_release, NULL, &local_error);
|
||||
if (!contents)
|
||||
goto out;
|
||||
|
||||
lines = g_strsplit (contents, "\n", -1);
|
||||
for (iter = lines; iter && *iter; iter++)
|
||||
{
|
||||
char *line = *iter;
|
||||
char *eq;
|
||||
char *value;
|
||||
const char *quotedval;
|
||||
|
||||
if (g_str_has_prefix (line, "#"))
|
||||
continue;
|
||||
|
||||
eq = strchr (line, '=');
|
||||
if (!eq)
|
||||
continue;
|
||||
|
||||
*eq = '\0';
|
||||
quotedval = eq + 1;
|
||||
value = g_shell_unquote (quotedval, NULL);
|
||||
if (!value)
|
||||
continue;
|
||||
|
||||
g_hash_table_insert (os_release_keys, g_strdup (line), value);
|
||||
}
|
||||
|
||||
operating_system_value = g_hash_table_lookup (os_release_keys, "PRETTY_NAME");
|
||||
if (operating_system_value)
|
||||
g_object_set (manager, "operating-system", operating_system_value, NULL);
|
||||
|
||||
out:
|
||||
g_strfreev (lines);
|
||||
if (local_error)
|
||||
{
|
||||
g_warning ("Failed to load /etc/os-release: %s",
|
||||
local_error->message);
|
||||
g_error_free (local_error);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_etc_os_release_changed (GFileMonitor *monitor,
|
||||
GFile *file,
|
||||
GFile *other_file,
|
||||
GFileMonitorEvent *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
Manager *manager = user_data;
|
||||
reread_os_release (manager);
|
||||
}
|
||||
|
||||
static void
|
||||
manager_constructed (GObject *object)
|
||||
{
|
||||
Manager *manager = MANAGER (object);
|
||||
GError *error = NULL;
|
||||
gs_unref_object GFile *etc_os_release = g_file_new_for_path ("/etc/os-release");
|
||||
|
||||
manager->etc_os_release_monitor = g_file_monitor (etc_os_release, G_FILE_MONITOR_NONE, NULL, &error);
|
||||
if (!manager->etc_os_release_monitor)
|
||||
{
|
||||
g_warning ("Error monitoring /etc/os-release: %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_signal_connect (manager->etc_os_release_monitor, "changed",
|
||||
G_CALLBACK (on_etc_os_release_changed), manager);
|
||||
reread_os_release (manager);
|
||||
}
|
||||
|
||||
manager->hostname1_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES,
|
||||
NULL, /* GDBusInterfaceInfo* */
|
||||
"org.freedesktop.hostname1",
|
||||
"/org/freedesktop/hostname1",
|
||||
"org.freedesktop.hostname1",
|
||||
NULL, /* GCancellable* */
|
||||
&error);
|
||||
if (manager->hostname1_proxy == NULL)
|
||||
{
|
||||
g_warning ("Unable to create hostname1 proxy: %s (%s, %d)",
|
||||
error->message, g_quark_to_string (error->domain), error->code);
|
||||
}
|
||||
else
|
||||
{
|
||||
update_hostname1 (manager);
|
||||
g_signal_connect (manager->hostname1_proxy,
|
||||
"g-properties-changed",
|
||||
G_CALLBACK (on_hostname1_properties_changed),
|
||||
manager);
|
||||
}
|
||||
|
||||
update_dmi (manager);
|
||||
|
||||
error = NULL;
|
||||
gs_unref_object GFile *f = g_file_new_for_path ("/run/systemd/shutdown/scheduled");
|
||||
manager->systemd_shutdown_schedule_monitor = g_file_monitor_file (f, 0, NULL, &error);
|
||||
if (error)
|
||||
{
|
||||
g_warning ("Can't watch: %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_signal_connect (manager->systemd_shutdown_schedule_monitor,
|
||||
"changed",
|
||||
G_CALLBACK (on_systemd_shutdown_scheduled_changed),
|
||||
manager);
|
||||
}
|
||||
|
||||
if (G_OBJECT_CLASS (manager_parent_class)->constructed != NULL)
|
||||
G_OBJECT_CLASS (manager_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
manager_class_init (ManagerClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = manager_finalize;
|
||||
gobject_class->constructed = manager_constructed;
|
||||
gobject_class->set_property = manager_set_property;
|
||||
gobject_class->get_property = manager_get_property;
|
||||
|
||||
/**
|
||||
* Manager:daemon:
|
||||
*
|
||||
* The #Daemon for the object.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_DAEMON,
|
||||
g_param_spec_object ("daemon",
|
||||
NULL,
|
||||
NULL,
|
||||
TYPE_DAEMON,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
/**
|
||||
* manager_new:
|
||||
* @daemon: A #Daemon.
|
||||
*
|
||||
* Creates a new #Manager instance.
|
||||
*
|
||||
* Returns: A new #Manager. Free with g_object_unref().
|
||||
*/
|
||||
CockpitManager *
|
||||
manager_new (Daemon *daemon)
|
||||
{
|
||||
g_return_val_if_fail (IS_DAEMON (daemon), NULL);
|
||||
return COCKPIT_MANAGER (g_object_new (COCKPIT_TYPE_DAEMON_MANAGER,
|
||||
"daemon", daemon,
|
||||
"version", PACKAGE_VERSION,
|
||||
NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* manager_get_daemon:
|
||||
* @manager: A #Manager.
|
||||
*
|
||||
* Gets the daemon used by @manager.
|
||||
*
|
||||
* Returns: A #Daemon. Do not free, the object is owned by @manager.
|
||||
*/
|
||||
Daemon *
|
||||
manager_get_daemon (Manager *manager)
|
||||
{
|
||||
g_return_val_if_fail (COCKPIT_IS_DAEMON_MANAGER (manager), NULL);
|
||||
return manager->daemon;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static const gchar *
|
||||
peek_str_prop (GDBusProxy *proxy,
|
||||
const gchar *name)
|
||||
{
|
||||
const gchar *ret = NULL;
|
||||
GVariant *value;
|
||||
|
||||
value = g_dbus_proxy_get_cached_property (proxy, name);
|
||||
if (value == NULL)
|
||||
goto out;
|
||||
|
||||
ret = g_variant_get_string (value, NULL);
|
||||
g_variant_unref (value);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
update_hostname1 (Manager *manager)
|
||||
{
|
||||
gchar *name_owner = NULL;
|
||||
|
||||
name_owner = g_dbus_proxy_get_name_owner (manager->hostname1_proxy);
|
||||
if (name_owner == NULL)
|
||||
goto out;
|
||||
|
||||
cockpit_manager_set_hostname (COCKPIT_MANAGER (manager), peek_str_prop (manager->hostname1_proxy, "Hostname"));
|
||||
cockpit_manager_set_static_hostname (COCKPIT_MANAGER (manager), peek_str_prop (manager->hostname1_proxy, "StaticHostname"));
|
||||
cockpit_manager_set_pretty_hostname (COCKPIT_MANAGER (manager), peek_str_prop (manager->hostname1_proxy, "PrettyHostname"));
|
||||
|
||||
out:
|
||||
g_free (name_owner);
|
||||
}
|
||||
|
||||
static void
|
||||
on_hostname1_properties_changed (GDBusProxy *proxy,
|
||||
GVariant *changed_properties,
|
||||
const gchar * const *invalidated_properties,
|
||||
gpointer user_data)
|
||||
{
|
||||
Manager *manager = MANAGER (user_data);
|
||||
update_hostname1 (manager);
|
||||
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gchar *
|
||||
get_stripped_sysfs_attr (GUdevDevice *device,
|
||||
const gchar *attr_name)
|
||||
{
|
||||
gchar *ret;
|
||||
|
||||
ret = g_strdup (g_udev_device_get_sysfs_attr (device, attr_name));
|
||||
if (ret == NULL)
|
||||
goto out;
|
||||
|
||||
g_strstrip (ret);
|
||||
|
||||
if (strlen (ret) == 0)
|
||||
{
|
||||
g_free (ret);
|
||||
ret = NULL;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
update_dmi (Manager *manager)
|
||||
{
|
||||
GUdevClient *client = NULL;
|
||||
GUdevDevice *device = NULL;
|
||||
GString *str;
|
||||
gchar *s;
|
||||
|
||||
/* TODO: Probably need some other and/or better heuristics to yield
|
||||
* useful info on as many systems as possible
|
||||
*/
|
||||
|
||||
client = g_udev_client_new (NULL);
|
||||
device = g_udev_client_query_by_sysfs_path (client, "/sys/devices/virtual/dmi/id");
|
||||
if (device == NULL)
|
||||
goto out;
|
||||
|
||||
str = g_string_new (NULL);
|
||||
g_string_append_printf (str, "%s %s (%s)",
|
||||
g_udev_device_get_sysfs_attr (device, "bios_vendor"),
|
||||
g_udev_device_get_sysfs_attr (device, "bios_version"),
|
||||
g_udev_device_get_sysfs_attr (device, "bios_date"));
|
||||
cockpit_manager_set_bios (COCKPIT_MANAGER (manager), str->str);
|
||||
g_string_free (str, TRUE);
|
||||
|
||||
str = g_string_new (NULL);
|
||||
g_string_append_printf (str, "%s %s",
|
||||
g_udev_device_get_sysfs_attr (device, "sys_vendor"),
|
||||
g_udev_device_get_sysfs_attr (device, "product_name"));
|
||||
s = get_stripped_sysfs_attr (device, "product_version");
|
||||
if (s != NULL)
|
||||
{
|
||||
g_string_append_printf (str, " (%s)", s);
|
||||
g_free (s);
|
||||
}
|
||||
cockpit_manager_set_system (COCKPIT_MANAGER (manager), str->str);
|
||||
g_string_free (str, TRUE);
|
||||
|
||||
s = get_stripped_sysfs_attr (device, "product_serial");
|
||||
if (s == NULL)
|
||||
s = get_stripped_sysfs_attr (device, "chassis_serial");
|
||||
cockpit_manager_set_system_serial (COCKPIT_MANAGER (manager), s);
|
||||
|
||||
out:
|
||||
g_clear_object (&device);
|
||||
g_clear_object (&client);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* runs in thread dedicated to handling the method call so may block */
|
||||
static gboolean
|
||||
handle_set_hostname (CockpitManager *_manager,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_pretty_hostname,
|
||||
const gchar *arg_hostname,
|
||||
GVariant *arg_options)
|
||||
{
|
||||
Manager *manager = MANAGER (_manager);
|
||||
GError *error;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
/* TODO: validate that passed @arg_hostname is not malformed (e.g. only ASCII etc.) */
|
||||
|
||||
if (strlen (arg_pretty_hostname) > 0)
|
||||
{
|
||||
error = NULL;
|
||||
if (!g_dbus_proxy_call_sync (manager->hostname1_proxy,
|
||||
"SetPrettyHostname",
|
||||
g_variant_new ("(sb)", arg_pretty_hostname, FALSE),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1, /* timeout_msec */
|
||||
NULL, /* GCancellable* */
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_take_error (invocation, error);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen (arg_hostname) > 0)
|
||||
{
|
||||
error = NULL;
|
||||
if (!g_dbus_proxy_call_sync (manager->hostname1_proxy,
|
||||
"SetHostname",
|
||||
g_variant_new ("(sb)", arg_hostname, FALSE),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1, /* timeout_msec */
|
||||
NULL, /* GCancellable* */
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_take_error (invocation, error);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
cockpit_manager_complete_set_hostname (COCKPIT_MANAGER (manager), invocation);
|
||||
|
||||
out:
|
||||
return TRUE; /* Means we handled the invocation */
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gchar *
|
||||
get_avatar_data_url (void)
|
||||
{
|
||||
const gchar *file = PACKAGE_SYSCONF_DIR "/cockpit/avatar.png";
|
||||
|
||||
gs_free gchar *raw_data = NULL;
|
||||
gsize raw_size;
|
||||
gs_free gchar *base64_data = NULL;
|
||||
|
||||
if (!g_file_get_contents (file, &raw_data, &raw_size, NULL))
|
||||
return NULL;
|
||||
|
||||
base64_data = g_base64_encode ((guchar *)raw_data, raw_size);
|
||||
return g_strdup_printf ("data:image/png;base64,%s", base64_data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_get_avatar_data_url (CockpitManager *_manager,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
gs_free gchar *data = get_avatar_data_url ();
|
||||
cockpit_manager_complete_get_avatar_data_url (_manager, invocation, data? data : "");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_set_avatar_data_url (CockpitManager *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_data)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
const gchar *base64_data = strstr (arg_data, "base64,");
|
||||
if (base64_data == NULL)
|
||||
goto out;
|
||||
|
||||
base64_data += strlen ("base64,");
|
||||
|
||||
gsize raw_size;
|
||||
gs_free gchar *raw_data = (gchar *)g_base64_decode (base64_data, &raw_size);
|
||||
|
||||
const gchar *file = PACKAGE_SYSCONF_DIR "/cockpit/avatar.png";
|
||||
if (!g_file_set_contents (file, raw_data, raw_size, &error))
|
||||
goto out;
|
||||
|
||||
cockpit_manager_emit_avatar_changed (object);
|
||||
|
||||
out:
|
||||
if (error)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR, COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
else
|
||||
cockpit_manager_complete_set_avatar_data_url (object, invocation);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gchar *
|
||||
get_cockpitdyn (Manager *manager,
|
||||
gssize *out_len)
|
||||
{
|
||||
GString *str;
|
||||
gchar *s;
|
||||
guint n;
|
||||
const struct {
|
||||
const gchar *name;
|
||||
const gchar *code;
|
||||
} supported_languages[] =
|
||||
{
|
||||
{NC_("display-language", "English"), ""},
|
||||
{NC_("display-language", "Danish"), "da"},
|
||||
{NC_("display-language", "German"), "de"},
|
||||
};
|
||||
|
||||
str = g_string_new (NULL);
|
||||
|
||||
s = g_strescape (cockpit_manager_get_hostname (COCKPIT_MANAGER (manager)), NULL);
|
||||
g_string_append_printf (str, "cockpitdyn_hostname = \"%s\";\n", s);
|
||||
g_free (s);
|
||||
|
||||
s = g_strescape (cockpit_manager_get_pretty_hostname (COCKPIT_MANAGER (manager)), NULL);
|
||||
g_string_append_printf (str, "cockpitdyn_pretty_hostname = \"%s\";\n", s);
|
||||
g_free (s);
|
||||
|
||||
s = get_avatar_data_url ();
|
||||
s = g_strescape (s? s : "", NULL);
|
||||
g_string_append_printf (str, "cockpitdyn_avatar_data_url = \"%s\";\n", s);
|
||||
g_free (s);
|
||||
|
||||
s = g_strescape (PACKAGE_VERSION, NULL);
|
||||
g_string_append_printf (str, "cockpitdyn_version = \"%s\";\n", s);
|
||||
g_free (s);
|
||||
|
||||
s = g_strescape (COCKPIT_BUILD_INFO, NULL);
|
||||
g_string_append_printf (str, "cockpitdyn_build_info = \"%s\";\n", s);
|
||||
g_free (s);
|
||||
|
||||
g_string_append (str, "cockpitdyn_supported_languages = {");
|
||||
for (n = 0; n < G_N_ELEMENTS(supported_languages); n++)
|
||||
{
|
||||
if (n > 0)
|
||||
g_string_append (str, ", ");
|
||||
g_string_append_printf (str, "\"%s\": {name: \"%s\"}",
|
||||
supported_languages[n].code,
|
||||
supported_languages[n].name);
|
||||
}
|
||||
g_string_append (str, "};\n");
|
||||
|
||||
if (out_len != NULL)
|
||||
*out_len = str->len;
|
||||
|
||||
return g_string_free (str, FALSE);
|
||||
}
|
||||
|
||||
/* runs in thread dedicated to handling the method call so may block */
|
||||
static gboolean
|
||||
handle_http_get (CockpitManager *_manager,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_resource,
|
||||
const gchar *arg_user)
|
||||
{
|
||||
Manager *manager = MANAGER (_manager);
|
||||
const gchar *http_root;
|
||||
GError *error = NULL;
|
||||
gchar *s = NULL;
|
||||
gchar path[PATH_MAX];
|
||||
gchar *contents = NULL;
|
||||
gssize contents_len = -1;
|
||||
gchar *query;
|
||||
|
||||
http_root = daemon_get_http_root (manager->daemon);
|
||||
|
||||
if (g_strcmp0 (arg_resource, "/") == 0)
|
||||
arg_resource = "/index.html";
|
||||
|
||||
/* This is a dynamically generated file with information that
|
||||
* needs to be available at login time, e.g. before we have
|
||||
* a D-Bus connection. It is used by the login page.
|
||||
*/
|
||||
if (g_strcmp0 (arg_resource, "/cockpitdyn.js") == 0)
|
||||
{
|
||||
contents = get_cockpitdyn (manager, &contents_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
query = strchr (arg_resource, '?');
|
||||
if (query != NULL)
|
||||
*query++ = '\0';
|
||||
|
||||
s = g_strdup_printf ("%s/%s", http_root, arg_resource);
|
||||
if (realpath (s, path) == NULL)
|
||||
{
|
||||
g_free (s);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"Error creating a canonicalized absolute pathname from `%s': %m",
|
||||
arg_resource);
|
||||
goto out;
|
||||
}
|
||||
g_free (s);
|
||||
|
||||
if (http_root[0] == '/' && !g_str_has_prefix (path, http_root))
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"Invalid resource `%s' resulting in path `%s'",
|
||||
arg_resource, path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = NULL;
|
||||
if (!g_file_get_contents (path,
|
||||
&contents,
|
||||
(gsize*) &contents_len,
|
||||
&error))
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"Error loading file at `%s': %s (%s, %d)", path,
|
||||
error->message, g_quark_to_string (error->domain), error->code);
|
||||
g_error_free (error);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (contents_len == -1)
|
||||
contents_len = strlen (contents);
|
||||
cockpit_manager_complete_http_get (COCKPIT_MANAGER (manager),
|
||||
invocation,
|
||||
g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
|
||||
contents,
|
||||
contents_len,
|
||||
sizeof (guchar)));
|
||||
out:
|
||||
g_free (contents);
|
||||
return TRUE; /* Means we handled the invocation */
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* SHUTDOWN & RESTART
|
||||
*/
|
||||
|
||||
static gboolean
|
||||
handle_get_server_time (CockpitManager *object,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
GDateTime *now = g_date_time_new_now_local ();
|
||||
cockpit_manager_complete_get_server_time (object, invocation,
|
||||
g_date_time_to_unix (now),
|
||||
g_date_time_get_timezone_abbreviation (now),
|
||||
g_date_time_get_utc_offset (now) / 1.0e6);
|
||||
g_date_time_unref (now);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_scheduled_contents (Manager *manager,
|
||||
const char *contents)
|
||||
{
|
||||
char **lines = NULL;
|
||||
char **lines_iter = NULL;
|
||||
const char *mode = NULL;
|
||||
gboolean found_usec = FALSE;
|
||||
guint64 usec = 0;
|
||||
|
||||
lines = g_strsplit (contents, "\n", -1);
|
||||
|
||||
for (lines_iter = lines; *lines_iter; lines_iter++)
|
||||
{
|
||||
const char *line = *lines_iter;
|
||||
|
||||
if (g_str_has_prefix (line, "USEC="))
|
||||
{
|
||||
usec = g_ascii_strtoull (line + strlen ("USEC="), NULL, 10);
|
||||
found_usec = TRUE;
|
||||
}
|
||||
else if (g_str_has_prefix (line, "MODE="))
|
||||
{
|
||||
mode = line + strlen ("MODE=");
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mode && found_usec)
|
||||
{
|
||||
GVariantBuilder schedule;
|
||||
g_variant_builder_init (&schedule, G_VARIANT_TYPE("a{sv}"));
|
||||
g_variant_builder_add (&schedule, "{sv}", "when_seconds",
|
||||
g_variant_new_double (usec / 1.0e6));
|
||||
if (strcmp (mode, "poweroff") == 0)
|
||||
mode = "shutdown";
|
||||
else if (strcmp (mode, "reboot") == 0)
|
||||
mode = "restart";
|
||||
g_variant_builder_add (&schedule, "{sv}", "kind",
|
||||
g_variant_new_string (mode));
|
||||
cockpit_manager_set_shutdown_schedule (COCKPIT_MANAGER (manager),
|
||||
g_variant_builder_end (&schedule));
|
||||
}
|
||||
else
|
||||
g_warning ("Failed to parse scheduled shutdown file");
|
||||
|
||||
g_strfreev (lines);
|
||||
}
|
||||
|
||||
static void
|
||||
on_systemd_shutdown_scheduled_changed (GFileMonitor *monitor,
|
||||
GFile *file,
|
||||
GFile *other_file,
|
||||
GFileMonitorEvent event_type,
|
||||
gpointer user_data)
|
||||
{
|
||||
Manager *manager = user_data;
|
||||
GError *error = NULL;
|
||||
gs_free char *scheduled_contents = NULL;
|
||||
|
||||
if (!g_file_load_contents (file, NULL,
|
||||
&scheduled_contents, NULL,
|
||||
NULL, &error))
|
||||
{
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
cockpit_manager_set_shutdown_schedule (COCKPIT_MANAGER(manager), NULL);
|
||||
else
|
||||
g_warning ("%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
parse_scheduled_contents (manager, scheduled_contents);
|
||||
}
|
||||
|
||||
static void
|
||||
redirect_stderr_to_stdout (gpointer unused)
|
||||
{
|
||||
dup2 (1, 2);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
run_cmd_for_invocation (GDBusMethodInvocation *invocation,
|
||||
char **output,
|
||||
const gchar *cmd,
|
||||
...)
|
||||
{
|
||||
const int max_args = 20;
|
||||
const gchar *argv[max_args];
|
||||
|
||||
va_list ap;
|
||||
va_start (ap, cmd);
|
||||
const gchar **p = argv;
|
||||
while (cmd && p < argv + max_args - 1)
|
||||
{
|
||||
*p++ = cmd;
|
||||
cmd = va_arg (ap, const gchar *);
|
||||
}
|
||||
*p = NULL;
|
||||
|
||||
GError *error = NULL;
|
||||
gint code;
|
||||
|
||||
g_spawn_sync (NULL, (gchar **)argv, NULL, G_SPAWN_SEARCH_PATH,
|
||||
redirect_stderr_to_stdout, NULL, output, NULL, &code, &error);
|
||||
if (error)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"Can't run '%s': %s", argv[0], error->message);
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
else if (output == NULL && !g_spawn_check_exit_status (code, &error))
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"'%s' failed: %s", argv[0], error->message);
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_shutdown (CockpitManager *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_kind,
|
||||
const gchar *arg_when,
|
||||
const gchar *arg_message)
|
||||
{
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
if (run_cmd_for_invocation (invocation, NULL,
|
||||
"shutdown",
|
||||
(strcmp (arg_kind, "shutdown") == 0 ? "--poweroff" : "--reboot"),
|
||||
arg_when,
|
||||
arg_message,
|
||||
NULL))
|
||||
cockpit_manager_complete_shutdown (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_cancel_shutdown (CockpitManager *object,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
if (run_cmd_for_invocation (invocation, NULL, "shutdown", "-c", NULL))
|
||||
cockpit_manager_complete_cancel_shutdown (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gboolean
|
||||
handle_run (CockpitManager *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const char *arg_command)
|
||||
{
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
gs_free char *output = NULL;
|
||||
if (run_cmd_for_invocation (invocation, &output, "/bin/sh", "-c", arg_command, NULL))
|
||||
cockpit_manager_complete_run (object, invocation, output);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
manager_iface_init (CockpitManagerIface *iface)
|
||||
{
|
||||
iface->handle_http_get = handle_http_get;
|
||||
iface->handle_set_hostname = handle_set_hostname;
|
||||
iface->handle_get_avatar_data_url = handle_get_avatar_data_url;
|
||||
iface->handle_set_avatar_data_url = handle_set_avatar_data_url;
|
||||
|
||||
iface->handle_get_server_time = handle_get_server_time;
|
||||
iface->handle_shutdown = handle_shutdown;
|
||||
iface->handle_cancel_shutdown = handle_cancel_shutdown;
|
||||
|
||||
iface->handle_run = handle_run;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __MANAGER_H__
|
||||
#define __MANAGER_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define COCKPIT_TYPE_DAEMON_MANAGER (manager_get_type ())
|
||||
#define MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), COCKPIT_TYPE_DAEMON_MANAGER, Manager))
|
||||
#define COCKPIT_IS_DAEMON_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), COCKPIT_TYPE_DAEMON_MANAGER))
|
||||
|
||||
GType manager_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CockpitManager * manager_new (Daemon *daemon);
|
||||
|
||||
Daemon * manager_get_daemon (Manager *manager);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __MANAGER_H__ */
|
|
@ -0,0 +1,374 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "memorymonitor.h"
|
||||
|
||||
/**
|
||||
* SECTION:memorymonitor
|
||||
* @title: MemoryMonitor
|
||||
* @short_description: Implementation of #CockpitResourceMonitor for memory usage
|
||||
*
|
||||
* This type provides an implementation of the #CockpitResourceMonitor interface for memory usage.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gint64 timestamp;
|
||||
gint64 free;
|
||||
gint64 used;
|
||||
gint64 cached;
|
||||
gint64 swap_used;
|
||||
} Sample;
|
||||
|
||||
typedef struct _MemoryMonitorClass MemoryMonitorClass;
|
||||
|
||||
/**
|
||||
* MemoryMonitor:
|
||||
*
|
||||
* The #MemoryMonitor structure contains only private data and should
|
||||
* only be accessed using the provided API.
|
||||
*/
|
||||
struct _MemoryMonitor
|
||||
{
|
||||
CockpitResourceMonitorSkeleton parent_instance;
|
||||
|
||||
Daemon *daemon;
|
||||
|
||||
guint samples_max;
|
||||
gint samples_prev;
|
||||
guint samples_next;
|
||||
|
||||
/* Arrays of samples_max Sample instances */
|
||||
Sample *samples;
|
||||
};
|
||||
|
||||
struct _MemoryMonitorClass
|
||||
{
|
||||
CockpitResourceMonitorSkeletonClass parent_class;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DAEMON
|
||||
};
|
||||
|
||||
static void resource_monitor_iface_init (CockpitResourceMonitorIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (MemoryMonitor, memory_monitor, COCKPIT_TYPE_RESOURCE_MONITOR_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (COCKPIT_TYPE_RESOURCE_MONITOR, resource_monitor_iface_init));
|
||||
|
||||
static void on_tick (Daemon *daemon,
|
||||
guint64 delta_usec,
|
||||
gpointer user_data);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
memory_monitor_init (MemoryMonitor *monitor)
|
||||
{
|
||||
const gchar *legends[5] = {"Free", "Used", "Cached", "Swap Used", NULL}; /* TODO: i18n */
|
||||
|
||||
g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (monitor),
|
||||
G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
|
||||
|
||||
/* Assign legends */
|
||||
cockpit_resource_monitor_set_legends (COCKPIT_RESOURCE_MONITOR (monitor), legends);
|
||||
|
||||
monitor->samples_prev = -1;
|
||||
monitor->samples_max = 300;
|
||||
monitor->samples = g_new0 (Sample, monitor->samples_max);
|
||||
}
|
||||
|
||||
static void
|
||||
memory_monitor_finalize (GObject *object)
|
||||
{
|
||||
MemoryMonitor *monitor = MEMORY_MONITOR (object);
|
||||
|
||||
g_free (monitor->samples);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (monitor->daemon, G_CALLBACK (on_tick), monitor);
|
||||
|
||||
G_OBJECT_CLASS (memory_monitor_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
memory_monitor_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MemoryMonitor *monitor = MEMORY_MONITOR (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DAEMON:
|
||||
g_value_set_object (value, memory_monitor_get_daemon (monitor));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
memory_monitor_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MemoryMonitor *monitor = MEMORY_MONITOR (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DAEMON:
|
||||
g_assert (monitor->daemon == NULL);
|
||||
/* we don't take a reference to the daemon */
|
||||
monitor->daemon = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void collect (MemoryMonitor *monitor);
|
||||
|
||||
static void
|
||||
on_tick (Daemon *daemon,
|
||||
guint64 delta_usec,
|
||||
gpointer user_data)
|
||||
{
|
||||
MemoryMonitor *monitor = MEMORY_MONITOR (user_data);
|
||||
collect (monitor);
|
||||
}
|
||||
|
||||
static void
|
||||
memory_monitor_constructed (GObject *object)
|
||||
{
|
||||
MemoryMonitor *monitor = MEMORY_MONITOR (object);
|
||||
|
||||
cockpit_resource_monitor_set_num_samples (COCKPIT_RESOURCE_MONITOR (monitor), monitor->samples_max);
|
||||
cockpit_resource_monitor_set_num_series (COCKPIT_RESOURCE_MONITOR (monitor), 4);
|
||||
|
||||
g_signal_connect (monitor->daemon, "tick", G_CALLBACK (on_tick), monitor);
|
||||
collect (monitor);
|
||||
|
||||
if (G_OBJECT_CLASS (memory_monitor_parent_class)->constructed != NULL)
|
||||
G_OBJECT_CLASS (memory_monitor_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
memory_monitor_class_init (MemoryMonitorClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = memory_monitor_finalize;
|
||||
gobject_class->constructed = memory_monitor_constructed;
|
||||
gobject_class->set_property = memory_monitor_set_property;
|
||||
gobject_class->get_property = memory_monitor_get_property;
|
||||
|
||||
/**
|
||||
* MemoryMonitor:daemon:
|
||||
*
|
||||
* The #Daemon for the object.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_DAEMON,
|
||||
g_param_spec_object ("daemon",
|
||||
NULL,
|
||||
NULL,
|
||||
TYPE_DAEMON,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
/**
|
||||
* memory_monitor_new:
|
||||
* @daemon: A #Daemon.
|
||||
*
|
||||
* Creates a new #MemoryMonitor instance.
|
||||
*
|
||||
* Returns: A new #MemoryMonitor. Free with g_object_unref().
|
||||
*/
|
||||
CockpitResourceMonitor *
|
||||
memory_monitor_new (Daemon *daemon)
|
||||
{
|
||||
g_return_val_if_fail (IS_DAEMON (daemon), NULL);
|
||||
return COCKPIT_RESOURCE_MONITOR (g_object_new (TYPE_MEMORY_MONITOR,
|
||||
"daemon", daemon,
|
||||
NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* memory_monitor_get_daemon:
|
||||
* @monitor: A #MemoryMonitor.
|
||||
*
|
||||
* Gets the daemon used by @monitor.
|
||||
*
|
||||
* Returns: A #Daemon. Do not free, the object is owned by @monitor.
|
||||
*/
|
||||
Daemon *
|
||||
memory_monitor_get_daemon (MemoryMonitor *monitor)
|
||||
{
|
||||
g_return_val_if_fail (IS_MEMORY_MONITOR (monitor), NULL);
|
||||
return monitor->daemon;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* TODO: this should be optimized so we don't allocate memory and call open()/close() all the time */
|
||||
static void
|
||||
collect (MemoryMonitor *monitor)
|
||||
{
|
||||
gchar *contents = NULL;
|
||||
gsize len;
|
||||
GError *error;
|
||||
gchar **lines = NULL;
|
||||
guint n;
|
||||
gint64 now;
|
||||
Sample *sample = NULL;
|
||||
GVariantBuilder builder;
|
||||
guint64 free_kb = 0;
|
||||
guint64 total_kb = 0;
|
||||
guint64 buffers_kb = 0;
|
||||
guint64 cached_kb = 0;
|
||||
guint64 swap_total_kb = 0;
|
||||
guint64 swap_free_kb = 0;
|
||||
|
||||
error = NULL;
|
||||
if (!g_file_get_contents ("/proc/meminfo",
|
||||
&contents,
|
||||
&len,
|
||||
&error))
|
||||
{
|
||||
g_warning ("Error loading contents /proc/meminfo: %s (%s, %d)",
|
||||
error->message, g_quark_to_string (error->domain), error->code);
|
||||
g_error_free (error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
now = g_get_real_time ();
|
||||
|
||||
sample = &(monitor->samples[monitor->samples_next]);
|
||||
|
||||
/* see 'man proc' for the format of /proc/stat */
|
||||
|
||||
lines = g_strsplit (contents, "\n", -1);
|
||||
for (n = 0; lines != NULL && lines[n] != NULL; n++)
|
||||
{
|
||||
const gchar *line = lines[n];
|
||||
if (g_str_has_prefix (line, "MemTotal:"))
|
||||
g_warn_if_fail (sscanf (line + sizeof ("MemTotal:") - 1, "%" G_GUINT64_FORMAT, &total_kb) == 1);
|
||||
else if (g_str_has_prefix (line, "MemFree:"))
|
||||
g_warn_if_fail (sscanf (line + sizeof ("MemFree:") - 1, "%" G_GUINT64_FORMAT, &free_kb) == 1);
|
||||
else if (g_str_has_prefix (line, "SwapTotal:"))
|
||||
g_warn_if_fail (sscanf (line + sizeof ("SwapTotal:") - 1, "%" G_GUINT64_FORMAT, &swap_total_kb) == 1);
|
||||
else if (g_str_has_prefix (line, "SwapFree:"))
|
||||
g_warn_if_fail (sscanf (line + sizeof ("SwapFree:") - 1, "%" G_GUINT64_FORMAT, &swap_free_kb) == 1);
|
||||
else if (g_str_has_prefix (line, "Buffers:"))
|
||||
g_warn_if_fail (sscanf (line + sizeof ("Buffers:") - 1, "%" G_GUINT64_FORMAT, &buffers_kb) == 1);
|
||||
else if (g_str_has_prefix (line, "Cached:"))
|
||||
g_warn_if_fail (sscanf (line + sizeof ("Cached:") - 1, "%" G_GUINT64_FORMAT, &cached_kb) == 1);
|
||||
}
|
||||
|
||||
sample->timestamp = now;
|
||||
sample->free = free_kb * 1024;
|
||||
sample->used = (total_kb - free_kb) * 1024;
|
||||
sample->cached = (buffers_kb + cached_kb) * 1024;
|
||||
sample->swap_used = (swap_total_kb - swap_free_kb) * 1024;
|
||||
|
||||
out:
|
||||
g_strfreev (lines);
|
||||
g_free (contents);
|
||||
if (sample != NULL)
|
||||
{
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("ad"));
|
||||
g_variant_builder_add (&builder, "d", (gdouble)sample->free);
|
||||
g_variant_builder_add (&builder, "d", (gdouble)sample->used);
|
||||
g_variant_builder_add (&builder, "d", (gdouble)sample->cached);
|
||||
g_variant_builder_add (&builder, "d", (gdouble)sample->swap_used);
|
||||
cockpit_resource_monitor_emit_new_sample (COCKPIT_RESOURCE_MONITOR (monitor), now,
|
||||
g_variant_builder_end (&builder));
|
||||
}
|
||||
|
||||
monitor->samples_prev = monitor->samples_next;
|
||||
monitor->samples_next += 1;
|
||||
if (monitor->samples_next == monitor->samples_max)
|
||||
monitor->samples_next = 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gboolean
|
||||
handle_get_samples (CockpitResourceMonitor *_monitor,
|
||||
GDBusMethodInvocation *invocation,
|
||||
GVariant *arg_options)
|
||||
{
|
||||
MemoryMonitor *monitor = MEMORY_MONITOR (_monitor);
|
||||
GVariantBuilder builder;
|
||||
gint n;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(xad)"));
|
||||
for (n = 0; n < monitor->samples_max; n++)
|
||||
{
|
||||
gint pos;
|
||||
GVariantBuilder sample_builder;
|
||||
|
||||
pos = monitor->samples_next + n;
|
||||
if (pos > monitor->samples_max)
|
||||
pos -= monitor->samples_max;
|
||||
|
||||
if (monitor->samples[pos].timestamp == 0)
|
||||
continue;
|
||||
|
||||
g_variant_builder_init (&sample_builder, G_VARIANT_TYPE ("ad"));
|
||||
g_variant_builder_add (&sample_builder, "d", (gdouble)monitor->samples[pos].free);
|
||||
g_variant_builder_add (&sample_builder, "d", (gdouble)monitor->samples[pos].used);
|
||||
g_variant_builder_add (&sample_builder, "d", (gdouble)monitor->samples[pos].cached);
|
||||
g_variant_builder_add (&sample_builder, "d", (gdouble)monitor->samples[pos].swap_used);
|
||||
|
||||
g_variant_builder_add (&builder, "(x@ad)",
|
||||
monitor->samples[pos].timestamp,
|
||||
g_variant_builder_end (&sample_builder));
|
||||
}
|
||||
cockpit_resource_monitor_complete_get_samples (_monitor, invocation,
|
||||
g_variant_builder_end (&builder));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
resource_monitor_iface_init (CockpitResourceMonitorIface *iface)
|
||||
{
|
||||
iface->handle_get_samples = handle_get_samples;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __MEMORY_MONITOR_H__
|
||||
#define __MEMORY_MONITOR_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_MEMORY_MONITOR (memory_monitor_get_type ())
|
||||
#define MEMORY_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_MEMORY_MONITOR, MemoryMonitor))
|
||||
#define IS_MEMORY_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_MEMORY_MONITOR))
|
||||
|
||||
GType memory_monitor_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CockpitResourceMonitor * memory_monitor_new (Daemon *daemon);
|
||||
|
||||
Daemon * memory_monitor_get_daemon (MemoryMonitor *monitor);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __MEMORY_MONITOR_H__ */
|
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "network.h"
|
||||
#include "netinterface.h"
|
||||
#include "utils.h"
|
||||
|
||||
/**
|
||||
* SECTION:netinterface
|
||||
* @title: Network Interface
|
||||
* @short_description: Implementation of #Netinterface
|
||||
*
|
||||
* The #Netinterface represents a single network interface.
|
||||
*/
|
||||
|
||||
typedef struct _NetinterfaceClass NetinterfaceClass;
|
||||
|
||||
/**
|
||||
* <private>
|
||||
* Netinterface:
|
||||
*
|
||||
* Private.
|
||||
*/
|
||||
struct _Netinterface
|
||||
{
|
||||
CockpitNetworkNetinterfaceSkeleton parent_instance;
|
||||
|
||||
Network *network;
|
||||
|
||||
gchar *name;
|
||||
};
|
||||
|
||||
struct _NetinterfaceClass
|
||||
{
|
||||
CockpitNetworkNetinterfaceSkeletonClass parent_class;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_NETWORK
|
||||
};
|
||||
|
||||
static void network_netinterface_iface_init (CockpitNetworkNetinterfaceIface *iface);
|
||||
static gboolean netinterface_ensure_initialized (Netinterface *impl, GCancellable *cancellable, GError **error);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (Netinterface, netinterface, COCKPIT_TYPE_NETWORK_NETINTERFACE_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (COCKPIT_TYPE_NETWORK_NETINTERFACE, network_netinterface_iface_init));
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
netinterface_finalize (GObject *object)
|
||||
{
|
||||
Netinterface *self = NETINTERFACE (object);
|
||||
|
||||
(void)self;
|
||||
|
||||
G_OBJECT_CLASS (netinterface_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
netinterface_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
Netinterface *self = NETINTERFACE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_NETWORK:
|
||||
g_value_set_object (value, netinterface_get_network (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
netinterface_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
Netinterface *self = NETINTERFACE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_NETWORK:
|
||||
g_assert (self->network == NULL);
|
||||
self->network = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
netinterface_init (Netinterface *self)
|
||||
{
|
||||
GError *local_error = NULL;
|
||||
GError **error = &local_error;
|
||||
|
||||
if (!netinterface_ensure_initialized (self, NULL, error))
|
||||
goto out;
|
||||
|
||||
out:
|
||||
if (local_error)
|
||||
g_warning ("Failed to initialize interface: %s", local_error->message);
|
||||
g_clear_error (&local_error);
|
||||
}
|
||||
|
||||
static void
|
||||
netinterface_constructed (GObject *object)
|
||||
{
|
||||
Netinterface *self = NETINTERFACE (object);
|
||||
|
||||
(void)self;
|
||||
|
||||
if (G_OBJECT_CLASS (netinterface_parent_class)->constructed != NULL)
|
||||
G_OBJECT_CLASS (netinterface_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
netinterface_class_init (NetinterfaceClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = netinterface_finalize;
|
||||
gobject_class->constructed = netinterface_constructed;
|
||||
gobject_class->set_property = netinterface_set_property;
|
||||
gobject_class->get_property = netinterface_get_property;
|
||||
|
||||
/**
|
||||
* Netinterface:network:
|
||||
*
|
||||
* The #Network for the object.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_NETWORK,
|
||||
g_param_spec_object ("network",
|
||||
NULL,
|
||||
NULL,
|
||||
TYPE_NETWORK,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
/**
|
||||
* netinterface_new:
|
||||
* @network: A #Network
|
||||
*
|
||||
* Creates a new #Netinterface instance.
|
||||
*
|
||||
* Returns: A new #Netinterface. Free with g_object_unref().
|
||||
*/
|
||||
CockpitNetworkNetinterface *
|
||||
netinterface_new (Network *network,
|
||||
const gchar *name)
|
||||
{
|
||||
g_return_val_if_fail (IS_NETWORK (network), NULL);
|
||||
return COCKPIT_NETWORK_NETINTERFACE (g_object_new (TYPE_NETINTERFACE,
|
||||
"network", network,
|
||||
"name", name,
|
||||
NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* netinterface_get_network:
|
||||
* @self: A #Netinterface.
|
||||
*
|
||||
* Gets the network used by @self.
|
||||
*
|
||||
* Returns: A #Network. Do not free, the object is owned by @self.
|
||||
*/
|
||||
Network *
|
||||
netinterface_get_network (Netinterface *self)
|
||||
{
|
||||
g_return_val_if_fail (IS_NETINTERFACE (self), NULL);
|
||||
return self->network;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
network_netinterface_iface_init (CockpitNetworkNetinterfaceIface *iface)
|
||||
{
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gboolean
|
||||
netinterface_ensure_initialized (Netinterface *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __NETINTERFACE_H__
|
||||
#define __NETINTERFACE_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_NETINTERFACE (netinterface_get_type ())
|
||||
#define NETINTERFACE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_NETINTERFACE, Netinterface))
|
||||
#define IS_NETINTERFACE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_NETINTERFACE))
|
||||
|
||||
GType netinterface_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CockpitNetworkNetinterface * netinterface_new (Network *network,
|
||||
const gchar *name);
|
||||
|
||||
Network * netinterface_get_network (Netinterface *network);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __NETINTERFACE_H__ */
|
|
@ -0,0 +1,701 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Very heavily based on code from NetworkManager:
|
||||
* src/ip6-manager/nm-ip6-manager.c
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <gio/gunixcredentialsmessage.h>
|
||||
#include <gudev/gudev.h>
|
||||
#include <netinet/icmp6.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/ether.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <nm-client.h>
|
||||
#include <nm-remote-settings.h>
|
||||
#include <nm-setting-ip4-config.h>
|
||||
#include <nm-setting-ip6-config.h>
|
||||
#include <nm-device-ethernet.h>
|
||||
#include <nm-device-wifi.h>
|
||||
#include <nm-device-wimax.h>
|
||||
#include <nm-device-infiniband.h>
|
||||
#include <nm-utils.h>
|
||||
|
||||
#include "libgsystem.h"
|
||||
|
||||
#include "daemon.h"
|
||||
#include "network.h"
|
||||
#include "netinterface.h"
|
||||
#include "utils.h"
|
||||
|
||||
/**
|
||||
* SECTION:network
|
||||
* @title: Network
|
||||
* @short_description: Implementation of #Network
|
||||
*
|
||||
* The #Network interface allows inspection and control over
|
||||
* system networking.
|
||||
*/
|
||||
|
||||
typedef struct _NetworkClass NetworkClass;
|
||||
|
||||
/**
|
||||
* <private>
|
||||
* Network:
|
||||
*
|
||||
* Private.
|
||||
*/
|
||||
struct _Network
|
||||
{
|
||||
CockpitNetworkSkeleton parent_instance;
|
||||
|
||||
Daemon *daemon;
|
||||
|
||||
NMClient *client;
|
||||
NMRemoteSettings *settings;
|
||||
|
||||
GHashTable *ifname_to_netinterface;
|
||||
};
|
||||
|
||||
struct _NetworkClass
|
||||
{
|
||||
CockpitNetworkSkeletonClass parent_class;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DAEMON
|
||||
};
|
||||
|
||||
static void network_iface_init (CockpitNetworkIface *iface);
|
||||
static gboolean network_initialize (Network *impl, GCancellable *cancellable, GError **error);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (Network, network, COCKPIT_TYPE_NETWORK_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (COCKPIT_TYPE_NETWORK, network_iface_init));
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
network_finalize (GObject *object)
|
||||
{
|
||||
Network *self = NETWORK (object);
|
||||
|
||||
g_hash_table_unref (self->ifname_to_netinterface);
|
||||
|
||||
G_OBJECT_CLASS (network_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
network_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
Network *self = NETWORK (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DAEMON:
|
||||
g_value_set_object (value, network_get_daemon (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
network_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
Network *self = NETWORK (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DAEMON:
|
||||
g_assert (self->daemon == NULL);
|
||||
/* we don't take a reference to the daemon */
|
||||
self->daemon = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
network_init (Network *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
network_constructed (GObject *object)
|
||||
{
|
||||
Network *self = NETWORK (object);
|
||||
GError *local_error = NULL;
|
||||
GError **error = &local_error;
|
||||
|
||||
if (!network_initialize (self, NULL, error))
|
||||
goto out;
|
||||
|
||||
out:
|
||||
if (local_error)
|
||||
g_warning ("Failed to initialize network: %s", local_error->message);
|
||||
g_clear_error (&local_error);
|
||||
|
||||
if (G_OBJECT_CLASS (network_parent_class)->constructed != NULL)
|
||||
G_OBJECT_CLASS (network_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
network_class_init (NetworkClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = network_finalize;
|
||||
gobject_class->constructed = network_constructed;
|
||||
gobject_class->set_property = network_set_property;
|
||||
gobject_class->get_property = network_get_property;
|
||||
|
||||
/**
|
||||
* Network:daemon:
|
||||
*
|
||||
* The #Daemon for the object.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_DAEMON,
|
||||
g_param_spec_object ("daemon",
|
||||
NULL,
|
||||
NULL,
|
||||
TYPE_DAEMON,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
/**
|
||||
* network_new:
|
||||
* @daemon: A #Daemon.
|
||||
*
|
||||
* Creates a new #Network instance.
|
||||
*
|
||||
* Returns: A new #Network. Free with g_object_unref().
|
||||
*/
|
||||
CockpitNetwork *
|
||||
network_new (Daemon *daemon)
|
||||
{
|
||||
g_return_val_if_fail (IS_DAEMON (daemon), NULL);
|
||||
return COCKPIT_NETWORK (g_object_new (TYPE_NETWORK,
|
||||
"daemon", daemon,
|
||||
NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* network_get_daemon:
|
||||
* @network: A #Network.
|
||||
*
|
||||
* Gets the daemon used by @network.
|
||||
*
|
||||
* Returns: A #Daemon. Do not free, the object is owned by @network.
|
||||
*/
|
||||
Daemon *
|
||||
network_get_daemon (Network *self)
|
||||
{
|
||||
g_return_val_if_fail (IS_NETWORK (self), NULL);
|
||||
return self->daemon;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
network_iface_init (CockpitNetworkIface *iface)
|
||||
{
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static GVariant *
|
||||
ip6_addr_variant_new (const struct in6_addr *addr,
|
||||
guint32 prefix)
|
||||
{
|
||||
return g_variant_new ("(yyyyyyyyyyyyyyyyu)",
|
||||
addr->__in6_u.__u6_addr8[0],
|
||||
addr->__in6_u.__u6_addr8[1],
|
||||
addr->__in6_u.__u6_addr8[2],
|
||||
addr->__in6_u.__u6_addr8[3],
|
||||
addr->__in6_u.__u6_addr8[4],
|
||||
addr->__in6_u.__u6_addr8[5],
|
||||
addr->__in6_u.__u6_addr8[6],
|
||||
addr->__in6_u.__u6_addr8[7],
|
||||
addr->__in6_u.__u6_addr8[8],
|
||||
addr->__in6_u.__u6_addr8[9],
|
||||
addr->__in6_u.__u6_addr8[10],
|
||||
addr->__in6_u.__u6_addr8[11],
|
||||
addr->__in6_u.__u6_addr8[12],
|
||||
addr->__in6_u.__u6_addr8[13],
|
||||
addr->__in6_u.__u6_addr8[14],
|
||||
addr->__in6_u.__u6_addr8[15],
|
||||
prefix);
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
ip4_addr_variant_new (guint32 address,
|
||||
guint32 prefix)
|
||||
{
|
||||
return g_variant_new ("(yyyyu)",
|
||||
(address >> 24) & 0xFF,
|
||||
(address >> 16) & 0xFF,
|
||||
(address >> 8) & 0xFF,
|
||||
(address >> 0) & 0xFF,
|
||||
prefix);
|
||||
}
|
||||
|
||||
static GSList *
|
||||
valid_connections_for_device (NMRemoteSettings *remote_settings,
|
||||
NMDevice *device)
|
||||
{
|
||||
GSList *all, *filtered, *iterator, *valid;
|
||||
NMConnection *connection;
|
||||
NMSettingConnection *s_con;
|
||||
|
||||
all = nm_remote_settings_list_connections (remote_settings);
|
||||
filtered = nm_device_filter_connections (device, all);
|
||||
g_slist_free (all);
|
||||
|
||||
valid = NULL;
|
||||
for (iterator = filtered; iterator; iterator = iterator->next)
|
||||
{
|
||||
connection = iterator->data;
|
||||
s_con = nm_connection_get_setting_connection (connection);
|
||||
if (!s_con)
|
||||
continue;
|
||||
|
||||
if (nm_setting_connection_get_master (s_con))
|
||||
continue;
|
||||
|
||||
valid = g_slist_prepend (valid, connection);
|
||||
}
|
||||
g_slist_free (filtered);
|
||||
|
||||
return g_slist_reverse (valid);
|
||||
}
|
||||
|
||||
/* return value must be freed by caller with g_free() */
|
||||
static gchar *
|
||||
get_mac_address_of_connection (NMConnection *connection)
|
||||
{
|
||||
const GByteArray *mac = NULL;
|
||||
|
||||
if (!connection)
|
||||
return NULL;
|
||||
|
||||
/* check the connection type */
|
||||
if (nm_connection_is_type (connection,
|
||||
NM_SETTING_WIRELESS_SETTING_NAME))
|
||||
{
|
||||
/* check wireless settings */
|
||||
NMSettingWireless *s_wireless = nm_connection_get_setting_wireless (connection);
|
||||
if (!s_wireless)
|
||||
return NULL;
|
||||
mac = nm_setting_wireless_get_mac_address (s_wireless);
|
||||
if (mac)
|
||||
return nm_utils_hwaddr_ntoa (mac->data, ARPHRD_ETHER);
|
||||
}
|
||||
else if (nm_connection_is_type (connection,
|
||||
NM_SETTING_WIRED_SETTING_NAME))
|
||||
{
|
||||
/* check wired settings */
|
||||
NMSettingWired *s_wired = nm_connection_get_setting_wired (connection);
|
||||
if (!s_wired)
|
||||
return NULL;
|
||||
mac = nm_setting_wired_get_mac_address (s_wired);
|
||||
if (mac)
|
||||
return nm_utils_hwaddr_ntoa (mac->data, ARPHRD_ETHER);
|
||||
}
|
||||
else if (nm_connection_is_type (connection,
|
||||
NM_SETTING_WIMAX_SETTING_NAME))
|
||||
{
|
||||
/* check wimax settings */
|
||||
NMSettingWimax *s_wimax = nm_connection_get_setting_wimax (connection);
|
||||
if (!s_wimax)
|
||||
return NULL;
|
||||
mac = nm_setting_wimax_get_mac_address (s_wimax);
|
||||
if (mac)
|
||||
return nm_utils_hwaddr_ntoa (mac->data, ARPHRD_ETHER);
|
||||
}
|
||||
else if (nm_connection_is_type (connection,
|
||||
NM_SETTING_INFINIBAND_SETTING_NAME))
|
||||
{
|
||||
/* check infiniband settings */
|
||||
NMSettingInfiniband *s_infiniband = \
|
||||
nm_connection_get_setting_infiniband (connection);
|
||||
if (!s_infiniband)
|
||||
return NULL;
|
||||
mac = nm_setting_infiniband_get_mac_address (s_infiniband);
|
||||
if (mac)
|
||||
return nm_utils_hwaddr_ntoa (mac->data,
|
||||
ARPHRD_INFINIBAND);
|
||||
}
|
||||
/* no MAC address found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* return value must not be freed! */
|
||||
static const gchar *
|
||||
get_mac_address_of_device (NMDevice *device)
|
||||
{
|
||||
const gchar *mac = NULL;
|
||||
switch (nm_device_get_device_type (device))
|
||||
{
|
||||
case NM_DEVICE_TYPE_WIFI:
|
||||
{
|
||||
NMDeviceWifi *device_wifi = NM_DEVICE_WIFI (device);
|
||||
mac = nm_device_wifi_get_hw_address (device_wifi);
|
||||
break;
|
||||
}
|
||||
case NM_DEVICE_TYPE_ETHERNET:
|
||||
{
|
||||
NMDeviceEthernet *device_ethernet = NM_DEVICE_ETHERNET (device);
|
||||
mac = nm_device_ethernet_get_hw_address (device_ethernet);
|
||||
break;
|
||||
}
|
||||
case NM_DEVICE_TYPE_WIMAX:
|
||||
{
|
||||
NMDeviceWimax *device_wimax = NM_DEVICE_WIMAX (device);
|
||||
mac = nm_device_wimax_get_hw_address (device_wimax);
|
||||
break;
|
||||
}
|
||||
case NM_DEVICE_TYPE_INFINIBAND:
|
||||
{
|
||||
NMDeviceInfiniband *device_infiniband = NM_DEVICE_INFINIBAND (device);
|
||||
mac = nm_device_infiniband_get_hw_address (device_infiniband);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* no MAC address found */
|
||||
return mac;
|
||||
}
|
||||
|
||||
/* returns TRUE if both MACs are equal */
|
||||
static gboolean
|
||||
compare_mac_device_with_mac_connection (NMDevice *device,
|
||||
NMConnection *connection)
|
||||
{
|
||||
const gchar *mac_dev = NULL;
|
||||
gs_free gchar *mac_conn = NULL;
|
||||
|
||||
mac_dev = get_mac_address_of_device (device);
|
||||
if (mac_dev != NULL)
|
||||
{
|
||||
mac_conn = get_mac_address_of_connection (connection);
|
||||
if (mac_conn)
|
||||
{
|
||||
/* compare both MACs */
|
||||
if (g_strcmp0 (mac_dev, mac_conn) == 0)
|
||||
return TRUE;
|
||||
|
||||
g_clear_pointer (&mac_conn, g_free);
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static NMConnection *
|
||||
device_find_connection (NMRemoteSettings *remote_settings,
|
||||
NMDevice *device)
|
||||
{
|
||||
GSList *list, *iterator;
|
||||
NMConnection *connection = NULL;
|
||||
NMActiveConnection *ac;
|
||||
|
||||
ac = nm_device_get_active_connection (device);
|
||||
if (ac)
|
||||
{
|
||||
return (NMConnection*)nm_remote_settings_get_connection_by_path (remote_settings,
|
||||
nm_active_connection_get_connection (ac));
|
||||
}
|
||||
|
||||
/* not found in active connections - check all available connections */
|
||||
list = valid_connections_for_device (remote_settings, device);
|
||||
if (list != NULL)
|
||||
{
|
||||
/* if list has only one connection, use this connection */
|
||||
if (g_slist_length (list) == 1)
|
||||
{
|
||||
connection = list->data;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* is there connection with the MAC address of the device? */
|
||||
for (iterator = list; iterator; iterator = iterator->next)
|
||||
{
|
||||
connection = iterator->data;
|
||||
if (compare_mac_device_with_mac_connection (device, connection))
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* no connection found for the given device */
|
||||
connection = NULL;
|
||||
out:
|
||||
g_slist_free (list);
|
||||
return connection;
|
||||
}
|
||||
|
||||
static void
|
||||
synchronize_device_config (Network *self,
|
||||
Netinterface *iface,
|
||||
NMDevice *device)
|
||||
{
|
||||
NMConnection *connection;
|
||||
NMSettingIP4Config *ip4config;
|
||||
NMSettingIP6Config *ip6config;
|
||||
const char *ip4_method = "";
|
||||
const char *ip6_method = "";
|
||||
|
||||
connection = device_find_connection (self->settings, device);
|
||||
|
||||
if (!connection)
|
||||
{
|
||||
g_message ("No settings connection for device %p", device);
|
||||
return;
|
||||
}
|
||||
|
||||
ip4config = nm_connection_get_setting_ip4_config (connection);
|
||||
if (ip4config)
|
||||
ip4_method = nm_setting_ip4_config_get_method (ip4config);
|
||||
cockpit_network_netinterface_set_ip4_config_mode (COCKPIT_NETWORK_NETINTERFACE (iface),
|
||||
ip4_method);
|
||||
|
||||
ip6config = nm_connection_get_setting_ip6_config (connection);
|
||||
if (ip6config)
|
||||
ip6_method = nm_setting_ip6_config_get_method (ip6config);
|
||||
cockpit_network_netinterface_set_ip6_config_mode (COCKPIT_NETWORK_NETINTERFACE (iface),
|
||||
ip6_method);
|
||||
}
|
||||
|
||||
static void
|
||||
synchronize_device_ethernet (Network *self,
|
||||
Netinterface *iface,
|
||||
NMDeviceEthernet *device)
|
||||
{
|
||||
cockpit_network_netinterface_set_hw_address (COCKPIT_NETWORK_NETINTERFACE (iface),
|
||||
nm_device_ethernet_get_hw_address (device));
|
||||
}
|
||||
|
||||
static void
|
||||
synchronize_device_wifi (Network *self,
|
||||
Netinterface *iface,
|
||||
NMDeviceWifi *device)
|
||||
{
|
||||
cockpit_network_netinterface_set_hw_address (COCKPIT_NETWORK_NETINTERFACE (iface),
|
||||
nm_device_wifi_get_hw_address (device));
|
||||
}
|
||||
|
||||
static void
|
||||
synchronize_device (Network *self,
|
||||
NMDevice *device)
|
||||
{
|
||||
const char *iface_name = nm_device_get_iface (device);
|
||||
Netinterface *iface;
|
||||
NMIP4Config *ip4config;
|
||||
NMIP6Config *ip6config;
|
||||
|
||||
iface = g_hash_table_lookup (self->ifname_to_netinterface,
|
||||
iface_name);
|
||||
g_assert (iface);
|
||||
cockpit_network_netinterface_set_name (COCKPIT_NETWORK_NETINTERFACE (iface), iface_name);
|
||||
|
||||
ip4config = nm_device_get_ip4_config (device);
|
||||
if (ip4config)
|
||||
{
|
||||
const GSList *addresses = nm_ip4_config_get_addresses (ip4config);
|
||||
const GSList *iter;
|
||||
GVariantBuilder builder;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(yyyyu)"));
|
||||
|
||||
for (iter = addresses; iter; iter = iter->next)
|
||||
{
|
||||
NMIP4Address *ip4addr = iter->data;
|
||||
guint32 ipaddr = ntohl (nm_ip4_address_get_address (ip4addr));
|
||||
guint32 prefix = nm_ip4_address_get_prefix (ip4addr);
|
||||
|
||||
g_variant_builder_add_value (&builder, ip4_addr_variant_new (ipaddr, prefix));
|
||||
}
|
||||
|
||||
cockpit_network_netinterface_set_ip4_addresses (COCKPIT_NETWORK_NETINTERFACE (iface), g_variant_builder_end (&builder));
|
||||
}
|
||||
ip6config = nm_device_get_ip6_config (device);
|
||||
if (ip6config)
|
||||
{
|
||||
const GSList *addresses = nm_ip6_config_get_addresses (ip6config);
|
||||
const GSList *iter;
|
||||
GVariantBuilder builder;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(yyyyyyyyyyyyyyyyu)"));
|
||||
|
||||
for (iter = addresses; iter; iter = iter->next)
|
||||
{
|
||||
NMIP6Address *ip6addr = iter->data;
|
||||
|
||||
g_variant_builder_add_value (&builder, ip6_addr_variant_new (nm_ip6_address_get_address (ip6addr),
|
||||
nm_ip6_address_get_prefix (ip6addr)));
|
||||
}
|
||||
|
||||
cockpit_network_netinterface_set_ip6_addresses (COCKPIT_NETWORK_NETINTERFACE (iface), g_variant_builder_end (&builder));
|
||||
}
|
||||
|
||||
synchronize_device_config (self, iface, device);
|
||||
|
||||
switch (nm_device_get_device_type (device))
|
||||
{
|
||||
case NM_DEVICE_TYPE_ETHERNET:
|
||||
synchronize_device_ethernet (self, iface, NM_DEVICE_ETHERNET (device));
|
||||
break;
|
||||
case NM_DEVICE_TYPE_WIFI:
|
||||
synchronize_device_wifi (self, iface, NM_DEVICE_WIFI (device));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_nm_device_state_changed (NMDevice *device,
|
||||
guint new_state,
|
||||
guint old_state,
|
||||
guint reason,
|
||||
gpointer user_data)
|
||||
{
|
||||
Network *self = user_data;
|
||||
|
||||
synchronize_device (self, device);
|
||||
}
|
||||
|
||||
static void
|
||||
on_nm_device_added (NMClient *client,
|
||||
NMDevice *device,
|
||||
gpointer user_data)
|
||||
{
|
||||
Network *self = user_data;
|
||||
Netinterface *iface;
|
||||
CockpitNetworkNetinterface *cockpit_iface;
|
||||
const char *iface_name;
|
||||
Daemon *daemon;
|
||||
gs_unref_object CockpitObjectSkeleton *object = NULL;
|
||||
gs_free char *path = NULL;
|
||||
|
||||
g_assert (client != NULL);
|
||||
g_assert (self != NULL);
|
||||
|
||||
iface_name = nm_device_get_iface (device);
|
||||
if (!iface_name)
|
||||
return;
|
||||
|
||||
iface = g_hash_table_lookup (self->ifname_to_netinterface, iface_name);
|
||||
if (iface != NULL)
|
||||
return;
|
||||
|
||||
iface = (Netinterface*)netinterface_new (self, iface_name);
|
||||
cockpit_iface = COCKPIT_NETWORK_NETINTERFACE (iface);
|
||||
g_hash_table_insert (self->ifname_to_netinterface, g_strdup (iface_name), iface);
|
||||
path = g_strdup_printf ("/com/redhat/Cockpit/Network/%s", iface_name);
|
||||
object = cockpit_object_skeleton_new (path);
|
||||
daemon = network_get_daemon (self);
|
||||
cockpit_object_skeleton_set_network_netinterface (object, cockpit_iface);
|
||||
g_dbus_object_manager_server_export (daemon_get_object_manager (daemon),
|
||||
G_DBUS_OBJECT_SKELETON (object));
|
||||
|
||||
g_signal_connect (device, "state-changed", G_CALLBACK(on_nm_device_state_changed),
|
||||
self);
|
||||
synchronize_device (self, device);
|
||||
}
|
||||
|
||||
static void
|
||||
on_nm_device_removed (NMClient *client,
|
||||
NMDevice *device,
|
||||
gpointer user_data)
|
||||
{
|
||||
Network *self = user_data;
|
||||
const char *iface_name = nm_device_get_iface (device);
|
||||
|
||||
if (!iface_name)
|
||||
return;
|
||||
|
||||
g_hash_table_remove (self->ifname_to_netinterface, iface_name);
|
||||
}
|
||||
|
||||
static void
|
||||
on_nm_settings_read (NMRemoteSettings *settings,
|
||||
Network *self)
|
||||
{
|
||||
const GPtrArray *devices = NULL;
|
||||
guint i;
|
||||
|
||||
devices = nm_client_get_devices (self->client);
|
||||
if (devices)
|
||||
{
|
||||
for (i = 0; i < devices->len; i++)
|
||||
{
|
||||
NMDevice *device = devices->pdata[i];
|
||||
on_nm_device_added (self->client, device, self);
|
||||
}
|
||||
}
|
||||
|
||||
g_signal_connect (self->client, "device-added", G_CALLBACK (on_nm_device_added), self);
|
||||
g_signal_connect (self->client, "device-removed", G_CALLBACK (on_nm_device_removed), self);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
network_initialize (Network *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
|
||||
self->ifname_to_netinterface = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
g_free, (GDestroyNotify) g_object_unref);
|
||||
|
||||
self->client = nm_client_new ();
|
||||
self->settings = nm_remote_settings_new (dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL));
|
||||
if (!g_initable_init (G_INITABLE (self->settings), cancellable, error))
|
||||
goto out;
|
||||
g_signal_connect (self->settings, NM_REMOTE_SETTINGS_CONNECTIONS_READ,
|
||||
G_CALLBACK (on_nm_settings_read), self);
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __NETWORK_H__
|
||||
#define __NETWORK_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_NETWORK (network_get_type ())
|
||||
#define NETWORK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_NETWORK, Network))
|
||||
#define IS_NETWORK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_NETWORK))
|
||||
|
||||
GType network_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CockpitNetwork * network_new (Daemon *daemon);
|
||||
|
||||
Daemon * network_get_daemon (Network *network);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __NETWORK_H__ */
|
|
@ -0,0 +1,418 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "networkmonitor.h"
|
||||
|
||||
/**
|
||||
* SECTION:networkmonitor
|
||||
* @title: NetworkMonitor
|
||||
* @short_description: Implementation of #CockpitResourceMonitor for network usage
|
||||
*
|
||||
* This type provides an implementation of the #CockpitResourceMonitor interface for network usage.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gint64 timestamp;
|
||||
gint64 bytes_rx;
|
||||
gint64 bytes_tx;
|
||||
gdouble bytes_rx_per_sec;
|
||||
gdouble bytes_tx_per_sec;
|
||||
} Sample;
|
||||
|
||||
typedef struct _NetworkMonitorClass NetworkMonitorClass;
|
||||
|
||||
/**
|
||||
* NetworkMonitor:
|
||||
*
|
||||
* The #NetworkMonitor structure contains only private data and should
|
||||
* only be accessed using the provided API.
|
||||
*/
|
||||
struct _NetworkMonitor
|
||||
{
|
||||
CockpitResourceMonitorSkeleton parent_instance;
|
||||
|
||||
Daemon *daemon;
|
||||
|
||||
guint user_hz;
|
||||
|
||||
guint samples_max;
|
||||
gint samples_prev;
|
||||
guint samples_next;
|
||||
|
||||
/* Arrays of samples_max Sample instances */
|
||||
Sample *samples;
|
||||
};
|
||||
|
||||
struct _NetworkMonitorClass
|
||||
{
|
||||
CockpitResourceMonitorSkeletonClass parent_class;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DAEMON
|
||||
};
|
||||
|
||||
static void resource_monitor_iface_init (CockpitResourceMonitorIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (NetworkMonitor, network_monitor, COCKPIT_TYPE_RESOURCE_MONITOR_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (COCKPIT_TYPE_RESOURCE_MONITOR, resource_monitor_iface_init));
|
||||
|
||||
static void on_tick (Daemon *daemon,
|
||||
guint64 delta_usec,
|
||||
gpointer user_data);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
network_monitor_init (NetworkMonitor *monitor)
|
||||
{
|
||||
const gchar *legends[3] = {"Incoming Traffic", "Outgoing Traffic", NULL}; /* TODO: i18n */
|
||||
|
||||
g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (monitor),
|
||||
G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
|
||||
|
||||
/* Assign legends */
|
||||
cockpit_resource_monitor_set_legends (COCKPIT_RESOURCE_MONITOR (monitor), legends);
|
||||
|
||||
monitor->samples_prev = -1;
|
||||
monitor->samples_max = 300;
|
||||
monitor->samples = g_new0 (Sample, monitor->samples_max);
|
||||
}
|
||||
|
||||
static void
|
||||
network_monitor_finalize (GObject *object)
|
||||
{
|
||||
NetworkMonitor *monitor = NETWORK_MONITOR (object);
|
||||
|
||||
g_free (monitor->samples);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (monitor->daemon, G_CALLBACK (on_tick), monitor);
|
||||
|
||||
G_OBJECT_CLASS (network_monitor_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
network_monitor_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
NetworkMonitor *monitor = NETWORK_MONITOR (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DAEMON:
|
||||
g_value_set_object (value, network_monitor_get_daemon (monitor));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
network_monitor_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
NetworkMonitor *monitor = NETWORK_MONITOR (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DAEMON:
|
||||
g_assert (monitor->daemon == NULL);
|
||||
/* we don't take a reference to the daemon */
|
||||
monitor->daemon = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void collect (NetworkMonitor *monitor);
|
||||
|
||||
static void
|
||||
on_tick (Daemon *daemon,
|
||||
guint64 delta_usec,
|
||||
gpointer user_data)
|
||||
{
|
||||
NetworkMonitor *monitor = NETWORK_MONITOR (user_data);
|
||||
collect (monitor);
|
||||
}
|
||||
|
||||
static void
|
||||
network_monitor_constructed (GObject *object)
|
||||
{
|
||||
NetworkMonitor *monitor = NETWORK_MONITOR (object);
|
||||
|
||||
cockpit_resource_monitor_set_num_samples (COCKPIT_RESOURCE_MONITOR (monitor), monitor->samples_max);
|
||||
cockpit_resource_monitor_set_num_series (COCKPIT_RESOURCE_MONITOR (monitor), 2);
|
||||
|
||||
g_signal_connect (monitor->daemon, "tick", G_CALLBACK (on_tick), monitor);
|
||||
collect (monitor);
|
||||
|
||||
if (G_OBJECT_CLASS (network_monitor_parent_class)->constructed != NULL)
|
||||
G_OBJECT_CLASS (network_monitor_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
network_monitor_class_init (NetworkMonitorClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = network_monitor_finalize;
|
||||
gobject_class->constructed = network_monitor_constructed;
|
||||
gobject_class->set_property = network_monitor_set_property;
|
||||
gobject_class->get_property = network_monitor_get_property;
|
||||
|
||||
/**
|
||||
* NetworkMonitor:daemon:
|
||||
*
|
||||
* The #Daemon for the object.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_DAEMON,
|
||||
g_param_spec_object ("daemon",
|
||||
NULL,
|
||||
NULL,
|
||||
TYPE_DAEMON,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
/**
|
||||
* network_monitor_new:
|
||||
* @daemon: A #Daemon.
|
||||
*
|
||||
* Creates a new #NetworkMonitor instance.
|
||||
*
|
||||
* Returns: A new #NetworkMonitor. Free with g_object_unref().
|
||||
*/
|
||||
CockpitResourceMonitor *
|
||||
network_monitor_new (Daemon *daemon)
|
||||
{
|
||||
g_return_val_if_fail (IS_DAEMON (daemon), NULL);
|
||||
return COCKPIT_RESOURCE_MONITOR (g_object_new (TYPE_NETWORK_MONITOR,
|
||||
"daemon", daemon,
|
||||
NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* network_monitor_get_daemon:
|
||||
* @monitor: A #NetworkMonitor.
|
||||
*
|
||||
* Gets the daemon used by @monitor.
|
||||
*
|
||||
* Returns: A #Daemon. Do not free, the object is owned by @monitor.
|
||||
*/
|
||||
Daemon *
|
||||
network_monitor_get_daemon (NetworkMonitor *monitor)
|
||||
{
|
||||
g_return_val_if_fail(IS_NETWORK_MONITOR (monitor), NULL);
|
||||
return monitor->daemon;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gboolean
|
||||
calc_bandwidth (NetworkMonitor *monitor,
|
||||
Sample *sample,
|
||||
Sample *last,
|
||||
gint64 sample_value,
|
||||
gint64 last_value)
|
||||
{
|
||||
gdouble ret;
|
||||
gdouble bytes_in_period;
|
||||
gdouble period;
|
||||
|
||||
bytes_in_period = sample_value - last_value;
|
||||
period = ((gdouble) (sample->timestamp - last->timestamp)) / ((gdouble) G_USEC_PER_SEC);
|
||||
ret = bytes_in_period / period;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* TODO: this should be optimized so we don't allocate network and call open()/close() all the time */
|
||||
static void
|
||||
collect (NetworkMonitor *monitor)
|
||||
{
|
||||
gchar *contents = NULL;
|
||||
gsize len;
|
||||
GError *error;
|
||||
gchar **lines = NULL;
|
||||
guint n;
|
||||
gint64 now;
|
||||
Sample *sample = NULL;
|
||||
Sample *last = NULL;
|
||||
GVariantBuilder builder;
|
||||
|
||||
error = NULL;
|
||||
if (!g_file_get_contents ("/proc/net/dev",
|
||||
&contents,
|
||||
&len,
|
||||
&error))
|
||||
{
|
||||
g_warning ("Error loading contents /proc/net/dev: %s (%s, %d)",
|
||||
error->message, g_quark_to_string (error->domain), error->code);
|
||||
g_error_free (error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
now = g_get_real_time ();
|
||||
|
||||
sample = &(monitor->samples[monitor->samples_next]);
|
||||
sample->timestamp = now;
|
||||
sample->bytes_rx = 0;
|
||||
sample->bytes_tx = 0;
|
||||
|
||||
if (monitor->samples_prev != -1)
|
||||
last = &(monitor->samples[monitor->samples_prev]);
|
||||
|
||||
lines = g_strsplit (contents, "\n", -1);
|
||||
for (n = 0; lines != NULL && lines[n] != NULL; n++)
|
||||
{
|
||||
const gchar *line = lines[n];
|
||||
gchar iface_name[64]; /* guaranteed to be max 16 chars */
|
||||
guint64 bytes_rx, packets_rx, errors_rx, dropped_rx, fifo_rx, frame_rx, compressed_rx, multicast_rx;
|
||||
guint64 bytes_tx, packets_tx, errors_tx, dropped_tx, fifo_tx, frame_tx, compressed_tx, multicast_tx;
|
||||
gint num_parsed;
|
||||
|
||||
/* Format is
|
||||
*
|
||||
* Inter-| Receive | Transmit
|
||||
* face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
|
||||
* lo: 2776770 11307 0 0 0 0 0 0 2776770 11307 0 0 0 0 0 0
|
||||
* eth0: 1215645 2751 0 0 0 0 0 0 1782404 4324 0 0 0 427 0 0
|
||||
* ppp0: 1622270 5552 1 0 0 0 0 0 354130 5669 0 0 0 0 0 0
|
||||
* tap0: 7714 81 0 0 0 0 0 0 7714 81 0 0 0 0 0 0
|
||||
*/
|
||||
|
||||
if (n < 2 || strlen (line) == 0)
|
||||
continue;
|
||||
|
||||
num_parsed = sscanf (line,
|
||||
"%s %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT
|
||||
" %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT
|
||||
" %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT
|
||||
" %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT,
|
||||
iface_name,
|
||||
&bytes_rx, &packets_rx, &errors_rx, &dropped_rx,
|
||||
&fifo_rx, &frame_rx, &compressed_rx, &multicast_rx,
|
||||
&bytes_tx, &packets_tx, &errors_tx, &dropped_tx,
|
||||
&fifo_tx, &frame_tx, &compressed_tx, &multicast_tx);
|
||||
if (num_parsed != 17)
|
||||
{
|
||||
g_warning ("Error parsing line %d of file /proc/net/dev (num_parsed=%d): `%s'", n, num_parsed, line);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip loopback */
|
||||
if (g_strcmp0 (iface_name, "lo:") == 0)
|
||||
continue;
|
||||
|
||||
sample->bytes_rx += bytes_rx;
|
||||
sample->bytes_tx += bytes_tx;
|
||||
}
|
||||
|
||||
if (last != NULL)
|
||||
{
|
||||
sample->bytes_rx_per_sec = calc_bandwidth (monitor, sample, last, sample->bytes_rx, last->bytes_rx);
|
||||
sample->bytes_tx_per_sec = calc_bandwidth (monitor, sample, last, sample->bytes_tx, last->bytes_tx);
|
||||
}
|
||||
|
||||
out:
|
||||
g_strfreev (lines);
|
||||
g_free (contents);
|
||||
if (sample != NULL)
|
||||
{
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("ad"));
|
||||
g_variant_builder_add (&builder, "d", sample->bytes_rx_per_sec);
|
||||
g_variant_builder_add (&builder, "d", sample->bytes_tx_per_sec);
|
||||
cockpit_resource_monitor_emit_new_sample (COCKPIT_RESOURCE_MONITOR(monitor), now,
|
||||
g_variant_builder_end (&builder));
|
||||
}
|
||||
|
||||
monitor->samples_prev = monitor->samples_next;
|
||||
monitor->samples_next += 1;
|
||||
if (monitor->samples_next == monitor->samples_max)
|
||||
monitor->samples_next = 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gboolean
|
||||
handle_get_samples (CockpitResourceMonitor *_monitor,
|
||||
GDBusMethodInvocation *invocation,
|
||||
GVariant *arg_options)
|
||||
{
|
||||
NetworkMonitor *monitor = NETWORK_MONITOR (_monitor);
|
||||
GVariantBuilder builder;
|
||||
gint n;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(xad)"));
|
||||
for (n = 0; n < monitor->samples_max; n++)
|
||||
{
|
||||
gint pos;
|
||||
GVariantBuilder sample_builder;
|
||||
|
||||
pos = monitor->samples_next + n;
|
||||
if (pos > monitor->samples_max)
|
||||
pos -= monitor->samples_max;
|
||||
|
||||
if (monitor->samples[pos].timestamp == 0)
|
||||
continue;
|
||||
|
||||
g_variant_builder_init (&sample_builder, G_VARIANT_TYPE("ad"));
|
||||
g_variant_builder_add (&sample_builder, "d", monitor->samples[pos].bytes_rx_per_sec);
|
||||
g_variant_builder_add (&sample_builder, "d", monitor->samples[pos].bytes_tx_per_sec);
|
||||
|
||||
g_variant_builder_add (&builder, "(x@ad)",
|
||||
monitor->samples[pos].timestamp,
|
||||
g_variant_builder_end (&sample_builder));
|
||||
}
|
||||
cockpit_resource_monitor_complete_get_samples (_monitor,
|
||||
invocation,
|
||||
g_variant_builder_end (&builder));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
resource_monitor_iface_init (CockpitResourceMonitorIface *iface)
|
||||
{
|
||||
iface->handle_get_samples = handle_get_samples;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __NETWORK_MONITOR_H__
|
||||
#define __NETWORK_MONITOR_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_NETWORK_MONITOR (network_monitor_get_type ())
|
||||
#define NETWORK_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_NETWORK_MONITOR, NetworkMonitor))
|
||||
#define IS_NETWORK_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_NETWORK_MONITOR))
|
||||
|
||||
GType network_monitor_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CockpitResourceMonitor * network_monitor_new (Daemon *daemon);
|
||||
|
||||
Daemon * network_monitor_get_daemon (NetworkMonitor *monitor);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __NETWORK_MONITOR_H__ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __REALMS_H__
|
||||
#define __REALMS_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_REALMS (realms_get_type ())
|
||||
#define REALMS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_REALMS, Realms))
|
||||
#define IS_REALMS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_REALMS))
|
||||
|
||||
GType realms_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CockpitRealms * realms_new (Daemon *daemon);
|
||||
|
||||
Daemon * realms_get_daemon (Realms *realms);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __REALMS_H__ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __SERVICES_H__
|
||||
#define __SERVICES_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_SERVICES (services_get_type ())
|
||||
#define SERVICES(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_SERVICES, Services))
|
||||
#define IS_SERVICES(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_SERVICES))
|
||||
|
||||
GType services_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CockpitServices * services_new (Daemon *daemon);
|
||||
|
||||
Daemon * services_get_daemon (Services *realms);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __SERVICES_H__ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __STORAGE_BLOCK_H__
|
||||
#define __STORAGE_BLOCK_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_STORAGE_BLOCK (storage_block_get_type ())
|
||||
#define STORAGE_BLOCK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_STORAGE_BLOCK, StorageBlock))
|
||||
#define IS_STORAGE_BLOCK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_STORAGE_BLOCK))
|
||||
|
||||
GType storage_block_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CockpitStorageBlock * storage_block_new (StorageObject *object);
|
||||
|
||||
void storage_block_update (StorageBlock *block);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __STORAGE_BLOCK_H__ */
|
|
@ -0,0 +1,346 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "storageprovider.h"
|
||||
#include "storageobject.h"
|
||||
#include "storagedrive.h"
|
||||
|
||||
/**
|
||||
* SECTION:storagedrive
|
||||
* @title: Drives
|
||||
* @short_description: Implementation of #CockpitStorageDrive
|
||||
*
|
||||
* Instances of the #CockpitStorageDrive type are drives (typically hard
|
||||
* disks).
|
||||
*/
|
||||
|
||||
typedef struct _StorageDriveClass StorageDriveClass;
|
||||
|
||||
/**
|
||||
* <private>
|
||||
* StorageDrive:
|
||||
*
|
||||
* Private.
|
||||
*/
|
||||
struct _StorageDrive
|
||||
{
|
||||
CockpitStorageDriveSkeleton parent_instance;
|
||||
|
||||
UDisksDrive *udisks_drive;
|
||||
UDisksDriveAta *udisks_drive_ata; /* may be NULL */
|
||||
|
||||
StorageObject *object;
|
||||
};
|
||||
|
||||
struct _StorageDriveClass
|
||||
{
|
||||
CockpitStorageDriveSkeletonClass parent_class;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_OBJECT
|
||||
};
|
||||
|
||||
static void storage_drive_iface_init (CockpitStorageDriveIface *iface);
|
||||
|
||||
static void on_udisks_drive_notify (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (StorageDrive, storage_drive, COCKPIT_TYPE_STORAGE_DRIVE_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (COCKPIT_TYPE_STORAGE_DRIVE, storage_drive_iface_init));
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
storage_drive_finalize (GObject *object)
|
||||
{
|
||||
StorageDrive *drive = STORAGE_DRIVE (object);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (drive->udisks_drive,
|
||||
G_CALLBACK (on_udisks_drive_notify),
|
||||
drive);
|
||||
g_object_unref (drive->udisks_drive);
|
||||
if (drive->udisks_drive_ata != NULL)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (drive->udisks_drive_ata,
|
||||
G_CALLBACK (on_udisks_drive_notify),
|
||||
drive);
|
||||
g_object_unref (drive->udisks_drive_ata);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (storage_drive_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_drive_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StorageDrive *drive = STORAGE_DRIVE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_OBJECT:
|
||||
g_value_set_object (value, drive->object);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
storage_drive_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StorageDrive *drive = STORAGE_DRIVE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_OBJECT:
|
||||
g_assert (drive->object == NULL);
|
||||
drive->object = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
storage_drive_update (StorageDrive *drive)
|
||||
{
|
||||
CockpitStorageDrive *iface = COCKPIT_STORAGE_DRIVE (drive);
|
||||
const gchar *classification = "";
|
||||
const gchar *vendor;
|
||||
const gchar *model;
|
||||
const gchar *serial;
|
||||
const gchar *wwn;
|
||||
GString *s;
|
||||
|
||||
cockpit_storage_drive_set_vendor (iface, udisks_drive_get_vendor (drive->udisks_drive));
|
||||
cockpit_storage_drive_set_model (iface, udisks_drive_get_model (drive->udisks_drive));
|
||||
cockpit_storage_drive_set_revision (iface, udisks_drive_get_revision (drive->udisks_drive));
|
||||
cockpit_storage_drive_set_serial (iface, udisks_drive_get_serial (drive->udisks_drive));
|
||||
cockpit_storage_drive_set_wwn (iface, udisks_drive_get_wwn (drive->udisks_drive));
|
||||
cockpit_storage_drive_set_size (iface, udisks_drive_get_size (drive->udisks_drive));
|
||||
cockpit_storage_drive_set_sort_key (iface, udisks_drive_get_sort_key (drive->udisks_drive));
|
||||
|
||||
/* sort out name */
|
||||
vendor = udisks_drive_get_vendor (drive->udisks_drive);
|
||||
model = udisks_drive_get_model (drive->udisks_drive);
|
||||
serial = udisks_drive_get_serial (drive->udisks_drive);
|
||||
wwn = udisks_drive_get_wwn (drive->udisks_drive);
|
||||
s = g_string_new (NULL);
|
||||
if (strlen (vendor) > 0 && strlen (model) > 0)
|
||||
g_string_append_printf (s, "%s %s", vendor, model);
|
||||
else if (strlen (vendor) > 0)
|
||||
g_string_append (s, vendor);
|
||||
else
|
||||
g_string_append (s, model);
|
||||
/* user may have tens of this kind of drive - append something unique */
|
||||
if (strlen (serial) > 0)
|
||||
{
|
||||
g_string_append_printf (s, " (%s)", serial);
|
||||
}
|
||||
else if (strlen (wwn) > 0)
|
||||
{
|
||||
g_string_append_printf (s, " (%s)", wwn);
|
||||
}
|
||||
#if 0
|
||||
/* disabled for now, because if you have a lot of similar drives (same vendor/model), then
|
||||
* they probably have serial/wwn anyway
|
||||
*/
|
||||
else
|
||||
{
|
||||
UDisksClient *client;
|
||||
UDisksBlock *block;
|
||||
client = storage_provider_get_udisks_client (storage_object_get_provider (drive->object));
|
||||
block = udisks_client_get_block_for_drive (client,
|
||||
drive->udisks_drive,
|
||||
TRUE);
|
||||
if (block != NULL)
|
||||
{
|
||||
const gchar *device_file;
|
||||
device_file = udisks_block_get_preferred_device (block);
|
||||
g_string_append_printf (s, " (%s)", strrchr (device_file, '/') + 1);
|
||||
g_object_unref (block);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
cockpit_storage_drive_set_name (iface, s->str);
|
||||
g_string_free (s, TRUE);
|
||||
|
||||
/* sort out classification */
|
||||
if (udisks_drive_get_rotation_rate (drive->udisks_drive) == 0)
|
||||
{
|
||||
if (udisks_drive_get_media_removable (drive->udisks_drive))
|
||||
classification = "removable";
|
||||
else
|
||||
classification = "ssd";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (udisks_drive_get_media_removable (drive->udisks_drive))
|
||||
{
|
||||
gboolean optical = FALSE;
|
||||
const gchar *const *media_compat;
|
||||
guint n;
|
||||
media_compat = udisks_drive_get_media_compatibility (drive->udisks_drive);
|
||||
for (n = 0; media_compat != NULL && media_compat[n] != NULL; n++)
|
||||
{
|
||||
if (g_str_has_prefix (media_compat[n], "optical"))
|
||||
{
|
||||
optical = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (optical)
|
||||
classification = "optical";
|
||||
else
|
||||
classification = "removable";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g_strcmp0 (udisks_drive_get_media (drive->udisks_drive), "") == 0)
|
||||
classification = "hdd";
|
||||
else
|
||||
classification = "removable";
|
||||
}
|
||||
}
|
||||
cockpit_storage_drive_set_classification (iface, classification);
|
||||
|
||||
if (drive->udisks_drive_ata != NULL)
|
||||
{
|
||||
cockpit_storage_drive_set_temperature (iface, udisks_drive_ata_get_smart_temperature (drive->udisks_drive_ata));
|
||||
cockpit_storage_drive_set_failing (iface, udisks_drive_ata_get_smart_failing (drive->udisks_drive_ata));
|
||||
cockpit_storage_drive_set_failing_valid (iface, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
cockpit_storage_drive_set_failing_valid (iface, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_udisks_drive_notify (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
StorageDrive *drive = STORAGE_DRIVE (user_data);
|
||||
storage_drive_update (drive);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_drive_constructed (GObject *_object)
|
||||
{
|
||||
StorageDrive *drive = STORAGE_DRIVE(_object);
|
||||
UDisksObject *object;
|
||||
|
||||
drive->udisks_drive = g_object_ref (storage_object_get_udisks_drive (drive->object));
|
||||
g_signal_connect (drive->udisks_drive,
|
||||
"notify",
|
||||
G_CALLBACK (on_udisks_drive_notify),
|
||||
drive);
|
||||
|
||||
object = UDISKS_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (drive->udisks_drive)));
|
||||
drive->udisks_drive_ata = udisks_object_get_drive_ata (object);
|
||||
if (drive->udisks_drive_ata != NULL)
|
||||
{
|
||||
g_signal_connect (drive->udisks_drive_ata,
|
||||
"notify",
|
||||
G_CALLBACK (on_udisks_drive_notify),
|
||||
drive);
|
||||
}
|
||||
|
||||
storage_drive_update (drive);
|
||||
|
||||
if (G_OBJECT_CLASS (storage_drive_parent_class)->constructed != NULL)
|
||||
G_OBJECT_CLASS (storage_drive_parent_class)->constructed (_object);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_drive_init (StorageDrive *drive)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
storage_drive_class_init (StorageDriveClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = storage_drive_finalize;
|
||||
gobject_class->constructed = storage_drive_constructed;
|
||||
gobject_class->set_property = storage_drive_set_property;
|
||||
gobject_class->get_property = storage_drive_get_property;
|
||||
|
||||
/**
|
||||
* StorageDrive:object:
|
||||
*
|
||||
* The #CockpitStorageObject for the object.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_OBJECT,
|
||||
g_param_spec_object ("object",
|
||||
NULL,
|
||||
NULL,
|
||||
TYPE_STORAGE_OBJECT,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
/**
|
||||
* storage_drive_new:
|
||||
* @object: A #CockpitStorageObject
|
||||
*
|
||||
* Creates a new #StorageDrive instance.
|
||||
*
|
||||
* Returns: A new #StorageDrive. Free with g_object_unref().
|
||||
*/
|
||||
CockpitStorageDrive *
|
||||
storage_drive_new (StorageObject *object)
|
||||
{
|
||||
g_return_val_if_fail (IS_STORAGE_OBJECT (object), NULL);
|
||||
return COCKPIT_STORAGE_DRIVE (g_object_new (TYPE_STORAGE_DRIVE,
|
||||
"object", object,
|
||||
NULL));
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
storage_drive_iface_init (CockpitStorageDriveIface *iface)
|
||||
{
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __STORAGE_DRIVE_H__
|
||||
#define __STORAGE_DRIVE_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_STORAGE_DRIVE (storage_drive_get_type ())
|
||||
#define STORAGE_DRIVE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_STORAGE_DRIVE, StorageDrive))
|
||||
#define IS_STORAGE_DRIVE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_STORAGE_DRIVE))
|
||||
|
||||
GType storage_drive_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CockpitStorageDrive * storage_drive_new (StorageObject *object);
|
||||
|
||||
void storage_drive_update (StorageDrive *drive);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __STORAGE_DRIVE_H__ */
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "libgsystem.h"
|
||||
#include "daemon.h"
|
||||
#include "auth.h"
|
||||
#include "storagejob.h"
|
||||
#include "storageprovider.h"
|
||||
|
||||
typedef struct _StorageJobClass StorageJobClass;
|
||||
|
||||
struct _StorageJob
|
||||
{
|
||||
CockpitJobSkeleton parent_instance;
|
||||
|
||||
UDisksJob *udisks_job;
|
||||
};
|
||||
|
||||
struct _StorageJobClass
|
||||
{
|
||||
CockpitJobSkeletonClass parent_class;
|
||||
};
|
||||
|
||||
static void storage_job_iface_init (CockpitJobIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (StorageJob, storage_job, COCKPIT_TYPE_JOB_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (COCKPIT_TYPE_JOB, storage_job_iface_init));
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
on_completed (UDisksJob *object,
|
||||
gboolean arg_success,
|
||||
gchar *arg_message,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (!arg_success)
|
||||
g_log ("storage", G_LOG_LEVEL_WARNING, "%s", arg_message);
|
||||
}
|
||||
|
||||
static void
|
||||
update (StorageJob *job)
|
||||
{
|
||||
CockpitJob *rjob = COCKPIT_JOB(job);
|
||||
cockpit_job_set_cancellable (rjob, udisks_job_get_cancelable (job->udisks_job));
|
||||
|
||||
cockpit_job_set_progress (rjob, udisks_job_get_progress (job->udisks_job));
|
||||
cockpit_job_set_progress_valid (rjob, udisks_job_get_progress_valid (job->udisks_job));
|
||||
|
||||
guint64 end = udisks_job_get_expected_end_time (job->udisks_job);
|
||||
guint64 now = g_get_real_time ();
|
||||
if (end > now)
|
||||
cockpit_job_set_remaining_usecs (rjob, end - now);
|
||||
else
|
||||
cockpit_job_set_remaining_usecs (rjob, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
on_notify (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
StorageJob *job = STORAGE_JOB (user_data);
|
||||
update (job);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_cancel (CockpitJob *object,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
StorageJob *job = STORAGE_JOB (object);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
if (!udisks_job_call_cancel_sync (job->udisks_job,
|
||||
g_variant_new ("a{sv}", NULL),
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_method_invocation_take_error (invocation, error);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cockpit_job_complete_cancel (object, invocation);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
storage_job_finalize (GObject *object)
|
||||
{
|
||||
StorageJob *job = STORAGE_JOB (object);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (job->udisks_job, G_CALLBACK (on_completed), job);
|
||||
g_signal_handlers_disconnect_by_func (job->udisks_job, G_CALLBACK (on_notify), job);
|
||||
g_object_unref (job->udisks_job);
|
||||
|
||||
G_OBJECT_CLASS (storage_job_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_job_init (StorageJob *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
storage_job_class_init (StorageJobClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = storage_job_finalize;
|
||||
}
|
||||
|
||||
CockpitJob *
|
||||
storage_job_new (StorageProvider *provider,
|
||||
UDisksJob *udisks_job)
|
||||
{
|
||||
CockpitJob *job = COCKPIT_JOB (g_object_new (TYPE_STORAGE_JOB, NULL));
|
||||
|
||||
STORAGE_JOB(job)->udisks_job = g_object_ref (udisks_job);
|
||||
|
||||
g_signal_connect (udisks_job, "completed", G_CALLBACK (on_completed), job);
|
||||
g_signal_connect (udisks_job, "notify", G_CALLBACK (on_notify), job);
|
||||
|
||||
cockpit_job_set_domain (job, "storage");
|
||||
cockpit_job_set_operation (job, udisks_job_get_operation (udisks_job));
|
||||
|
||||
const gchar *const *objects = udisks_job_get_objects (udisks_job);
|
||||
int n_objects = g_strv_length ((gchar **)objects);
|
||||
const gchar **targets = g_new0 (const gchar *, n_objects + 1);
|
||||
for (int i = 0; i < n_objects; i++)
|
||||
targets[i] = storage_provider_translate_path (provider, objects[i]);
|
||||
cockpit_job_set_targets (job, targets);
|
||||
g_free (targets);
|
||||
|
||||
update (STORAGE_JOB(job));
|
||||
|
||||
return job;
|
||||
}
|
||||
|
||||
static void
|
||||
storage_job_iface_init (CockpitJobIface *iface)
|
||||
{
|
||||
iface->handle_cancel = handle_cancel;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __STORAGE_JOB_H__
|
||||
#define __STORAGE_JOB_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_STORAGE_JOB (storage_job_get_type ())
|
||||
#define STORAGE_JOB(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_STORAGE_JOB, StorageJob))
|
||||
#define IS_STORAGE_JOB(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_STORAGE_JOB))
|
||||
|
||||
GType storage_job_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CockpitJob * storage_job_new (StorageProvider *provider,
|
||||
UDisksJob *udisks_job);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __JOB_H__ */
|
|
@ -0,0 +1,450 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "auth.h"
|
||||
#include "storagemanager.h"
|
||||
#include "storageprovider.h"
|
||||
#include "storageobject.h"
|
||||
#include "storageblock.h"
|
||||
#include "storagelogicalvolume.h"
|
||||
|
||||
#include "libgsystem.h"
|
||||
|
||||
/**
|
||||
* SECTION:storagelogicalvolume
|
||||
* @title: LogicalVolume devices
|
||||
* @short_description: Implementation of #CockpitStorageLogicalVolume
|
||||
*/
|
||||
|
||||
typedef struct _StorageLogicalVolumeClass StorageLogicalVolumeClass;
|
||||
|
||||
/**
|
||||
* <private>
|
||||
* StorageLogicalVolume:
|
||||
*
|
||||
* Private.
|
||||
*/
|
||||
struct _StorageLogicalVolume
|
||||
{
|
||||
CockpitStorageLogicalVolumeSkeleton parent_instance;
|
||||
|
||||
UDisksLogicalVolume *udisks_logical_volume;
|
||||
|
||||
StorageObject *object;
|
||||
};
|
||||
|
||||
struct _StorageLogicalVolumeClass
|
||||
{
|
||||
CockpitStorageLogicalVolumeSkeletonClass parent_class;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_OBJECT
|
||||
};
|
||||
|
||||
static void storage_logical_volume_iface_init (CockpitStorageLogicalVolumeIface *iface);
|
||||
|
||||
static void on_udisks_logical_volume_notify (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (StorageLogicalVolume, storage_logical_volume, COCKPIT_TYPE_STORAGE_LOGICAL_VOLUME_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (COCKPIT_TYPE_STORAGE_LOGICAL_VOLUME, storage_logical_volume_iface_init));
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
storage_logical_volume_finalize (GObject *object)
|
||||
{
|
||||
StorageLogicalVolume *logical_volume = STORAGE_LOGICAL_VOLUME (object);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (logical_volume->udisks_logical_volume,
|
||||
G_CALLBACK (on_udisks_logical_volume_notify),
|
||||
logical_volume);
|
||||
g_object_unref (logical_volume->udisks_logical_volume);
|
||||
|
||||
G_OBJECT_CLASS (storage_logical_volume_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_logical_volume_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StorageLogicalVolume *logical_volume = STORAGE_LOGICAL_VOLUME (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_OBJECT:
|
||||
g_value_set_object (value, logical_volume->object);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
storage_logical_volume_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StorageLogicalVolume *logical_volume = STORAGE_LOGICAL_VOLUME (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_OBJECT:
|
||||
g_assert (logical_volume->object == NULL);
|
||||
logical_volume->object = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
storage_logical_volume_update (StorageLogicalVolume *logical_volume)
|
||||
{
|
||||
StorageProvider *provider = storage_object_get_provider (logical_volume->object);
|
||||
|
||||
CockpitStorageLogicalVolume *iface = COCKPIT_STORAGE_LOGICAL_VOLUME (logical_volume);
|
||||
cockpit_storage_logical_volume_set_uuid
|
||||
(iface, udisks_logical_volume_get_uuid (logical_volume->udisks_logical_volume));
|
||||
cockpit_storage_logical_volume_set_name
|
||||
(iface, udisks_logical_volume_get_name (logical_volume->udisks_logical_volume));
|
||||
cockpit_storage_logical_volume_set_display_name
|
||||
(iface, udisks_logical_volume_get_display_name (logical_volume->udisks_logical_volume));
|
||||
cockpit_storage_logical_volume_set_size
|
||||
(iface, udisks_logical_volume_get_size (logical_volume->udisks_logical_volume));
|
||||
cockpit_storage_logical_volume_set_type_
|
||||
(iface, udisks_logical_volume_get_type_ (logical_volume->udisks_logical_volume));
|
||||
cockpit_storage_logical_volume_set_data_allocated_ratio
|
||||
(iface, udisks_logical_volume_get_data_allocated_ratio (logical_volume->udisks_logical_volume));
|
||||
cockpit_storage_logical_volume_set_metadata_allocated_ratio
|
||||
(iface, udisks_logical_volume_get_metadata_allocated_ratio (logical_volume->udisks_logical_volume));
|
||||
cockpit_storage_logical_volume_set_volume_group
|
||||
(iface,
|
||||
storage_provider_translate_path
|
||||
(provider,
|
||||
udisks_logical_volume_get_volume_group (logical_volume->udisks_logical_volume)));
|
||||
cockpit_storage_logical_volume_set_thin_pool
|
||||
(iface,
|
||||
storage_provider_translate_path
|
||||
(provider,
|
||||
udisks_logical_volume_get_thin_pool (logical_volume->udisks_logical_volume)));
|
||||
}
|
||||
|
||||
static void
|
||||
on_udisks_logical_volume_notify (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
StorageLogicalVolume *logical_volume = STORAGE_LOGICAL_VOLUME (user_data);
|
||||
storage_logical_volume_update (logical_volume);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_logical_volume_constructed (GObject *object)
|
||||
{
|
||||
StorageLogicalVolume *logical_volume = STORAGE_LOGICAL_VOLUME(object);
|
||||
|
||||
logical_volume->udisks_logical_volume = g_object_ref (storage_object_get_udisks_logical_volume (logical_volume->object));
|
||||
g_signal_connect (logical_volume->udisks_logical_volume,
|
||||
"notify",
|
||||
G_CALLBACK (on_udisks_logical_volume_notify),
|
||||
logical_volume);
|
||||
|
||||
storage_logical_volume_update (logical_volume);
|
||||
|
||||
if (G_OBJECT_CLASS (storage_logical_volume_parent_class)->constructed != NULL)
|
||||
G_OBJECT_CLASS (storage_logical_volume_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_logical_volume_init (StorageLogicalVolume *logical_volume)
|
||||
{
|
||||
g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (logical_volume),
|
||||
G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_logical_volume_class_init (StorageLogicalVolumeClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = storage_logical_volume_finalize;
|
||||
gobject_class->constructed = storage_logical_volume_constructed;
|
||||
gobject_class->set_property = storage_logical_volume_set_property;
|
||||
gobject_class->get_property = storage_logical_volume_get_property;
|
||||
|
||||
/**
|
||||
* StorageLogicalVolume:object:
|
||||
*
|
||||
* The #CockpitStorageObject for the object.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_OBJECT,
|
||||
g_param_spec_object ("object",
|
||||
NULL,
|
||||
NULL,
|
||||
TYPE_STORAGE_OBJECT,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
/**
|
||||
* storage_logical_volume_new:
|
||||
* @object: A #CockpitStorageObject
|
||||
*
|
||||
* Creates a new #StorageLogicalVolume instance.
|
||||
*
|
||||
* Returns: A new #StorageLogicalVolume. Free with g_object_unref().
|
||||
*/
|
||||
CockpitStorageLogicalVolume *
|
||||
storage_logical_volume_new (StorageObject *object)
|
||||
{
|
||||
g_return_val_if_fail (IS_STORAGE_OBJECT (object), NULL);
|
||||
return COCKPIT_STORAGE_LOGICAL_VOLUME (g_object_new (TYPE_STORAGE_LOGICAL_VOLUME,
|
||||
"object", object,
|
||||
NULL));
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
null_asv (void)
|
||||
{
|
||||
GVariantBuilder options;
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE("a{sv}"));
|
||||
return g_variant_builder_end (&options);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_delete (CockpitStorageLogicalVolume *object,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
StorageLogicalVolume *volume = STORAGE_LOGICAL_VOLUME(object);
|
||||
StorageProvider *provider = storage_object_get_provider (volume->object);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
if (!storage_cleanup_logical_volume (provider,
|
||||
volume->udisks_logical_volume,
|
||||
&error)
|
||||
|| !udisks_logical_volume_call_delete_sync (volume->udisks_logical_volume,
|
||||
null_asv (),
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
cockpit_storage_logical_volume_complete_delete (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_rename (CockpitStorageLogicalVolume *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_new_name)
|
||||
{
|
||||
StorageLogicalVolume *volume = STORAGE_LOGICAL_VOLUME(object);
|
||||
GError *error = NULL;
|
||||
gs_free gchar *result = NULL;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
if (!udisks_logical_volume_call_rename_sync (volume->udisks_logical_volume,
|
||||
arg_new_name,
|
||||
null_asv (),
|
||||
&result,
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
cockpit_storage_logical_volume_complete_rename (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_resize (CockpitStorageLogicalVolume *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
guint64 arg_new_size,
|
||||
int arg_stripes,
|
||||
guint64 arg_stripesize)
|
||||
{
|
||||
StorageLogicalVolume *volume = STORAGE_LOGICAL_VOLUME(object);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
if (!udisks_logical_volume_call_resize_sync (volume->udisks_logical_volume,
|
||||
arg_new_size,
|
||||
arg_stripes,
|
||||
arg_stripesize,
|
||||
null_asv (),
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
cockpit_storage_logical_volume_complete_resize (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_activate (CockpitStorageLogicalVolume *object,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
StorageLogicalVolume *volume = STORAGE_LOGICAL_VOLUME(object);
|
||||
GError *error = NULL;
|
||||
gs_free gchar *result = NULL;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
if (!udisks_logical_volume_call_activate_sync (volume->udisks_logical_volume,
|
||||
null_asv (),
|
||||
&result,
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
cockpit_storage_logical_volume_complete_activate (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_deactivate (CockpitStorageLogicalVolume *object,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
StorageLogicalVolume *volume = STORAGE_LOGICAL_VOLUME(object);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
if (!udisks_logical_volume_call_deactivate_sync (volume->udisks_logical_volume,
|
||||
null_asv (),
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
cockpit_storage_logical_volume_complete_deactivate (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_create_snapshot (CockpitStorageLogicalVolume *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_name,
|
||||
guint64 arg_size)
|
||||
{
|
||||
StorageLogicalVolume *volume = STORAGE_LOGICAL_VOLUME(object);
|
||||
GError *error = NULL;
|
||||
gs_free gchar *result = NULL;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
if (!udisks_logical_volume_call_create_snapshot_sync (volume->udisks_logical_volume,
|
||||
arg_name,
|
||||
arg_size,
|
||||
null_asv (),
|
||||
&result,
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
cockpit_storage_logical_volume_complete_create_snapshot (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
storage_logical_volume_iface_init (CockpitStorageLogicalVolumeIface *iface)
|
||||
{
|
||||
iface->handle_delete = handle_delete;
|
||||
iface->handle_rename = handle_rename;
|
||||
iface->handle_resize = handle_resize;
|
||||
iface->handle_activate = handle_activate;
|
||||
iface->handle_deactivate = handle_deactivate;
|
||||
iface->handle_create_snapshot = handle_create_snapshot;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __STORAGE_LOGICAL_VOLUME_H__
|
||||
#define __STORAGE_LOGICAL_VOLUME_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_STORAGE_LOGICAL_VOLUME (storage_logical_volume_get_type ())
|
||||
#define STORAGE_LOGICAL_VOLUME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_STORAGE_LOGICAL_VOLUME, StorageLogicalVolume))
|
||||
#define IS_STORAGE_LOGICAL_VOLUME(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_STORAGE_LOGICAL_VOLUME))
|
||||
|
||||
GType storage_logical_volume_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CockpitStorageLogicalVolume * storage_logical_volume_new (StorageObject *object);
|
||||
|
||||
void storage_logical_volume_update (StorageLogicalVolume *logical_volume);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __STORAGE_LOGICAL_VOLUME_H__ */
|
|
@ -0,0 +1,902 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libgsystem.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include "daemon.h"
|
||||
#include "auth.h"
|
||||
#include "storagemanager.h"
|
||||
#include "storageprovider.h"
|
||||
#include "storageobject.h"
|
||||
|
||||
#include <cockpit/cockpit.h>
|
||||
|
||||
typedef struct _StorageManagerClass StorageManagerClass;
|
||||
|
||||
struct _StorageManager
|
||||
{
|
||||
CockpitStorageManagerSkeleton parent_instance;
|
||||
Daemon *daemon;
|
||||
|
||||
UDisksClient *udisks;
|
||||
};
|
||||
|
||||
struct _StorageManagerClass
|
||||
{
|
||||
CockpitStorageManagerSkeletonClass parent_class;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DAEMON,
|
||||
};
|
||||
|
||||
static void storage_manager_iface_init (CockpitStorageManagerIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (StorageManager, storage_manager, COCKPIT_TYPE_STORAGE_MANAGER_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (COCKPIT_TYPE_STORAGE_MANAGER, storage_manager_iface_init));
|
||||
|
||||
static void
|
||||
storage_manager_finalize (GObject *object)
|
||||
{
|
||||
StorageManager *storage_manager = STORAGE_MANAGER (object);
|
||||
|
||||
g_clear_object (&storage_manager->udisks);
|
||||
|
||||
if (G_OBJECT_CLASS (storage_manager_parent_class)->finalize != NULL)
|
||||
G_OBJECT_CLASS (storage_manager_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_manager_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StorageManager *storage_manager = STORAGE_MANAGER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DAEMON:
|
||||
g_value_set_object (value, storage_manager_get_daemon (storage_manager));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
storage_manager_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StorageManager *storage_manager = STORAGE_MANAGER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DAEMON:
|
||||
g_assert (storage_manager->daemon == NULL);
|
||||
storage_manager->daemon = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
storage_manager_init (StorageManager *storage_manager)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
storage_manager_constructed (GObject *_object)
|
||||
{
|
||||
StorageManager *storage_manager = STORAGE_MANAGER (_object);
|
||||
GError *error = NULL;
|
||||
|
||||
storage_manager->udisks = udisks_client_new_sync (NULL, &error);
|
||||
if (storage_manager->udisks == NULL)
|
||||
{
|
||||
g_warning ("Error connecting to udisks: %s (%s, %d)",
|
||||
error->message, g_quark_to_string (error->domain), error->code);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
if (G_OBJECT_CLASS (storage_manager_parent_class)->constructed != NULL)
|
||||
G_OBJECT_CLASS (storage_manager_parent_class)->constructed (_object);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_manager_class_init (StorageManagerClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = storage_manager_finalize;
|
||||
gobject_class->constructed = storage_manager_constructed;
|
||||
gobject_class->set_property = storage_manager_set_property;
|
||||
gobject_class->get_property = storage_manager_get_property;
|
||||
|
||||
/**
|
||||
* StorageManager:daemon:
|
||||
*
|
||||
* The #Daemon to use.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_DAEMON,
|
||||
g_param_spec_object ("daemon",
|
||||
"Daemon",
|
||||
"The Daemon to use",
|
||||
TYPE_DAEMON,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
/**
|
||||
* storage_manager_new:
|
||||
* @daemon: A #Daemon.
|
||||
*
|
||||
* Create a new #StorageManager instance.
|
||||
*
|
||||
* Returns: A #StorageManager object. Free with g_object_unref().
|
||||
*/
|
||||
CockpitStorageManager *
|
||||
storage_manager_new (Daemon *daemon)
|
||||
{
|
||||
g_return_val_if_fail (IS_DAEMON (daemon), NULL);
|
||||
return COCKPIT_STORAGE_MANAGER (g_object_new (TYPE_STORAGE_MANAGER,
|
||||
"daemon", daemon,
|
||||
NULL));
|
||||
}
|
||||
|
||||
Daemon *
|
||||
storage_manager_get_daemon (StorageManager *storage_manager)
|
||||
{
|
||||
g_return_val_if_fail (IS_STORAGE_MANAGER (storage_manager), NULL);
|
||||
return storage_manager->daemon;
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
null_asv (void)
|
||||
{
|
||||
GVariantBuilder options;
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE("a{sv}"));
|
||||
return g_variant_builder_end (&options);
|
||||
}
|
||||
|
||||
/* MDRAID_CREATE */
|
||||
|
||||
static gboolean
|
||||
handle_mdraid_create (CockpitStorageManager *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *const *arg_blocks,
|
||||
const gchar *arg_level,
|
||||
const gchar *arg_name,
|
||||
guint64 arg_chunk)
|
||||
{
|
||||
StorageManager *storage_manager = STORAGE_MANAGER(object);
|
||||
GDBusObjectManagerServer *object_manager_server = daemon_get_object_manager (storage_manager->daemon);
|
||||
GDBusObjectManager *object_manager = G_DBUS_OBJECT_MANAGER (object_manager_server);
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
GError *error = NULL;
|
||||
|
||||
int n_blocks = 0;
|
||||
for (int i = 0; arg_blocks[i]; i++)
|
||||
n_blocks += 1;
|
||||
|
||||
const gchar *udisks_blocks[n_blocks + 1];
|
||||
|
||||
for (int i = 0; arg_blocks[i]; i++)
|
||||
{
|
||||
StorageObject *stobj =
|
||||
STORAGE_OBJECT (g_dbus_object_manager_get_object (object_manager, arg_blocks[i]));
|
||||
UDisksBlock *block = storage_object_get_udisks_block (stobj);
|
||||
if (block)
|
||||
udisks_blocks[i] = g_dbus_proxy_get_object_path (G_DBUS_PROXY(block));
|
||||
else
|
||||
udisks_blocks[i] = "XXX";
|
||||
}
|
||||
|
||||
udisks_blocks[n_blocks] = NULL;
|
||||
|
||||
UDisksManager *manager = udisks_client_get_manager (storage_manager->udisks);
|
||||
if (manager == NULL)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"UDisks daemon is not running");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GVariantBuilder options;
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE("a{sv}"));
|
||||
|
||||
if (!udisks_manager_call_mdraid_create_sync (manager,
|
||||
udisks_blocks,
|
||||
arg_level,
|
||||
arg_name,
|
||||
arg_chunk,
|
||||
null_asv (),
|
||||
NULL,
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cockpit_storage_manager_complete_mdraid_create (object, invocation);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_volume_group_create (CockpitStorageManager *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *const *arg_blocks,
|
||||
const gchar *arg_name,
|
||||
guint64 arg_extent_size)
|
||||
{
|
||||
StorageManager *storage_manager = STORAGE_MANAGER(object);
|
||||
GDBusObjectManagerServer *object_manager_server = daemon_get_object_manager (storage_manager->daemon);
|
||||
GDBusObjectManager *object_manager = G_DBUS_OBJECT_MANAGER (object_manager_server);
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
GError *error = NULL;
|
||||
|
||||
int n_blocks = 0;
|
||||
for (int i = 0; arg_blocks[i]; i++)
|
||||
n_blocks += 1;
|
||||
|
||||
const gchar *udisks_blocks[n_blocks + 1];
|
||||
|
||||
for (int i = 0; arg_blocks[i]; i++)
|
||||
{
|
||||
StorageObject *stobj =
|
||||
STORAGE_OBJECT (g_dbus_object_manager_get_object (object_manager, arg_blocks[i]));
|
||||
UDisksBlock *block = storage_object_get_udisks_block (stobj);
|
||||
if (block)
|
||||
udisks_blocks[i] = g_dbus_proxy_get_object_path (G_DBUS_PROXY(block));
|
||||
else
|
||||
udisks_blocks[i] = "XXX";
|
||||
}
|
||||
|
||||
udisks_blocks[n_blocks] = NULL;
|
||||
|
||||
UDisksManager *manager = udisks_client_get_manager (storage_manager->udisks);
|
||||
if (manager == NULL)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"UDisks daemon is not running");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!udisks_manager_call_volume_group_create_sync (manager,
|
||||
udisks_blocks,
|
||||
arg_name,
|
||||
arg_extent_size,
|
||||
null_asv (),
|
||||
NULL,
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cockpit_storage_manager_complete_volume_group_create (object, invocation);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* INTERFACE */
|
||||
|
||||
static void
|
||||
storage_manager_iface_init (CockpitStorageManagerIface *iface)
|
||||
{
|
||||
iface->handle_mdraid_create = handle_mdraid_create;
|
||||
iface->handle_volume_group_create = handle_volume_group_create;
|
||||
}
|
||||
|
||||
/* Utiltities */
|
||||
|
||||
static void
|
||||
storage_remove_config (StorageProvider *provider,
|
||||
UDisksBlock *block,
|
||||
GVariant *config)
|
||||
{
|
||||
GVariantIter iter;
|
||||
GVariant *item;
|
||||
GError *error = NULL;
|
||||
gs_unref_object UDisksBlock *block_to_use = NULL;
|
||||
|
||||
if (block == NULL)
|
||||
{
|
||||
/* Any block can be used to add/remove any configuration item.
|
||||
Let's hope we have at least one...
|
||||
|
||||
XXX - UDisks should offer a method for manipulating fstab and
|
||||
crypttab on the Manager.
|
||||
*/
|
||||
|
||||
UDisksClient *client = storage_provider_get_udisks_client (provider);
|
||||
GDBusObjectManager *manager = udisks_client_get_object_manager (client);
|
||||
GList *objects = g_dbus_object_manager_get_objects (manager);
|
||||
for (GList *l = objects; l; l = l->next)
|
||||
{
|
||||
UDisksObject *object = l->data;
|
||||
block_to_use = udisks_object_get_block (object);
|
||||
if (block_to_use)
|
||||
break;
|
||||
}
|
||||
g_list_free_full (objects, g_object_unref);
|
||||
|
||||
if (block_to_use == NULL)
|
||||
{
|
||||
g_warning ("Can't remove config: no block object found.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
block_to_use = g_object_ref (block);
|
||||
|
||||
g_variant_iter_init (&iter, config);
|
||||
while ((item = g_variant_iter_next_value (&iter)) != NULL)
|
||||
{
|
||||
if (!udisks_block_call_remove_configuration_item_sync (block_to_use,
|
||||
item,
|
||||
g_variant_new ("a{sv}", NULL),
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
gs_free gchar *config_text = g_variant_print (config, FALSE);
|
||||
g_warning ("Can't remove storage configuration '%s': %s",
|
||||
config_text, error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
storage_remove_fstab_config (UDisksBlock *block,
|
||||
GError **error)
|
||||
{
|
||||
GVariant *conf = udisks_block_get_configuration (block);
|
||||
GVariantIter iter;
|
||||
GVariant *item;
|
||||
g_variant_iter_init (&iter, conf);
|
||||
while ((item = g_variant_iter_next_value (&iter)))
|
||||
{
|
||||
const gchar *type;
|
||||
g_variant_get (item, "(&s*)", &type, NULL);
|
||||
if (strcmp (type, "fstab") == 0)
|
||||
{
|
||||
if (!udisks_block_call_remove_configuration_item_sync (block,
|
||||
item,
|
||||
g_variant_new ("a{sv}", NULL),
|
||||
NULL,
|
||||
error))
|
||||
{
|
||||
g_variant_unref (item);
|
||||
return FALSE;
|
||||
}
|
||||
g_variant_unref (item);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
storage_remove_crypto_config (UDisksBlock *block,
|
||||
GError **error)
|
||||
{
|
||||
GVariant *conf = udisks_block_get_configuration (block);
|
||||
GVariantIter iter;
|
||||
GVariant *item;
|
||||
g_variant_iter_init (&iter, conf);
|
||||
while ((item = g_variant_iter_next_value (&iter)))
|
||||
{
|
||||
const gchar *type;
|
||||
g_variant_get (item, "(&s*)", &type, NULL);
|
||||
if (strcmp (type, "crypttab") == 0)
|
||||
{
|
||||
if (!udisks_block_call_remove_configuration_item_sync (block,
|
||||
item,
|
||||
g_variant_new ("a{sv}", NULL),
|
||||
NULL,
|
||||
error))
|
||||
{
|
||||
g_variant_unref (item);
|
||||
return FALSE;
|
||||
}
|
||||
g_variant_unref (item);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef gboolean BlockWalker (UDisksClient *client,
|
||||
UDisksBlock *block,
|
||||
gboolean is_leaf,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
|
||||
static gboolean
|
||||
walk_block (UDisksClient *client,
|
||||
UDisksBlock *block,
|
||||
BlockWalker *walker,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
gboolean is_leaf = TRUE;
|
||||
|
||||
UDisksObject *object = (UDisksObject *)g_dbus_interface_get_object (G_DBUS_INTERFACE(block));
|
||||
if (object != NULL)
|
||||
{
|
||||
// Recurse for all primary and extended partitions if this is a
|
||||
// partition table, or for all logical partitions if this is a
|
||||
// extended partition.
|
||||
|
||||
UDisksPartitionTable *table;
|
||||
gboolean is_container;
|
||||
|
||||
UDisksPartition *partition = udisks_object_peek_partition (object);
|
||||
if (partition && udisks_partition_get_is_container (partition))
|
||||
{
|
||||
table = udisks_client_get_partition_table (client, partition);
|
||||
is_container = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
table = udisks_object_peek_partition_table (object);
|
||||
is_container = FALSE;
|
||||
}
|
||||
|
||||
if (table)
|
||||
{
|
||||
GList *ps, *l;
|
||||
ps = udisks_client_get_partitions (client, table);
|
||||
for (l = ps; l != NULL; l = l->next)
|
||||
{
|
||||
UDisksPartition *p = UDISKS_PARTITION (l->data);
|
||||
UDisksObject *o = (UDisksObject *) g_dbus_interface_get_object (G_DBUS_INTERFACE (p));
|
||||
UDisksBlock *b = o ? udisks_object_peek_block (o) : NULL;
|
||||
if (b && !is_container == !udisks_partition_get_is_contained (p))
|
||||
{
|
||||
is_leaf = FALSE;
|
||||
if (!walk_block (client, b, walker, user_data, error))
|
||||
{
|
||||
g_list_free_full (ps, g_object_unref);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
g_list_free_full (ps, g_object_unref);
|
||||
}
|
||||
}
|
||||
|
||||
gs_unref_object UDisksBlock *cleartext = udisks_client_get_cleartext_block (client, block);
|
||||
if (cleartext)
|
||||
{
|
||||
is_leaf = FALSE;
|
||||
if (!walk_block (client, cleartext, walker, user_data, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return walker (client, block, is_leaf, user_data, error);
|
||||
}
|
||||
|
||||
typedef gboolean LogicalVolumeWalker (UDisksClient *client,
|
||||
UDisksLogicalVolume *logical_volume,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
|
||||
static gboolean
|
||||
walk_logical_volume (UDisksClient *client,
|
||||
UDisksLogicalVolume *vol,
|
||||
LogicalVolumeWalker *walker,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
if (!walker (client, vol, user_data, error))
|
||||
return FALSE;
|
||||
|
||||
const gchar *vol_objpath = g_dbus_object_get_object_path (g_dbus_interface_get_object (G_DBUS_INTERFACE (vol)));
|
||||
UDisksVolumeGroup *group = udisks_client_get_volume_group_for_logical_volume (client, vol);
|
||||
GList *siblings = group ? udisks_client_get_logical_volumes_for_volume_group (client, group) : NULL;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
for (GList *l = siblings; l; l = l->next)
|
||||
{
|
||||
UDisksLogicalVolume *s = l->data;
|
||||
|
||||
if ((g_strcmp0 (udisks_logical_volume_get_type_ (s), "snapshot") == 0
|
||||
&& g_strcmp0 (udisks_logical_volume_get_origin (s), vol_objpath) == 0)
|
||||
|| (g_strcmp0 (udisks_logical_volume_get_type_ (s), "thin") == 0
|
||||
&& g_strcmp0 (udisks_logical_volume_get_thin_pool (s), vol_objpath) == 0))
|
||||
{
|
||||
if (!walk_logical_volume (client, s, walker, user_data, error))
|
||||
{
|
||||
ret = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free_full (siblings, g_object_unref);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
walk_volume_group (UDisksClient *client,
|
||||
UDisksVolumeGroup *group,
|
||||
LogicalVolumeWalker *walker,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
GList *lvs = group ? udisks_client_get_logical_volumes_for_volume_group (client, group) : NULL;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
for (GList *l = lvs; l; l = l->next)
|
||||
{
|
||||
UDisksLogicalVolume *s = l->data;
|
||||
|
||||
if (!walker (client, s, user_data, error))
|
||||
{
|
||||
ret = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free_full (lvs, g_object_unref);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cleanup_block_walker (UDisksClient *client,
|
||||
UDisksBlock *block,
|
||||
gboolean is_leaf,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
StorageProvider *provider = user_data;
|
||||
UDisksObject *object = UDISKS_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (block)));
|
||||
UDisksEncrypted *enc = udisks_object_peek_encrypted (object);
|
||||
|
||||
if (enc)
|
||||
{
|
||||
UDisksBlock *cleartext = udisks_client_get_cleartext_block (client, block);
|
||||
if (cleartext)
|
||||
{
|
||||
/* The crypto backing device is unlocked and the cleartext
|
||||
device has been cleaned up. Lock the backing device so
|
||||
that we can format or wipe it later.
|
||||
*/
|
||||
if (enc && !udisks_encrypted_call_lock_sync (enc,
|
||||
g_variant_new ("a{sv}", NULL),
|
||||
NULL,
|
||||
error))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The crypto backing device is locked and the cleartext
|
||||
device has not been cleaned up (since it doesn't exist).
|
||||
Remove its remembered configs.
|
||||
*/
|
||||
GList *remembered_configs = storage_provider_get_and_forget_remembered_configs
|
||||
(provider, g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
|
||||
for (GList *l = remembered_configs; l; l = l->next)
|
||||
{
|
||||
GVariant *config = l->data;
|
||||
storage_remove_config (provider, block, config);
|
||||
}
|
||||
g_list_free_full (remembered_configs, (GDestroyNotify)g_variant_unref);
|
||||
}
|
||||
}
|
||||
|
||||
storage_remove_config (provider, block, udisks_block_get_configuration (block));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cleanup_block (StorageProvider *provider,
|
||||
UDisksBlock *block,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = walk_block (storage_provider_get_udisks_client (provider),
|
||||
block, cleanup_block_walker, provider, error);
|
||||
storage_provider_save_remembered_configs (provider);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cleanup_logical_volume_walker (UDisksClient *client,
|
||||
UDisksLogicalVolume *logical_volume,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
StorageProvider *provider = user_data;
|
||||
UDisksBlock *block = udisks_client_get_block_for_logical_volume (client, logical_volume);
|
||||
if (block)
|
||||
{
|
||||
/* The logical volume is active, let's clean it up by walking
|
||||
the tree of block devices hanging off of it.
|
||||
*/
|
||||
return cleanup_block (provider, block, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The logical volume is inactive, let's clean it up by removing
|
||||
the remembered configs from its children.
|
||||
*/
|
||||
UDisksObject *object = UDISKS_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (logical_volume)));
|
||||
GList *remembered_configs = storage_provider_get_and_forget_remembered_configs
|
||||
(provider, g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
|
||||
for (GList *l = remembered_configs; l; l = l->next)
|
||||
{
|
||||
GVariant *config = l->data;
|
||||
storage_remove_config (provider, NULL, config);
|
||||
}
|
||||
g_list_free_full (remembered_configs, (GDestroyNotify)g_variant_unref);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cleanup_logical_volume (StorageProvider *provider,
|
||||
UDisksLogicalVolume *logical_volume,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = walk_logical_volume (storage_provider_get_udisks_client (provider), logical_volume,
|
||||
cleanup_logical_volume_walker, provider, error);
|
||||
storage_provider_save_remembered_configs (provider);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cleanup_volume_group (StorageProvider *provider,
|
||||
UDisksVolumeGroup *group,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = walk_volume_group (storage_provider_get_udisks_client (provider), group,
|
||||
cleanup_logical_volume_walker, provider, error);
|
||||
storage_provider_save_remembered_configs (provider);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
block_is_unused_walker (UDisksClient *client,
|
||||
UDisksBlock *block,
|
||||
gboolean is_leaf,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
const gchar *device_file;
|
||||
int fd;
|
||||
|
||||
if (is_leaf)
|
||||
{
|
||||
device_file = udisks_block_get_device (block);
|
||||
fd = open (device_file, O_RDONLY | O_EXCL);
|
||||
if (fd < 0)
|
||||
{
|
||||
g_set_error (error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
|
||||
"Error opening device %s: %m",
|
||||
device_file);
|
||||
return FALSE;
|
||||
}
|
||||
close (fd);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
block_is_unused (UDisksClient *client,
|
||||
UDisksBlock *block,
|
||||
GError **error)
|
||||
{
|
||||
return walk_block (client, block, block_is_unused_walker, NULL, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
logical_volume_is_unused_walker (UDisksClient *client,
|
||||
UDisksLogicalVolume *logical_volume,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
UDisksBlock *block = udisks_client_get_block_for_logical_volume (client, logical_volume);
|
||||
if (block)
|
||||
return block_is_unused (client, block, error);
|
||||
else
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
logical_volume_is_unused (UDisksClient *client,
|
||||
UDisksLogicalVolume *vol,
|
||||
GError **error)
|
||||
{
|
||||
return walk_logical_volume (client, vol, logical_volume_is_unused_walker, NULL, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
volume_group_is_unused (UDisksClient *client,
|
||||
UDisksVolumeGroup *group,
|
||||
GError **error)
|
||||
{
|
||||
return walk_volume_group (client, group, logical_volume_is_unused_walker, NULL, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
reload_systemd (GError **error)
|
||||
{
|
||||
// XXX - do it.
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
storage_cleanup_block (StorageProvider *provider,
|
||||
UDisksBlock *block,
|
||||
GError **error)
|
||||
{
|
||||
return (block_is_unused (storage_provider_get_udisks_client (provider), block, error)
|
||||
&& cleanup_block (provider, block, error)
|
||||
&& reload_systemd (error));
|
||||
}
|
||||
|
||||
gboolean
|
||||
storage_cleanup_logical_volume (StorageProvider *provider,
|
||||
UDisksLogicalVolume *volume,
|
||||
GError **error)
|
||||
{
|
||||
return (logical_volume_is_unused (storage_provider_get_udisks_client (provider), volume, error)
|
||||
&& cleanup_logical_volume (provider, volume, error)
|
||||
&& reload_systemd (error));
|
||||
}
|
||||
|
||||
gboolean
|
||||
storage_cleanup_volume_group (StorageProvider *provider,
|
||||
UDisksVolumeGroup *group,
|
||||
GError **error)
|
||||
{
|
||||
return (volume_group_is_unused (storage_provider_get_udisks_client (provider), group, error)
|
||||
&& cleanup_volume_group (provider, group, error)
|
||||
&& reload_systemd (error));
|
||||
}
|
||||
|
||||
typedef gboolean ObjectWalker (UDisksClient *client,
|
||||
UDisksObject *object,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
|
||||
static gboolean
|
||||
walk_block_parents (UDisksClient *client,
|
||||
UDisksBlock *block,
|
||||
ObjectWalker *walker,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
/* Parents are
|
||||
- of a block that is a logical volume, the logical volume object
|
||||
- of a clear text device, the encrypted device.
|
||||
|
||||
XXX - support the whole tree.
|
||||
*/
|
||||
|
||||
while (block)
|
||||
{
|
||||
const gchar *logical_volume_path = udisks_block_get_logical_volume (block);
|
||||
const gchar *crypto_path = udisks_block_get_crypto_backing_device (block);
|
||||
|
||||
if (g_strcmp0 (logical_volume_path, "/") != 0)
|
||||
{
|
||||
UDisksObject *logical_volume_object = udisks_client_get_object (client, logical_volume_path);
|
||||
if (logical_volume_object)
|
||||
{
|
||||
if (!walker (client, logical_volume_object, user_data, error))
|
||||
return FALSE;
|
||||
}
|
||||
block = NULL;
|
||||
}
|
||||
else if (g_strcmp0 (crypto_path, "/") != 0)
|
||||
{
|
||||
UDisksObject *crypto_object = udisks_client_get_object (client, crypto_path);
|
||||
if (crypto_object)
|
||||
{
|
||||
if (!walker (client, crypto_object, user_data, error))
|
||||
return FALSE;
|
||||
}
|
||||
block = udisks_object_peek_block (crypto_object);
|
||||
}
|
||||
else
|
||||
block = NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
struct RememberData {
|
||||
StorageProvider *provider;
|
||||
const gchar *child_path;
|
||||
GVariant *config;
|
||||
};
|
||||
|
||||
static gboolean
|
||||
remember_configs (UDisksClient *client,
|
||||
UDisksObject *object,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
struct RememberData *data = user_data;
|
||||
const gchar *parent_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
|
||||
storage_provider_remember_config (data->provider, parent_path, data->child_path, data->config);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
storage_remember_block_configs (StorageProvider *provider,
|
||||
UDisksBlock *block)
|
||||
{
|
||||
GVariant *config = udisks_block_get_configuration (block);
|
||||
if (g_variant_n_children (config) > 0)
|
||||
{
|
||||
UDisksClient *client = storage_provider_get_udisks_client (provider);
|
||||
GDBusObject *object = g_dbus_interface_get_object (G_DBUS_INTERFACE (block));
|
||||
struct RememberData data;
|
||||
data.provider = provider;
|
||||
data.child_path = g_dbus_object_get_object_path (object);
|
||||
data.config = config;
|
||||
walk_block_parents (client, block, remember_configs, &data, NULL);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __STORAGE_MANAGER_H__
|
||||
#define __STORAGE_MANAGER_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_STORAGE_MANAGER (storage_manager_get_type ())
|
||||
#define STORAGE_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_STORAGE_MANAGER, StorageManager))
|
||||
#define IS_STORAGE_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_STORAGE_MANAGER))
|
||||
|
||||
GType storage_manager_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CockpitStorageManager * storage_manager_new (Daemon *daemon);
|
||||
|
||||
Daemon * storage_manager_get_daemon (StorageManager *storage_manager);
|
||||
|
||||
// Utility functions
|
||||
|
||||
/* These clean up block device etc before they are used for something
|
||||
else. Specifically:
|
||||
|
||||
- Any entries in fstab and crpyttab that refer to it are removed.
|
||||
|
||||
- If this device contains a partition table, then all contained
|
||||
partitions are cleaned up as well.
|
||||
|
||||
- If this device is encrypted, then the corresponding cleartext
|
||||
device is cleaned up, and this device is locked so that it is no
|
||||
longer in use.
|
||||
|
||||
- Snapshots of logical volumes are cleaned up.
|
||||
|
||||
- Thin volumes belonging to a thin pool are cleaned up.
|
||||
|
||||
- Logical volumes of a volume group are cleaned up.
|
||||
|
||||
- Systemd is reloaded so that it re-syncs itself with the modified
|
||||
fstab and crypttab.
|
||||
|
||||
The functions also check whether any of the block devices etc that
|
||||
are to be cleaned are in active use before making any changes.
|
||||
*/
|
||||
|
||||
gboolean storage_remove_fstab_config (UDisksBlock *block,
|
||||
GError **error);
|
||||
|
||||
gboolean storage_remove_crypto_config (UDisksBlock *block,
|
||||
GError **error);
|
||||
|
||||
gboolean storage_cleanup_block (StorageProvider *provider,
|
||||
UDisksBlock *block,
|
||||
GError **error);
|
||||
|
||||
gboolean storage_cleanup_logical_volume (StorageProvider *provider,
|
||||
UDisksLogicalVolume *volume,
|
||||
GError **error);
|
||||
|
||||
gboolean storage_cleanup_volume_group (StorageProvider *provider,
|
||||
UDisksVolumeGroup *group,
|
||||
GError **error);
|
||||
|
||||
void storage_remember_block_configs (StorageProvider *provider,
|
||||
UDisksBlock *block);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __STORAGE_MANAGER_H__ */
|
|
@ -0,0 +1,588 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "auth.h"
|
||||
#include "storageprovider.h"
|
||||
#include "storageobject.h"
|
||||
#include "storagemdraid.h"
|
||||
|
||||
#include "libgsystem.h"
|
||||
|
||||
/**
|
||||
* SECTION:storagemdraid
|
||||
* @title: Mdraid devices
|
||||
* @short_description: Implementation of #CockpitStorageMDRaid
|
||||
*
|
||||
* Instances of the #CockpitStorageMDRaid type are mdraid devices.
|
||||
*/
|
||||
|
||||
typedef struct _StorageMDRaidClass StorageMDRaidClass;
|
||||
|
||||
/**
|
||||
* <private>
|
||||
* StorageMDRaid:
|
||||
*
|
||||
* Private.
|
||||
*/
|
||||
struct _StorageMDRaid
|
||||
{
|
||||
CockpitStorageMDRaidSkeleton parent_instance;
|
||||
|
||||
UDisksMDRaid *udisks_mdraid;
|
||||
|
||||
StorageObject *object;
|
||||
};
|
||||
|
||||
struct _StorageMDRaidClass
|
||||
{
|
||||
CockpitStorageMDRaidSkeletonClass parent_class;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_OBJECT
|
||||
};
|
||||
|
||||
static void storage_mdraid_iface_init (CockpitStorageMDRaidIface *iface);
|
||||
|
||||
static void on_udisks_mdraid_notify (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (StorageMDRaid, storage_mdraid, COCKPIT_TYPE_STORAGE_MDRAID_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (COCKPIT_TYPE_STORAGE_MDRAID, storage_mdraid_iface_init));
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
storage_mdraid_finalize (GObject *object)
|
||||
{
|
||||
StorageMDRaid *mdraid = STORAGE_MDRAID (object);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (mdraid->udisks_mdraid,
|
||||
G_CALLBACK (on_udisks_mdraid_notify),
|
||||
mdraid);
|
||||
g_object_unref (mdraid->udisks_mdraid);
|
||||
|
||||
G_OBJECT_CLASS (storage_mdraid_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_mdraid_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StorageMDRaid *mdraid = STORAGE_MDRAID (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_OBJECT:
|
||||
g_value_set_object (value, mdraid->object);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
storage_mdraid_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StorageMDRaid *mdraid = STORAGE_MDRAID (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_OBJECT:
|
||||
g_assert (mdraid->object == NULL);
|
||||
mdraid->object = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
storage_mdraid_update (StorageMDRaid *mdraid)
|
||||
{
|
||||
UDisksMDRaid *udisks_mdraid = mdraid->udisks_mdraid;
|
||||
CockpitStorageMDRaid *iface = COCKPIT_STORAGE_MDRAID (mdraid);
|
||||
StorageProvider *provider = storage_object_get_provider (mdraid->object);
|
||||
UDisksClient *udisks_client = storage_provider_get_udisks_client (provider);
|
||||
|
||||
cockpit_storage_mdraid_set_uuid (iface, udisks_mdraid_get_uuid (udisks_mdraid));
|
||||
cockpit_storage_mdraid_set_name (iface, udisks_mdraid_get_name (udisks_mdraid));
|
||||
cockpit_storage_mdraid_set_level (iface, udisks_mdraid_get_level (udisks_mdraid));
|
||||
cockpit_storage_mdraid_set_num_devices (iface, udisks_mdraid_get_num_devices (udisks_mdraid));
|
||||
cockpit_storage_mdraid_set_size (iface, udisks_mdraid_get_size (udisks_mdraid));
|
||||
cockpit_storage_mdraid_set_sync_action (iface, udisks_mdraid_get_sync_action (udisks_mdraid));
|
||||
cockpit_storage_mdraid_set_sync_completed (iface, udisks_mdraid_get_sync_completed (udisks_mdraid));
|
||||
cockpit_storage_mdraid_set_sync_rate (iface, udisks_mdraid_get_sync_rate (udisks_mdraid));
|
||||
cockpit_storage_mdraid_set_sync_remaining_time (iface, udisks_mdraid_get_sync_remaining_time (udisks_mdraid));
|
||||
cockpit_storage_mdraid_set_degraded (iface, udisks_mdraid_get_degraded (udisks_mdraid));
|
||||
{
|
||||
gs_free gchar *loc = g_locale_to_utf8 (udisks_mdraid_get_bitmap_location (udisks_mdraid),
|
||||
-1, NULL, NULL, NULL);
|
||||
cockpit_storage_mdraid_set_bitmap_location (iface, loc);
|
||||
}
|
||||
cockpit_storage_mdraid_set_chunk_size (iface, udisks_mdraid_get_chunk_size (udisks_mdraid));
|
||||
|
||||
GVariantBuilder devices;
|
||||
g_variant_builder_init (&devices, G_VARIANT_TYPE("a(oiast)"));
|
||||
|
||||
GVariantIter iter;
|
||||
gint disk_slot;
|
||||
const gchar *disk_block_objpath;
|
||||
gs_unref_variant GVariant *disk_states = NULL;
|
||||
guint64 disk_num_errors;
|
||||
g_variant_iter_init (&iter, udisks_mdraid_get_active_devices (udisks_mdraid));
|
||||
while (g_variant_iter_next (&iter, "(&oi@asta{sv})",
|
||||
&disk_block_objpath,
|
||||
&disk_slot,
|
||||
&disk_states,
|
||||
&disk_num_errors,
|
||||
NULL))
|
||||
{
|
||||
UDisksObject *udisks_object;
|
||||
UDisksBlock *udisks_block;
|
||||
StorageObject *object;
|
||||
|
||||
if ((udisks_object = udisks_client_peek_object (udisks_client, disk_block_objpath))
|
||||
&& (udisks_block = udisks_object_peek_block (udisks_object))
|
||||
&& (object = storage_provider_lookup_for_udisks_block (provider, udisks_block)))
|
||||
{
|
||||
g_variant_builder_add (&devices, "(oi@ast)",
|
||||
g_dbus_object_get_object_path (G_DBUS_OBJECT(object)),
|
||||
disk_slot,
|
||||
disk_states,
|
||||
disk_num_errors);
|
||||
}
|
||||
}
|
||||
cockpit_storage_mdraid_set_active_devices (iface, g_variant_builder_end (&devices));
|
||||
}
|
||||
|
||||
static void
|
||||
on_udisks_mdraid_notify (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
StorageMDRaid *mdraid = STORAGE_MDRAID (user_data);
|
||||
storage_mdraid_update (mdraid);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_mdraid_constructed (GObject *object)
|
||||
{
|
||||
StorageMDRaid *mdraid = STORAGE_MDRAID (object);
|
||||
|
||||
mdraid->udisks_mdraid = g_object_ref (storage_object_get_udisks_mdraid (mdraid->object));
|
||||
g_signal_connect (mdraid->udisks_mdraid,
|
||||
"notify",
|
||||
G_CALLBACK (on_udisks_mdraid_notify),
|
||||
mdraid);
|
||||
|
||||
storage_mdraid_update (mdraid);
|
||||
|
||||
if (G_OBJECT_CLASS (storage_mdraid_parent_class)->constructed != NULL)
|
||||
G_OBJECT_CLASS (storage_mdraid_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_mdraid_init (StorageMDRaid *mdraid)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
storage_mdraid_class_init (StorageMDRaidClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = storage_mdraid_finalize;
|
||||
gobject_class->constructed = storage_mdraid_constructed;
|
||||
gobject_class->set_property = storage_mdraid_set_property;
|
||||
gobject_class->get_property = storage_mdraid_get_property;
|
||||
|
||||
/**
|
||||
* StorageMDRaid:object:
|
||||
*
|
||||
* The #CockpitStorageObject for the object.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_OBJECT,
|
||||
g_param_spec_object ("object",
|
||||
NULL,
|
||||
NULL,
|
||||
TYPE_STORAGE_OBJECT,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
/**
|
||||
* storage_mdraid_new:
|
||||
* @object: A #CockpitStorageObject
|
||||
*
|
||||
* Creates a new #StorageMDRaid instance.
|
||||
*
|
||||
* Returns: A new #StorageMDRaid. Free with g_object_unref().
|
||||
*/
|
||||
CockpitStorageMDRaid *
|
||||
storage_mdraid_new (StorageObject *object)
|
||||
{
|
||||
g_return_val_if_fail (IS_STORAGE_OBJECT (object), NULL);
|
||||
return COCKPIT_STORAGE_MDRAID (g_object_new (TYPE_STORAGE_MDRAID,
|
||||
"object", object,
|
||||
NULL));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_start (CockpitStorageMDRaid *object,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
StorageMDRaid *mdraid = STORAGE_MDRAID(object);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
GVariantBuilder options;
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE("a{sv}"));
|
||||
g_variant_builder_add (&options, "{sv}", "start-degraded", g_variant_new_boolean (TRUE));
|
||||
|
||||
if (!udisks_mdraid_call_start_sync (mdraid->udisks_mdraid,
|
||||
g_variant_builder_end (&options),
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
cockpit_storage_mdraid_complete_start (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_stop (CockpitStorageMDRaid *object,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
StorageMDRaid *mdraid = STORAGE_MDRAID(object);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
GVariantBuilder options;
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE("a{sv}"));
|
||||
|
||||
if (!udisks_mdraid_call_stop_sync (mdraid->udisks_mdraid,
|
||||
g_variant_builder_end (&options),
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
cockpit_storage_mdraid_complete_stop (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_delete (CockpitStorageMDRaid *object,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
StorageMDRaid *mdraid = STORAGE_MDRAID(object);
|
||||
GList *members = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
/* Delete is Stop followed by wiping of all member devices.
|
||||
*/
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
GVariantBuilder options;
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE("a{sv}"));
|
||||
|
||||
if (!udisks_mdraid_call_stop_sync (mdraid->udisks_mdraid,
|
||||
g_variant_builder_end (&options),
|
||||
NULL,
|
||||
&error))
|
||||
goto out;
|
||||
|
||||
StorageProvider *provider = storage_object_get_provider (mdraid->object);
|
||||
UDisksClient *udisks_client = storage_provider_get_udisks_client (provider);
|
||||
members = udisks_client_get_members_for_mdraid (udisks_client,
|
||||
mdraid->udisks_mdraid);
|
||||
for (GList *m = members; m; m = m->next)
|
||||
{
|
||||
UDisksBlock *block = m->data;
|
||||
GVariantBuilder options;
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE("a{sv}"));
|
||||
udisks_block_call_format_sync (block,
|
||||
"empty",
|
||||
g_variant_builder_end (&options),
|
||||
NULL,
|
||||
error ? NULL : &error);
|
||||
}
|
||||
|
||||
out:
|
||||
if (error)
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
}
|
||||
else
|
||||
cockpit_storage_mdraid_complete_stop (object, invocation);
|
||||
|
||||
g_list_free_full (members, g_object_unref);
|
||||
g_clear_error (&error);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_request_sync_action (CockpitStorageMDRaid *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_sync_action)
|
||||
{
|
||||
StorageMDRaid *mdraid = STORAGE_MDRAID(object);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
GVariantBuilder options;
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE("a{sv}"));
|
||||
|
||||
if (!udisks_mdraid_call_request_sync_action_sync (mdraid->udisks_mdraid,
|
||||
arg_sync_action,
|
||||
g_variant_builder_end (&options),
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
cockpit_storage_mdraid_complete_request_sync_action (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gboolean
|
||||
handle_set_bitmap_location (CockpitStorageMDRaid *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_value)
|
||||
{
|
||||
StorageMDRaid *mdraid = STORAGE_MDRAID(object);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
GVariantBuilder options;
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE("a{sv}"));
|
||||
|
||||
if (!udisks_mdraid_call_set_bitmap_location_sync (mdraid->udisks_mdraid,
|
||||
arg_value,
|
||||
g_variant_builder_end (&options),
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
cockpit_storage_mdraid_complete_set_bitmap_location (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gboolean
|
||||
handle_remove_devices (CockpitStorageMDRaid *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *const *arg_devices)
|
||||
{
|
||||
StorageMDRaid *mdraid = STORAGE_MDRAID(object);
|
||||
StorageProvider *provider = storage_object_get_provider (mdraid->object);
|
||||
Daemon *daemon = storage_provider_get_daemon (provider);
|
||||
GDBusObjectManagerServer *object_manager_server = daemon_get_object_manager (daemon);
|
||||
GDBusObjectManager *object_manager = G_DBUS_OBJECT_MANAGER (object_manager_server);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
int n_devices = 0;
|
||||
for (int i = 0; arg_devices[i]; i++)
|
||||
n_devices += 1;
|
||||
|
||||
const gchar *udisks_devices[n_devices + 1];
|
||||
|
||||
for (int i = 0; arg_devices[i]; i++)
|
||||
{
|
||||
StorageObject *stobj =
|
||||
STORAGE_OBJECT(g_dbus_object_manager_get_object (object_manager, arg_devices[i]));
|
||||
UDisksBlock *block = storage_object_get_udisks_block (stobj);
|
||||
if (block)
|
||||
udisks_devices[i] = g_dbus_proxy_get_object_path (G_DBUS_PROXY(block));
|
||||
else
|
||||
udisks_devices[i] = "XXX";
|
||||
}
|
||||
udisks_devices[n_devices] = NULL;
|
||||
|
||||
for (int i = 0; udisks_devices[i]; i++)
|
||||
{
|
||||
GVariantBuilder options;
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE("a{sv}"));
|
||||
g_variant_builder_add (&options, "{sv}", "wipe", g_variant_new_boolean (TRUE));
|
||||
|
||||
if (!udisks_mdraid_call_remove_device_sync (mdraid->udisks_mdraid,
|
||||
udisks_devices[i],
|
||||
g_variant_builder_end (&options),
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
cockpit_storage_mdraid_complete_remove_devices (object, invocation);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gboolean
|
||||
handle_add_devices (CockpitStorageMDRaid *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar * const *arg_devices)
|
||||
{
|
||||
StorageMDRaid *mdraid = STORAGE_MDRAID(object);
|
||||
StorageProvider *provider = storage_object_get_provider (mdraid->object);
|
||||
Daemon *daemon = storage_provider_get_daemon (provider);
|
||||
GDBusObjectManagerServer *object_manager_server = daemon_get_object_manager (daemon);
|
||||
GDBusObjectManager *object_manager = G_DBUS_OBJECT_MANAGER (object_manager_server);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
int n_devices = 0;
|
||||
for (int i = 0; arg_devices[i]; i++)
|
||||
n_devices += 1;
|
||||
|
||||
const gchar *udisks_devices[n_devices + 1];
|
||||
|
||||
for (int i = 0; arg_devices[i]; i++)
|
||||
{
|
||||
StorageObject *stobj =
|
||||
STORAGE_OBJECT (g_dbus_object_manager_get_object (object_manager, arg_devices[i]));
|
||||
UDisksBlock *block = storage_object_get_udisks_block (stobj);
|
||||
if (block)
|
||||
udisks_devices[i] = g_dbus_proxy_get_object_path (G_DBUS_PROXY(block));
|
||||
else
|
||||
udisks_devices[i] = "XXX";
|
||||
}
|
||||
udisks_devices[n_devices] = NULL;
|
||||
|
||||
for (int i = 0; udisks_devices[i]; i++)
|
||||
{
|
||||
GVariantBuilder options;
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE("a{sv}"));
|
||||
|
||||
if (!udisks_mdraid_call_add_device_sync (mdraid->udisks_mdraid,
|
||||
udisks_devices[i],
|
||||
g_variant_builder_end (&options),
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
cockpit_storage_mdraid_complete_add_devices (object, invocation);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
storage_mdraid_iface_init (CockpitStorageMDRaidIface *iface)
|
||||
{
|
||||
iface->handle_start = handle_start;
|
||||
iface->handle_stop = handle_stop;
|
||||
iface->handle_delete = handle_delete;
|
||||
iface->handle_request_sync_action = handle_request_sync_action;
|
||||
iface->handle_set_bitmap_location = handle_set_bitmap_location;
|
||||
iface->handle_remove_devices = handle_remove_devices;
|
||||
iface->handle_add_devices = handle_add_devices;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __STORAGE_MDRAID_H__
|
||||
#define __STORAGE_MDRAID_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_STORAGE_MDRAID (storage_mdraid_get_type ())
|
||||
#define STORAGE_MDRAID(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_STORAGE_MDRAID, StorageMDRaid))
|
||||
#define IS_STORAGE_MDRAID(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_STORAGE_MDRAID))
|
||||
|
||||
GType storage_mdraid_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CockpitStorageMDRaid * storage_mdraid_new (StorageObject *object);
|
||||
|
||||
void storage_mdraid_update (StorageMDRaid *mdraid);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __STORAGE_MDRAID_H__ */
|
|
@ -0,0 +1,526 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "storagemanager.h"
|
||||
#include "storageprovider.h"
|
||||
#include "storageobject.h"
|
||||
#include "storageblock.h"
|
||||
#include "storagedrive.h"
|
||||
#include "storagemdraid.h"
|
||||
#include "storagevolumegroup.h"
|
||||
#include "storagelogicalvolume.h"
|
||||
#include "utils.h"
|
||||
|
||||
/**
|
||||
* SECTION:storageobject
|
||||
* @title: Storage object
|
||||
* @short_description: Object for storage interfaces
|
||||
*
|
||||
* Object for storage infaces.
|
||||
*/
|
||||
|
||||
typedef struct _StorageObjectClass StorageObjectClass;
|
||||
|
||||
/**
|
||||
* <private>
|
||||
* StorageObject:
|
||||
*
|
||||
* Private.
|
||||
*/
|
||||
struct _StorageObject
|
||||
{
|
||||
CockpitObjectSkeleton parent_instance;
|
||||
|
||||
StorageProvider *provider;
|
||||
|
||||
UDisksBlock *udisks_block;
|
||||
UDisksDrive *udisks_drive;
|
||||
UDisksMDRaid *udisks_mdraid;
|
||||
UDisksVolumeGroup *udisks_volume_group;
|
||||
UDisksLogicalVolume *udisks_logical_volume;
|
||||
|
||||
CockpitStorageBlock *storage_block_iface;
|
||||
CockpitStorageDrive *storage_drive_iface;
|
||||
CockpitStorageMDRaid *storage_mdraid_iface;
|
||||
CockpitStorageVolumeGroup *storage_volume_group_iface;
|
||||
CockpitStorageLogicalVolume *storage_logical_volume_iface;
|
||||
};
|
||||
|
||||
struct _StorageObjectClass
|
||||
{
|
||||
CockpitObjectSkeletonClass parent_class;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_PROVIDER,
|
||||
PROP_UDISKS_BLOCK,
|
||||
PROP_UDISKS_DRIVE,
|
||||
PROP_UDISKS_MDRAID,
|
||||
PROP_UDISKS_VOLUME_GROUP,
|
||||
PROP_UDISKS_LOGICAL_VOLUME,
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (StorageObject, storage_object, COCKPIT_TYPE_OBJECT_SKELETON);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
storage_object_finalize (GObject *_object)
|
||||
{
|
||||
StorageObject *object = STORAGE_OBJECT (_object);
|
||||
|
||||
/* ->provider is a borrowed reference */
|
||||
g_clear_object (&object->udisks_block);
|
||||
g_clear_object (&object->udisks_drive);
|
||||
g_clear_object (&object->udisks_mdraid);
|
||||
g_clear_object (&object->udisks_volume_group);
|
||||
g_clear_object (&object->udisks_logical_volume);
|
||||
|
||||
G_OBJECT_CLASS (storage_object_parent_class)->finalize (_object);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_object_get_property (GObject *_object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StorageObject *object = STORAGE_OBJECT (_object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PROVIDER:
|
||||
g_value_set_object (value, storage_object_get_provider (object));
|
||||
break;
|
||||
|
||||
case PROP_UDISKS_BLOCK:
|
||||
g_value_set_object (value, storage_object_get_udisks_block (object));
|
||||
break;
|
||||
|
||||
case PROP_UDISKS_DRIVE:
|
||||
g_value_set_object (value, storage_object_get_udisks_drive (object));
|
||||
break;
|
||||
|
||||
case PROP_UDISKS_MDRAID:
|
||||
g_value_set_object (value, storage_object_get_udisks_mdraid (object));
|
||||
break;
|
||||
|
||||
case PROP_UDISKS_VOLUME_GROUP:
|
||||
g_value_set_object (value, storage_object_get_udisks_volume_group (object));
|
||||
break;
|
||||
|
||||
case PROP_UDISKS_LOGICAL_VOLUME:
|
||||
g_value_set_object (value, storage_object_get_udisks_logical_volume (object));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
storage_object_set_property (GObject *_object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StorageObject *object = STORAGE_OBJECT (_object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PROVIDER:
|
||||
g_assert (object->provider == NULL);
|
||||
object->provider = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
case PROP_UDISKS_BLOCK:
|
||||
g_assert (object->udisks_block == NULL);
|
||||
object->udisks_block = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
case PROP_UDISKS_DRIVE:
|
||||
g_assert (object->udisks_drive == NULL);
|
||||
object->udisks_drive = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
case PROP_UDISKS_MDRAID:
|
||||
g_assert (object->udisks_mdraid == NULL);
|
||||
object->udisks_mdraid = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
case PROP_UDISKS_VOLUME_GROUP:
|
||||
g_assert (object->udisks_volume_group == NULL);
|
||||
object->udisks_volume_group = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
case PROP_UDISKS_LOGICAL_VOLUME:
|
||||
g_assert (object->udisks_logical_volume == NULL);
|
||||
object->udisks_logical_volume = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
storage_object_init (StorageObject *object)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
storage_object_update (StorageObject *object)
|
||||
{
|
||||
if (object->udisks_drive != NULL)
|
||||
{
|
||||
if (object->storage_drive_iface == NULL)
|
||||
{
|
||||
object->storage_drive_iface = storage_drive_new (object);
|
||||
cockpit_object_skeleton_set_storage_drive (COCKPIT_OBJECT_SKELETON (object), object->storage_drive_iface);
|
||||
}
|
||||
else
|
||||
{
|
||||
storage_drive_update (STORAGE_DRIVE (object->storage_drive_iface));
|
||||
}
|
||||
}
|
||||
|
||||
if (object->udisks_block != NULL)
|
||||
{
|
||||
if (object->storage_block_iface == NULL)
|
||||
{
|
||||
object->storage_block_iface = storage_block_new (object);
|
||||
cockpit_object_skeleton_set_storage_block (COCKPIT_OBJECT_SKELETON (object), object->storage_block_iface);
|
||||
}
|
||||
else
|
||||
{
|
||||
storage_block_update (STORAGE_BLOCK (object->storage_block_iface));
|
||||
}
|
||||
storage_remember_block_configs (object->provider, object->udisks_block);
|
||||
}
|
||||
|
||||
if (object->udisks_mdraid != NULL)
|
||||
{
|
||||
if (object->storage_mdraid_iface == NULL)
|
||||
{
|
||||
object->storage_mdraid_iface = storage_mdraid_new (object);
|
||||
cockpit_object_skeleton_set_storage_mdraid (COCKPIT_OBJECT_SKELETON (object), object->storage_mdraid_iface);
|
||||
}
|
||||
else
|
||||
{
|
||||
storage_mdraid_update (STORAGE_MDRAID (object->storage_mdraid_iface));
|
||||
}
|
||||
}
|
||||
|
||||
if (object->udisks_volume_group != NULL)
|
||||
{
|
||||
if (object->storage_volume_group_iface == NULL)
|
||||
{
|
||||
object->storage_volume_group_iface = storage_volume_group_new (object);
|
||||
cockpit_object_skeleton_set_storage_volume_group (COCKPIT_OBJECT_SKELETON (object), object->storage_volume_group_iface);
|
||||
}
|
||||
else
|
||||
{
|
||||
storage_volume_group_update (STORAGE_VOLUME_GROUP (object->storage_volume_group_iface));
|
||||
}
|
||||
}
|
||||
|
||||
if (object->udisks_logical_volume != NULL)
|
||||
{
|
||||
if (object->storage_logical_volume_iface == NULL)
|
||||
{
|
||||
object->storage_logical_volume_iface = storage_logical_volume_new (object);
|
||||
cockpit_object_skeleton_set_storage_logical_volume (COCKPIT_OBJECT_SKELETON (object), object->storage_logical_volume_iface);
|
||||
}
|
||||
else
|
||||
{
|
||||
storage_logical_volume_update (STORAGE_LOGICAL_VOLUME (object->storage_logical_volume_iface));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
storage_object_constructed (GObject *_object)
|
||||
{
|
||||
StorageObject *object = STORAGE_OBJECT (_object);
|
||||
|
||||
/* TODO: listen for changes when we go into the add/remove interfaces as needed */
|
||||
storage_object_update (object);
|
||||
|
||||
if (G_OBJECT_CLASS (storage_object_parent_class)->constructed != NULL)
|
||||
G_OBJECT_CLASS (storage_object_parent_class)->constructed (_object);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_object_class_init (StorageObjectClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = storage_object_finalize;
|
||||
gobject_class->constructed = storage_object_constructed;
|
||||
gobject_class->set_property = storage_object_set_property;
|
||||
gobject_class->get_property = storage_object_get_property;
|
||||
|
||||
/**
|
||||
* StorageObject:provider:
|
||||
*
|
||||
* The #StorageProvider for the object.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_PROVIDER,
|
||||
g_param_spec_object ("provider",
|
||||
NULL,
|
||||
NULL,
|
||||
TYPE_STORAGE_PROVIDER,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* StorageObject:udisks-block:
|
||||
*
|
||||
* The #UDisksBlock for the object.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_UDISKS_BLOCK,
|
||||
g_param_spec_object ("udisks-block",
|
||||
NULL,
|
||||
NULL,
|
||||
UDISKS_TYPE_BLOCK,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* StorageObject:udisks-drive:
|
||||
*
|
||||
* The #UDisksDrive for the object.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_UDISKS_DRIVE,
|
||||
g_param_spec_object ("udisks-drive",
|
||||
NULL,
|
||||
NULL,
|
||||
UDISKS_TYPE_DRIVE,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
/**
|
||||
* StorageObject:udisks-drive:
|
||||
*
|
||||
* The #UDisksMDRaid for the object.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_UDISKS_MDRAID,
|
||||
g_param_spec_object ("udisks-mdraid",
|
||||
NULL,
|
||||
NULL,
|
||||
UDISKS_TYPE_MDRAID,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* StorageObject:udisks-volume-group:
|
||||
*
|
||||
* The #UDisksVolumeGroup for the object.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_UDISKS_VOLUME_GROUP,
|
||||
g_param_spec_object ("udisks-volume-group",
|
||||
NULL,
|
||||
NULL,
|
||||
UDISKS_TYPE_VOLUME_GROUP,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
/**
|
||||
* StorageObject:udisks-logical-volume:
|
||||
*
|
||||
* The #UDisksLogicalVolume for the object.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_UDISKS_LOGICAL_VOLUME,
|
||||
g_param_spec_object ("udisks-logical-volume",
|
||||
NULL,
|
||||
NULL,
|
||||
UDISKS_TYPE_LOGICAL_VOLUME,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
/**
|
||||
* storage_object_new:
|
||||
* @provider: A #StorageProvider.
|
||||
* @udisks_block: A #UDisksBlock instance or %NULL.
|
||||
* @udisks_drive: A #UDisksDrive instance or %NULL.
|
||||
*
|
||||
* Creates a new #StorageObject instance.
|
||||
*
|
||||
* Returns: A new #StorageObject. Free with g_object_unref().
|
||||
*/
|
||||
StorageObject *
|
||||
storage_object_new (StorageProvider *provider,
|
||||
UDisksBlock *udisks_block,
|
||||
UDisksDrive *udisks_drive,
|
||||
UDisksMDRaid *udisks_mdraid,
|
||||
UDisksVolumeGroup *udisks_volume_group,
|
||||
UDisksLogicalVolume *udisks_logical_volume)
|
||||
{
|
||||
g_return_val_if_fail (udisks_block == NULL || UDISKS_IS_BLOCK (udisks_block), NULL);
|
||||
g_return_val_if_fail (udisks_drive == NULL || UDISKS_IS_DRIVE (udisks_drive), NULL);
|
||||
g_return_val_if_fail (udisks_mdraid == NULL || UDISKS_IS_MDRAID (udisks_mdraid), NULL);
|
||||
g_return_val_if_fail (udisks_volume_group == NULL || UDISKS_IS_VOLUME_GROUP (udisks_volume_group), NULL);
|
||||
g_return_val_if_fail (udisks_logical_volume == NULL || UDISKS_IS_LOGICAL_VOLUME (udisks_logical_volume), NULL);
|
||||
return STORAGE_OBJECT (g_object_new (TYPE_STORAGE_OBJECT,
|
||||
"provider", provider,
|
||||
"udisks-block", udisks_block,
|
||||
"udisks-drive", udisks_drive,
|
||||
"udisks-mdraid", udisks_mdraid,
|
||||
"udisks-volume-group", udisks_volume_group,
|
||||
"udisks-logical-volume", udisks_logical_volume,
|
||||
NULL));
|
||||
}
|
||||
|
||||
StorageProvider *
|
||||
storage_object_get_provider (StorageObject *object)
|
||||
{
|
||||
g_return_val_if_fail (IS_STORAGE_OBJECT (object), NULL);
|
||||
return object->provider;
|
||||
}
|
||||
|
||||
UDisksBlock *
|
||||
storage_object_get_udisks_block (StorageObject *object)
|
||||
{
|
||||
g_return_val_if_fail (IS_STORAGE_OBJECT (object), NULL);
|
||||
return object->udisks_block;
|
||||
}
|
||||
|
||||
UDisksDrive *
|
||||
storage_object_get_udisks_drive (StorageObject *object)
|
||||
{
|
||||
g_return_val_if_fail (IS_STORAGE_OBJECT (object), NULL);
|
||||
return object->udisks_drive;
|
||||
}
|
||||
|
||||
UDisksMDRaid *
|
||||
storage_object_get_udisks_mdraid (StorageObject *object)
|
||||
{
|
||||
g_return_val_if_fail (IS_STORAGE_OBJECT (object), NULL);
|
||||
return object->udisks_mdraid;
|
||||
}
|
||||
|
||||
UDisksVolumeGroup *
|
||||
storage_object_get_udisks_volume_group (StorageObject *object)
|
||||
{
|
||||
g_return_val_if_fail (IS_STORAGE_OBJECT (object), NULL);
|
||||
return object->udisks_volume_group;
|
||||
}
|
||||
|
||||
UDisksLogicalVolume *
|
||||
storage_object_get_udisks_logical_volume (StorageObject *object)
|
||||
{
|
||||
g_return_val_if_fail (IS_STORAGE_OBJECT (object), NULL);
|
||||
return object->udisks_logical_volume;
|
||||
}
|
||||
|
||||
gchar *
|
||||
storage_object_make_object_path (StorageObject *object)
|
||||
{
|
||||
g_return_val_if_fail (IS_STORAGE_OBJECT (object), NULL);
|
||||
|
||||
if (object->udisks_block)
|
||||
{
|
||||
/* Avoid leading /dev/ in object path, if possible */
|
||||
const gchar *device_file = udisks_block_get_device (object->udisks_block);
|
||||
if (g_str_has_prefix (device_file, "/dev/"))
|
||||
return utils_generate_object_path ("/com/redhat/Cockpit/Storage/block_devices",
|
||||
device_file + strlen ("/dev/"));
|
||||
else
|
||||
return utils_generate_object_path ("/com/redhat/Cockpit/Storage/block_devices", device_file);
|
||||
}
|
||||
|
||||
if (object->udisks_drive)
|
||||
{
|
||||
GString *s = g_string_new (NULL);
|
||||
gchar *object_path;
|
||||
g_string_append (s, udisks_drive_get_vendor (object->udisks_drive));
|
||||
if (s->len > 0)
|
||||
g_string_append_c (s, '_');
|
||||
g_string_append (s, udisks_drive_get_model (object->udisks_drive));
|
||||
if (s->len > 0)
|
||||
g_string_append_c (s, '_');
|
||||
g_string_append (s, udisks_drive_get_revision (object->udisks_drive));
|
||||
if (s->len > 0)
|
||||
g_string_append_c (s, '_');
|
||||
g_string_append (s, udisks_drive_get_serial (object->udisks_drive));
|
||||
object_path = utils_generate_object_path ("/com/redhat/Cockpit/Storage/drives", s->str);
|
||||
g_string_free (s, TRUE);
|
||||
return object_path;
|
||||
}
|
||||
|
||||
if (object->udisks_mdraid)
|
||||
{
|
||||
return utils_generate_object_path ("/com/redhat/Cockpit/Storage/raids",
|
||||
udisks_mdraid_get_uuid (object->udisks_mdraid));
|
||||
}
|
||||
|
||||
if (object->udisks_volume_group)
|
||||
{
|
||||
return utils_generate_object_path ("/com/redhat/Cockpit/Storage/lvm",
|
||||
udisks_volume_group_get_name (object->udisks_volume_group));
|
||||
}
|
||||
|
||||
if (object->udisks_logical_volume)
|
||||
{
|
||||
const gchar *vg_path = udisks_logical_volume_get_volume_group (object->udisks_logical_volume);
|
||||
UDisksClient *client = storage_provider_get_udisks_client (object->provider);
|
||||
GDBusObjectManager *manager = udisks_client_get_object_manager (client);
|
||||
UDisksVolumeGroup *vg =
|
||||
UDISKS_VOLUME_GROUP (g_dbus_object_manager_get_interface (manager, vg_path,
|
||||
"org.freedesktop.UDisks2.VolumeGroup"));
|
||||
|
||||
gchar *prefix = utils_generate_object_path ("/com/redhat/Cockpit/Storage/lvm",
|
||||
udisks_volume_group_get_name (vg));
|
||||
gchar *full = utils_generate_object_path (prefix,
|
||||
udisks_logical_volume_get_name (object->udisks_logical_volume));
|
||||
g_free (prefix);
|
||||
return full;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __STORAGE_OBJECT_H__
|
||||
#define __STORAGE_OBJECT_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_STORAGE_OBJECT (storage_object_get_type ())
|
||||
#define STORAGE_OBJECT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_STORAGE_OBJECT, StorageObject))
|
||||
#define IS_STORAGE_OBJECT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_STORAGE_OBJECT))
|
||||
|
||||
GType storage_object_get_type (void) G_GNUC_CONST;
|
||||
|
||||
StorageObject * storage_object_new (StorageProvider *provider,
|
||||
UDisksBlock *udisks_block,
|
||||
UDisksDrive *udisks_drive,
|
||||
UDisksMDRaid *udisks_raid,
|
||||
UDisksVolumeGroup *udisks_volume_group,
|
||||
UDisksLogicalVolume *udisks_logical_volume);
|
||||
|
||||
StorageProvider * storage_object_get_provider (StorageObject *object);
|
||||
|
||||
UDisksBlock * storage_object_get_udisks_block (StorageObject *object);
|
||||
|
||||
UDisksDrive * storage_object_get_udisks_drive (StorageObject *object);
|
||||
|
||||
UDisksMDRaid * storage_object_get_udisks_mdraid (StorageObject *object);
|
||||
|
||||
UDisksVolumeGroup * storage_object_get_udisks_volume_group (StorageObject *object);
|
||||
|
||||
UDisksLogicalVolume * storage_object_get_udisks_logical_volume (StorageObject *object);
|
||||
|
||||
void storage_object_update (StorageObject *object);
|
||||
|
||||
gchar * storage_object_make_object_path (StorageObject *object);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __STORAGE_OBJECT_H__ */
|
|
@ -0,0 +1,824 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "daemon.h"
|
||||
#include "storageprovider.h"
|
||||
#include "storageobject.h"
|
||||
#include "storagejob.h"
|
||||
|
||||
#include "libgsystem.h"
|
||||
|
||||
#include <cockpit/cockpit.h>
|
||||
|
||||
/**
|
||||
* SECTION:storageprovider
|
||||
* @title: StorageProvider
|
||||
* @short_description: Provider of storage objects.
|
||||
*
|
||||
* Object for providing storage objects.
|
||||
*/
|
||||
|
||||
typedef struct _StorageProviderClass StorageProviderClass;
|
||||
|
||||
/**
|
||||
* StorageProvider:
|
||||
*
|
||||
* The #StorageProvider structure contains only private data and
|
||||
* should only be accessed using the provided API.
|
||||
*/
|
||||
struct _StorageProvider
|
||||
{
|
||||
GObject parent_instance;
|
||||
Daemon *daemon;
|
||||
|
||||
UDisksClient *udisks_client;
|
||||
|
||||
GHashTable *hash_udisk_interface_to_storage_object;
|
||||
GHashTable *hash_udisk_job_to_storage_job;
|
||||
|
||||
GMutex remembered_configs_mutex;
|
||||
GHashTable *remembered_configs;
|
||||
gboolean remembered_configs_need_save;
|
||||
|
||||
GList *ifaces;
|
||||
GList *jobs;
|
||||
};
|
||||
|
||||
struct _StorageProviderClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DAEMON,
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (StorageProvider, storage_provider, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
storage_provider_finalize (GObject *object)
|
||||
{
|
||||
StorageProvider *provider = STORAGE_PROVIDER (object);
|
||||
|
||||
g_hash_table_unref (provider->hash_udisk_interface_to_storage_object);
|
||||
g_hash_table_unref (provider->hash_udisk_job_to_storage_job);
|
||||
|
||||
g_hash_table_unref (provider->remembered_configs);
|
||||
g_mutex_clear (&provider->remembered_configs_mutex);
|
||||
|
||||
g_list_free_full (provider->ifaces, g_object_unref);
|
||||
g_list_free_full (provider->jobs, g_object_unref);
|
||||
g_clear_object (&provider->udisks_client);
|
||||
|
||||
if (G_OBJECT_CLASS (storage_provider_parent_class)->finalize != NULL)
|
||||
G_OBJECT_CLASS (storage_provider_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_provider_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StorageProvider *provider = STORAGE_PROVIDER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DAEMON:
|
||||
g_value_set_object (value, storage_provider_get_daemon (provider));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
storage_provider_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StorageProvider *provider = STORAGE_PROVIDER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DAEMON:
|
||||
g_assert (provider->daemon == NULL);
|
||||
provider->daemon = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
storage_provider_init (StorageProvider *provider)
|
||||
{
|
||||
provider->hash_udisk_interface_to_storage_object = g_hash_table_new_full (g_direct_hash,
|
||||
g_direct_equal,
|
||||
g_object_unref,
|
||||
g_object_unref);
|
||||
provider->hash_udisk_job_to_storage_job = g_hash_table_new_full (g_direct_hash,
|
||||
g_direct_equal,
|
||||
g_object_unref,
|
||||
g_object_unref);
|
||||
|
||||
provider->remembered_configs = g_hash_table_new_full (g_str_hash,
|
||||
g_str_equal,
|
||||
g_free,
|
||||
(GDestroyNotify)g_hash_table_unref);
|
||||
g_mutex_init (&provider->remembered_configs_mutex);
|
||||
|
||||
storage_provider_load_remembered_configs (provider);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
diff_sorted_lists (GList *list1,
|
||||
GList *list2,
|
||||
GCompareFunc compare,
|
||||
GList **added,
|
||||
GList **removed,
|
||||
GList **unchanged)
|
||||
{
|
||||
int order;
|
||||
|
||||
*added = *removed = NULL;
|
||||
if (unchanged != NULL)
|
||||
*unchanged = NULL;
|
||||
|
||||
while (list1 != NULL &&
|
||||
list2 != NULL)
|
||||
{
|
||||
order = (*compare) (list1->data, list2->data);
|
||||
if (order < 0)
|
||||
{
|
||||
*removed = g_list_prepend (*removed, list1->data);
|
||||
list1 = list1->next;
|
||||
}
|
||||
else if (order > 0)
|
||||
{
|
||||
*added = g_list_prepend (*added, list2->data);
|
||||
list2 = list2->next;
|
||||
}
|
||||
else
|
||||
{ /* same item */
|
||||
if (unchanged != NULL)
|
||||
*unchanged = g_list_prepend (*unchanged, list1->data);
|
||||
list1 = list1->next;
|
||||
list2 = list2->next;
|
||||
}
|
||||
}
|
||||
|
||||
while (list1 != NULL)
|
||||
{
|
||||
*removed = g_list_prepend (*removed, list1->data);
|
||||
list1 = list1->next;
|
||||
}
|
||||
while (list2 != NULL)
|
||||
{
|
||||
*added = g_list_prepend (*added, list2->data);
|
||||
list2 = list2->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gint
|
||||
udisks_iface_compare_func (GDBusInterface *a,
|
||||
GDBusInterface *b)
|
||||
{
|
||||
return (char *)a - (char *)b;
|
||||
}
|
||||
|
||||
static gint
|
||||
_udisks_job_compare_func (UDisksJob *a,
|
||||
UDisksJob *b)
|
||||
{
|
||||
return (char *)a - (char *)b;
|
||||
}
|
||||
|
||||
static GDBusInterface *
|
||||
get_udisk_iface (UDisksObject *object)
|
||||
{
|
||||
UDisksBlock *block = udisks_object_peek_block (object);
|
||||
if (block)
|
||||
{
|
||||
/* don't include unused loop or nbd devices */
|
||||
if (udisks_block_get_size (block) == 0 &&
|
||||
(g_str_has_prefix (udisks_block_get_device (block), "/dev/loop") ||
|
||||
g_str_has_prefix (udisks_block_get_device (block), "/dev/nbd")))
|
||||
return NULL;
|
||||
|
||||
return G_DBUS_INTERFACE (block);
|
||||
}
|
||||
|
||||
UDisksDrive *drive = udisks_object_peek_drive (object);
|
||||
if (drive)
|
||||
{
|
||||
return G_DBUS_INTERFACE (drive);
|
||||
}
|
||||
|
||||
UDisksMDRaid *mdraid = udisks_object_peek_mdraid (object);
|
||||
if (mdraid)
|
||||
{
|
||||
return G_DBUS_INTERFACE (mdraid);
|
||||
}
|
||||
|
||||
UDisksVolumeGroup *volume_group = udisks_object_peek_volume_group (object);
|
||||
if (volume_group)
|
||||
{
|
||||
return G_DBUS_INTERFACE (volume_group);
|
||||
}
|
||||
|
||||
UDisksLogicalVolume *logical_volume = udisks_object_peek_logical_volume (object);
|
||||
if (logical_volume)
|
||||
{
|
||||
return G_DBUS_INTERFACE (logical_volume);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static StorageObject *
|
||||
make_storage_object (StorageProvider *provider,
|
||||
GDBusInterface *iface)
|
||||
{
|
||||
UDisksBlock *block = UDISKS_IS_BLOCK (iface) ? UDISKS_BLOCK (iface) : NULL;
|
||||
UDisksDrive *drive = UDISKS_IS_DRIVE (iface) ? UDISKS_DRIVE (iface) : NULL;
|
||||
UDisksMDRaid *mdraid = UDISKS_IS_MDRAID (iface) ? UDISKS_MDRAID (iface) : NULL;
|
||||
UDisksVolumeGroup *volume_group = UDISKS_IS_VOLUME_GROUP (iface) ? UDISKS_VOLUME_GROUP (iface) : NULL;
|
||||
UDisksLogicalVolume *logical_volume = UDISKS_IS_LOGICAL_VOLUME (iface) ? UDISKS_LOGICAL_VOLUME (iface) : NULL;
|
||||
return storage_object_new (provider, block, drive, mdraid, volume_group, logical_volume);
|
||||
}
|
||||
|
||||
static void
|
||||
provider_update_objects (StorageProvider *provider)
|
||||
{
|
||||
GDBusObjectManagerServer *object_manager;
|
||||
GList *udisks_objects;
|
||||
GList *wanted;
|
||||
GList *added, *removed;
|
||||
GList *l;
|
||||
|
||||
object_manager = G_DBUS_OBJECT_MANAGER_SERVER (daemon_get_object_manager (provider->daemon));
|
||||
udisks_objects = g_dbus_object_manager_get_objects (udisks_client_get_object_manager (provider->udisks_client));
|
||||
|
||||
wanted = NULL;
|
||||
for (l = udisks_objects; l != NULL; l = l->next)
|
||||
{
|
||||
GDBusInterface *iface = get_udisk_iface (UDISKS_OBJECT (l->data));
|
||||
if (iface == NULL)
|
||||
continue;
|
||||
|
||||
wanted = g_list_prepend (wanted, g_object_ref (iface));
|
||||
}
|
||||
|
||||
wanted = g_list_sort (wanted, (GCompareFunc)udisks_iface_compare_func);
|
||||
provider->ifaces = g_list_sort (provider->ifaces, (GCompareFunc)udisks_iface_compare_func);
|
||||
diff_sorted_lists (provider->ifaces, wanted, (GCompareFunc)udisks_iface_compare_func,
|
||||
&added, &removed, NULL);
|
||||
|
||||
for (l = removed; l != NULL; l = l->next)
|
||||
{
|
||||
GDBusInterface *iface = G_DBUS_INTERFACE (l->data);
|
||||
StorageObject *object;
|
||||
|
||||
object = g_hash_table_lookup (provider->hash_udisk_interface_to_storage_object, iface);
|
||||
g_warn_if_fail (object != NULL);
|
||||
if (object)
|
||||
{
|
||||
g_warn_if_fail (g_dbus_object_manager_server_unexport (object_manager,
|
||||
g_dbus_object_get_object_path (G_DBUS_OBJECT (object))));
|
||||
}
|
||||
|
||||
g_hash_table_remove (provider->hash_udisk_interface_to_storage_object, iface);
|
||||
provider->ifaces = g_list_remove (provider->ifaces, iface);
|
||||
g_object_unref (iface);
|
||||
}
|
||||
|
||||
for (l = added; l != NULL; l = l->next)
|
||||
{
|
||||
GDBusInterface *iface = G_DBUS_INTERFACE (l->data);
|
||||
StorageObject *object = make_storage_object (provider, iface);
|
||||
|
||||
g_warn_if_fail (g_hash_table_lookup (provider->hash_udisk_interface_to_storage_object, iface) == NULL);
|
||||
g_hash_table_insert (provider->hash_udisk_interface_to_storage_object,
|
||||
g_object_ref (iface),
|
||||
object);
|
||||
|
||||
gs_free gchar *object_path = storage_object_make_object_path (object);
|
||||
g_dbus_object_skeleton_set_object_path (G_DBUS_OBJECT_SKELETON (object), object_path);
|
||||
g_dbus_object_manager_server_export_uniquely (object_manager, G_DBUS_OBJECT_SKELETON (object));
|
||||
|
||||
provider->ifaces = g_list_prepend (provider->ifaces, g_object_ref (iface));
|
||||
}
|
||||
|
||||
g_list_free (added);
|
||||
g_list_free (removed);
|
||||
g_list_free_full (udisks_objects, g_object_unref);
|
||||
g_list_free_full (wanted, g_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
provider_update_jobs (StorageProvider *provider)
|
||||
{
|
||||
GDBusObjectManagerServer *object_manager;
|
||||
GList *udisks_objects;
|
||||
GList *wanted;
|
||||
GList *added, *removed;
|
||||
GList *l;
|
||||
|
||||
object_manager = G_DBUS_OBJECT_MANAGER_SERVER (daemon_get_object_manager (provider->daemon));
|
||||
udisks_objects = g_dbus_object_manager_get_objects (udisks_client_get_object_manager (provider->udisks_client));
|
||||
|
||||
wanted = NULL;
|
||||
for (l = udisks_objects; l != NULL; l = l->next)
|
||||
{
|
||||
UDisksObject *object = UDISKS_OBJECT (l->data);
|
||||
UDisksJob *job;
|
||||
|
||||
job = udisks_object_peek_job (object);
|
||||
if (job == NULL)
|
||||
continue;
|
||||
|
||||
const gchar *operation = udisks_job_get_operation (job);
|
||||
|
||||
if (strcmp (operation, "format-mkfs") != 0
|
||||
&& strcmp (operation, "format-erase") != 0
|
||||
&& strcmp (operation, "lvm-vg-empty-device") != 0)
|
||||
continue;
|
||||
|
||||
wanted = g_list_prepend (wanted, g_object_ref (job));
|
||||
}
|
||||
|
||||
wanted = g_list_sort (wanted, (GCompareFunc)_udisks_job_compare_func);
|
||||
provider->jobs = g_list_sort (provider->jobs, (GCompareFunc)_udisks_job_compare_func);
|
||||
diff_sorted_lists (provider->jobs, wanted, (GCompareFunc)_udisks_job_compare_func,
|
||||
&added, &removed, NULL);
|
||||
|
||||
for (l = removed; l != NULL; l = l->next)
|
||||
{
|
||||
UDisksJob *job = UDISKS_JOB (l->data);
|
||||
CockpitJob *object;
|
||||
|
||||
object = g_hash_table_lookup (provider->hash_udisk_job_to_storage_job, job);
|
||||
if (object == NULL)
|
||||
{
|
||||
g_warning ("No object for job %p", job);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warn_if_fail (g_dbus_object_manager_server_unexport (object_manager,
|
||||
g_dbus_object_get_object_path (G_DBUS_OBJECT (object))));
|
||||
g_hash_table_remove (provider->hash_udisk_job_to_storage_job, job);
|
||||
}
|
||||
|
||||
provider->jobs = g_list_remove (provider->jobs, job);
|
||||
g_object_unref (job);
|
||||
}
|
||||
|
||||
for (l = added; l != NULL; l = l->next)
|
||||
{
|
||||
UDisksJob *job = UDISKS_JOB (l->data);
|
||||
CockpitObjectSkeleton *object;
|
||||
CockpitJob *cockpit_job;
|
||||
gs_free gchar *object_path;
|
||||
|
||||
object_path = utils_generate_object_path ("/com/redhat/Cockpit/Jobs",
|
||||
udisks_job_get_operation (job));
|
||||
|
||||
cockpit_job = storage_job_new (provider, job);
|
||||
object = cockpit_object_skeleton_new (object_path);
|
||||
cockpit_object_skeleton_set_job (object, cockpit_job);
|
||||
g_object_unref (cockpit_job);
|
||||
|
||||
g_warn_if_fail (g_hash_table_lookup (provider->hash_udisk_job_to_storage_job, job) == NULL);
|
||||
g_hash_table_insert (provider->hash_udisk_job_to_storage_job,
|
||||
g_object_ref (job),
|
||||
object);
|
||||
|
||||
g_dbus_object_manager_server_export_uniquely (object_manager, G_DBUS_OBJECT_SKELETON (object));
|
||||
|
||||
provider->jobs = g_list_prepend (provider->jobs, g_object_ref (job));
|
||||
}
|
||||
|
||||
g_list_free (added);
|
||||
g_list_free (removed);
|
||||
g_list_free_full (udisks_objects, g_object_unref);
|
||||
g_list_free_full (wanted, g_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
provider_update (StorageProvider *provider)
|
||||
{
|
||||
provider_update_objects (provider);
|
||||
|
||||
for (GList *l = provider->ifaces; l != NULL; l = l->next)
|
||||
{
|
||||
GDBusInterface *iface = G_DBUS_INTERFACE (l->data);
|
||||
StorageObject *object;
|
||||
object = g_hash_table_lookup (provider->hash_udisk_interface_to_storage_object,
|
||||
iface);
|
||||
g_assert (object != NULL);
|
||||
storage_object_update (object);
|
||||
}
|
||||
|
||||
storage_provider_save_remembered_configs (provider);
|
||||
}
|
||||
|
||||
static void
|
||||
on_udisks_client_changed (UDisksClient *client,
|
||||
gpointer user_data)
|
||||
{
|
||||
StorageProvider *provider = STORAGE_PROVIDER (user_data);
|
||||
provider_update (provider);
|
||||
}
|
||||
|
||||
static void
|
||||
on_object_added (GDBusObjectManager *manager,
|
||||
GDBusObject *object,
|
||||
gpointer user_data)
|
||||
{
|
||||
StorageProvider *provider = STORAGE_PROVIDER (user_data);
|
||||
provider_update_jobs (provider);
|
||||
}
|
||||
|
||||
static void
|
||||
on_object_removed (GDBusObjectManager *manager,
|
||||
GDBusObject *object,
|
||||
gpointer user_data)
|
||||
{
|
||||
StorageProvider *provider = STORAGE_PROVIDER (user_data);
|
||||
provider_update_jobs (provider);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_provider_constructed (GObject *_object)
|
||||
{
|
||||
StorageProvider *provider = STORAGE_PROVIDER (_object);
|
||||
GError *error = NULL;
|
||||
|
||||
/* TODO: use GInitable/GAsyncInitable or start() pattern here */
|
||||
|
||||
provider->udisks_client = udisks_client_new_sync (NULL, &error);
|
||||
if (provider->udisks_client == NULL)
|
||||
{
|
||||
g_warning ("Error connecting to udisks: %s (%s, %d)",
|
||||
error->message, g_quark_to_string (error->domain), error->code);
|
||||
g_clear_error (&error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* init */
|
||||
provider_update (provider);
|
||||
|
||||
g_signal_connect (provider->udisks_client,
|
||||
"changed",
|
||||
G_CALLBACK (on_udisks_client_changed),
|
||||
provider);
|
||||
|
||||
/* We don't use the "changed" signal to watch jobs since we might
|
||||
miss some that only exist for a very short period, but we still
|
||||
want to report their failures.
|
||||
*/
|
||||
GDBusObjectManager *object_manager;
|
||||
object_manager = udisks_client_get_object_manager (provider->udisks_client);
|
||||
g_signal_connect (object_manager,
|
||||
"object-added",
|
||||
G_CALLBACK (on_object_added),
|
||||
provider);
|
||||
g_signal_connect (object_manager,
|
||||
"object-removed",
|
||||
G_CALLBACK (on_object_removed),
|
||||
provider);
|
||||
|
||||
out:
|
||||
if (G_OBJECT_CLASS (storage_provider_parent_class)->constructed != NULL)
|
||||
G_OBJECT_CLASS (storage_provider_parent_class)->constructed (_object);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_provider_class_init (StorageProviderClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = storage_provider_finalize;
|
||||
gobject_class->constructed = storage_provider_constructed;
|
||||
gobject_class->set_property = storage_provider_set_property;
|
||||
gobject_class->get_property = storage_provider_get_property;
|
||||
|
||||
/**
|
||||
* StorageProvider:daemon:
|
||||
*
|
||||
* The #Daemon to use.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_DAEMON,
|
||||
g_param_spec_object ("daemon",
|
||||
"Daemon",
|
||||
"The Daemon to use",
|
||||
TYPE_DAEMON,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
/**
|
||||
* storage_provider_new:
|
||||
* @daemon: A #Daemon.
|
||||
*
|
||||
* Create a new #StorageProvider instance.
|
||||
*
|
||||
* Returns: A #StorageProvider object. Free with g_object_unref().
|
||||
*/
|
||||
StorageProvider *
|
||||
storage_provider_new (Daemon *daemon)
|
||||
{
|
||||
g_return_val_if_fail (IS_DAEMON (daemon), NULL);
|
||||
return STORAGE_PROVIDER (g_object_new (TYPE_STORAGE_PROVIDER,
|
||||
"daemon", daemon,
|
||||
NULL));
|
||||
}
|
||||
|
||||
Daemon *
|
||||
storage_provider_get_daemon (StorageProvider *provider)
|
||||
{
|
||||
g_return_val_if_fail (IS_STORAGE_PROVIDER (provider), NULL);
|
||||
return provider->daemon;
|
||||
}
|
||||
|
||||
UDisksClient *
|
||||
storage_provider_get_udisks_client (StorageProvider *provider)
|
||||
{
|
||||
g_return_val_if_fail (IS_STORAGE_PROVIDER (provider), NULL);
|
||||
return provider->udisks_client;
|
||||
}
|
||||
|
||||
StorageObject *
|
||||
storage_provider_lookup_for_udisks_block (StorageProvider *provider,
|
||||
UDisksBlock *udisks_block)
|
||||
{
|
||||
g_return_val_if_fail (IS_STORAGE_PROVIDER (provider), NULL);
|
||||
g_return_val_if_fail (UDISKS_IS_BLOCK (udisks_block), NULL);
|
||||
return g_hash_table_lookup (provider->hash_udisk_interface_to_storage_object,
|
||||
udisks_block);
|
||||
}
|
||||
|
||||
StorageObject *
|
||||
storage_provider_lookup_for_udisks_drive (StorageProvider *provider,
|
||||
UDisksDrive *udisks_drive)
|
||||
{
|
||||
g_return_val_if_fail (IS_STORAGE_PROVIDER (provider), NULL);
|
||||
g_return_val_if_fail (UDISKS_IS_DRIVE (udisks_drive), NULL);
|
||||
return g_hash_table_lookup (provider->hash_udisk_interface_to_storage_object,
|
||||
udisks_drive);
|
||||
}
|
||||
|
||||
StorageObject *
|
||||
storage_provider_lookup_for_udisks_mdraid (StorageProvider *provider,
|
||||
UDisksMDRaid *udisks_mdraid)
|
||||
{
|
||||
g_return_val_if_fail (IS_STORAGE_PROVIDER (provider), NULL);
|
||||
g_return_val_if_fail (UDISKS_IS_MDRAID (udisks_mdraid), NULL);
|
||||
return g_hash_table_lookup (provider->hash_udisk_interface_to_storage_object,
|
||||
udisks_mdraid);
|
||||
}
|
||||
|
||||
StorageObject *
|
||||
storage_provider_lookup_for_udisks_volume_group (StorageProvider *provider,
|
||||
UDisksVolumeGroup *udisks_volume_group)
|
||||
{
|
||||
g_return_val_if_fail (IS_STORAGE_PROVIDER (provider), NULL);
|
||||
g_return_val_if_fail (UDISKS_IS_VOLUME_GROUP (udisks_volume_group), NULL);
|
||||
return g_hash_table_lookup (provider->hash_udisk_interface_to_storage_object,
|
||||
udisks_volume_group);
|
||||
}
|
||||
|
||||
StorageObject *
|
||||
storage_provider_lookup_for_udisks_logical_volume (StorageProvider *provider,
|
||||
UDisksLogicalVolume *udisks_logical_volume)
|
||||
{
|
||||
g_return_val_if_fail (IS_STORAGE_PROVIDER (provider), NULL);
|
||||
g_return_val_if_fail (UDISKS_IS_LOGICAL_VOLUME (udisks_logical_volume), NULL);
|
||||
return g_hash_table_lookup (provider->hash_udisk_interface_to_storage_object,
|
||||
udisks_logical_volume);
|
||||
}
|
||||
|
||||
const gchar *
|
||||
storage_provider_translate_path (StorageProvider *provider,
|
||||
const gchar *udisks_path)
|
||||
{
|
||||
UDisksObject *udisks_object = udisks_client_peek_object (provider->udisks_client, udisks_path);
|
||||
if (udisks_object != NULL)
|
||||
{
|
||||
StorageObject *object = NULL;
|
||||
|
||||
UDisksDrive *udisks_drive = udisks_object_peek_drive (udisks_object);
|
||||
if (udisks_drive != NULL)
|
||||
object = storage_provider_lookup_for_udisks_drive (provider, udisks_drive);
|
||||
|
||||
UDisksBlock *udisks_block = udisks_object_peek_block (udisks_object);
|
||||
if (udisks_block != NULL)
|
||||
object = storage_provider_lookup_for_udisks_block (provider, udisks_block);
|
||||
|
||||
UDisksMDRaid *udisks_raid = udisks_object_peek_mdraid (udisks_object);
|
||||
if (udisks_raid != NULL)
|
||||
object = storage_provider_lookup_for_udisks_mdraid (provider, udisks_raid);
|
||||
|
||||
UDisksVolumeGroup *udisks_volume_group = udisks_object_peek_volume_group (udisks_object);
|
||||
if (udisks_volume_group != NULL)
|
||||
object = storage_provider_lookup_for_udisks_volume_group (provider, udisks_volume_group);
|
||||
|
||||
UDisksLogicalVolume *udisks_logical_volume = udisks_object_peek_logical_volume (udisks_object);
|
||||
if (udisks_logical_volume != NULL)
|
||||
object = storage_provider_lookup_for_udisks_logical_volume (provider, udisks_logical_volume);
|
||||
|
||||
if (object != NULL)
|
||||
return g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
|
||||
}
|
||||
|
||||
return "/";
|
||||
}
|
||||
|
||||
static void
|
||||
remember_config_inlock (StorageProvider *provider,
|
||||
const gchar *parent_path,
|
||||
const gchar *child_path,
|
||||
GVariant *config)
|
||||
{
|
||||
GHashTable *child_configs = g_hash_table_lookup (provider->remembered_configs, parent_path);
|
||||
if (child_configs == NULL)
|
||||
{
|
||||
child_configs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref);
|
||||
g_hash_table_insert (provider->remembered_configs, g_strdup (parent_path), child_configs);
|
||||
}
|
||||
|
||||
GVariant *old = g_hash_table_lookup (child_configs, child_path);
|
||||
if (old == NULL || !g_variant_equal (old, config))
|
||||
{
|
||||
g_hash_table_insert (child_configs, g_strdup (child_path), g_variant_ref (config));
|
||||
provider->remembered_configs_need_save = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
storage_provider_remember_config (StorageProvider *provider,
|
||||
const gchar *parent_path,
|
||||
const gchar *child_path,
|
||||
GVariant *config)
|
||||
{
|
||||
g_mutex_lock (&provider->remembered_configs_mutex);
|
||||
remember_config_inlock (provider, parent_path, child_path, config);
|
||||
g_mutex_unlock (&provider->remembered_configs_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
storage_provider_save_remembered_configs (StorageProvider *provider)
|
||||
{
|
||||
g_mutex_lock (&provider->remembered_configs_mutex);
|
||||
|
||||
if (!provider->remembered_configs_need_save)
|
||||
{
|
||||
g_mutex_unlock (&provider->remembered_configs_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
GVariantBuilder parent_builder;
|
||||
GHashTableIter parent_iter;
|
||||
gpointer parent_key, parent_value;
|
||||
|
||||
g_variant_builder_init (&parent_builder, G_VARIANT_TYPE("a{sa{sv}}"));
|
||||
g_hash_table_iter_init (&parent_iter, provider->remembered_configs);
|
||||
while (g_hash_table_iter_next (&parent_iter, &parent_key, &parent_value))
|
||||
{
|
||||
const gchar *parent_path = parent_key;
|
||||
GHashTable *child_configs = parent_value;
|
||||
|
||||
GVariantBuilder child_builder;
|
||||
GHashTableIter child_iter;
|
||||
gpointer child_key, child_value;
|
||||
|
||||
g_variant_builder_init (&child_builder, G_VARIANT_TYPE("a{sv}"));
|
||||
g_hash_table_iter_init (&child_iter, child_configs);
|
||||
while (g_hash_table_iter_next (&child_iter, &child_key, &child_value))
|
||||
{
|
||||
const gchar *child_path = child_key;
|
||||
GVariant *config = child_value;
|
||||
g_variant_builder_add (&child_builder, "{sv}", child_path, config);
|
||||
}
|
||||
|
||||
g_variant_builder_add (&parent_builder, "{sa{sv}}", parent_path, &child_builder);
|
||||
}
|
||||
|
||||
gs_unref_variant GVariant *info = g_variant_builder_end (&parent_builder);
|
||||
gconstpointer info_data = g_variant_get_data (info);
|
||||
gsize info_size = g_variant_get_size (info);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!g_file_set_contents (PACKAGE_LOCALSTATE_DIR "/lib/cockpit/hidden-configs",
|
||||
info_data, info_size,
|
||||
&error))
|
||||
{
|
||||
g_warning ("Can't save hidden configs: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
g_mutex_unlock (&provider->remembered_configs_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
storage_provider_load_remembered_configs (StorageProvider *provider)
|
||||
{
|
||||
gchar *info_data;
|
||||
gsize info_size;
|
||||
GError *error = NULL;
|
||||
|
||||
g_mutex_lock (&provider->remembered_configs_mutex);
|
||||
|
||||
if (!g_file_get_contents (PACKAGE_LOCALSTATE_DIR "/lib/cockpit/hidden-configs",
|
||||
&info_data, &info_size,
|
||||
&error))
|
||||
{
|
||||
if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
|
||||
g_warning ("Can't load hidden configs: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
g_mutex_unlock (&provider->remembered_configs_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
gs_unref_variant GVariant *info = g_variant_new_from_data (G_VARIANT_TYPE ("a{sa{sv}}"),
|
||||
info_data, info_size, TRUE,
|
||||
g_free, NULL);
|
||||
|
||||
GVariantIter parent_iter, *child_iter;
|
||||
const gchar *parent_path, *child_path;
|
||||
GVariant *config;
|
||||
|
||||
g_hash_table_remove_all (provider->remembered_configs);
|
||||
g_variant_iter_init (&parent_iter, info);
|
||||
while (g_variant_iter_next (&parent_iter, "{&sa{sv}}", &parent_path, &child_iter))
|
||||
{
|
||||
while (g_variant_iter_next (child_iter, "{&sv}", &child_path, &config))
|
||||
{
|
||||
remember_config_inlock (provider, parent_path, child_path, config);
|
||||
g_variant_unref (config);
|
||||
}
|
||||
g_variant_iter_free (child_iter);
|
||||
}
|
||||
provider->remembered_configs_need_save = FALSE;
|
||||
|
||||
g_mutex_unlock (&provider->remembered_configs_mutex);
|
||||
}
|
||||
|
||||
GList *
|
||||
storage_provider_get_and_forget_remembered_configs (StorageProvider *provider,
|
||||
const gchar *parent_path)
|
||||
{
|
||||
g_mutex_lock (&provider->remembered_configs_mutex);
|
||||
|
||||
GList *result = NULL;
|
||||
GHashTable *child_configs = g_hash_table_lookup (provider->remembered_configs, parent_path);
|
||||
if (child_configs)
|
||||
{
|
||||
result = g_hash_table_get_values (child_configs);
|
||||
for (GList *l = result; l; l = l->next)
|
||||
g_variant_ref ((GVariant *)l->data);
|
||||
g_hash_table_remove (provider->remembered_configs, parent_path);
|
||||
provider->remembered_configs_need_save = TRUE;
|
||||
}
|
||||
|
||||
g_mutex_unlock (&provider->remembered_configs_mutex);
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __STORAGE_PROVIDER_H__
|
||||
#define __STORAGE_PROVIDER_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_STORAGE_PROVIDER (storage_provider_get_type ())
|
||||
#define STORAGE_PROVIDER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_STORAGE_PROVIDER, StorageProvider))
|
||||
#define IS_STORAGE_PROVIDER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_STORAGE_PROVIDER))
|
||||
|
||||
GType storage_provider_get_type (void) G_GNUC_CONST;
|
||||
|
||||
StorageProvider * storage_provider_new (Daemon *daemon);
|
||||
|
||||
Daemon * storage_provider_get_daemon (StorageProvider *provider);
|
||||
|
||||
UDisksClient * storage_provider_get_udisks_client (StorageProvider *provider);
|
||||
|
||||
StorageObject* storage_provider_lookup_for_udisks_block (StorageProvider *provider,
|
||||
UDisksBlock *udisks_block);
|
||||
|
||||
StorageObject* storage_provider_lookup_for_udisks_drive (StorageProvider *provider,
|
||||
UDisksDrive *udisks_drive);
|
||||
|
||||
StorageObject* storage_provider_lookup_for_udisks_mdraid (StorageProvider *provider,
|
||||
UDisksMDRaid *udisks_mdraid);
|
||||
|
||||
StorageObject* storage_provider_lookup_for_udisks_volume_group (StorageProvider *provider,
|
||||
UDisksVolumeGroup *udisks_volume_group);
|
||||
|
||||
StorageObject * storage_provider_lookup_for_udisks_logical_volume (StorageProvider *provider,
|
||||
UDisksLogicalVolume *udisks_logical_volume);
|
||||
|
||||
const gchar * storage_provider_translate_path (StorageProvider *provider,
|
||||
const gchar *udisks_path);
|
||||
|
||||
void storage_provider_remember_config (StorageProvider *provider,
|
||||
const gchar *parent_path,
|
||||
const gchar *child_path,
|
||||
GVariant *config);
|
||||
|
||||
void storage_provider_load_remembered_configs (StorageProvider *provider);
|
||||
|
||||
void storage_provider_save_remembered_configs (StorageProvider *provider);
|
||||
|
||||
GList * storage_provider_get_and_forget_remembered_configs (StorageProvider *provider,
|
||||
const gchar *parent_path);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __STORAGE_PROVIDER_H__ */
|
|
@ -0,0 +1,595 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "auth.h"
|
||||
#include "storagemanager.h"
|
||||
#include "storageprovider.h"
|
||||
#include "storageobject.h"
|
||||
#include "storagevolumegroup.h"
|
||||
|
||||
#include "libgsystem.h"
|
||||
|
||||
/**
|
||||
* SECTION:storagevolume_group
|
||||
* @title: Volume_Group devices
|
||||
* @short_description: Implementation of #CockpitStorageVolumeGroup
|
||||
*/
|
||||
|
||||
typedef struct _StorageVolumeGroupClass StorageVolumeGroupClass;
|
||||
|
||||
/**
|
||||
* <private>
|
||||
* StorageVolumeGroup:
|
||||
*
|
||||
* Private.
|
||||
*/
|
||||
|
||||
struct _StorageVolumeGroup
|
||||
{
|
||||
CockpitStorageVolumeGroupSkeleton parent_instance;
|
||||
|
||||
UDisksVolumeGroup *udisks_volume_group;
|
||||
StorageObject *object;
|
||||
};
|
||||
|
||||
struct _StorageVolumeGroupClass
|
||||
{
|
||||
CockpitStorageVolumeGroupSkeletonClass parent_class;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_OBJECT
|
||||
};
|
||||
|
||||
static void storage_volume_group_iface_init (CockpitStorageVolumeGroupIface *iface);
|
||||
|
||||
static void on_udisks_volume_group_notify (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (StorageVolumeGroup, storage_volume_group, COCKPIT_TYPE_STORAGE_VOLUME_GROUP_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (COCKPIT_TYPE_STORAGE_VOLUME_GROUP, storage_volume_group_iface_init));
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
storage_volume_group_finalize (GObject *object)
|
||||
{
|
||||
StorageVolumeGroup *volume_group = STORAGE_VOLUME_GROUP (object);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (volume_group->udisks_volume_group,
|
||||
G_CALLBACK (on_udisks_volume_group_notify),
|
||||
volume_group);
|
||||
g_object_unref (volume_group->udisks_volume_group);
|
||||
|
||||
G_OBJECT_CLASS (storage_volume_group_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_volume_group_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StorageVolumeGroup *volume_group = STORAGE_VOLUME_GROUP (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_OBJECT:
|
||||
g_value_set_object (value, volume_group->object);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
storage_volume_group_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StorageVolumeGroup *volume_group = STORAGE_VOLUME_GROUP (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_OBJECT:
|
||||
g_assert (volume_group->object == NULL);
|
||||
volume_group->object = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
storage_volume_group_update (StorageVolumeGroup *volume_group)
|
||||
{
|
||||
CockpitStorageVolumeGroup *iface = COCKPIT_STORAGE_VOLUME_GROUP (volume_group);
|
||||
cockpit_storage_volume_group_set_uuid (iface, udisks_volume_group_get_uuid (volume_group->udisks_volume_group));
|
||||
cockpit_storage_volume_group_set_name (iface, udisks_volume_group_get_name (volume_group->udisks_volume_group));
|
||||
cockpit_storage_volume_group_set_display_name (iface, udisks_volume_group_get_display_name (volume_group->udisks_volume_group));
|
||||
cockpit_storage_volume_group_set_size (iface, udisks_volume_group_get_size (volume_group->udisks_volume_group));
|
||||
cockpit_storage_volume_group_set_free_size (iface, udisks_volume_group_get_free_size (volume_group->udisks_volume_group));
|
||||
cockpit_storage_volume_group_set_needs_polling (iface, udisks_volume_group_get_needs_polling (volume_group->udisks_volume_group));
|
||||
}
|
||||
|
||||
static void
|
||||
on_udisks_volume_group_notify (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
StorageVolumeGroup *volume_group = STORAGE_VOLUME_GROUP (user_data);
|
||||
storage_volume_group_update (volume_group);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_volume_group_constructed (GObject *object)
|
||||
{
|
||||
StorageVolumeGroup *volume_group = STORAGE_VOLUME_GROUP (object);
|
||||
|
||||
volume_group->udisks_volume_group = g_object_ref (storage_object_get_udisks_volume_group (volume_group->object));
|
||||
g_signal_connect (volume_group->udisks_volume_group,
|
||||
"notify",
|
||||
G_CALLBACK (on_udisks_volume_group_notify),
|
||||
volume_group);
|
||||
|
||||
storage_volume_group_update (volume_group);
|
||||
|
||||
if (G_OBJECT_CLASS (storage_volume_group_parent_class)->constructed != NULL)
|
||||
G_OBJECT_CLASS (storage_volume_group_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_volume_group_init (StorageVolumeGroup *volume_group)
|
||||
{
|
||||
g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (volume_group),
|
||||
G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
|
||||
}
|
||||
|
||||
static void
|
||||
storage_volume_group_class_init (StorageVolumeGroupClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = storage_volume_group_finalize;
|
||||
gobject_class->constructed = storage_volume_group_constructed;
|
||||
gobject_class->set_property = storage_volume_group_set_property;
|
||||
gobject_class->get_property = storage_volume_group_get_property;
|
||||
|
||||
/**
|
||||
* StorageVolumeGroup:object:
|
||||
*
|
||||
* The #CockpitStorageObject for the object.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_OBJECT,
|
||||
g_param_spec_object ("object",
|
||||
NULL,
|
||||
NULL,
|
||||
TYPE_STORAGE_OBJECT,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
/**
|
||||
* storage_volume_group_new:
|
||||
* @object: A #CockpitStorageObject
|
||||
*
|
||||
* Creates a new #StorageVolumeGroup instance.
|
||||
*
|
||||
* Returns: A new #StorageVolumeGroup. Free with g_object_unref().
|
||||
*/
|
||||
CockpitStorageVolumeGroup *
|
||||
storage_volume_group_new (StorageObject *object)
|
||||
{
|
||||
g_return_val_if_fail (IS_STORAGE_OBJECT (object), NULL);
|
||||
return COCKPIT_STORAGE_VOLUME_GROUP (g_object_new (TYPE_STORAGE_VOLUME_GROUP,
|
||||
"object", object,
|
||||
NULL));
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
null_asv (void)
|
||||
{
|
||||
GVariantBuilder options;
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE("a{sv}"));
|
||||
return g_variant_builder_end (&options);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_poll (CockpitStorageVolumeGroup *object,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
StorageVolumeGroup *group = STORAGE_VOLUME_GROUP(object);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!udisks_volume_group_call_poll_sync (group->udisks_volume_group,
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
cockpit_storage_volume_group_complete_poll (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_delete (CockpitStorageVolumeGroup *object,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
StorageVolumeGroup *group = STORAGE_VOLUME_GROUP(object);
|
||||
StorageProvider *provider = storage_object_get_provider (group->object);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
GVariantBuilder options;
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE("a{sv}"));
|
||||
g_variant_builder_add (&options, "{sv}", "wipe", g_variant_new_boolean (TRUE));
|
||||
|
||||
if (!storage_cleanup_volume_group (provider,
|
||||
group->udisks_volume_group,
|
||||
&error)
|
||||
|| !udisks_volume_group_call_delete_sync (group->udisks_volume_group,
|
||||
g_variant_builder_end (&options),
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
cockpit_storage_volume_group_complete_delete (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_rename (CockpitStorageVolumeGroup *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_new_name)
|
||||
{
|
||||
StorageVolumeGroup *group = STORAGE_VOLUME_GROUP(object);
|
||||
GError *error = NULL;
|
||||
gs_free gchar *result = NULL;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
if (!udisks_volume_group_call_rename_sync (group->udisks_volume_group,
|
||||
arg_new_name,
|
||||
null_asv (),
|
||||
&result,
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
cockpit_storage_volume_group_complete_rename (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_add_device (CockpitStorageVolumeGroup *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_objpath)
|
||||
{
|
||||
StorageVolumeGroup *group = STORAGE_VOLUME_GROUP(object);
|
||||
GError *error = NULL;
|
||||
const gchar *block_path = "/";
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
StorageProvider *provider = storage_object_get_provider (group->object);
|
||||
Daemon *daemon = storage_provider_get_daemon (provider);
|
||||
GDBusObjectManagerServer *object_manager_server = daemon_get_object_manager (daemon);
|
||||
GDBusObjectManager *object_manager = G_DBUS_OBJECT_MANAGER (object_manager_server);
|
||||
|
||||
StorageObject *block_object =
|
||||
STORAGE_OBJECT (g_dbus_object_manager_get_object (object_manager, arg_objpath));
|
||||
UDisksBlock *udisks_block = storage_object_get_udisks_block (block_object);
|
||||
|
||||
if (udisks_block)
|
||||
block_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (udisks_block));
|
||||
|
||||
if (!udisks_volume_group_call_add_device_sync (group->udisks_volume_group,
|
||||
block_path,
|
||||
null_asv (),
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
cockpit_storage_volume_group_complete_add_device (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_remove_device (CockpitStorageVolumeGroup *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_objpath)
|
||||
{
|
||||
StorageVolumeGroup *group = STORAGE_VOLUME_GROUP(object);
|
||||
GError *error = NULL;
|
||||
const gchar *block_path = "/";
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
StorageProvider *provider = storage_object_get_provider (group->object);
|
||||
Daemon *daemon = storage_provider_get_daemon (provider);
|
||||
GDBusObjectManagerServer *object_manager_server = daemon_get_object_manager (daemon);
|
||||
GDBusObjectManager *object_manager = G_DBUS_OBJECT_MANAGER (object_manager_server);
|
||||
|
||||
StorageObject *block_object =
|
||||
STORAGE_OBJECT (g_dbus_object_manager_get_object (object_manager, arg_objpath));
|
||||
UDisksBlock *udisks_block = storage_object_get_udisks_block (block_object);
|
||||
|
||||
if (udisks_block)
|
||||
block_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (udisks_block));
|
||||
|
||||
GVariantBuilder options;
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE("a{sv}"));
|
||||
g_variant_builder_add (&options, "{sv}", "wipe", g_variant_new_boolean (TRUE));
|
||||
|
||||
if (!udisks_volume_group_call_remove_device_sync (group->udisks_volume_group,
|
||||
block_path,
|
||||
g_variant_builder_end (&options),
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
cockpit_storage_volume_group_complete_remove_device (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_empty_device (CockpitStorageVolumeGroup *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_objpath)
|
||||
{
|
||||
StorageVolumeGroup *group = STORAGE_VOLUME_GROUP(object);
|
||||
GError *error = NULL;
|
||||
const gchar *block_path = "/";
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
StorageProvider *provider = storage_object_get_provider (group->object);
|
||||
Daemon *daemon = storage_provider_get_daemon (provider);
|
||||
GDBusObjectManagerServer *object_manager_server = daemon_get_object_manager (daemon);
|
||||
GDBusObjectManager *object_manager = G_DBUS_OBJECT_MANAGER (object_manager_server);
|
||||
|
||||
StorageObject *block_object =
|
||||
STORAGE_OBJECT (g_dbus_object_manager_get_object (object_manager, arg_objpath));
|
||||
UDisksBlock *udisks_block = storage_object_get_udisks_block (block_object);
|
||||
|
||||
if (udisks_block)
|
||||
block_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (udisks_block));
|
||||
|
||||
GVariantBuilder options;
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE("a{sv}"));
|
||||
g_variant_builder_add (&options, "{sv}", "no-block", g_variant_new_boolean (TRUE));
|
||||
|
||||
if (!udisks_volume_group_call_empty_device_sync (group->udisks_volume_group,
|
||||
block_path,
|
||||
g_variant_builder_end (&options),
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
cockpit_storage_volume_group_complete_empty_device (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_create_plain_volume (CockpitStorageVolumeGroup *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_name,
|
||||
guint64 arg_size,
|
||||
gint arg_stripes,
|
||||
guint64 arg_stripesize)
|
||||
{
|
||||
StorageVolumeGroup *group = STORAGE_VOLUME_GROUP(object);
|
||||
GError *error = NULL;
|
||||
gs_free gchar *result = NULL;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
if (!udisks_volume_group_call_create_plain_volume_sync (group->udisks_volume_group,
|
||||
arg_name,
|
||||
arg_size,
|
||||
arg_stripes,
|
||||
arg_stripesize,
|
||||
null_asv (),
|
||||
&result,
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
cockpit_storage_volume_group_complete_create_plain_volume (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_create_thin_pool_volume (CockpitStorageVolumeGroup *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_name,
|
||||
guint64 arg_size)
|
||||
{
|
||||
StorageVolumeGroup *group = STORAGE_VOLUME_GROUP(object);
|
||||
GError *error = NULL;
|
||||
gs_free gchar *result = NULL;
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
if (!udisks_volume_group_call_create_thin_pool_volume_sync (group->udisks_volume_group,
|
||||
arg_name,
|
||||
arg_size,
|
||||
null_asv (),
|
||||
&result,
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
cockpit_storage_volume_group_complete_create_thin_pool_volume (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_create_thin_volume (CockpitStorageVolumeGroup *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_name,
|
||||
guint64 arg_size,
|
||||
const gchar *arg_pool)
|
||||
{
|
||||
StorageVolumeGroup *group = STORAGE_VOLUME_GROUP(object);
|
||||
GError *error = NULL;
|
||||
gs_free gchar *result = NULL;
|
||||
const gchar *pool_path = "/";
|
||||
|
||||
if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
|
||||
return TRUE;
|
||||
|
||||
StorageProvider *provider = storage_object_get_provider (group->object);
|
||||
Daemon *daemon = storage_provider_get_daemon (provider);
|
||||
GDBusObjectManagerServer *object_manager_server = daemon_get_object_manager (daemon);
|
||||
GDBusObjectManager *object_manager = G_DBUS_OBJECT_MANAGER (object_manager_server);
|
||||
|
||||
StorageObject *pool_object =
|
||||
STORAGE_OBJECT (g_dbus_object_manager_get_object (object_manager, arg_pool));
|
||||
UDisksLogicalVolume *udisks_pool_lvol = storage_object_get_udisks_logical_volume (pool_object);
|
||||
|
||||
if (udisks_pool_lvol)
|
||||
pool_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (udisks_pool_lvol));
|
||||
|
||||
if (!udisks_volume_group_call_create_thin_volume_sync (group->udisks_volume_group,
|
||||
arg_name,
|
||||
arg_size,
|
||||
pool_path,
|
||||
null_asv (),
|
||||
&result,
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
COCKPIT_ERROR,
|
||||
COCKPIT_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
cockpit_storage_volume_group_complete_create_thin_pool_volume (object, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
storage_volume_group_iface_init (CockpitStorageVolumeGroupIface *iface)
|
||||
{
|
||||
iface->handle_poll = handle_poll;
|
||||
|
||||
iface->handle_delete = handle_delete;
|
||||
iface->handle_rename = handle_rename;
|
||||
|
||||
iface->handle_add_device = handle_add_device;
|
||||
iface->handle_remove_device = handle_remove_device;
|
||||
iface->handle_empty_device = handle_empty_device;
|
||||
|
||||
iface->handle_create_plain_volume = handle_create_plain_volume;
|
||||
iface->handle_create_thin_pool_volume = handle_create_thin_pool_volume;
|
||||
iface->handle_create_thin_volume = handle_create_thin_volume;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __STORAGE_VOLUME_GROUP_H__
|
||||
#define __STORAGE_VOLUME_GROUP_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_STORAGE_VOLUME_GROUP (storage_volume_group_get_type ())
|
||||
#define STORAGE_VOLUME_GROUP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_STORAGE_VOLUME_GROUP, StorageVolumeGroup))
|
||||
#define IS_STORAGE_VOLUME_GROUP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_STORAGE_VOLUME_GROUP))
|
||||
|
||||
GType storage_volume_group_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CockpitStorageVolumeGroup * storage_volume_group_new (StorageObject *object);
|
||||
|
||||
void storage_volume_group_update (StorageVolumeGroup *volume_group);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __STORAGE_VOLUME_GROUP_H__ */
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __TYPES_H__
|
||||
#define __TYPES_H__
|
||||
|
||||
#include <glib-unix.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#define UDISKS_API_IS_SUBJECT_TO_CHANGE
|
||||
#include <udisks/udisks.h>
|
||||
|
||||
#include <cockpit/cockpit.h>
|
||||
|
||||
struct _Daemon;
|
||||
typedef struct _Daemon Daemon;
|
||||
|
||||
struct _Manager;
|
||||
typedef struct _Manager Manager;
|
||||
|
||||
struct _CpuMonitor;
|
||||
typedef struct _CpuMonitor CpuMonitor;
|
||||
|
||||
struct _Network;
|
||||
typedef struct _Network Network;
|
||||
|
||||
struct _Netinterface;
|
||||
typedef struct _Netinterface Netinterface;
|
||||
|
||||
struct _MemoryMonitor;
|
||||
typedef struct _MemoryMonitor MemoryMonitor;
|
||||
|
||||
struct _NetworkMonitor;
|
||||
typedef struct _NetworkMonitor NetworkMonitor;
|
||||
|
||||
struct _DiskIOMonitor;
|
||||
typedef struct _DiskIOMonitor DiskIOMonitor;
|
||||
|
||||
struct _StorageManager;
|
||||
typedef struct _StorageManager StorageManager;
|
||||
|
||||
struct _StorageProvider;
|
||||
typedef struct _StorageProvider StorageProvider;
|
||||
|
||||
struct _StorageObject;
|
||||
typedef struct _StorageObject StorageObject;
|
||||
|
||||
struct _StorageBlock;
|
||||
typedef struct _StorageBlock StorageBlock;
|
||||
|
||||
struct _StorageDrive;
|
||||
typedef struct _StorageDrive StorageDrive;
|
||||
|
||||
struct _StorageMDRaid;
|
||||
typedef struct _StorageMDRaid StorageMDRaid;
|
||||
|
||||
struct _StorageVolumeGroup;
|
||||
typedef struct _StorageVolumeGroup StorageVolumeGroup;
|
||||
|
||||
struct _StorageLogicalVolume;
|
||||
typedef struct _StorageLogicalVolume StorageLogicalVolume;
|
||||
|
||||
struct _StorageJob;
|
||||
typedef struct _StorageJob StorageJob;
|
||||
|
||||
struct _Realms;
|
||||
typedef struct _Realms Realms;
|
||||
|
||||
struct _Services;
|
||||
typedef struct _Services Services;
|
||||
|
||||
struct _Journal;
|
||||
typedef struct _Journal Journal;
|
||||
|
||||
struct _Accounts;
|
||||
typedef struct _Accounts Accounts;
|
||||
|
||||
struct _Account;
|
||||
typedef struct _Account Account;
|
||||
|
||||
#endif /* __TYPES_H__ */
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cockpit/cockpit.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
/**
|
||||
* SECTION:utils
|
||||
* @title: Utilities
|
||||
* @short_description: Various utility routines
|
||||
*
|
||||
* Various utility routines.
|
||||
*/
|
||||
|
||||
/**
|
||||
* utils_generate_object_path:
|
||||
* @base: The base object path (without trailing '/').
|
||||
* @s: A UTF-8 string.
|
||||
*
|
||||
* Appends @s to @base in a way such that only characters that can be
|
||||
* used in a D-Bus object path will be used. E.g. a character not in
|
||||
* <literal>[A-Z][a-z][0-9]_</literal> will be escaped as _HEX where
|
||||
* HEX is a two-digit hexadecimal number.
|
||||
*
|
||||
* Note that his mapping is not bijective - e.g. you cannot go back
|
||||
* to the original string.
|
||||
*
|
||||
* Returns: An allocated string that must be freed with g_free().
|
||||
*/
|
||||
gchar *
|
||||
utils_generate_object_path (const gchar *base,
|
||||
const gchar *s)
|
||||
{
|
||||
guint n;
|
||||
GString *str;
|
||||
|
||||
g_return_val_if_fail (g_variant_is_object_path (base), NULL);
|
||||
g_return_val_if_fail (g_utf8_validate (s, -1, NULL), NULL);
|
||||
|
||||
str = g_string_new (base);
|
||||
g_string_append_c (str, '/');
|
||||
for (n = 0; s[n] != '\0'; n++)
|
||||
{
|
||||
gint c = s[n];
|
||||
/* D-Bus spec sez:
|
||||
*
|
||||
* Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_"
|
||||
*/
|
||||
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_')
|
||||
{
|
||||
g_string_append_c (str, c);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Escape bytes not in [A-Z][a-z][0-9] as _<hex-with-two-digits> */
|
||||
g_string_append_printf (str, "_%02x", c & 0xFF);
|
||||
}
|
||||
}
|
||||
return g_string_free (str, FALSE);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __UTILS_H__
|
||||
#define __UTILS_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
gchar * utils_generate_object_path (const gchar *base,
|
||||
const gchar *s);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __UTILS_H__ */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue