Imported Upstream version 2.6.0
This commit is contained in:
parent
26fb71b504
commit
459aaf9392
510 changed files with 40508 additions and 18859 deletions
|
|
@ -1,16 +1,14 @@
|
|||
Desc: Information for developers
|
||||
File: developers.txt
|
||||
Date: 18 February 2004
|
||||
Auth: Russell Kroll <rkroll@exploits.org>
|
||||
Information for developers
|
||||
==========================
|
||||
|
||||
This document is intended to explain some of the more useful things
|
||||
within the tree and provide a standard for working on the code.
|
||||
|
||||
General stuff - common subdirectory
|
||||
===================================
|
||||
-----------------------------------
|
||||
|
||||
String handling
|
||||
---------------
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Use snprintf. It's even provided with a compatibility module if the
|
||||
target host doesn't have it natively.
|
||||
|
|
@ -24,7 +22,7 @@ that allows you to append to char * with a format string and all the usual
|
|||
string length checking of snprintf.
|
||||
|
||||
Error reporting
|
||||
---------------
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Don't call syslog() directly. Use upslog_with_errno() and upslogx().
|
||||
They may write to the syslog, stderr, or both as appropriate. This
|
||||
|
|
@ -38,21 +36,21 @@ fatal_with_errno and fatalx work the same way, but they
|
|||
exit(EXIT_FAILURE) afterwards. Don't call exit() directly.
|
||||
|
||||
Debugging information
|
||||
---------------------
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
upsdebug_with_errno(), upsdebugx() and upsdebug_hex() use the
|
||||
global nut_debug_level so you don't have to mess around with
|
||||
printfs yourself. Use them.
|
||||
|
||||
Memory allocation
|
||||
-----------------
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
xmalloc, xcalloc, xrealloc and xstrdup all check the results of the base
|
||||
calls before continuing, so you don't have to. Don't use the raw calls
|
||||
directly.
|
||||
|
||||
Config file parsing
|
||||
-------------------
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The configuration parser, called parseconf, is now up to its fourth
|
||||
major version. It has multiple entry points, and can handle many
|
||||
|
|
@ -67,7 +65,7 @@ Escaping special characters and quoting multiple-word elements is all
|
|||
handled by the state machine. Using the same code for all config files
|
||||
avoids code duplication.
|
||||
|
||||
Note: this does not apply to drivers. Driver authors should use the
|
||||
NOTE: this does not apply to drivers. Driver authors should use the
|
||||
upsdrv_makevartable() scheme to pick up values from ups.conf. Drivers
|
||||
should not have their own config files.
|
||||
|
||||
|
|
@ -78,56 +76,63 @@ under normal circumstances. This technique might be used to add more
|
|||
hardware support to a driver without recompiling.
|
||||
|
||||
<time.h> vs. <sys/time.h>
|
||||
-------------------------
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This is already handled by autoconf, so just include "timehead.h" and you
|
||||
will get the right headers on every system.
|
||||
|
||||
UPS drivers - main.c
|
||||
====================
|
||||
Device drivers - main.c
|
||||
-----------------------
|
||||
|
||||
The UPS drivers use main.c as their core. The only exception is
|
||||
dummycons, which only looks like a driver by using the same dstate
|
||||
function calls.
|
||||
The device drivers use main.c as their core. The only exceptions are the
|
||||
HAL-based drivers, which use the same dstate function calls while integrating
|
||||
with the DBUS event loop.
|
||||
|
||||
To write a new driver, you create a file with a series of support
|
||||
functions that will be called by main. These all have names that start
|
||||
with "upsdrv_", and they will be called at different times by main
|
||||
with `upsdrv_`, and they will be called at different times by main
|
||||
depending on what needs to happen.
|
||||
|
||||
See new-drivers.txt for information on writing drivers, and also refer
|
||||
to the skeletal driver in skel.c.
|
||||
See the <<new-drivers,driver documentation>> for information on writing
|
||||
drivers, and also refer to the skeletal driver in skel.c.
|
||||
|
||||
Portability
|
||||
===========
|
||||
-----------
|
||||
|
||||
Avoid things that will break on other systems. All the world is not an
|
||||
x86 Linux box.
|
||||
|
||||
There are still older systems out there that don't do C++ style comments.
|
||||
That means you have to comment /* like this */, and // this is right out.
|
||||
|
||||
--------------------------------------
|
||||
/* Comments look like this. */
|
||||
// Not like this.
|
||||
--------------------------------------
|
||||
|
||||
Newer versions of gcc allow you to declare a variable inside a function
|
||||
somewhat like the way C++ operates, like this:
|
||||
|
||||
function do_stuff(void)
|
||||
{
|
||||
check_something();
|
||||
--------------------------------------------------------------------------------
|
||||
function do_stuff(void)
|
||||
{
|
||||
check_something();
|
||||
|
||||
int a;
|
||||
int a;
|
||||
|
||||
a = do_something_else();
|
||||
}
|
||||
a = do_something_else();
|
||||
}
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
While this will compile and run on these newer versions, it will fail
|
||||
miserably for anyone on an older system. That means you must not use
|
||||
it. gcc only warns about this with -pedantic.
|
||||
|
||||
Coding style
|
||||
============
|
||||
------------
|
||||
|
||||
This is how I do things.
|
||||
This is how we do things:
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
int open_subspace(char *ship, int privacy)
|
||||
{
|
||||
if (!privacy)
|
||||
|
|
@ -138,8 +143,7 @@ int open_subspace(char *ship, int privacy)
|
|||
|
||||
return secure_channel(ship);
|
||||
}
|
||||
|
||||
(The example that used to be in this file wasn't particularly clear)
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
The basic idea is that I try to group things into functions, and then
|
||||
find ways to drop out of them when we can't go any further. There's
|
||||
|
|
@ -159,7 +163,7 @@ easier to read, and it enables tools (such as indent and emacs) to
|
|||
display the source code correctly.
|
||||
|
||||
Indenting with tabs vs. spaces
|
||||
------------------------------
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Another thing to notice is that the indenting happens with tabs instead
|
||||
of spaces. This lets everyone have their personal tab-width setting
|
||||
|
|
@ -180,7 +184,7 @@ kernel - Documentation/CodingStyle. He's done a far better job of
|
|||
explaining this.
|
||||
|
||||
Line breaks
|
||||
-----------
|
||||
~~~~~~~~~~~
|
||||
|
||||
It is better to have lines that are longer than 80 characters than to
|
||||
wrap lines in random places. This makes it easier to work with tools
|
||||
|
|
@ -193,13 +197,17 @@ long when there is a better alternative (see the note on
|
|||
pretentiousVariableNamingSchemes above). Certainly there should not
|
||||
be more than one statement per line. Please do not use
|
||||
|
||||
if (condition) break;
|
||||
--------------------------------------------------------------------------------
|
||||
if (condition) break;
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
but use the following:
|
||||
|
||||
if (condition) {
|
||||
break;
|
||||
}
|
||||
--------------------------------------------------------------------------------
|
||||
if (condition) {
|
||||
break;
|
||||
}
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Miscellaneous coding style tools
|
||||
--------------------------------
|
||||
|
|
@ -207,12 +215,12 @@ Miscellaneous coding style tools
|
|||
You can go a long way towards converting your source code to the NUT
|
||||
coding style by piping it through the following command:
|
||||
|
||||
indent -kr -i8 -T FILE -l1000 -nhnl
|
||||
indent -kr -i8 -T FILE -l1000 -nhnl
|
||||
|
||||
This next command does a reasonable job of converting most C++ style
|
||||
comments (but not URLs and DOCTYPE strings):
|
||||
|
||||
sed 's#\(^\|[ \t]\)//[ \t]*\(.*\)[ \t]*#/* \2 */#'
|
||||
sed 's#\(^\|[ \t]\)//[ \t]*\(.*\)[ \t]*#/* \2 */#'
|
||||
|
||||
Emacs users can adjust how tabs are displayed. For example, it is
|
||||
possible to set a tab stop to be 3 spaces, rather than the usual 8.
|
||||
|
|
@ -222,25 +230,27 @@ rendered on screen). It is even possible to set this on a
|
|||
per-directory basis, by putting something like this into your .emacs
|
||||
file:
|
||||
|
||||
;; NUT style
|
||||
--------------------------------------------------------------------------------
|
||||
;; NUT style
|
||||
|
||||
(defun nut-c-mode ()
|
||||
"C mode with adjusted defaults for use with the NUT sources."
|
||||
(interactive)
|
||||
(c-mode)
|
||||
(c-set-style "K&R")
|
||||
(setq c-basic-offset 3) ;; 3 spaces C-indentation
|
||||
(setq tab-width 3)) ;; 3 spaces per tab
|
||||
(defun nut-c-mode ()
|
||||
"C mode with adjusted defaults for use with the NUT sources."
|
||||
(interactive)
|
||||
(c-mode)
|
||||
(c-set-style "K&R")
|
||||
(setq c-basic-offset 3) ;; 3 spaces C-indentation
|
||||
(setq tab-width 3)) ;; 3 spaces per tab
|
||||
|
||||
;; apply NUT style to all C source files in all subdirectories of nut/
|
||||
;; apply NUT style to all C source files in all subdirectories of nut/
|
||||
|
||||
(setq auto-mode-alist (cons '(".*/nut/.*\\.[ch]$". nut-c-mode)
|
||||
auto-mode-alist))
|
||||
(setq auto-mode-alist (cons '(".*/nut/.*\\.[ch]$". nut-c-mode)
|
||||
auto-mode-alist))
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Finishing touches
|
||||
-----------------
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
I like code that uses const and static liberally. If you don't need to
|
||||
We like code that uses const and static liberally. If you don't need to
|
||||
expose a function or global variable to the outside world, static is
|
||||
your friend. If nobody should edit the contents of some buffer that's
|
||||
behind a pointer, const keeps them honest.
|
||||
|
|
@ -250,25 +260,23 @@ find implementation flaws. Functions that attempt to modify a constant
|
|||
or access something outside their scope will throw a warning or even
|
||||
fail to compile in some cases. This is what we want.
|
||||
|
||||
Spaghetti
|
||||
---------
|
||||
|
||||
If you use a goto, expect me to drop it when my head stops spinning.
|
||||
It gives me flashbacks to the BASIC code I wrote on the 8 bit systems of
|
||||
the 80s. I've tried to clean up my act, and you should make the effort
|
||||
Spaghetti
|
||||
~~~~~~~~~
|
||||
|
||||
If you use a goto, expect us to drop it when our head stops spinning.
|
||||
It gives us flashbacks to the very old code we wrote.
|
||||
We've tried to clean up our act, and you should make the effort
|
||||
as well.
|
||||
|
||||
I'm not making a blanket statement about gotos, since everything
|
||||
We're not making a blanket statement about gotos, since everything
|
||||
probably has at least one good use. There are a few cases where a goto
|
||||
is more efficient than any other approach, but you probably won't
|
||||
encounter them in this software.
|
||||
encounter them very often in this software.
|
||||
|
||||
Hint: there *was* a good use of a goto in upsd until the 1.3 series. At
|
||||
this point we are back to zero gotos since that code was replaced by
|
||||
another technique that doesn't need it.
|
||||
|
||||
Legacy code
|
||||
-----------
|
||||
~~~~~~~~~~~
|
||||
|
||||
There are parts of the source tree that do not yet conform to these
|
||||
specs. Part of this is due to the fact that the coding style has been
|
||||
|
|
@ -278,74 +286,94 @@ since then. Don't worry - it'll get cleaned up the next time something
|
|||
in the vicinity gets a visit.
|
||||
|
||||
Memory leak checking
|
||||
--------------------
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
I can't say enough good things about valgrind. If you do anything with
|
||||
We can't say enough good things about valgrind. If you do anything with
|
||||
dynamic memory in your code, you need to use this. Just compile with -g
|
||||
and start the program inside valgrind. Run it through the suspected
|
||||
area and then exit cleanly. valgrind will tell you if you've done
|
||||
anything dodgy like freeing regions twice, reading uninitialized memory,
|
||||
or if you've leaked memory anywhere.
|
||||
|
||||
http://valgrind.kde.org/
|
||||
For more information, refer to the link:http://valgrind.kde.org[Valgrind]
|
||||
project.
|
||||
|
||||
Conclusion
|
||||
----------
|
||||
~~~~~~~~~~
|
||||
|
||||
The summary: please be kind to my eyes. There's a lot of stuff in here.
|
||||
The summary: please be kind to our eyes. There's a lot of stuff in here,
|
||||
and many people have put a lot of time and energy to improve it.
|
||||
|
||||
Submitting patches
|
||||
==================
|
||||
------------------
|
||||
|
||||
Patches that arrive in unified format (diff -u) as plain text with no
|
||||
HTML, no attachments and a brief summary at the top are the easiest to
|
||||
handle. They show the context, explain what's going on, and get saved as
|
||||
one message. Everything stays together until it's time to merge.
|
||||
Patches that arrive in unified format (diff -u) as plain text attachments with
|
||||
no HTML and a brief summary at the top are the easiest to handle.
|
||||
|
||||
Patches that arrive as attachments have to be moved around as separate
|
||||
files - the body of the message is one, and the patch is in another.
|
||||
This is not my preferred mode of operation.
|
||||
If a patch is sent to the nut-upsdev mailing list, it stands a better chance of
|
||||
being seen immediately. However, it is likely to be dropped if any issues
|
||||
cannot be resolved quickly. If your code might not work for others, or if it is
|
||||
a large change, your best bet is to submit a
|
||||
link:https://alioth.debian.org/tracker/?atid=411544&group_id=30602&func=browse[ticket on Alioth].
|
||||
|
||||
When sending patches to the lists, be sure to add me as an explicit
|
||||
recipient to make sure it is considered for merging. A patch which only
|
||||
goes to a list is generally treated as a RFC and is relatively low
|
||||
priority.
|
||||
This allows us to track the patches over a longer period of time, and it is
|
||||
less likely that a patch will fall through the cracks. Posting a reminder to
|
||||
the developers (via the nut-upsdev list) about a patch on the tracker is fair
|
||||
game.
|
||||
|
||||
If your mailer is brain dead and rewrites tabs into spaces, wraps your
|
||||
patch body, or anything else like that, just attach the patch. I'd
|
||||
rather deal with an attachment instead of a patch that has tab damage,
|
||||
rewrapped lines, or worse.
|
||||
|
||||
Patch cohesion
|
||||
==============
|
||||
--------------
|
||||
|
||||
Patches should have some kind of unifying element. One patch set is one
|
||||
message, and it should all touch similar things. If you have to edit 6
|
||||
files to add support for neutrino detection in UPS hardware, that's
|
||||
fine.
|
||||
|
||||
However, sending one huge patch that does massive separate changes
|
||||
all over the tree is not recommended. That kind of patch has to be
|
||||
split up and evaluated separately, assuming I care enough to do that
|
||||
However, sending one huge patch that does massive separate changes all over
|
||||
the tree is not recommended. That kind of patch has to be split up and
|
||||
evaluated separately, assuming the core developers care enough to do that
|
||||
instead of just dropping it.
|
||||
|
||||
If you have to make big changes in lots of places, send multiple
|
||||
patches - one per item.
|
||||
|
||||
Man pages
|
||||
=========
|
||||
The completion touch: manual pages and device entry in HCL
|
||||
----------------------------------------------------------
|
||||
|
||||
If you change something that involves an argument to a program or
|
||||
configuration file parsing, the man page is probably now out of date.
|
||||
If you don't update it, I have to, and I have enough to do as it is.
|
||||
If you don't update it, we have to, and we have enough to do as it is.
|
||||
|
||||
If you write a new driver, send in the man page when you send me the
|
||||
source code for your driver. Otherwise, I will be forced to write a
|
||||
If you write a new driver, send in the man page when you send us the
|
||||
source code for your driver. Otherwise, we will be forced to write a
|
||||
skeletal man page that will probably miss many of the finer points of
|
||||
the driver and hardware.
|
||||
|
||||
The same remark goes for device entries: if you add support for new models,
|
||||
remember to also complete the hardware compatibility list, present
|
||||
in data/driver.list.in. This will be used to generate both textual, static
|
||||
HTML and dynamic searchable HTML for the website.
|
||||
|
||||
Source code management
|
||||
----------------------
|
||||
|
||||
We currently use a Subversion (SVN) repository hosted at Alioth to track
|
||||
changes to the NUT source code. To obtain permission to commit to the SVN
|
||||
repository, you must be prepared to spend a fair amount of time contributing to
|
||||
the NUT codebase. For occasional contributions over time, you may wish to
|
||||
investigate one of the <<_distributed_scm_systems,distributed SCM tools>>
|
||||
listed below.
|
||||
|
||||
Anonymous SVN checkouts are possible:
|
||||
|
||||
svn co svn://svn.debian.org/nut/trunk nut-svn-readonly
|
||||
|
||||
If you change a file in the SVN working copy, you can use `svn diff` to
|
||||
generate a patch to send to the nut-upsdev mailing list.
|
||||
|
||||
Repository etiquette and quality assurance
|
||||
==========================================
|
||||
------------------------------------------
|
||||
|
||||
Please keep the SVN trunk in working condition at all times. The trunk
|
||||
may be used to generate daily tarballs, and should not contain broken
|
||||
|
|
@ -353,22 +381,103 @@ code if possible. If you need to commit incremental changes that leave
|
|||
the system in a broken state, please do so in a separate branch and
|
||||
merge the changes back to the trunk once they are complete.
|
||||
|
||||
Before committing, please remember to:
|
||||
Before committing, please remember to run "make distcheck-light". This checks
|
||||
that the Makefiles are not broken, that all the relevant files are distributed,
|
||||
and that there are no compilation or installation errors.
|
||||
|
||||
* update the ChangeLog, if appropriate. Dates are listed in UTC
|
||||
("date --utc").
|
||||
|
||||
* run "make distcheck-light". This checks that the Makefiles are not
|
||||
broken, that all the relevant files are distributed, and that there
|
||||
are no compilation or installation errors.
|
||||
|
||||
Running "make distcheck-light" is especially important if you have
|
||||
added or removed files, or updated configure.in or some Makefile.am.
|
||||
Remember: simply adding a file to SVN does not mean it will be
|
||||
distributed. To distribute a file, you must update the corresponding
|
||||
Makefile.am.
|
||||
Running "make distcheck-light" is especially important if you have added or
|
||||
removed files, or updated configure.in or some Makefile.am. Remember: simply
|
||||
adding a file to SVN does not mean it will be distributed. To distribute a
|
||||
file, you must update the corresponding Makefile.am.
|
||||
|
||||
There is also "make distcheck", which runs an even stricter set of
|
||||
tests, but will not work unless you have all the optional libraries
|
||||
and features installed.
|
||||
|
||||
Distributed SCM systems
|
||||
-----------------------
|
||||
|
||||
Git and Mercurial (Hg) are two popular distributed SCM tools which provide a
|
||||
bridge to a SVN repository. This makes it possible for a new developer to stay
|
||||
synchronized with the latest changes to NUT, while keeping a local version
|
||||
history of their changes before they are merged by the core NUT developers.
|
||||
|
||||
A complete introduction to either Git or Mercurial is beyond the scope of this
|
||||
document, but many others have written excellent tutorials on both the DSCM
|
||||
tools, and their SVN interfaces.
|
||||
|
||||
Git and SVN
|
||||
~~~~~~~~~~~
|
||||
|
||||
The `git svn` tool synchronizes a Git repository with a
|
||||
link:http://www.kernel.org/pub/software/scm/git/docs/git-svn.html[SVN repository].
|
||||
|
||||
In many cases, NUT developers will not need access to the entire repository
|
||||
history - a snapshot starting at the most recent revision will work nicely:
|
||||
|
||||
git svn clone --revision HEAD svn://svn.debian.org/nut/trunk nut-git
|
||||
|
||||
From the resulting nut-git directory, you may use all of the Git commands to
|
||||
record your changes, and even create new branches for working on different
|
||||
aspects of the code.
|
||||
|
||||
Git offers a little more flexibility than the `svn update` command. You may
|
||||
fetch other developers' changes from SVN into your repository, but hold off on
|
||||
actually combining them with your branch until you have compared the two
|
||||
branches (for instance, with `gitk --all`).
|
||||
|
||||
To import the new SVN revisions, simply run the following command from any
|
||||
directory under your Git checkout (`nut-git` in the example above). Note that
|
||||
this only changes the history stored in your repository - it does not touch
|
||||
your checked-out files.
|
||||
|
||||
git svn fetch
|
||||
|
||||
Initially, the Git `master` branch tracks the SVN `trunk`. The `git svn`
|
||||
command updates the `remotes/trunk` reference every time you run `git svn
|
||||
fetch`, but it does not adjust the `master` branch automatically. To update
|
||||
your master branch with new SVN revisions, you can run the following commands:
|
||||
|
||||
git checkout master
|
||||
git svn fetch # (optional; this gets commits other than on your current branch)
|
||||
git svn rebase
|
||||
|
||||
You may create as many branches as you like in your local Git repository. When
|
||||
using `git svn`, the preferred way to combine your changes with SVN changes is
|
||||
to use `git rebase` on your local branch. This re-applies your branch's changes
|
||||
to the new SVN changes, much as though your branch were a series of patches.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
git checkout master
|
||||
git branch my-new-feature
|
||||
git checkout my-new-feature
|
||||
|
||||
# Hack away
|
||||
|
||||
git add changed-file.c
|
||||
git commit
|
||||
|
||||
# Someone committed something to SVN. Fetch it.
|
||||
|
||||
git svn fetch
|
||||
git rebase remotes/trunk
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
You are encouraged to use `git rebase -i` on your private Git branches to
|
||||
separate your changes into <<_patch_cohesion,logical changes>>.
|
||||
|
||||
From there, you can generate patches for the Tracker, or the nut-upsdev list.
|
||||
|
||||
If you are new to Git, but are familiar with SVN, the
|
||||
link:http://git-scm.com/course/svn.html[following link] may be of use.
|
||||
|
||||
|
||||
Mercurial and SVN
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Synchronizing a Mercurial repository against the NUT SVN repository should be
|
||||
similar in spirit to the Git method discussed above.
|
||||
link:http://mercurial.selenic.com/wiki/WorkingWithSubversion[This wiki page]
|
||||
discusses your options.
|
||||
|
||||
We would welcome any feedback about this process on the nut-upsdev mailing list.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue