Repository: trafficserver
Updated Branches:
  refs/heads/master 1d6f7d156 -> 683a377d1


TS-3367: add traffic_ctl, a new command-line interface to the management API

traffic_ctl is a new commanline to administer Traffic Server using
the management API. It uses the subcommand pattern, making the
syntax more regular and extensible than traffic_line.  This first
implementation is feature-equivalent to traffic_line.


Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/683a377d
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/683a377d
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/683a377d

Branch: refs/heads/master
Commit: 683a377d199bddb41b1b5497bb894778df44ff90
Parents: 1d6f7d1
Author: James Peach <[email protected]>
Authored: Tue Feb 3 12:56:26 2015 -0800
Committer: James Peach <[email protected]>
Committed: Mon Feb 23 13:36:06 2015 -0800

----------------------------------------------------------------------
 .gitignore                     |   1 +
 CHANGES                        |   2 +
 cmd/Makefile.am                |   5 +-
 cmd/traffic_ctl/Makefile.am    |  40 +++++++
 cmd/traffic_ctl/alarm.cc       | 137 +++++++++++++++++++++
 cmd/traffic_ctl/config.cc      | 216 +++++++++++++++++++++++++++++++++
 cmd/traffic_ctl/metric.cc      | 142 ++++++++++++++++++++++
 cmd/traffic_ctl/server.cc      | 174 +++++++++++++++++++++++++++
 cmd/traffic_ctl/storage.cc     |  56 +++++++++
 cmd/traffic_ctl/traffic_ctl.cc | 233 ++++++++++++++++++++++++++++++++++++
 cmd/traffic_ctl/traffic_ctl.h  | 201 +++++++++++++++++++++++++++++++
 configure.ac                   |   2 +
 lib/ts/ink_args.cc             |  49 +++++---
 lib/ts/ink_args.h              |  11 ++
 lib/ts/ink_llqueue.h           |   2 +-
 lib/ts/llqueue.cc              |   7 +-
 mgmt/api/INKMgmtAPI.cc         |  13 +-
 mgmt/api/include/mgmtapi.h     |   4 +-
 18 files changed, 1261 insertions(+), 34 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 5728268..044b972 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,6 +48,7 @@ pm_to_blib
 cmd/traffic_line/traffic_line
 cmd/traffic_shell/traffic_shell
 cmd/traffic_cop/traffic_cop
+cmd/traffic_ctl/traffic_ctl
 cmd/traffic_crashlog/traffic_crashlog
 cmd/traffic_top/traffic_top
 cmd/traffic_manager/traffic_manager

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 9511ce1..b3ba2ba 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,8 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache Traffic Server 5.3.0
 
+  *) [TS-3376] Add traffic_ctl, a new command line management tool.
+
   *) [TS-3403] Stop parsing command-line options at the first non-option.
 
   *) [TS-3402] Rationalize lock debugging infrastructure.

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/cmd/Makefile.am
----------------------------------------------------------------------
diff --git a/cmd/Makefile.am b/cmd/Makefile.am
index 3636cfe..b482056 100644
--- a/cmd/Makefile.am
+++ b/cmd/Makefile.am
@@ -17,14 +17,15 @@
 
 SUBDIRS = \
   traffic_cop \
+  traffic_ctl \
   traffic_crashlog \
   traffic_layout \
   traffic_line \
   traffic_manager \
   traffic_top \
-  traffic_via 
+  traffic_via
 
-if BUILD_WCCP 
+if BUILD_WCCP
 
 SUBDIRS += traffic_wccp
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/cmd/traffic_ctl/Makefile.am
----------------------------------------------------------------------
diff --git a/cmd/traffic_ctl/Makefile.am b/cmd/traffic_ctl/Makefile.am
new file mode 100644
index 0000000..51cc05c
--- /dev/null
+++ b/cmd/traffic_ctl/Makefile.am
@@ -0,0 +1,40 @@
+#
+# Makefile.am for the Enterprise Management module.
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+AM_CPPFLAGS = \
+  $(iocore_include_dirs) \
+  -I$(top_srcdir)/lib \
+  -I$(top_srcdir)/lib/ts \
+  -I$(top_srcdir)/mgmt/api/include
+
+bin_PROGRAMS = traffic_ctl
+
+traffic_ctl_SOURCES = \
+  alarm.cc \
+  config.cc \
+  metric.cc \
+  server.cc \
+  storage.cc \
+  traffic_ctl.cc
+
+traffic_ctl_LDFLAGS = @EXTRA_CXX_LDFLAGS@ @LIBTOOL_LINK_FLAGS@
+traffic_ctl_LDADD = \
+  $(top_builddir)/mgmt/api/libtsmgmt.la \
+  $(top_builddir)/lib/ts/libtsutil.la \
+  @LIBRESOLV@ @LIBTCL@

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/cmd/traffic_ctl/alarm.cc
----------------------------------------------------------------------
diff --git a/cmd/traffic_ctl/alarm.cc b/cmd/traffic_ctl/alarm.cc
new file mode 100644
index 0000000..404069c
--- /dev/null
+++ b/cmd/traffic_ctl/alarm.cc
@@ -0,0 +1,137 @@
+/** @file
+
+  traffic_ctl
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include "traffic_ctl.h"
+
+struct AlarmListPolicy
+{
+  typedef char * entry_type;
+
+  static void free(entry_type e) {
+    TSfree(e);
+  }
+
+  static entry_type cast(void * ptr) {
+    return (entry_type)ptr;
+  }
+};
+
+typedef CtrlMgmtList<AlarmListPolicy> CtrlAlarmList;
+
+static int
+alarm_list(unsigned argc, const char ** argv)
+{
+  TSMgmtError error;
+  CtrlAlarmList alarms;
+
+  if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments != 0) {
+    return CtrlCommandUsage("alarm list", NULL, 0);
+  }
+
+  error = TSActiveEventGetMlt(alarms.list);
+  if (error != TS_ERR_OKAY) {
+    CtrlMgmtError(error, "failed to fetch active alarms");
+    return CTRL_EX_ERROR;
+  }
+
+  while (!alarms.empty()) {
+    char * a = alarms.next();
+    printf("%s\n", a);
+    TSfree(a);
+  }
+
+  return CTRL_EX_OK;
+}
+
+static int
+alarm_clear(unsigned argc, const char ** argv)
+{
+  TSMgmtError error;
+  CtrlAlarmList alarms;
+
+  if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments != 0) {
+    return CtrlCommandUsage("alarm clear", NULL, 0);
+  }
+
+  // First get the active alarms ...
+  error = TSActiveEventGetMlt(alarms.list);
+  if (error != TS_ERR_OKAY) {
+    CtrlMgmtError(error, "failed to fetch active alarms");
+    return CTRL_EX_ERROR;
+  }
+
+  // Now resolve them all ...
+  while (!alarms.empty()) {
+    char * a = alarms.next();
+
+    error = TSEventResolve(a);
+    if (error != TS_ERR_OKAY) {
+      CtrlMgmtError(error, "failed to resolve %s", a);
+      TSfree(a);
+      return CTRL_EX_ERROR;
+    }
+
+    TSfree(a);
+  }
+
+  return CTRL_EX_OK;
+}
+
+static int
+alarm_resolve(unsigned argc, const char ** argv)
+{
+  TSMgmtError error;
+  CtrlAlarmList alarms;
+
+  if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments == 0) {
+    return CtrlCommandUsage("alarm resolve ALARM [ALARM ...]", NULL, 0);
+  }
+
+  for (unsigned i = 0; i < n_file_arguments; ++i) {
+    error = TSEventResolve(file_arguments[i]);
+    if (error != TS_ERR_OKAY) {
+      CtrlMgmtError(error, "failed to resolve %s", file_arguments[i]);
+      return CTRL_EX_ERROR;
+    }
+  }
+
+  return CTRL_EX_OK;
+}
+
+int
+subcommand_alarm(unsigned argc, const char ** argv)
+{
+  const subcommand commands[] =
+  {
+    { alarm_clear, "clear", "Clear all current alarms" },
+    { alarm_list, "list", "List all current alarms" },
+
+    // Note that we separate resolve one from resolve all for the same reasons 
that
+    // we have "metric zero" and "metric clear".
+    { alarm_resolve, "resolve", "Resolve the listed alarms" },
+    /* XXX describe a specific alarm? */
+    /* XXX raise an alarm? */
+  };
+
+  return CtrlGenericSubcommand("alarm", commands, countof(commands), argc, 
argv);
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/cmd/traffic_ctl/config.cc
----------------------------------------------------------------------
diff --git a/cmd/traffic_ctl/config.cc b/cmd/traffic_ctl/config.cc
new file mode 100644
index 0000000..66e10de
--- /dev/null
+++ b/cmd/traffic_ctl/config.cc
@@ -0,0 +1,216 @@
+/** @file
+
+  traffic_ctl
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include "traffic_ctl.h"
+#include <time.h>
+
+static std::string
+timestr(time_t tm)
+{
+  char buf[32];
+  return std::string(ctime_r(&tm, buf));
+}
+
+static void
+format_record(const CtrlMgmtRecord& record, bool recfmt)
+{
+  const char * typestr[] = {
+    "INT", "COUNTER", "FLOAT", "STRING", "UNDEFINED"
+  };
+
+  if (recfmt) {
+    // XXX Detect CONFIG or LOCAL ...
+    printf("CONFIG %s %s %s\n", record.name(), typestr[record.type()], 
record.c_str());
+  } else {
+    printf("%s: %s\n", record.name(), record.c_str());
+  }
+}
+
+static int
+config_get(unsigned argc, const char ** argv)
+{
+  int recfmt = 0;
+  const ArgumentDescription opts[] = {
+    { "records", '-', "Emit output in records.config format", "F", &recfmt, 
NULL, NULL },
+  };
+
+  if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) || 
n_file_arguments < 1) {
+    return CtrlCommandUsage("config get [OPTIONS] RECORD [RECORD ...]", opts, 
countof(opts));
+  }
+
+  for (unsigned i = 0; i < n_file_arguments; ++i) {
+    CtrlMgmtRecord record;
+    TSMgmtError error;
+
+    error = record.fetch(file_arguments[i]);
+    if (error != TS_ERR_OKAY) {
+      CtrlMgmtError(error, "failed to fetch %s", file_arguments[i]);
+      return CTRL_EX_ERROR;
+    }
+
+    format_record(record, recfmt);
+  }
+
+  return CTRL_EX_OK;
+}
+
+static int
+config_set(unsigned argc, const char ** argv)
+{
+  TSMgmtError error;
+  TSActionNeedT action;
+
+  if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments != 2) {
+    return CtrlCommandUsage("config set RECORD VALUE");
+  }
+
+  error = TSRecordSet(file_arguments[0], file_arguments[1], &action);
+  if (error  != TS_ERR_OKAY) {
+    CtrlMgmtError(error, "failed to set %s", file_arguments[0]);
+    return CTRL_EX_ERROR;
+  }
+
+  switch (action) {
+  case TS_ACTION_SHUTDOWN:
+    printf("set %s, full shutdown required\n", file_arguments[0]);
+    break;
+  case TS_ACTION_RESTART:
+    printf("set %s, restart required\n", file_arguments[0]);
+    break;
+  case TS_ACTION_RECONFIGURE:
+    // printf("Set %s, reconfiguration required\n", file_arguments[0]);
+    break;
+  case TS_ACTION_DYNAMIC:
+  default:
+    printf("set %s\n", file_arguments[0]);
+    break;
+  }
+
+  return CTRL_EX_OK;
+}
+
+static int
+config_match(unsigned argc, const char ** argv)
+{
+  int recfmt = 0;
+  const ArgumentDescription opts[] = {
+    { "records", '-', "Emit output in records.config format", "F", &recfmt, 
NULL, NULL },
+  };
+
+  if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) || 
n_file_arguments < 1) {
+    return CtrlCommandUsage("config match [OPTIONS] REGEX [REGEX ...]", opts, 
countof(opts));
+  }
+
+  for (unsigned i = 0; i < n_file_arguments; ++i) {
+    CtrlMgmtRecordList reclist;
+    TSMgmtError error;
+
+    // XXX filter the results to only match configuration records.
+
+    error = reclist.match(file_arguments[i]);
+    if (error != TS_ERR_OKAY) {
+      CtrlMgmtError(error, "failed to fetch %s", file_arguments[i]);
+      return CTRL_EX_ERROR;
+    }
+
+    while (!reclist.empty()) {
+      CtrlMgmtRecord record(reclist.next());
+      format_record(record, recfmt);
+    }
+  }
+
+  return CTRL_EX_OK;
+}
+
+static int
+config_reload(unsigned argc, const char ** argv)
+{
+  if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments != 0) {
+    return CtrlCommandUsage("config reload");
+  }
+
+  TSMgmtError error = TSReconfigure();
+  if (error != TS_ERR_OKAY) {
+    CtrlMgmtError(error, "configuration reload request failed");
+    return CTRL_EX_ERROR;
+  }
+
+  return CTRL_EX_OK;
+}
+
+static int
+config_status(unsigned argc, const char ** argv)
+{
+  if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments != 0) {
+    return CtrlCommandUsage("config status");
+  }
+
+  CtrlMgmtRecord version;
+  CtrlMgmtRecord configtime;
+  CtrlMgmtRecord starttime;
+  CtrlMgmtRecord reconfig;
+  CtrlMgmtRecord proxy;
+  CtrlMgmtRecord manager;
+  CtrlMgmtRecord cop;
+
+  CTRL_MGMT_CHECK(version.fetch("proxy.process.version.server.long"));
+  CTRL_MGMT_CHECK(starttime.fetch("proxy.node.restarts.proxy.start_time"));
+  CTRL_MGMT_CHECK(configtime.fetch("proxy.node.config.reconfigure_time"));
+  CTRL_MGMT_CHECK(reconfig.fetch("proxy.node.config.reconfigure_required"));
+  CTRL_MGMT_CHECK(proxy.fetch("proxy.node.config.restart_required.proxy"));
+  CTRL_MGMT_CHECK(manager.fetch("proxy.node.config.restart_required.manager"));
+  CTRL_MGMT_CHECK(cop.fetch("proxy.node.config.restart_required.cop"));
+
+  printf("%s\n", version.c_str());
+  printf("Started at %s", timestr((time_t)starttime.as_int()).c_str());
+  printf("Last reconfiguration at %s", 
timestr((time_t)configtime.as_int()).c_str());
+  printf("%s\n", reconfig.as_int() ? "Reconfiguration required" : 
"Configuration is current");
+
+  if (proxy.as_int()) {
+    printf("traffic_server requires restarting\n");
+  }
+  if (manager.as_int()) {
+    printf("traffic_manager requires restarting\n");
+  }
+  if (cop.as_int()) {
+    printf("traffic_cop requires restarting\n");
+  }
+
+  return CTRL_EX_OK;
+}
+
+int
+subcommand_config(unsigned argc, const char ** argv)
+{
+  const subcommand commands[] =
+  {
+    { CtrlUnimplementedCommand, "describe", "Show detailed information about 
configuration values" },
+    { config_get, "get", "Get one or more configuration values" },
+    { config_match, "match", "Get configuration matching a regular expression" 
},
+    { config_reload, "reload", "Request a configuration reload" },
+    { config_set, "set", "Set a configuration value" },
+    { config_status, "status", "Check the configuration status" },
+  };
+
+  return CtrlGenericSubcommand("config", commands, countof(commands), argc, 
argv);
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/cmd/traffic_ctl/metric.cc
----------------------------------------------------------------------
diff --git a/cmd/traffic_ctl/metric.cc b/cmd/traffic_ctl/metric.cc
new file mode 100644
index 0000000..5cfdbc3
--- /dev/null
+++ b/cmd/traffic_ctl/metric.cc
@@ -0,0 +1,142 @@
+/** @file
+
+  traffic_ctl
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include "traffic_ctl.h"
+
+static int
+metric_get(unsigned argc, const char ** argv)
+{
+  if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments < 1) {
+    return CtrlCommandUsage("metric get RECORD [RECORD ...]", NULL, 0);
+  }
+
+  for (unsigned i = 0; i < n_file_arguments; ++i) {
+    CtrlMgmtRecord record;
+    TSMgmtError error;
+
+    error = record.fetch(file_arguments[i]);
+    if (error != TS_ERR_OKAY) {
+      CtrlMgmtError(error, "failed to fetch %s", file_arguments[i]);
+      return CTRL_EX_ERROR;
+    }
+
+    printf("%s %s\n", record.name(), record.c_str());
+  }
+
+  return CTRL_EX_OK;
+}
+
+static int
+metric_match(unsigned argc, const char ** argv)
+{
+  if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments < 1) {
+    return CtrlCommandUsage("metric match [OPTIONS] REGEX [REGEX ...]", NULL, 
0);
+  }
+
+  for (unsigned i = 0; i < n_file_arguments; ++i) {
+    CtrlMgmtRecordList reclist;
+    TSMgmtError error;
+
+    // XXX filter the results to only match metric records.
+
+    error = reclist.match(file_arguments[i]);
+    if (error != TS_ERR_OKAY) {
+      CtrlMgmtError(error, "failed to fetch %s", file_arguments[i]);
+      return CTRL_EX_ERROR;
+    }
+
+    while (!reclist.empty()) {
+      CtrlMgmtRecord record(reclist.next());
+      printf("%s %s\n", record.name(), record.c_str());
+    }
+  }
+
+  return CTRL_EX_OK;
+}
+
+static int
+metric_clear(unsigned argc, const char ** argv)
+{
+  int cluster = 0;
+  TSMgmtError error;
+
+  const ArgumentDescription opts[] = {
+    { "cluster", '-', "Clear cluster metrics", "F", &cluster, NULL, NULL },
+  };
+
+  if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) || 
n_file_arguments != 0) {
+    return CtrlCommandUsage("config clear [OPTIONS]", opts, countof(opts));
+  }
+
+  error = TSStatsReset(cluster, NULL);
+  if (error != TS_ERR_OKAY) {
+    CtrlMgmtError(error, "failed to clear %smetrics", cluster ? "cluster " : 
"");
+    return CTRL_EX_ERROR;
+  }
+
+  return CTRL_EX_OK;
+}
+
+static int
+metric_zero(unsigned argc, const char ** argv)
+{
+  int cluster = 0;
+  TSMgmtError error;
+
+  const ArgumentDescription opts[] = {
+    { "cluster", '-', "Zero cluster metrics", "F", &cluster, NULL, NULL },
+  };
+
+  if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) || 
n_file_arguments == 0) {
+    return CtrlCommandUsage("config zero [OPTIONS]", opts, countof(opts));
+  }
+
+  for (unsigned i = 0; i < n_file_arguments; ++i) {
+    error = TSStatsReset(cluster, NULL);
+    if (error != TS_ERR_OKAY) {
+      CtrlMgmtError(error, "failed to clear %smetrics", cluster ? "cluster " : 
"");
+      return CTRL_EX_ERROR;
+    }
+  }
+
+  return CTRL_EX_OK;
+}
+
+int
+subcommand_metric(unsigned argc, const char ** argv)
+{
+  const subcommand commands[] =
+  {
+    { metric_get, "get", "Get one or more metric values" },
+    { metric_clear, "clear", "Clear all metric values" },
+    { CtrlUnimplementedCommand, "describe", "Show detailed information about 
one or more metric values" },
+    { metric_match, "match", "Get metrics matching a regular expression" },
+    { CtrlUnimplementedCommand, "monitor", "Display the value of a metric over 
time" },
+
+    // We could allow clearing all the metrics in the "clear" subcommand, but 
that seems error-prone. It
+    // would be too easy to just expect a help message and accidentally nuke 
all the metrics.
+    { metric_zero, "zero", "Clear one or more metric values" },
+  };
+
+  return CtrlGenericSubcommand("metric", commands, countof(commands), argc, 
argv);
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/cmd/traffic_ctl/server.cc
----------------------------------------------------------------------
diff --git a/cmd/traffic_ctl/server.cc b/cmd/traffic_ctl/server.cc
new file mode 100644
index 0000000..3b0e387
--- /dev/null
+++ b/cmd/traffic_ctl/server.cc
@@ -0,0 +1,174 @@
+/** @file
+
+  traffic_ctl
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include "traffic_ctl.h"
+
+static int drain = 0;
+
+const ArgumentDescription opts[] = {
+  { "drain", '-', "Wait for client connections to drain before restarting", 
"F", &drain, NULL, NULL },
+};
+
+static int
+bounce(unsigned argc, const char ** argv, unsigned flags)
+{
+  TSMgmtError error;
+  const char * usage = (flags & TS_RESTART_OPT_CLUSTER) ?  "cluster bounce 
[OPTIONS]" :  "server bounce [OPTIONS]";
+
+  if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) || 
n_file_arguments != 0) {
+    return CtrlCommandUsage(usage, opts, countof(opts));
+  }
+
+  if (drain) {
+    flags |= TS_RESTART_OPT_DRAIN;
+  }
+
+  error = TSBounce(flags);
+  if (error != TS_ERR_OKAY) {
+    CtrlMgmtError(error, "%s bounce failed", (flags & TS_RESTART_OPT_CLUSTER) 
? "cluster" : "server");
+    return CTRL_EX_ERROR;
+  }
+
+  return CTRL_EX_OK;
+}
+
+static int
+restart(unsigned argc, const char ** argv, unsigned flags)
+{
+  TSMgmtError error;
+  const char * usage = (flags & TS_RESTART_OPT_CLUSTER) ?  "cluster restart 
[OPTIONS]" :  "server restart [OPTIONS]";
+
+  if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) || 
n_file_arguments != 0) {
+    return CtrlCommandUsage(usage, opts, countof(opts));
+  }
+
+  if (drain) {
+    flags |= TS_RESTART_OPT_DRAIN;
+  }
+
+  error = TSRestart(flags);
+  if (error != TS_ERR_OKAY) {
+    CtrlMgmtError(error, "%s restart failed", (flags & TS_RESTART_OPT_CLUSTER) 
? "cluster" : "server");
+    return CTRL_EX_ERROR;
+  }
+
+  return CTRL_EX_OK;
+}
+
+static int
+cluster_bounce(unsigned argc, const char ** argv)
+{
+  return bounce(argc, argv, TS_RESTART_OPT_CLUSTER);
+}
+
+static int
+server_bounce(unsigned argc, const char ** argv)
+{
+  return bounce(argc, argv, TS_RESTART_OPT_NONE);
+}
+
+static int
+cluster_restart(unsigned argc, const char ** argv)
+{
+  return restart(argc, argv, TS_RESTART_OPT_CLUSTER);
+}
+
+static int
+server_restart(unsigned argc, const char ** argv)
+{
+  return restart(argc, argv, TS_RESTART_OPT_NONE);
+}
+
+static int
+server_backtrace(unsigned argc, const char ** argv)
+{
+  TSMgmtError error;
+  TSString trace = NULL;
+
+  if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments != 0) {
+    return CtrlCommandUsage("server backtrace");
+  }
+
+  error = TSProxyBacktraceGet(0, &trace);
+  if (error != TS_ERR_OKAY) {
+    CtrlMgmtError(error, "server backtrace failed");
+    return CTRL_EX_ERROR;
+  }
+
+  printf("%s\n", trace);
+  TSfree(trace);
+  return CTRL_EX_OK;
+}
+
+static int
+server_status(unsigned argc, const char ** argv)
+{
+  if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments != 0) {
+    return CtrlCommandUsage("server status");
+  }
+
+  switch (TSProxyStateGet()) {
+  case TS_PROXY_ON:
+    printf("Proxy -- on\n");
+    break;
+  case TS_PROXY_OFF:
+    printf("Proxy -- off\n");
+    break;
+  case TS_PROXY_UNDEFINED:
+    printf("Proxy status undefined\n");
+    break;
+  }
+
+  // XXX Surely we can report more useful status that this !?!!
+
+  return CTRL_EX_OK;
+}
+
+int
+subcommand_cluster(unsigned argc, const char ** argv)
+{
+  const subcommand commands[] =
+  {
+    { cluster_bounce, "bounce", "Restart traffic_server across the cluster" },
+    { cluster_restart, "restart", "Restart traffic_server and traffic_server  
across the cluster" },
+    { CtrlUnimplementedCommand, "status", "Show the cluster status" },
+  };
+
+  return CtrlGenericSubcommand("cluster", commands, countof(commands), argc, 
argv);
+}
+
+int
+subcommand_server(unsigned argc, const char ** argv)
+{
+  const subcommand commands[] =
+  {
+    { server_bounce, "bounce", "Restart traffic_server" },
+    { server_restart, "restart", "Restart traffic_server and traffic_server" },
+    { server_backtrace, "backtrace", "Show a full stack trace of the 
traffic_server process" },
+    { server_status, "status", "Show the proxy status" },
+
+    /* XXX do the 'shutdown' and 'startup' commands make sense? */
+  };
+
+  return CtrlGenericSubcommand("server", commands, countof(commands), argc, 
argv);
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/cmd/traffic_ctl/storage.cc
----------------------------------------------------------------------
diff --git a/cmd/traffic_ctl/storage.cc b/cmd/traffic_ctl/storage.cc
new file mode 100644
index 0000000..fbd6720
--- /dev/null
+++ b/cmd/traffic_ctl/storage.cc
@@ -0,0 +1,56 @@
+/** @file
+
+  traffic_ctl
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include "traffic_ctl.h"
+
+static int
+storage_offline(unsigned argc, const char ** argv)
+{
+  if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments == 0) {
+    return CtrlCommandUsage("storage offline DEVICE [DEVICE ...]");
+  }
+
+  for (unsigned i = 0; i < n_file_arguments; ++i) {
+    TSMgmtError error;
+
+    error = TSStorageDeviceCmdOffline(file_arguments[i]);
+    if (error  != TS_ERR_OKAY) {
+      CtrlMgmtError(error, "failed to take %s offline", file_arguments[0]);
+      return CTRL_EX_ERROR;
+    }
+  }
+
+  return CTRL_EX_OK;
+}
+
+int
+subcommand_storage(unsigned argc, const char ** argv)
+{
+  const subcommand commands[] =
+  {
+    { storage_offline, "offline", "Take one or more storage volumes offline" },
+    { CtrlUnimplementedCommand, "status", "Show the storage configuration" },
+  };
+
+  return CtrlGenericSubcommand("storage", commands, countof(commands), argc, 
argv);
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/cmd/traffic_ctl/traffic_ctl.cc
----------------------------------------------------------------------
diff --git a/cmd/traffic_ctl/traffic_ctl.cc b/cmd/traffic_ctl/traffic_ctl.cc
new file mode 100644
index 0000000..39b81fb
--- /dev/null
+++ b/cmd/traffic_ctl/traffic_ctl.cc
@@ -0,0 +1,233 @@
+/** @file
+
+  traffic_ctl
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include "traffic_ctl.h"
+
+AppVersionInfo CtrlVersionInfo;
+
+const char *
+CtrlMgmtRecord::name() const
+{
+  return this->ele->rec_name;
+}
+
+TSRecordT
+CtrlMgmtRecord::type() const
+{
+  return this->ele->rec_type;
+}
+
+int64_t
+CtrlMgmtRecord::as_int() const
+{
+  switch (this->ele->rec_type) {
+  case TS_REC_INT:
+    return this->ele->valueT.int_val;
+  case TS_REC_COUNTER:
+    return this->ele->valueT.counter_val;
+  default:
+    return 0;
+  }
+}
+
+const char *
+CtrlMgmtRecord::c_str() const
+{
+  switch (this->ele->rec_type) {
+  case TS_REC_INT:
+    snprintf(this->nbuf, sizeof(this->nbuf), "%" PRId64, 
this->ele->valueT.int_val);
+    return this->nbuf;
+  case TS_REC_COUNTER:
+    snprintf(this->nbuf, sizeof(this->nbuf), "%" PRId64, 
this->ele->valueT.counter_val);
+    return this->nbuf;
+  case TS_REC_FLOAT:
+    snprintf(this->nbuf, sizeof(this->nbuf), "%f", 
this->ele->valueT.float_val);
+    return this->nbuf;
+  case TS_REC_STRING:
+    return this->ele->valueT.string_val;
+  default:
+    return "(invalid)";
+  }
+}
+
+TSMgmtError
+CtrlMgmtRecord::fetch(const char * name)
+{
+  return TSRecordGet(name, this->ele);
+}
+
+TSMgmtError
+CtrlMgmtRecordList::match(const char * name)
+{
+  return TSRecordGetMatchMlt(name, this->list);
+}
+
+void
+CtrlMgmtError(TSMgmtError err, const char * fmt, ...)
+{
+  ats_scoped_str msg(TSGetErrorMessage(err));
+
+  if (fmt) {
+    va_list ap;
+
+    fprintf(stderr, "%s: ", program_name);
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+
+    fprintf(stderr, ": %s\n", (const char *)msg);
+  } else {
+    fprintf(stderr, "%s: %s\n", program_name, (const char *)msg);
+  }
+
+}
+
+int
+CtrlSubcommandUsage(const char * name, const subcommand * cmds, unsigned 
ncmds, const ArgumentDescription * desc, unsigned ndesc)
+{
+  const char * opt = ndesc ? "[OPTIONS]" : "";
+  const char * sep = (ndesc && name) ? " " : "";
+
+  fprintf(stderr, "Usage: traffic_ctl %s%s%s CMD [ARGS 
...]\n\nSubcommands:\n", name ? name : "", sep, opt);
+
+  for (unsigned i = 0; i < ncmds; ++i) {
+    fprintf(stderr, "    %-16s%s\n", cmds[i].name, cmds[i].help);
+  }
+
+  if (ndesc) {
+    usage(desc, ndesc, "\nOptions:");
+  }
+
+  return CTRL_EX_USAGE;
+}
+
+int
+CtrlCommandUsage(const char * msg, const ArgumentDescription * desc, unsigned 
ndesc)
+{
+  fprintf(stderr, "Usage: traffic_ctl %s\n", msg);
+
+  if (ndesc) {
+    usage(desc, ndesc, "\nOptions:");
+  }
+
+  return CTRL_EX_USAGE;
+}
+
+bool
+CtrlProcessArguments(int /* argc */, const char ** argv, const 
ArgumentDescription * desc, unsigned ndesc)
+{
+  n_file_arguments = 0;
+  return process_args_ex(&CtrlVersionInfo, desc, ndesc, argv);
+}
+
+int
+CtrlUnimplementedCommand(unsigned /* argc */, const char ** argv)
+{
+  CtrlDebug("the '%s' command is not implemented", *argv);
+  return CTRL_EX_UNIMPLEMENTED;
+}
+
+int
+CtrlGenericSubcommand(const char * name, const subcommand * cmds, unsigned 
ncmds, unsigned argc, const char ** argv)
+{
+  CtrlCommandLine cmdline;
+
+  // Process command line arguments and dump into variables
+  if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments < 1) {
+    return CtrlSubcommandUsage(name, cmds, ncmds, NULL, 0);
+  }
+
+  cmdline.init(n_file_arguments, file_arguments);
+
+  for (unsigned i = 0; i < ncmds; ++i) {
+    if (strcmp(file_arguments[0], cmds[i].name) == 0) {
+      return cmds[i].handler(cmdline.argc(), cmdline.argv());
+    }
+  }
+
+  return CtrlSubcommandUsage(name, cmds, ncmds, NULL, 0);
+}
+
+int
+main(int argc, const char **argv)
+{
+  TSMgmtError status;
+  CtrlCommandLine cmdline;
+  int debug = false;
+
+  CtrlVersionInfo.setup(PACKAGE_NAME, "traffic_ctl", PACKAGE_VERSION, 
__DATE__, __TIME__, BUILD_MACHINE, BUILD_PERSON, "");
+  program_name = CtrlVersionInfo.AppStr;
+
+  ArgumentDescription argument_descriptions[] = {
+    { "debug", '-', "Enable debugging output", "F", &debug, NULL, NULL },
+    HELP_ARGUMENT_DESCRIPTION(),
+    VERSION_ARGUMENT_DESCRIPTION()
+  };
+
+  const subcommand commands[] = {
+    { subcommand_alarm, "alarm", "Manipulate alarms" },
+    { subcommand_cluster, "cluster", "Stop, restart and examine the cluster" },
+    { subcommand_config, "config", "Manipulate configuration records" },
+    { subcommand_metric, "metric", "Manipulate performance metrics" },
+    { subcommand_server, "server", "Stop, restart and examine the server" },
+    { subcommand_storage, "storage", "Manipulate cache storage" },
+  };
+
+  diags = new Diags("" /* tags */, "" /* actions */, stderr);
+
+  // Process command line arguments and dump into variables
+  if (!CtrlProcessArguments(argc, argv, argument_descriptions, 
countof(argument_descriptions))) {
+    return CtrlSubcommandUsage(NULL, commands, countof(commands), 
argument_descriptions, countof(argument_descriptions));
+  }
+
+  if (debug) {
+    diags->activate_taglist("traffic_ctl", DiagsTagType_Debug);
+    diags->config.enabled[DiagsTagType_Debug] = true;
+    diags->show_location = true;
+  }
+
+  CtrlDebug("debug logging active");
+
+  if (n_file_arguments < 1) {
+    return CtrlSubcommandUsage(NULL, commands, countof(commands), 
argument_descriptions, countof(argument_descriptions));
+  }
+
+  status = TSInit(NULL, static_cast<TSInitOptionT>(TS_MGMT_OPT_NO_EVENTS | 
TS_MGMT_OPT_NO_SOCK_TESTS));
+  if (status != TS_ERR_OKAY) {
+    CtrlMgmtError(status, "failed to attach to the API server");
+    return CTRL_EX_UNAVAILABLE;
+  }
+
+  for (unsigned i = 0; i < countof(commands); ++i) {
+    if (strcmp(file_arguments[0], commands[i].name) == 0) {
+      CtrlCommandLine cmdline;
+
+      cmdline.init(n_file_arguments, file_arguments);
+      return commands[i].handler(cmdline.argc(), cmdline.argv());
+    }
+  }
+
+  // Done with the mgmt API.
+  TSTerminate();
+  return CtrlSubcommandUsage(NULL, commands, countof(commands), 
argument_descriptions, countof(argument_descriptions));
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/cmd/traffic_ctl/traffic_ctl.h
----------------------------------------------------------------------
diff --git a/cmd/traffic_ctl/traffic_ctl.h b/cmd/traffic_ctl/traffic_ctl.h
new file mode 100644
index 0000000..62d2c5e
--- /dev/null
+++ b/cmd/traffic_ctl/traffic_ctl.h
@@ -0,0 +1,201 @@
+/** @file
+
+  traffic_ctl
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#ifndef _TRAFFIC_CTRL_H_
+#define _TRAFFIC_CTRL_H_
+
+#include "libts.h"
+#include "mgmtapi.h"
+#include "ink_args.h"
+#include "I_Version.h"
+
+#include <vector>
+
+struct subcommand
+{
+  int (*handler) (unsigned, const char **);
+  const char * name;
+  const char * help;
+};
+
+extern AppVersionInfo CtrlVersionInfo;
+
+#define CtrlDebug(...) Debug("traffic_ctl", __VA_ARGS__)
+
+void CtrlMgmtError(TSMgmtError err, const char * fmt, ...) TS_PRINTFLIKE(2, 3);
+int CtrlSubcommandUsage(const char * name, const subcommand * cmds, unsigned 
ncmds, const ArgumentDescription * desc, unsigned ndesc);
+int CtrlCommandUsage(const char * msg, const ArgumentDescription * desc = 
NULL, unsigned ndesc = 0);
+
+bool CtrlProcessArguments(int argc, const char ** argv, const 
ArgumentDescription * desc, unsigned ndesc);
+int CtrlUnimplementedCommand(unsigned argc, const char ** argv);
+
+int CtrlGenericSubcommand(const char *, const subcommand * cmds, unsigned 
ncmds, unsigned argc, const char ** argv);
+
+#define CTRL_MGMT_CHECK(expr) do { \
+  TSMgmtError e = (expr); \
+  if (e != TS_ERR_OKAY) {  \
+    CtrlDebug("%s failed with status %d", #expr, e);\
+    CtrlMgmtError(e, NULL); \
+    return CTRL_EX_ERROR; \
+  } \
+} while (0)
+
+struct CtrlMgmtRecord
+{
+  explicit CtrlMgmtRecord(TSRecordEle * e) : ele(e) {
+  }
+
+  CtrlMgmtRecord() : ele(TSRecordEleCreate()) {
+  }
+
+  ~CtrlMgmtRecord() {
+    if (this->ele) {
+      TSRecordEleDestroy(this->ele);
+    }
+  }
+
+  TSMgmtError fetch(const char *);
+  const char * name() const;
+  TSRecordT type() const;
+  const char * c_str() const;
+
+  int64_t as_int() const;
+
+private:
+  CtrlMgmtRecord(const CtrlMgmtRecord&); // disabled
+  CtrlMgmtRecord& operator=(const CtrlMgmtRecord&); // disabled
+
+  TSRecordEle * ele;
+  mutable char nbuf[32];
+};
+
+struct CtrlMgmtRecordList
+{
+  CtrlMgmtRecordList() : list(TSListCreate()) {
+  }
+
+  ~CtrlMgmtRecordList() {
+    this->clear();
+    TSListDestroy(this->list);
+  }
+
+  bool empty() const {
+    return TSListIsEmpty(this->list);
+  }
+
+  void clear() const {
+    while (!this->empty()) {
+        TSRecordEleDestroy((TSRecordEle *)TSListDequeue(this->list));
+    }
+  }
+
+  // Return (ownership of) the next list entry.
+  TSRecordEle * next() {
+    return (TSRecordEle *)TSListDequeue(this->list);
+  }
+
+  TSMgmtError match(const char *);
+
+private:
+  CtrlMgmtRecordList(const CtrlMgmtRecordList&); // disabled
+  CtrlMgmtRecordList& operator=(const CtrlMgmtRecordList&); // disabled
+
+  TSList list;
+};
+
+template<typename T>
+struct CtrlMgmtList
+{
+  CtrlMgmtList() : list(TSListCreate()) {
+  }
+
+  ~CtrlMgmtList() {
+    this->clear();
+    TSListDestroy(this->list);
+  }
+
+  bool empty() const {
+    return TSListIsEmpty(this->list);
+  }
+
+  void clear() const {
+    while (!this->empty()) {
+      T::free(T::cast(TSListDequeue(this->list)));
+    }
+  }
+
+  // Return (ownership of) the next list entry.
+  typename T::entry_type next() {
+    return T::cast(TSListDequeue(this->list));
+  }
+
+  TSList list;
+
+private:
+  CtrlMgmtList(const CtrlMgmtList&); // disabled
+  CtrlMgmtList& operator=(const CtrlMgmtList&); // disabled
+};
+
+struct CtrlCommandLine
+{
+  CtrlCommandLine() {
+    this->args.push_back(NULL);
+  }
+
+  void init(unsigned argc, const char ** argv) {
+    this->args.clear();
+    for (unsigned i = 0; i < argc; ++i) {
+      this->args.push_back(argv[i]);
+    }
+
+    // Always NULL-terminate to keep ink_args happy. Note that we adjust arg() 
accordingly.
+    this->args.push_back(NULL);
+  }
+
+  unsigned argc() {
+    return args.size() - 1;
+  }
+
+  const char ** argv() {
+    return &args[0];
+  }
+
+private:
+  std::vector<const char *> args;
+};
+
+int subcommand_alarm(unsigned argc, const char ** argv);
+int subcommand_cluster(unsigned argc, const char ** argv);
+int subcommand_config(unsigned argc, const char ** argv);
+int subcommand_metric(unsigned argc, const char ** argv);
+int subcommand_server(unsigned argc, const char ** argv);
+int subcommand_storage(unsigned argc, const char ** argv);
+
+// Exit status codes, following BSD's sysexits(3)
+#define CTRL_EX_OK            0
+#define CTRL_EX_ERROR         2
+#define CTRL_EX_UNIMPLEMENTED 3
+#define CTRL_EX_USAGE         EX_USAGE
+#define CTRL_EX_UNAVAILABLE   69
+
+#endif /* _TRAFFIC_CTRL_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 11cadf1..0442407 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1492,6 +1492,7 @@ AC_CHECK_HEADERS([sys/types.h \
                   math.h \
                   stdint.h \
                   stdbool.h \
+                  sysexits.h \
                   net/ppp_defs.h \
                   ifaddrs.h\
                   readline/readline.h \
@@ -1860,6 +1861,7 @@ AC_CONFIG_FILES([
   cmd/Makefile
   cmd/traffic_cop/Makefile
   cmd/traffic_crashlog/Makefile
+  cmd/traffic_ctl/Makefile
   cmd/traffic_layout/Makefile
   cmd/traffic_line/Makefile
   cmd/traffic_manager/Makefile

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/lib/ts/ink_args.cc
----------------------------------------------------------------------
diff --git a/lib/ts/ink_args.cc b/lib/ts/ink_args.cc
index de4fb5d..c121813 100644
--- a/lib/ts/ink_args.cc
+++ b/lib/ts/ink_args.cc
@@ -72,9 +72,9 @@ append_file_argument(const char * arg)
     file_arguments[n_file_arguments++] = arg;
 }
 
-static void
+static bool
 process_arg(const AppVersionInfo * appinfo, const ArgumentDescription * 
argument_descriptions,
-            unsigned n_argument_descriptions, int i, const char ***argv, const 
char *usage_string)
+            unsigned n_argument_descriptions, int i, const char ***argv)
 {
   const char *arg = NULL;
 
@@ -85,14 +85,15 @@ process_arg(const AppVersionInfo * appinfo, const 
ArgumentDescription * argument
 
   if (argument_descriptions[i].type) {
     char type = argument_descriptions[i].type[0];
-    if (type == 'F' || type == 'f')
+    if (type == 'F' || type == 'f') {
       *(int *) argument_descriptions[i].location = type == 'F' ? 1 : 0;
-    else if (type == 'T')
+    } else if (type == 'T') {
       *(int *) argument_descriptions[i].location = !*(int *) 
argument_descriptions[i].location;
-    else {
+    } else {
       arg = *++(**argv) ? **argv : *++(*argv);
-      if (!arg)
-        usage(argument_descriptions, n_argument_descriptions, usage_string);
+      if (!arg) {
+        return false;
+      }
       switch (type) {
       case 'I':
         *(int *) argument_descriptions[i].location = atoi(arg);
@@ -118,8 +119,12 @@ process_arg(const AppVersionInfo * appinfo, const 
ArgumentDescription * argument
       **argv += strlen(**argv) - 1;
     }
   }
-  if (argument_descriptions[i].pfn)
+
+  if (argument_descriptions[i].pfn) {
     argument_descriptions[i].pfn(argument_descriptions, 
n_argument_descriptions, arg);
+  }
+
+  return true;
 }
 
 
@@ -160,6 +165,15 @@ show_argument_configuration(const ArgumentDescription * 
argument_descriptions, u
 void
 process_args(const AppVersionInfo * appinfo, const ArgumentDescription * 
argument_descriptions, unsigned n_argument_descriptions, const char **argv, 
const char *usage_string)
 {
+  if (!process_args_ex(appinfo, argument_descriptions, 
n_argument_descriptions, argv)) {
+      usage(argument_descriptions, n_argument_descriptions, usage_string);
+  }
+}
+
+bool
+process_args_ex(const AppVersionInfo * appinfo, const ArgumentDescription * 
argument_descriptions,
+                  unsigned n_argument_descriptions, const char **argv)
+{
   unsigned i = 0;
   //
   // Grab Environment Variables
@@ -210,23 +224,28 @@ process_args(const AppVersionInfo * appinfo, const 
ArgumentDescription * argumen
       for (i = 0; i < n_argument_descriptions; i++)
         if (!strcmp(argument_descriptions[i].name, (*argv) + 2)) {
           *argv += strlen(*argv) - 1;
-          process_arg(appinfo, argument_descriptions, n_argument_descriptions, 
i, &argv, usage_string);
+          if (!process_arg(appinfo, argument_descriptions, 
n_argument_descriptions, i, &argv)) {
+            return false;
+          }
           break;
         }
-      if (i >= n_argument_descriptions)
-        usage(argument_descriptions, n_argument_descriptions, usage_string);
+      if (i >= n_argument_descriptions) {
+        return false;
+      }
     } else {
       // Deal with (possibly combined) short options ...
       while (*++(*argv)) {
         for (i = 0; i < n_argument_descriptions; i++) {
           if (argument_descriptions[i].key == **argv) {
-            process_arg(appinfo, argument_descriptions, 
n_argument_descriptions, i, &argv, usage_string);
+            if (!process_arg(appinfo, argument_descriptions, 
n_argument_descriptions, i, &argv)) {
+              return false;
+            }
             break;
           }
         }
 
         if (i >= n_argument_descriptions) {
-          usage(argument_descriptions, n_argument_descriptions, usage_string);
+          return false;
         }
       }
     }
@@ -239,6 +258,8 @@ process_args(const AppVersionInfo * appinfo, const 
ArgumentDescription * argumen
       append_file_argument(*argv);
     }
   }
+
+  return true;
 }
 
 void
@@ -312,5 +333,5 @@ usage(const ArgumentDescription * argument_descriptions, 
unsigned n_argument_des
     }
     fprintf(stderr, " %s\n", argument_descriptions[i].description);
   }
-  _exit(1);
+  exit(EX_USAGE);
 }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/lib/ts/ink_args.h
----------------------------------------------------------------------
diff --git a/lib/ts/ink_args.h b/lib/ts/ink_args.h
index aedd0f8..824f919 100644
--- a/lib/ts/ink_args.h
+++ b/lib/ts/ink_args.h
@@ -31,6 +31,14 @@ Process arguments
 #include "ink_defs.h"
 #include "ink_apidefs.h"
 
+#if HAVE_SYSEXITS_H
+#include <sysexits.h>
+#endif
+
+#ifndef EX_USAGE
+#define EX_USAGE 64
+#endif
+
 #define MAX_FILE_ARGUMENTS 100
 
 struct ArgumentDescription;
@@ -80,4 +88,7 @@ void usage(const ArgumentDescription * argument_descriptions, 
unsigned n_argumen
 void process_args(const AppVersionInfo * appinfo, const ArgumentDescription * 
argument_descriptions,
                   unsigned n_argument_descriptions, const char **argv, const 
char *usage_string = 0);
 
+bool process_args_ex(const AppVersionInfo * appinfo, const ArgumentDescription 
* argument_descriptions,
+                  unsigned n_argument_descriptions, const char **argv);
+
 #endif /*_INK_ARGS_H*/

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/lib/ts/ink_llqueue.h
----------------------------------------------------------------------
diff --git a/lib/ts/ink_llqueue.h b/lib/ts/ink_llqueue.h
index 670ec2d..67df59d 100644
--- a/lib/ts/ink_llqueue.h
+++ b/lib/ts/ink_llqueue.h
@@ -49,7 +49,7 @@ typedef struct llq_s
 LLQ *create_queue(void);
 int enqueue(LLQ * q, void *data);
 void *dequeue(LLQ * q);
-int queue_is_empty(LLQ * q);
+bool queue_is_empty(LLQ * q);
 uint64_t queue_len(LLQ * Q);
 uint64_t queue_highwater(LLQ * Q);
 void delete_queue(LLQ * Q);     /* only deletes an empty queue but

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/lib/ts/llqueue.cc
----------------------------------------------------------------------
diff --git a/lib/ts/llqueue.cc b/lib/ts/llqueue.cc
index 38f08d8..81125e2 100644
--- a/lib/ts/llqueue.cc
+++ b/lib/ts/llqueue.cc
@@ -169,17 +169,14 @@ queue_highwater(LLQ * Q)
  *
  *---------------------------------------------------------------------------
  */
-int
+bool
 queue_is_empty(LLQ * Q)
 {
   uint64_t len;
 
   len = queue_len(Q);
 
-  if (len)
-    return 0;
-  else
-    return 1;
+  return len == 0;
 }
 
 void *

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/mgmt/api/INKMgmtAPI.cc
----------------------------------------------------------------------
diff --git a/mgmt/api/INKMgmtAPI.cc b/mgmt/api/INKMgmtAPI.cc
index 55a2e41..c84d83f 100644
--- a/mgmt/api/INKMgmtAPI.cc
+++ b/mgmt/api/INKMgmtAPI.cc
@@ -126,18 +126,11 @@ TSListDequeue(TSList l)
 tsapi bool
 TSListIsEmpty(TSList l)
 {
-  int ret;
-
   ink_assert(l);
   if (!l)
     return true;                // list doesn't exist, so it's empty
 
-  ret = queue_is_empty((LLQ *) l);      /* returns 0 if empty, non-zero if not 
empty */
-  if (ret == 0) {               /* empty */
-    return true;
-  } else {
-    return false;
-  }
+  return queue_is_empty((LLQ *) l);
 }
 
 tsapi int
@@ -1449,7 +1442,7 @@ TSStatsReset(bool cluster, const char *name)
 /* Call the CfgFileIO variable operations */
 
 tsapi TSMgmtError
-TSRecordGet(char *rec_name, TSRecordEle * rec_val)
+TSRecordGet(const char *rec_name, TSRecordEle * rec_val)
 {
   return MgmtRecordGet(rec_name, rec_val);
 }
@@ -2282,7 +2275,7 @@ TSEventSignal(char *event_name, ...)
 }
 
 tsapi TSMgmtError
-TSEventResolve(char *event_name)
+TSEventResolve(const char *event_name)
 {
   return EventResolve(event_name);
 }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/mgmt/api/include/mgmtapi.h
----------------------------------------------------------------------
diff --git a/mgmt/api/include/mgmtapi.h b/mgmt/api/include/mgmtapi.h
index 2b78693..a04bb11 100644
--- a/mgmt/api/include/mgmtapi.h
+++ b/mgmt/api/include/mgmtapi.h
@@ -1117,7 +1117,7 @@ extern "C"
  *         rec_val  - allocated TSRecordEle structure, value stored inside
  * Output: TSMgmtError (if the rec_name does not exist, returns TS_ERR_FAIL)
  */
-  tsapi TSMgmtError TSRecordGet(char *rec_name, TSRecordEle * rec_val);
+  tsapi TSMgmtError TSRecordGet(const char *rec_name, TSRecordEle * rec_val);
 
 /* TSRecordGet*: gets a record w/ a known type
  * Input:  rec_name - the name of the record (proxy.config.record_name)
@@ -1187,7 +1187,7 @@ extern "C"
  * Input:  event_name - event to resolve
  * Output: TSMgmtError
  */
-  tsapi TSMgmtError TSEventResolve(char *event_name);
+  tsapi TSMgmtError TSEventResolve(const char *event_name);
 
 /* TSActiveEventGetMlt: query for a list of all the currently active events
  * Input:  active_events - an empty TSList; if function call is successful,

Reply via email to