CUBRID cubrid Admin CLI — Verb Dispatcher, SA/CS-Routed Library Loading, and the Service · Server · Broker · Heartbeat Family
Theoretical Background
Section titled “Theoretical Background”A unified admin CLI is the single binary every database engine ships for non-interactive operations the DBA needs to script: start/stop the server, take a backup, dump statistics, list transactions, kill a runaway query, rebuild a catalog. The design question is how to organize many small operations behind one entry point without the dispatch logic itself becoming the bottleneck on adding new verbs.
Two design choices dominate the space:
-
Flat vs. nested verb namespace. A flat namespace puts every operation directly under the binary (
pg_basebackup,pg_dump,pg_restore,pg_isready— Postgres ships a separate binary per major operation). A nested namespace dispatches by a first argument that names the operation (mysqld --initialize,mongod --repair; or in the more developed form,kubectl get pods,aws s3 ls,cubrid loaddb). Flat is easier for shell completion andmanpages; nested concentrates discoverability (cubrid --helplists everything) and shares global option parsing. -
Built-in vs. dynamically-loaded verb implementations. Verbs can be compiled directly into the binary (the
kubectlmodel), or each verb can live in a separate shared library and bedlopen-ed only when invoked (the loadable-module model used by some DBA tool families). The dynamic model lets the verb code link against engine libraries without forcing every verb to share the same link mode (some verbs need a database connection, others need to be the database in standalone mode), at the cost of adlopenper invocation.
CUBRID picks nested verbs + dynamically loaded implementations + a two-axis verb taxonomy:
- The first axis is the subsystem family (
server,broker,heartbeat,manager,pl,gateway,service— “service” is the meta-family that orchestrates all the others). - The second axis is the action (
start,stop,restart,status, plus a handful of family-specific actions likederegister,reload,acl,reset,info). - A separate “admin” axis carries the database operations
(
createdb,backupdb,loaddb,unloaddb,tranlist,killtran,lockdb,plandump,statdump,paramdump,acldb, …) — these don’t have an “action” suffix; the verb name is the action.
The cross-product of (family × action) is large enough that the code
maintains an explicit bitmask compatibility table: each family
declares which actions are valid for it, and each action declares
which families accept it. A bare cubrid heartbeat reset fails at
parse time because reset is MASK_BROKER | MASK_GATEWAY, not
MASK_HEARTBEAT.
Common DBMS Design
Section titled “Common DBMS Design”| Engine | Admin CLI shape | Verb dispatch | Subprocess management |
|---|---|---|---|
| PostgreSQL | Many separate binaries (pg_ctl, pg_basebackup, pg_dump, pg_restore, pg_isready, pgbench) | Per-binary main; pg_ctl is the closest analogue to cubrid <action> server | pg_ctl start forks postgres; lifecycle managed via PID file under data/postmaster.pid |
| MySQL | Multiple binaries (mysqladmin, mysqldump, mysqlimport, mysqlcheck, mysql_upgrade); mysqld is the server itself | Per-binary main; mysqladmin is the catch-all command tool | systemd / mysql.server script; per-instance PID files |
| Oracle | srvctl, crsctl, lsnrctl, expdp, impdp, rman; the meta-tool is srvctl for cluster-wide operations | srvctl <verb> <noun> [args] — verb-noun nested dispatch | OHASD / CSSD / CRSD daemons; cluster registry in OCR |
| MongoDB | mongod is the server; mongosh is the shell; mongodump/mongorestore/mongoimport/mongoexport are operation-specific binaries | Per-binary main | mongod --fork or systemd unit |
| CUBRID | One binary cubrid for both subsystem control and database operations | cubrid <family> <action> [args] for service-family verbs; cubrid <verb> [args] for database-admin verbs | cub_master is the registry / supervisor; broker has its own per-CAS pool; heartbeat is a separate daemon |
CUBRID’s “all in one binary” choice descends from the engine’s
process model — cub_master is itself a long-lived supervisor for
cub_server and cub_pl instances (see
cubrid-master-process.md and cubrid-heartbeat.md), and the
cubrid binary is mostly a thin client that asks cub_master
to do things via a small RPC. Operations that don’t need
cub_master (the database-admin verbs like createdb, unloaddb)
are dispatched through a separate code path that loads the
SA-mode engine library directly.
CUBRID’s Approach
Section titled “CUBRID’s Approach”One binary, two dispatch arms
Section titled “One binary, two dispatch arms”The cubrid binary’s main lives in util_service.c. It looks at
argv[1] and decides between two dispatch arms:
cubrid <argv[1]> [argv[2] ...] │ ┌────────────────┴────────────────────┐ │ │ argv[1] is a service family argv[1] is a database-admin verb (service|server|broker|...) (createdb|loaddb|tranlist|...) │ │ ▼ ▼ parse argv[2] as command dispatch via process_admin() (start|stop|status|...) → util_get_utility_index() │ → util_get_library_name() (SA or CS) verify (family, command) → utility_load_library() bitmask compatibility → utility_load_symbol() │ → call function with UTIL_FUNCTION_ARG ▼ process_service / process_server / process_broker / process_heartbeat / process_manager / process_pl / process_gatewayThe detection happens in two parse_arg calls against
us_Service_map (~50 entries: 8 family names + 2 meta entries
--help / --version + 40 admin verb names all mapped to the
sentinel ADMIN). If the first parse succeeds with a family token,
the service arm runs; if it succeeds with ADMIN, the admin arm
runs; if neither, it’s an error.
The service-family arm
Section titled “The service-family arm”Family + command form a 2D grid. The cell at (family, command) is
“valid” when (family_mask & command_mask) != 0, where masks come
from us_Service_map (for families) and us_Command_map (for
commands). The masks are:
// util_service.c — family bitmasksMASK_SERVICE = 1 << 0MASK_SERVER = 1 << 1MASK_BROKER = 1 << 2MASK_MANAGER = 1 << 3MASK_HEARTBEAT = 1 << 4MASK_ADMIN = 1 << 5MASK_PL = 1 << 6MASK_GATEWAY = 1 << 7MASK_ALL = (1 << N) - 1// us_Command_map (paraphrased — full table in util_service.c:227){START, "start", MASK_ALL & ~MASK_PL},{STOP, "stop", MASK_ALL & ~MASK_PL},{RESTART, "restart", MASK_SERVICE | MASK_SERVER | MASK_BROKER | MASK_GATEWAY | MASK_PL},{STATUS, "status", MASK_ALL},{DEREGISTER, "deregister", MASK_HEARTBEAT},{LIST, "list", MASK_HEARTBEAT},{RELOAD, "reload", MASK_HEARTBEAT},{ON, "on", MASK_BROKER | MASK_GATEWAY},{OFF, "off", MASK_BROKER | MASK_GATEWAY},{ACCESS_CONTROL, "acl", MASK_SERVER | MASK_BROKER | MASK_GATEWAY},{RESET, "reset", MASK_BROKER | MASK_GATEWAY},{INFO, "info", MASK_BROKER | MASK_GATEWAY},{SC_COPYLOGDB, "copylogdb", MASK_HEARTBEAT},{SC_APPLYLOGDB,"applylogdb", MASK_HEARTBEAT},{GET_SHARID, "getid", MASK_BROKER},{TEST, "test", MASK_BROKER},{REPLICATION, "replication"|"repl", MASK_HEARTBEAT},The process_* family of static functions in util_service.c then
takes over. They do the actual work:
| Family | Dispatcher | What it does |
|---|---|---|
service | process_service | Meta-orchestrator — starts/stops every component listed in cubrid.conf’s service section (SERVICE_START_SERVER, SERVICE_START_BROKER, etc.); used by init scripts |
server | process_server | Forks cub_server per database name; uses is_server_running() + PID-file lookup; can register the server with heartbeat if ha_mode is on |
broker | process_broker | Manages cub_broker and the per-broker CAS pools; acl reload re-reads the broker ACL file; info dumps per-broker stats |
manager | process_manager | Manages the cubrid_manager HTTP daemon (the web admin tool) |
heartbeat | process_heartbeat (with sub-dispatchers _start/_stop/_deregister/_status/_reload/_util/_replication) | HA orchestration — see cubrid-heartbeat.md |
pl | process_pl (with _restart/_status sub-dispatchers) | Manages cub_pl per database name — see cubrid-pl-javasp.md §“Process topology” |
gateway | process_gateway | Manages cub_gateway for the gateway feature |
Most family dispatchers ultimately fork-and-exec the underlying
binary (cub_server, cub_broker, cub_master for service-family
operations, cub_pl for pl operations) using
proc_execute_internal — a small wrapper around fork/execv that
optionally redirects stdout/stderr and optionally hides command-line
args (for password-bearing args).
The database-admin arm: process_admin
Section titled “The database-admin arm: process_admin”The other arm is the database-admin verb dispatcher. It looks up the
verb in ua_Utility_Map (defined in util_admin.c:966 — 42
entries) to get a utility_index, then dlopens the right library
based on the verb’s mode column (SA_ONLY, CS_ONLY, or SA_CS):
// util_admin.c — UTIL_MAP entry shapetypedef struct { int utility_index; // CREATEDB, LOADDB, ... int mode; // SA_ONLY, CS_ONLY, SA_CS int min_args; // minimum required positional args const char * util_name; // "createdb", "loaddb", ... const char * function_name; // entry symbol in the loaded library GETOPT_LONG *option_table; UTIL_ARG_MAP *arg_map;} UTIL_MAP;
// Sample rows (~42 total):{CREATEDB, SA_ONLY, 2, UTIL_OPTION_CREATEDB, "createdb", ...},{BACKUPDB, SA_CS, 1, UTIL_OPTION_BACKUPDB, "backupdb", ...},{LOCKDB, CS_ONLY, 1, UTIL_OPTION_LOCKDB, "lockdb", ...},{KILLTRAN, CS_ONLY, 1, UTIL_OPTION_KILLTRAN, "killtran", ...},{LOADDB, SA_CS, 1, UTIL_OPTION_LOADDB, "loaddb_user",...},{UNLOADDB, SA_CS, 1, UTIL_OPTION_UNLOADDB, "unloaddb", ...},{COMPACTDB, SA_CS, 1, UTIL_OPTION_COMPACTDB, "compactdb", ...},{PARAMDUMP, SA_CS, 1, UTIL_OPTION_PARAMDUMP, "paramdump", ...},{STATDUMP, CS_ONLY, 1, UTIL_OPTION_STATDUMP, "statdump", ...},{TRANLIST, CS_ONLY, 1, UTIL_OPTION_TRANLIST, "tranlist", ...},{ACLDB, CS_ONLY, 1, UTIL_OPTION_ACLDB, "acldb", ...},{CHECKSUMDB, CS_ONLY, 1, UTIL_OPTION_CHECKSUMDB, "checksumdb", ...},{TDE, SA_CS, 1, UTIL_OPTION_TDE, "tde", ...},{FLASHBACK, CS_ONLY, 2, UTIL_OPTION_FLASHBACK, "flashback", ...},{MEMMON, CS_ONLY, 1, UTIL_OPTION_MEMMON, "memmon", ...},The dispatch code:
// util_admin.c::main (paraphrased)if (util_get_utility_index (&utility_index, argv[1]) != NO_ERROR) goto print_usage; // verb not in table
if (util_parse_argument (&ua_Utility_Map[utility_index], argc - 1, &argv[1]) != NO_ERROR) is_valid_arg = false; // bad args; still load lib for usage
library_name = util_get_library_name (utility_index);status = utility_load_library (&library_handle, library_name);
util_get_function_name (&symbol_name, argv[1]);utility_load_symbol (library_handle, &symbol_handle, symbol_name);
UTIL_FUNCTION_ARG util_func_arg;util_func_arg.arg_map = ua_Utility_Map[utility_index].arg_map;util_func_arg.command_name = ua_Utility_Map[utility_index].utility_name;util_func_arg.argv0 = argv[0];util_func_arg.argv = argv;util_func_arg.valid_arg = is_valid_arg;loaded_function = (UTILITY_FUNCTION) symbol_handle;status = (*loaded_function) (&util_func_arg);util_get_library_name returns:
libcubridsaforSA_ONLYverbs —createdb,restoredb,optimizedb,installdb,diagdb,patchdb,alterdbhost,genlocale,dumplocale,synccolldb,gen_tz,dump_tz,restoreslave. These verbs are the engine for the duration of the call (the SA library has the entire engine linked in).libcubridcsforCS_ONLYverbs —lockdb,killtran,plandump,statdump,tranlist,changemode,copylogdb,applylogdb,applyinfo,acldb,checksumdb,vacuumdb,flashback,memmon. These verbs talk to a runningcub_serverover the network.libcubridsaorlibcubridcsforSA_CSverbs —backupdb,addvoldb,spacedb,cleanfiledb,checkdb,loaddb,unloaddb,compactdb,paramdump,tde. These verbs accept either; the user picks via-S/--SA-modeor-C/--CS-modein the verb’s own option table. The library choice is then resolved at parse time beforedlopen.
The verb’s entry-function name comes from a fixed transformation of
the verb name (e.g., loaddb → loaddb_user per the table; most
verbs map identically). The util_get_function_name helper does this
mapping.
The full set of database-admin verbs:
| Family | Verbs |
|---|---|
| Database lifecycle | createdb, deletedb, renamedb, copydb, installdb, restoredb, restoreslave, alterdbhost |
| Volume / space | addvoldb, spacedb, cleanfiledb, diagdb, checkdb, patchdb |
| Bulk import / export | loaddb, unloaddb, compactdb, backupdb |
| Catalog statistics & tuning | optimizedb, statdump, paramdump, plandump, vacuumdb, memmon |
| Transactions & locks | lockdb, tranlist, killtran, acldb |
| HA & replication | changemode, copylogdb, applylogdb, applyinfo, checksumdb |
| Recovery | flashback |
| Encryption | tde |
| Locale / timezone | genlocale, dumplocale, synccolldb, gen_tz, dump_tz |
Each verb has its own dedicated subsection in this knowledge base or its own dedicated doc — see Adjacent reading at the end.
util_service.c::main flow in detail
Section titled “util_service.c::main flow in detail”// util_service.c::main (paraphrased)sprintf (env_buf, "%d", pid);envvar_set (UTIL_PID_ENVVAR_NAME, env_buf); // children read $CUBRID_UTIL_PID
ER_SAFE_INIT (NULL, ER_NEVER_EXIT); // no-exit error handler
if (argc == 2 && parse_arg (us_Service_map, argv[1]) == UTIL_VERSION) { util_service_version (argv[0]); // cubrid --version return EXIT_SUCCESS;}
util_type = parse_arg (us_Service_map, argv[1]);if (util_type == ER_GENERIC_ERROR) { util_type = parse_arg (us_Service_map, argv[2]); // some legacy invocations swap order if (util_type == ER_GENERIC_ERROR) goto error; if (util_type == ADMIN) util_name_pos = 2;} else if (util_type == ADMIN) { util_name_pos = 1;}
load_properties (); // read $CUBRID/conf/cubrid.confha_mode_in_common = prm_get_integer_value (PRM_ID_HA_MODE_FOR_SA_UTILS_ONLY);
if (util_type == ADMIN) { util_log_write_command (argc, argv, util_name_pos); status = process_admin (argc, argv); util_log_write_result (status); return status;}
if (util_type == UTIL_HELP) goto usage;if (argc < 3) goto usage;
command_type = parse_arg (us_Command_map, argv[2]);if (command_type != ER_GENERIC_ERROR) { int util_mask = util_get_service_option_mask (util_type); int command_mask = util_get_command_option_mask (command_type); if ((util_mask & command_mask) == 0) // bitmask cross-check goto error;}
util_log_write_command (argc, argv, util_name_pos);
/* dispatch into process_service / process_server / process_broker / ... */Three observations from the entry flow:
- Argv-order tolerance. The dispatcher tries
argv[1]first and, on failure, retriesargv[2]. This accommodates legacystart cubrid <db>invocations that came from older init scripts; the position of the family token wasn’t fixed. UTIL_PID_ENVVAR_NAMEis set so child processes (forkedcub_server,cub_broker, etc.) can correlate themselves back to the spawningcubridinvocation in audit logs.load_properties()readscubrid.confonce, populatesus_Property_map(database lists for service start, broker list, manager list, heartbeat config, gateway list), and these feed every subsequent process-family operation.
Logging: util_log_write_*
Section titled “Logging: util_log_write_*”Every admin invocation is logged to $CUBRID/log/cubrid_utility.log
via four helpers:
util_log_write_command (argc, argv, name_pos)— at start, logs the full command line (with sensitive args masked starting atname_pos).util_log_write_result (status)— at end, logs the exit code.util_log_write_errid (msgid)/util_log_write_errstr (msg)— for in-flight errors.
This is independent of the engine’s er_log and the DDL audit log;
it captures the operator’s activity at the binary level — useful
for reconstructing what was done when an HA failover misbehaves or
a database disappears.
Legacy compatibility shim (util_front.c)
Section titled “Legacy compatibility shim (util_front.c)”Older CUBRID releases shipped per-operation binaries:
createdb, loaddb, unloaddb, compactdb, backupdb,
restoredb, addvoldb, spacedb, lockdb, killtran, etc., plus
csql and commdb. Modern CUBRID still ships these names but each
is a front-end shim built from util_front.c whose main:
- Looks at
basename(argv[0])— its own program name. - Finds the matching entry in
ua_Util_table[](a 19-row table pairing program name → modern verb name → arg-translation table). - Builds a new
argvof the form["cubrid", "<modern-verb>", ...translated args...]. - Translates each old short-form arg (
-p,-c,-l,-mv, …) to the modern long-form (--pages,--comment,--log-path,--more-volumes-file, …) using the per-verb arg map (ua_Create_map,ua_Backup_map, etc.). execvps intoUTIL_ADMIN_NAME(the moderncubridbinary) with the translated args.
// util_front.c::main (paraphrased)program_name = basename (argv[0]);
if (strcmp (program_name, UTIL_SQLX_NAME) == 0) { /* csql via legacy name */ convert_argv (argc, &admin_argv[1], ua_Sqlx_map); execvp (UTIL_CSQL_NAME, admin_argv);} else if (strcmp (program_name, UTIL_OLD_COMMDB_NAME) == 0) { /* commdb via legacy name */ convert_argv (argc, &admin_argv[1], us_Commdb_map); execvp (UTIL_COMMDB_NAME, argv);} else { for (i = 0; ua_Util_table[i].app_name != 0; i++) { if (strcmp (ua_Util_table[i].app_name, program_name) == 0) { admin_argv[0] = UTIL_CUBRID; // "cubrid" admin_argv[1] = ua_Util_table[i].util_name; // modern verb memcpy (&admin_argv[2], &argv[1], (argc - 1) * sizeof (char *)); convert_argv (argc, &admin_argv[2], ua_Util_table[i].match_table); break; } } execvp (UTIL_ADMIN_NAME, admin_argv);}The convert_argv walker is straightforward: look up each argv[i]
that starts with - in the per-verb map; if found, replace with the
long form; if the long form is the sentinel (char *) -1, drop the
arg entirely (used for retired flags); if the arg starts with - but
isn’t in the map, fail with “invalid option”; otherwise pass through
unchanged.
The shim has two consequences:
- Old scripts still work. A 2010-era backup script doing
loaddb -u dba -p secret -d data.dat mydbruns end-to-end without modification becauseloaddbis a binary shim that translates and re-execs. - The
cubridbinary is the only “real” entry. Once the shimexecvps, the surviving process’sargv[0]iscubrid. Audit logs see the modern form, not the legacy form. (The shim itself doesn’t log — the unified entry does, viautil_log_write_command.)
commdb: the master-process probe
Section titled “commdb: the master-process probe”cubrid commdb (and the legacy bare commdb binary) is a thin
client to cub_master for service-list / server-shutdown commands.
Its main lives in commdb.c (separate from util_admin.c and
util_service.c):
cubrid commdb -P— list registered server processes.cubrid commdb -O— list everythingcub_masterknows about (including broker and pl).cubrid commdb -S <db>— request a shutdown of one server.cubrid commdb -A— request shutdown of every registered server.cubrid commdb -h <host>— target a remotecub_master(rare; most operations are local).
It’s logically part of the cubrid admin family but lives in its own
file because it speaks the master-process RPC directly rather than
forking a subprocess. Operators rarely call it by name; it’s used by
the service-family process_* functions to query / signal master.
Help and version
Section titled “Help and version”cubrid --help and cubrid --version are detected as special
entries in us_Service_map (the UTIL_HELP and UTIL_VERSION
sentinels). Help renders the family list + brief usage; version
forwards to print_admin_version which dlsyms the version symbol
out of libcubridsa and calls it. This is one of two places where
the binary dlopens a library purely for an informational call (the
other is print_admin_usage).
Source Walkthrough
Section titled “Source Walkthrough”Entry and dispatch (util_service.c)
Section titled “Entry and dispatch (util_service.c)”| Symbol | Role |
|---|---|
main | The cubrid binary’s entry; detects family / admin / help / version, runs the bitmask cross-check, dispatches to family or admin arm |
parse_arg | Resolves a string against an option-map array; returns the option type or ER_GENERIC_ERROR |
us_Service_map | The 50-entry table of family + admin-verb tokens |
us_Command_map | The 17-entry table of action commands with their family-acceptance bitmask |
us_Property_map | Ordered list of cubrid.conf property keys read by load_properties |
load_properties / finalize_properties / get_property | cubrid.conf reader and accessor |
process_service / process_server / process_broker / process_manager / process_heartbeat / process_pl / process_gateway | Per-family dispatchers; each takes (command_type, argc, argv, ...) |
process_admin | The admin arm — wraps util_admin.c::main-equivalent logic for the case where it’s invoked through cubrid <verb> rather than through the legacy compat shim |
proc_execute_internal / proc_execute / proc_execute_hide_cmd_args | fork/execv wrapper with optional output redirect and arg masking |
process_master | Issues a request to cub_master (for shutdown all, etc.) |
is_server_running / is_broker_running / is_gateway_running / is_manager_running / is_pl_running | PID-file or process-list probes; used by start to detect “already running” and by status to render |
util_log_write_command / util_log_write_result / util_log_write_errid / util_log_write_errstr | cubrid_utility.log writers |
print_message / print_result / command_string | Help and end-of-run messaging |
Verb table and SA/CS dispatch (util_admin.c)
Section titled “Verb table and SA/CS dispatch (util_admin.c)”| Symbol | Role |
|---|---|
main | Standalone admin binary entry (used by the legacy compat shim’s execvp target); same dispatch as process_admin in util_service.c |
ua_Utility_Map | The 42-entry table of admin verbs with mode/argv-min/option-table |
util_get_utility_index | Verb name → table index |
util_get_library_name | Verb’s mode → library name (libcubridsa or libcubridcs) |
util_get_function_name | Verb name → entry symbol in the loaded library |
util_parse_argument | Per-verb argv parser using the table’s GETOPT_LONG and UTIL_ARG_MAP columns |
print_admin_usage / print_admin_version | Forward to dlsym-ed libcubridsa symbols for usage/version text |
Per-verb option / arg-map types (util_common.c, util_admin.c)
Section titled “Per-verb option / arg-map types (util_common.c, util_admin.c)”Each verb declares a paired GETOPT_LONG ua_<Verb>_Option[] (the
getopt short→long table) and a UTIL_ARG_MAP ua_<Verb>_Option_Map[]
(the argv parse-result schema: positional args + per-flag value
type). Both are static arrays in util_admin.c. The shape:
// pattern repeated per verb in util_admin.cstatic GETOPT_LONG ua_Backup_Option[] = { {BACKUP_DESTINATION_PATH_L, 1, 0, BACKUP_DESTINATION_PATH_S}, {BACKUP_REMOVE_ARCHIVE_L, 0, 0, BACKUP_REMOVE_ARCHIVE_S}, /* ... */ {0, 0, 0, 0}};
static UTIL_ARG_MAP ua_Backup_Option_Map[] = { {OPTION_STRING_TABLE, {0}, {0}}, // positional args {BACKUP_DESTINATION_PATH_S, {ARG_STRING}, {0}}, {BACKUP_REMOVE_ARCHIVE_S, {ARG_BOOLEAN}, {0}}, /* ... */ {0, {0}, {0}}};The table-driven approach means adding a new admin verb is a
purely declarative change — declare two arrays, add a row to
ua_Utility_Map, and write the verb function in either
libcubridsa or libcubridcs (or both for SA_CS).
Legacy compat shim (util_front.c)
Section titled “Legacy compat shim (util_front.c)”| Symbol | Role |
|---|---|
main | Detects program name; picks the matching arg-translation table; rewrites argv; execvps into cubrid (or csql / commdb) |
ua_Util_table | Program-name → modern-verb-name + per-verb arg map (19 rows) |
ua_Create_map / ua_Rename_map / ua_Copy_map / … | Per-verb short→long arg translations (18 tables, one per legacy binary) |
get_long_arg_by_old_arg | Single-arg lookup |
convert_argv | Walks argv, replaces each entry via lookup, drops sentinel -1-marked args, errors on unknown -x |
Master-process probe (commdb.c)
Section titled “Master-process probe (commdb.c)”| Symbol | Role |
|---|---|
main | Parses -P/-O/-S/-A/-h; opens connection to cub_master; sends one of MASTER_CONN_LIST_* / MASTER_REQ_SHUTDOWN_* requests; renders or applies the response |
process_master_* (in util_service.c) | Higher-level wrappers that let the family dispatchers issue master requests without forking commdb |
Position hints (as of 2026-05-05)
Section titled “Position hints (as of 2026-05-05)”| Symbol | Path |
|---|---|
util_service.c::main | src/executables/util_service.c:534 |
us_Service_map | src/executables/util_service.c:152 |
us_Command_map | src/executables/util_service.c:227 |
us_Property_map | src/executables/util_service.c:249 |
Family MASK_* constants and UTIL_TYPE_* strings | src/executables/util_service.c:143 |
process_admin invocation site | src/executables/util_service.c:599 |
util_admin.c::main | src/executables/util_admin.c:1093 |
ua_Utility_Map | src/executables/util_admin.c:966 |
util_get_utility_index (declaration) | src/executables/util_admin.c:1015 |
util_get_library_name / util_get_function_name (declarations) | src/executables/util_admin.c:1013–1014 |
util_front.c::main | src/executables/util_front.c:369 |
ua_Util_table (legacy program-name → modern-verb) | src/executables/util_front.c:278 |
convert_argv | src/executables/util_front.c:333 |
Symbol names are the canonical anchor; line numbers are hints
scoped to the updated: date.
Cross-check Notes
Section titled “Cross-check Notes”- Two
mains, one binary. Bothutil_service.candutil_admin.cdefinemain. The CMake build linksutil_service.c::mainas thecubridbinary’s entry; theutil_admin.c::mainis built into a separatecub_adminbinary used by the legacyutil_front.cshim’sexecvptarget. The two shareua_Utility_Map(declared inutil_admin.c, referenced fromutil_service.c::process_admin) so verb resolution is consistent whichever binary the user actually hit. SA_CSresolution timing. Verbs flaggedSA_CSdefer the library choice until afterutil_parse_argument, because that parse is what discovers whether the user passed-S(SA mode) or-C(CS mode). This means the parse error path runs against the same library load logic as success — ensuring usage messages come from the right library even when args were rejected.is_valid_arg = falseis forwarded to the verb function. The verb is loaded and called even if its args parsed badly, so the verb can render its own usage. Thevalid_argfield tells it to print usage and exit rather than attempting work.load_propertiesis not idempotent across reload. It readscubrid.confonce at startup. Acubrid service startfollowed by a manualcubrid.confedit and acubrid service statusdoesn’t see the edits — operators have to restart thecubridinvocation. The heartbeat-onlyreloadaction is the exception; it re-reads ha-config independently.MASK_PLis excluded fromstart/stop. PL is started / stopped indirectly by the per-database server (cub_serverforkscub_pl); operators interact with it viarestartorstatusonly. Tryingcubrid pl start <db>fails the bitmask check.- The legacy shim does not log.
util_front.c::maindoes noutil_log_write_*; the audit log is populated by the moderncubridbinary after theexecvp. This means a script using legacy binaries appears in the audit log only as the modern verb invocation, with no record that the entry was the legacy name. commdbdual-path.commdbexists both as a standalone binary and ascubrid commdb; both speak directly tocub_master. Theprocess_masterhelpers inutil_service.care an in-process bypass of thecommdbbinary, used so that family dispatchers don’t need to fork.
Open Questions
Section titled “Open Questions”- Per-verb help granularity.
cubrid <verb> --helpis delegated to the loaded library’s usage function (different per-verb formatting). A unifiedcubrid --help <verb>form that pulls from a common message catalog is undocumented and may not exist in current message files. cubrid_utility.logrotation. The log is append-only; no documented rotation policy. Long-running clusters with frequent service operations accumulate the log indefinitely.- Bitmask collision audit. The (family, action) cross-check table is hand-maintained; a missing mask bit silently rejects a valid combination. There’s no test that walks every (family, action) pair to confirm the mask sets match documented behaviour.
- Legacy program-name list staleness.
ua_Util_tableis fixed at 19 rows. New admin verbs added toua_Utility_Map(memmon, flashback, tde) have no legacy short-name entry — operators must use thecubrid <verb>form. Whether this is intentional or a rolling retirement of the shim is undocumented. cubrid commdbdeprecation. Withprocess_masteravailable in-process, the standalonecommdbbinary is mostly redundant. Keeping it shipped is a backward-compat stance; the timeline for retirement isn’t recorded.
Sources
Section titled “Sources”src/executables/util_service.c— thecubridbinary’smain, family dispatcher, bitmask cross-check, properties loader, per-familyprocess_*functionssrc/executables/util_admin.c— admin-verb table (ua_Utility_Map), per-verb option tables, library-name and function-name helpers, the standalonecub_adminmainsrc/executables/util_common.c— shared verb helpers, message printing,UTIL_FUNCTION_ARGdefinitionssrc/executables/util_cs.c— CS-mode verb implementations (the symbolsdlsym-ed whenlibrary_name == libcubridcs)src/executables/util_sa.c— SA-mode verb implementationssrc/executables/util_front.c— legacy compatibility shim; per-verb arg-translation tables;execvpinto the modern entrysrc/executables/util_support.c—utility_load_library,utility_load_symbol,utility_load_print_error, message catalog wrapperssrc/executables/commdb.c—cub_masterprobe binarysrc/executables/AGENTS.md— agent guide; binary→source map- Adjacent docs:
cubrid-csql.md(the other major user-facing binary; uses the same SA/CS launcher pattern viacsql_launcher.c),cubrid-loaddb.md/cubrid-compactdb.md/cubrid-backup-restore.md(verbs that already have dedicated docs),cubrid-master-process.md(open — seecubrid-coverage.md) forcub_masteritself,cubrid-heartbeat.md(heartbeat family lifecycle),cubrid-broker.md(broker family lifecycle),cubrid-pl-javasp.md(pl family lifecycle),cubrid-system-parameters.md(thecubrid.confproperties consumed byload_properties)