[MEDIUM] add a maintenance mode to servers

This is a first attempt to add a maintenance mode on servers, using
the stat socket (in admin level).

It can be done with the following command :
   - disable server <backend>/<server>
   - enable  server <backend>/<server>

In this mode, no more checks will be performed on the server and it
will be marked as a special DOWN state (MAINT).

If some servers were tracking it, they'll go DOWN until the server
leaves the maintenance mode. The stats page and the CSV export also
display this special state.

This can be used to disable the server in haproxy before doing some
operations on this server itself. This is a good complement to the
"http-check disable-on-404" keyword and works in TCP mode.
diff --git a/src/checks.c b/src/checks.c
index f59fbbe..b235d9e 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -359,12 +359,16 @@
  * possible to other servers. It automatically recomputes the number of
  * servers, but not the map.
  */
-static void set_server_down(struct server *s)
+void set_server_down(struct server *s)
 {
 	struct server *srv;
 	struct chunk msg;
 	int xferred;
 
+	if (s->state & SRV_MAINTAIN) {
+		s->health = s->rise;
+	}
+
 	if (s->health == s->rise || s->tracked) {
 		int srv_was_paused = s->state & SRV_GOINGDOWN;
 
@@ -380,14 +384,19 @@
 
 		chunk_init(&msg, trash, sizeof(trash));
 
-		chunk_printf(&msg,
-			"%sServer %s/%s is DOWN", s->state & SRV_BACKUP ? "Backup " : "",
-			s->proxy->id, s->id);
+		if (s->state & SRV_MAINTAIN) {
+			chunk_printf(&msg,
+				"%sServer %s/%s is DOWN for maintenance", s->state & SRV_BACKUP ? "Backup " : "",
+				s->proxy->id, s->id);
+		} else {
+			chunk_printf(&msg,
+				"%sServer %s/%s is DOWN", s->state & SRV_BACKUP ? "Backup " : "",
+				s->proxy->id, s->id);
 
-		server_status_printf(&msg, s,
-					((!s->tracked && !(s->proxy->options2 & PR_O2_LOGHCHKS))?SSP_O_HCHK:0),
-					xferred);
-
+			server_status_printf(&msg, s,
+						((!s->tracked && !(s->proxy->options2 & PR_O2_LOGHCHKS))?SSP_O_HCHK:0),
+						xferred);
+		}
 		Warning("%s.\n", trash);
 
 		/* we don't send an alert if the server was previously paused */
@@ -403,18 +412,24 @@
 
 		if (s->state & SRV_CHECKED)
 			for(srv = s->tracknext; srv; srv = srv->tracknext)
-				set_server_down(srv);
+				if (! (srv->state & SRV_MAINTAIN))
+					/* Only notify tracking servers that are not already in maintenance. */
+					set_server_down(srv);
 	}
 
 	s->health = 0; /* failure */
 }
 
-static void set_server_up(struct server *s) {
+void set_server_up(struct server *s) {
 
 	struct server *srv;
 	struct chunk msg;
 	int xferred;
 
+	if (s->state & SRV_MAINTAIN) {
+		s->health = s->rise;
+	}
+
 	if (s->health == s->rise || s->tracked) {
 		if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
 			if (s->proxy->last_change < now.tv_sec)		// ignore negative times
@@ -448,20 +463,30 @@
 
 		chunk_init(&msg, trash, sizeof(trash));
 
-		chunk_printf(&msg,
-			"%sServer %s/%s is UP", s->state & SRV_BACKUP ? "Backup " : "",
-			s->proxy->id, s->id);
+		if (s->state & SRV_MAINTAIN) {
+			chunk_printf(&msg,
+				"%sServer %s/%s is UP (leaving maintenance)", s->state & SRV_BACKUP ? "Backup " : "",
+				s->proxy->id, s->id);
+		} else {
+			chunk_printf(&msg,
+				"%sServer %s/%s is UP", s->state & SRV_BACKUP ? "Backup " : "",
+				s->proxy->id, s->id);
 
-		server_status_printf(&msg, s,
-					((!s->tracked && !(s->proxy->options2 & PR_O2_LOGHCHKS))?SSP_O_HCHK:0),
-					xferred);
+			server_status_printf(&msg, s,
+						((!s->tracked && !(s->proxy->options2 & PR_O2_LOGHCHKS))?SSP_O_HCHK:0),
+						xferred);
+		}
 
 		Warning("%s.\n", trash);
 		send_log(s->proxy, LOG_NOTICE, "%s.\n", trash);
 
 		if (s->state & SRV_CHECKED)
 			for(srv = s->tracknext; srv; srv = srv->tracknext)
-				set_server_up(srv);
+				if (! (srv->state & SRV_MAINTAIN))
+					/* Only notify tracking servers if they're not in maintenance. */
+					set_server_up(srv);
+
+		s->state &= ~SRV_MAINTAIN;
 	}
 
 	if (s->health >= s->rise)
@@ -1007,7 +1032,7 @@
 		/* we don't send any health-checks when the proxy is stopped or when
 		 * the server should not be checked.
 		 */
-		if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
+		if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED || (s->state & SRV_MAINTAIN)) {
 			while (tick_is_expired(t->expire, now_ms))
 				t->expire = tick_add(t->expire, MS_TO_TICKS(s->inter));
 			return t;