1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 #include <strings.h> 28 #include <errno.h> 29 #include <unistd.h> 30 #include <sys/stat.h> 31 #include <stdlib.h> 32 #include <fcntl.h> 33 #include <sys/types.h> 34 #include <ctype.h> 35 #include <libnvpair.h> 36 37 #include "mms_mgmt.h" 38 #include "mgmt_util.h" 39 #include "mms_cfg.h" 40 #include "net_cfg_service.h" 41 42 static char *_SrcFile = __FILE__; 43 #define HERE _SrcFile, __LINE__ 44 #define MMS_MGMT_PGA ".pga" 45 46 typedef struct { 47 char port[10]; 48 char user[256]; 49 char bindir[MAXPATHLEN]; 50 char path[MAXPATHLEN]; 51 char logdir[MAXPATHLEN]; 52 char dbname[MAXPATHLEN]; 53 char dbhost[MAXHOSTNAMELEN]; 54 uid_t dbuid; 55 gid_t dbgid; 56 } mmsdb_opts_t; 57 58 /* If this path changes, make sure similar changes are made to mmsexplorer */ 59 static char db_cli_env[1024]; 60 61 static int get_db_user(char *buf, int buflen, uid_t *uid, gid_t *gid); 62 static int configure_pgconf(char *port, char *logdir); 63 static int get_dbver_from_optfile(char *path, int *version); 64 static int mk_cmds_from_optfile(mmsdb_opts_t *opts, char *path, int vers, 65 char cmdtype, int dopd, char **cmdfile); 66 static int mgmt_db_sql_exec(char *cmdfile, mmsdb_opts_t *opts); 67 static int set_mm_system_vars_db(nvlist_t *opts, char *cmdfile); 68 static int mgmt_get_db_opts(mmsdb_opts_t *opts); 69 static int create_db_dirs(char *dbpath, uid_t uid, gid_t gid, nvlist_t *errs); 70 static int update_pghba(boolean_t ismd5, mmsdb_opts_t *dbopts, nvlist_t *errs); 71 72 73 /* 74 * Functions to manage the MMS Database 75 */ 76 77 int 78 mgmt_set_db_opts(nvlist_t *opts, nvlist_t *errlist) 79 { 80 int st = 0; 81 mmsdb_opts_t oldopts; 82 int doconf = 0; 83 uid_t uid = 0; 84 gid_t gid = 0; 85 char *val; 86 char *port = NULL; 87 char *logdir = NULL; 88 89 if (!mgmt_chk_auth("solaris.mms.modify")) { 90 return (EACCES); 91 } 92 93 /* 94 * check to see if any options have been set for the DB yet. Only 95 * a few are user-configurable. Changing the DB user is handled 96 * by the admin with SMF and chown -R. (i.e., outside of our CLI, 97 * at least for now) 98 */ 99 (void) memset(&oldopts, 0, sizeof (mmsdb_opts_t)); 100 101 st = mgmt_get_db_opts(&oldopts); 102 if (st != 0) { 103 return (st); 104 } 105 106 uid = oldopts.dbuid; 107 gid = oldopts.dbgid; 108 109 /* TODO - should we allow change after set? Need to copy -R if so */ 110 st = nvlist_lookup_string(opts, O_DBDIR, &val); 111 if (st == 0) { 112 st = create_db_dirs(val, uid, gid, errlist); 113 if (st != 0) { 114 return (st); 115 } 116 } 117 118 st = nvlist_lookup_string(opts, O_DBPORT, &port); 119 if (st == 0) { 120 /* update the conf file */ 121 doconf = 1; 122 } 123 124 st = nvlist_lookup_string(opts, O_DBLOG, &logdir); 125 if (st == 0) { 126 /* update the conf file */ 127 doconf = 1; 128 /* create dblogdir if it doesn't exist */ 129 st = create_dir(logdir, 0711, NULL, uid, NULL, gid); 130 } 131 132 if ((st == 0) && (doconf)) { 133 st = configure_pgconf(port, logdir); 134 } 135 136 return (st); 137 } 138 139 static int 140 create_db_dirs(char *dbpath, uid_t uid, gid_t gid, nvlist_t *errs) 141 { 142 int st; 143 struct stat64 statbuf; 144 char *dbsubdirs[] = {"dump", "log", NULL}; 145 int i; 146 char buf[2048]; 147 148 if (!dbpath) { 149 return (MMS_MGMT_NOARG); 150 } 151 152 st = stat64(dbpath, &statbuf); 153 if ((st != 0) && (errno != ENOENT)) { 154 st = errno; 155 MGMT_ADD_ERR(errs, dbpath, st); 156 return (st); 157 } 158 159 st = create_dir(dbpath, 0711, NULL, uid, NULL, gid); 160 if (st != 0) { 161 st = errno; 162 MGMT_ADD_ERR(errs, dbpath, st); 163 return (st); 164 } 165 166 for (i = 0; dbsubdirs[i] != NULL; i++) { 167 (void) snprintf(buf, sizeof (buf), "%s/../%s", dbpath, 168 dbsubdirs[i]); 169 st = create_dir(buf, 0711, NULL, uid, NULL, gid); 170 if (st != 0) { 171 st = errno; 172 MGMT_ADD_ERR(errs, buf, st); 173 break; 174 } 175 } 176 177 return (st); 178 } 179 180 int 181 mgmt_db_init(void) 182 { 183 int st; 184 pid_t pid; 185 char buf[2048]; 186 char dbbuf[2048]; 187 mmsdb_opts_t opts; 188 char *cmd[4]; 189 190 if (!mgmt_chk_auth("solaris.mms.create")) { 191 return (EACCES); 192 } 193 194 st = mgmt_get_db_opts(&opts); 195 if (st != 0) { 196 mms_trace(MMS_DEBUG, 197 "mgmt_get_db_opts(&opts) error"); 198 return (st); 199 } 200 201 /* see if we've been initialized already, bail if so */ 202 (void) snprintf(buf, sizeof (buf), "%s/postgresql.conf", opts.path); 203 st = access(buf, F_OK); 204 if (st == 0) { 205 return (0); 206 } 207 208 (void) snprintf(dbbuf, sizeof (dbbuf), "%s/initdb", opts.bindir); 209 210 cmd[0] = dbbuf; 211 cmd[1] = "-D"; 212 cmd[2] = opts.path; 213 cmd[3] = NULL; 214 215 pid = exec_mgmt_cmd(NULL, NULL, opts.dbuid, opts.dbgid, 216 B_FALSE, cmd); 217 mms_trace(MMS_DEBUG, "exec_mgmt_cmd: %s %s %s", cmd[0], cmd[1], cmd[2]); 218 219 st = check_exit(pid, NULL); 220 if (st != 0) 221 mms_trace(MMS_DEBUG, 222 "exec_mgmt_cmd error"); 223 224 return (st); 225 } 226 227 static int 228 mgmt_get_db_opts(mmsdb_opts_t *opts) 229 { 230 int st; 231 struct passwd pwd; 232 struct passwd *pwdp; 233 char buf[2048]; 234 235 if (opts == NULL) { 236 return (MMS_MGMT_NOARG); 237 } 238 239 st = mms_cfg_getvar(MMS_CFG_DB_DATA, opts->path); 240 if (st == 0) { 241 st = mms_cfg_getvar(MMS_CFG_MM_DB_USER, opts->user); 242 } 243 if (st == 0) { 244 st = mms_cfg_getvar(MMS_CFG_MM_DB_HOST, opts->dbhost); 245 } 246 if (st == 0) { 247 st = mms_cfg_getvar(MMS_CFG_MM_DB_PORT, opts->port); 248 } 249 if (st == 0) { 250 st = mms_cfg_getvar(MMS_CFG_MM_DB_NAME, opts->dbname); 251 } 252 if (st == 0) { 253 st = mms_cfg_getvar(MMS_CFG_DB_BIN, opts->bindir); 254 } 255 if (st == 0) { 256 (void) snprintf(opts->logdir, sizeof (opts->logdir), 257 "%s/../log", opts->path); 258 } 259 260 if (st != 0) { 261 return (st); 262 } 263 264 (void) getpwnam_r(opts->user, &pwd, buf, sizeof (buf), &pwdp); 265 if (pwdp == NULL) { 266 return (MMS_MGMT_DB_USER_NOTFOUND); 267 } 268 269 opts->dbuid = pwdp->pw_uid; 270 opts->dbgid = pwdp->pw_gid; 271 272 /* set the envvar for PGPASSFILE */ 273 (void) snprintf(db_cli_env, sizeof (db_cli_env), 274 "PGPASSFILE=%s/../%s", opts->path, MMS_MGMT_PGA); 275 st = putenv(db_cli_env); 276 277 return (st); 278 } 279 280 static int 281 get_db_user(char *buf, int buflen, uid_t *uid, gid_t *gid) 282 { 283 int st; 284 struct passwd pwd; 285 struct passwd *pwdp; 286 287 if ((buf == NULL) || (uid == NULL)) { 288 return (MMS_MGMT_NOARG); 289 } 290 291 st = mms_cfg_getvar(MMS_CFG_MM_DB_USER, buf); 292 if (st != 0) { 293 return (st); 294 } 295 296 (void) getpwnam_r(buf, &pwd, buf, buflen, &pwdp); 297 if (pwdp == NULL) { 298 return (MMS_MGMT_DB_USER_NOTFOUND); 299 } 300 301 *uid = pwdp->pw_uid; 302 if (gid != NULL) { 303 *gid = pwdp->pw_gid; 304 } 305 306 return (0); 307 } 308 309 int 310 mgmt_db_create(int initialize, int populate, nvlist_t *optlist) 311 { 312 int st; 313 pid_t pid; 314 mmsdb_opts_t opts; 315 int oldver = -1; 316 int ver = -1; 317 char buf[MAXPATHLEN]; 318 char *pkgfile = MMSETCDIR"/db/mms_db"; 319 char *cmd[7]; 320 char dbbuf[2048]; 321 322 mms_trace(MMS_DEBUG, "Creating the MMS Database"); 323 324 if (!mgmt_chk_auth("solaris.mms.modify")) { 325 mms_trace(MMS_DEBUG, 326 "mgmt_chk_auth(\"solaris.mms.modify\") error"); 327 return (EACCES); 328 } 329 330 st = mgmt_get_db_opts(&opts); 331 if (st != 0) { 332 mms_trace(MMS_DEBUG, 333 "mgmt_get_db_opts(&opts) error"); 334 return (st); 335 } 336 337 (void) snprintf(dbbuf, sizeof (dbbuf), "%s/createdb", opts.bindir); 338 339 cmd[0] = dbbuf; 340 cmd[1] = "-h"; 341 cmd[2] = opts.dbhost; 342 cmd[3] = "-p"; 343 cmd[4] = opts.port; 344 cmd[5] = opts.dbname; 345 cmd[6] = NULL; 346 347 if (initialize) { 348 st = mgmt_db_check(); 349 if (st == 0) { 350 mms_trace(MMS_DEBUG, 351 "EALREADY error"); 352 /* db is alive, already inited */ 353 return (EALREADY); 354 } 355 356 /* check to see if files exist, even if svc is stopped */ 357 (void) snprintf(buf, sizeof (buf), "%s/base", opts.path); 358 if (access(buf, F_OK) == 0) { 359 mms_trace(MMS_DEBUG, 360 "access(buf, F_OK) error"); 361 return (EALREADY); 362 } 363 364 st = mgmt_db_init(); 365 if (st != 0) 366 mms_trace(MMS_DEBUG, 367 "mgmt_db_init() error"); 368 if (st == 0) { 369 st = configure_pgconf(opts.port, opts.logdir); 370 } 371 372 if (st != 0) { 373 mms_trace(MMS_DEBUG, 374 "configure_pgconf error"); 375 return (st); 376 } 377 378 /* create the dirs we need */ 379 st = create_db_dirs(opts.path, opts.dbuid, opts.dbgid, NULL); 380 if (st != 0) { 381 mms_trace(MMS_DEBUG, 382 "create_db_dirs error"); 383 return (st); 384 } 385 } 386 387 /* 388 * some callers may wish to populate the DB themselves, as in 389 * upgrade or downgrade. 390 */ 391 if (populate) { 392 st = get_dbver_from_optfile(pkgfile, &ver); 393 if (st != 0) { 394 mms_trace(MMS_DEBUG, 395 "get_dbver_from_optfile error"); 396 return (st); 397 } 398 399 (void) snprintf(buf, sizeof (buf), "%s/../mmsdb", opts.path); 400 st = get_dbver_from_optfile(buf, &oldver); 401 if (st != 0) { 402 if (st != ENOENT) { 403 mms_trace(MMS_DEBUG, 404 "get_dbver_from_optfile error"); 405 return (st); 406 } 407 st = 0; 408 } 409 410 if (ver > oldver) { 411 if (oldver != -1) { 412 /* save the old mod file */ 413 char newf[MAXPATHLEN]; 414 415 (void) snprintf(newf, sizeof (newf), "%s-%d", 416 buf, oldver); 417 (void) rename(buf, newf); 418 } 419 st = cp_file(pkgfile, buf); 420 if (st != 0) { 421 return (st); 422 } 423 (void) chown(buf, opts.dbuid, opts.dbgid); 424 } 425 } 426 427 /* make sure the DB is running */ 428 mms_trace(MMS_DEBUG, "enable db"); 429 st = mgmt_set_svc_state(DBSVC, ENABLE, NULL); 430 if (st != 0) { 431 mms_trace(MMS_DEBUG, 432 "mgmt_set_svc_state error"); 433 return (st); 434 } 435 436 st = mgmt_db_ready(); 437 if (st != 0) { 438 mms_trace(MMS_ERR, 439 "database did not go ready"); 440 return (st); 441 } 442 443 pid = exec_mgmt_cmd(NULL, NULL, opts.dbuid, opts.dbgid, 444 B_FALSE, cmd); 445 mms_trace(MMS_DEBUG, 446 "exec_mgmt_cmd: %s %s %s %s %s %s", 447 cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5]); 448 449 st = check_exit(pid, NULL); 450 if (st != 0) { 451 mms_trace(MMS_DEBUG, 452 "exec_mgmt_cmd error: st %d", st); 453 } 454 455 if ((st == 0) && (populate)) { 456 /* import all the sql cmds */ 457 char *cmdfile = NULL; 458 459 st = mk_cmds_from_optfile(&opts, buf, ver, 'u', 1, &cmdfile); 460 if ((st == 0) && optlist) { 461 st = set_mm_system_vars_db(optlist, cmdfile); 462 } 463 if (st == 0) { 464 st = mgmt_db_sql_exec(cmdfile, &opts); 465 } 466 467 if (cmdfile) { 468 (void) unlink(cmdfile); 469 free(cmdfile); 470 } 471 472 if (st == 0) { 473 char *passp; 474 475 st = nvlist_lookup_string(optlist, O_MMPASS, &passp); 476 if (st == 0) { 477 (void) snprintf(buf, sizeof (buf), 478 "%s_dbadmin", passp); 479 st = mgmt_set_db_pass(buf, NULL); 480 } 481 } 482 } 483 484 return (st); 485 } 486 487 int 488 mgmt_db_drop(void) 489 { 490 int st; 491 pid_t pid; 492 mmsdb_opts_t opts; 493 char *cmd[5]; 494 char dbbuf[2048]; 495 496 if (!mgmt_chk_auth("solaris.mms.modify")) { 497 return (EACCES); 498 } 499 500 st = mgmt_get_db_opts(&opts); 501 if (st != 0) { 502 return (st); 503 } 504 505 (void) snprintf(dbbuf, sizeof (dbbuf), "%s/dropdb", opts.bindir); 506 507 cmd[0] = dbbuf; 508 cmd[1] = "-p"; 509 cmd[2] = opts.port; 510 cmd[3] = opts.dbname; 511 cmd[4] = NULL; 512 513 pid = exec_mgmt_cmd(NULL, NULL, opts.dbuid, opts.dbgid, 514 B_FALSE, cmd); 515 mms_trace(MMS_DEBUG, "exec_mgmt_cmd: %s %s %s %s", 516 cmd[0], cmd[1], cmd[2], cmd[3]); 517 518 519 st = check_exit(pid, NULL); 520 521 if (st != 0) { 522 /* restart the service to force users to disconnect */ 523 524 mms_trace(MMS_DEBUG, "restart db"); 525 (void) mgmt_set_svc_state(DBSVC, RESTART, NULL); 526 527 st = mgmt_db_ready(); 528 if (st != 0) { 529 mms_trace(MMS_ERR, 530 "database did not go ready"); 531 } 532 533 if (st == 0) { 534 pid = exec_mgmt_cmd(NULL, NULL, opts.dbuid, opts.dbgid, 535 B_FALSE, cmd); 536 mms_trace(MMS_DEBUG, "exec_mgmt_cmd: %s %s %s %s", 537 cmd[0], cmd[1], cmd[2], cmd[3]); 538 539 st = check_exit(pid, NULL); 540 } 541 } 542 543 return (st); 544 } 545 546 int 547 mgmt_db_ready(void) 548 { 549 int i; 550 int st; 551 pid_t pid; 552 FILE *readf = NULL; 553 mmsdb_opts_t opts; 554 char *cmd[7]; 555 char dbbuf[2048]; 556 557 if (!mgmt_chk_auth("solaris.mms.modify")) { 558 return (EACCES); 559 } 560 561 st = mgmt_get_db_opts(&opts); 562 if (st != 0) { 563 return (st); 564 } 565 566 mms_trace(MMS_DEBUG, "check for database ready"); 567 568 (void) snprintf(dbbuf, sizeof (dbbuf), "%s/psql", opts.bindir); 569 570 /* simple test to list available databases to check for db ready */ 571 cmd[0] = dbbuf; 572 cmd[1] = "-h"; 573 cmd[2] = opts.dbhost; 574 cmd[3] = "-p"; 575 cmd[4] = opts.port; 576 cmd[5] = "-l"; 577 cmd[6] = NULL; 578 579 for (i = 0; i < 30; i++) { 580 581 /* when the simple test is successful the */ 582 /* database is ready for socket connections */ 583 584 pid = exec_mgmt_cmd(&readf, NULL, opts.dbuid, opts.dbgid, 585 B_FALSE, cmd); 586 mms_trace(MMS_DEBUG, "exec_mgmt_cmd: %s %s %s %s %s %s", 587 cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5]); 588 589 st = check_exit(pid, NULL); 590 if (st == 0) { 591 break; 592 } 593 (void) sleep(1); 594 } 595 596 (void) fclose(readf); 597 598 return (st); 599 } 600 601 int 602 mgmt_db_check(void) 603 { 604 int st; 605 pid_t pid; 606 char buf[1024]; 607 FILE *readf = NULL; 608 mmsdb_opts_t opts; 609 char *cmd[9]; 610 char dbbuf[2048]; 611 612 if (!mgmt_chk_auth("solaris.mms.modify")) { 613 return (EACCES); 614 } 615 616 st = mgmt_get_db_opts(&opts); 617 if (st != 0) { 618 return (st); 619 } 620 621 /* test to see if the mms database already exists */ 622 623 (void) snprintf(dbbuf, sizeof (dbbuf), "%s/psql", opts.bindir); 624 625 cmd[0] = dbbuf; 626 cmd[1] = "-h"; 627 cmd[2] = opts.dbhost; 628 cmd[3] = "-p"; 629 cmd[4] = opts.port; 630 cmd[5] = "-t"; 631 cmd[6] = "-c"; 632 cmd[7] = buf; 633 cmd[8] = NULL; 634 635 (void) snprintf(buf, sizeof (buf), 636 "SELECT datname FROM pg_database where datname = '%s'", 637 opts.dbname); 638 639 pid = exec_mgmt_cmd(&readf, NULL, opts.dbuid, opts.dbgid, 640 B_FALSE, cmd); 641 mms_trace(MMS_DEBUG, "exec_mgmt_cmd: %s %s %s %s %s %s %s %s", 642 cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], 643 cmd[5], cmd[6], cmd[7]); 644 645 st = check_exit(pid, NULL); 646 647 if (st == 0) { 648 buf[0] = '\0'; 649 (void) fgets(buf, sizeof (buf), readf); 650 if (buf[0] == '\0') { 651 st = -1; 652 } 653 } 654 655 (void) fclose(readf); 656 657 return (st); 658 } 659 660 int 661 mgmt_db_dump(char *dumpdir, char *dumpfile, int len) 662 { 663 int st; 664 char datebuf[256]; 665 char filbuf[MAXPATHLEN]; 666 time_t now = time(NULL); 667 struct tm *tm = NULL; 668 pid_t pid; 669 mmsdb_opts_t opts; 670 char *cmd[11]; 671 char dbbuf[2048]; 672 673 if (!dumpdir || !dumpfile) { 674 return (MMS_MGMT_NOARG); 675 } 676 677 if (!mgmt_chk_auth("solaris.mms.modify")) { 678 return (EACCES); 679 } 680 681 st = mgmt_get_db_opts(&opts); 682 if (st != 0) { 683 return (st); 684 } 685 686 tm = localtime(&now); 687 (void) strftime(datebuf, sizeof (datebuf), 688 "%Y-""%m-""%dT""%H""%M""%S", tm); 689 690 (void) snprintf(filbuf, sizeof (filbuf), "%s/mmsdb_dump_%s", dumpdir, 691 datebuf); 692 693 (void) snprintf(dbbuf, sizeof (dbbuf), "%s/pg_dump", opts.bindir); 694 695 cmd[0] = dbbuf; 696 cmd[1] = "-h"; 697 cmd[2] = opts.dbhost; 698 cmd[3] = "-p"; 699 cmd[4] = opts.port; 700 cmd[5] = "-F"; 701 cmd[6] = "p"; 702 cmd[7] = "-f"; 703 cmd[8] = filbuf; 704 cmd[9] = opts.dbname; 705 cmd[10] = NULL; 706 707 if (dumpfile != NULL) { 708 (void) strlcpy(dumpfile, filbuf, len); 709 } 710 711 st = create_dir(dumpdir, 0711, NULL, opts.dbuid, NULL, 0); 712 713 if (st != 0) { 714 return (st); 715 } 716 717 pid = exec_mgmt_cmd(NULL, NULL, opts.dbuid, opts.dbgid, 718 B_FALSE, cmd); 719 mms_trace(MMS_DEBUG, "exec_mgmt_cmd: %s %s %s %s %s %s %s %s %s %s", 720 cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], 721 cmd[5], cmd[6], cmd[7], cmd[8], cmd[9]); 722 723 st = check_exit(pid, NULL); 724 725 return (st); 726 } 727 728 729 /* 730 * TODO: Ensure this is done on the MM server host only when client 731 * configs are supported. 732 */ 733 int 734 mgmt_db_restore(char *dumpfile) 735 { 736 int st; 737 struct stat64 statbuf; 738 char *mmstate = NULL; 739 mmsdb_opts_t opts; 740 741 if (!mgmt_chk_auth("solaris.mms.modify")) { 742 return (EACCES); 743 } 744 745 st = mgmt_get_db_opts(&opts); 746 if (st != 0) { 747 return (st); 748 } 749 750 st = stat64(dumpfile, &statbuf); 751 if (st != 0) { 752 return (MMS_MGMT_DBDUMP_MISSING); 753 } 754 if (!S_ISREG(statbuf.st_mode)) { 755 return (MMS_MGMT_NOT_DBFILE); 756 } 757 758 /* shutdown MM */ 759 mms_trace(MMS_DEBUG, "disable mm"); 760 st = mgmt_set_svc_state(MMSVC, DISABLE, &mmstate); 761 if (st != 0) { 762 if (mmstate) { 763 free(mmstate); 764 } 765 return (st); 766 } 767 768 st = mgmt_db_create(1, 0, NULL); 769 if (st != 0) { 770 free(mmstate); 771 return (st); 772 } 773 774 st = mgmt_db_sql_exec(dumpfile, &opts); 775 776 if ((st == 0) && (strcmp(mmstate, "online") == 0)) { 777 mms_trace(MMS_DEBUG, "enable mm"); 778 st = mgmt_set_svc_state(MMSVC, ENABLE, NULL); 779 } 780 781 free(mmstate); 782 return (st); 783 } 784 785 typedef struct { 786 char *optnam; 787 char *val; 788 } pgconf_t; 789 790 static pgconf_t pgconf_opts[] = { 791 {"port", NULL}, 792 {"log_directory", NULL}, 793 {"external_pid_file", "'postgres.pid'"}, 794 {"log_destination", "'stderr'"}, 795 {"logging_collector", "on"}, 796 {"log_filename", "'log.%a'"}, 797 {"log_rotation_size", "10000"}, 798 {"log_truncate_on_rotation", "on"}, 799 {"log_line_prefix", "'%m %p '"}, 800 {"client_min_messages", "WARNING"}, 801 {"log_min_messages", "INFO"}, 802 {"log_disconnections", "on"}, 803 {"track_counts", "on"}, 804 {"autovacuum", "on"}, 805 {"autovacuum_naptime", "1200"} 806 }; 807 808 static int numpgopts = sizeof (pgconf_opts) / sizeof (pgconf_t); 809 810 static int 811 configure_pgconf( 812 char *port, 813 char *logdir) 814 { 815 int st = 0; 816 struct stat64 statbuf; 817 char nambuf[256]; 818 char buf[MAXPATHLEN]; 819 char dbpath[MAXPATHLEN]; 820 char logpath[MAXPATHLEN]; 821 uid_t uid; 822 size_t sz; 823 char *bufp; 824 struct tm usetime; 825 int infd; 826 int outfd; 827 FILE *infp; 828 FILE *outfp; 829 static char datefmt[] = "%y""%m""%d""%H""%M""%S"; 830 time_t now; 831 char filbuf[2048]; 832 int i; 833 char *cptr; 834 int changed = 0; 835 int matched = 0; 836 837 if ((port == NULL) || (logdir == NULL)) { 838 return (MMS_MGMT_NOARG); 839 } 840 841 pgconf_opts[0].val = port; 842 843 /* add quotes around the path */ 844 (void) snprintf(logpath, sizeof (logpath), "'%s'", logdir); 845 846 pgconf_opts[1].val = logpath; 847 848 st = get_db_user(nambuf, sizeof (nambuf), &uid, NULL); 849 if (st == 0) { 850 st = mms_cfg_getvar(MMS_CFG_DB_DATA, dbpath); 851 } 852 853 if (st != 0) { 854 return (st); 855 } 856 857 st = stat64(logdir, &statbuf); 858 if (st != 0) { 859 st = errno; 860 if (st == ENOENT) { 861 st = create_dir(logdir, 0711, NULL, uid, NULL, 0); 862 } 863 if (st != 0) { 864 return (st); 865 } 866 } else { 867 if (!S_ISDIR(statbuf.st_mode)) { 868 return (ENOTDIR); 869 } 870 } 871 872 sz = strlcat(dbpath, "/postgresql.conf", sizeof (dbpath)); 873 if (sz > sizeof (dbpath)) { 874 return (ENAMETOOLONG); 875 } 876 877 st = stat64(dbpath, &statbuf); 878 if (st != 0) { 879 if (errno != ENOENT) { 880 return (errno); 881 } else { 882 /* 883 * DB not initialized yet, bail without 884 * error as this function will be called 885 * later from db_create. 886 */ 887 return (0); 888 } 889 } 890 891 /* construct the name of the new version of this file */ 892 now = time(NULL); 893 (void) localtime_r(&now, &usetime); 894 (void) strftime(nambuf, sizeof (nambuf), datefmt, &usetime); 895 (void) snprintf(buf, sizeof (buf), "%s_%s", dbpath, nambuf); 896 897 /* open the original */ 898 infd = open64(dbpath, O_RDONLY); 899 if (infd == -1) { 900 st = errno; 901 return (st); 902 } 903 904 infp = fdopen(infd, "r"); 905 if (infp == NULL) { 906 st = errno; 907 (void) close(infd); 908 return (st); 909 } 910 911 /* open the target file */ 912 outfd = open64(buf, O_CREAT|O_RDWR, statbuf.st_mode); 913 if (outfd == -1) { 914 st = errno; 915 (void) close(infd); 916 return (st); 917 } 918 919 outfp = fdopen(outfd, "w"); 920 if (outfp == NULL) { 921 st = errno; 922 (void) fclose(infp); 923 (void) close(outfd); 924 return (st); 925 } 926 927 /* preserve, as much as possible, the existing format of the file */ 928 while ((bufp = fgets(filbuf, sizeof (filbuf), infp)) != NULL) { 929 matched = 0; 930 cptr = NULL; 931 932 for (; *bufp != '\0'; bufp++) { 933 /* options are initially commented out */ 934 if (*bufp == '#') { 935 continue; 936 } 937 if (!isspace(*bufp)) { 938 break; 939 } 940 } 941 942 if (*bufp == '\0') { 943 (void) fprintf(outfp, "%s", filbuf); 944 continue; 945 } 946 947 for (i = 0; i < numpgopts; i++) { 948 sz = strlen(pgconf_opts[i].optnam); 949 if (strncmp(bufp, pgconf_opts[i].optnam, sz) != 0) { 950 continue; 951 } 952 bufp += sz; 953 while ((*bufp != '\0') && (isspace(*bufp))) { 954 bufp++; 955 sz++; 956 } 957 if (*bufp == '=') { 958 /* found a match - update it */ 959 matched++; 960 961 /* TODO: check really needed to change */ 962 (void) fprintf(outfp, "%s = %s\n", 963 pgconf_opts[i].optnam, pgconf_opts[i].val); 964 cptr = strchr(bufp, '#'); 965 if (cptr) { 966 (void) fprintf(outfp, "\t\t\t\t\t%s", 967 cptr); 968 } 969 changed++; 970 break; 971 } else { 972 /* superstring or substring of another option */ 973 bufp -= sz; 974 } 975 } 976 977 if (!matched) { 978 (void) fprintf(outfp, "%s", filbuf); 979 } 980 } 981 (void) fchown(outfd, statbuf.st_uid, statbuf.st_gid); 982 (void) fclose(outfp); 983 (void) fclose(infp); 984 985 /* if we didn't change anything, we're done */ 986 if (!changed) { 987 (void) unlink(buf); 988 return (0); 989 } 990 991 /* construct the name of the backup copy of this file */ 992 (void) localtime_r(&(statbuf.st_mtime), &usetime); 993 (void) strftime(nambuf, sizeof (nambuf), datefmt, &usetime); 994 995 (void) snprintf(filbuf, sizeof (filbuf), "%s_%s", dbpath, nambuf); 996 997 /* finally, swap em */ 998 st = rename(dbpath, filbuf); 999 if (st != 0) { 1000 st = errno; 1001 (void) unlink(buf); 1002 } else { 1003 st = rename(buf, dbpath); 1004 if (st != 0) { 1005 st = errno; 1006 } 1007 } 1008 1009 return (st); 1010 } 1011 1012 static int 1013 get_dbver_from_optfile(char *path, int *version) 1014 { 1015 int st = 0; 1016 FILE *fp = NULL; 1017 char buf[1024]; 1018 char *bufp; 1019 int vers = -1; 1020 int last = -1; 1021 1022 if (!path || !version) { 1023 return (ENOENT); 1024 } 1025 1026 st = access(path, R_OK); 1027 if (st != 0) { 1028 st = errno; 1029 return (st); 1030 } 1031 1032 fp = fopen(path, "r"); 1033 if (fp == NULL) { 1034 st = errno; 1035 return (errno); 1036 } 1037 1038 while ((bufp = fgets(buf, sizeof (buf), fp)) != NULL) { 1039 if ((*bufp != '\0') && (!isdigit(*bufp))) { 1040 continue; 1041 } 1042 1043 do { 1044 bufp++; 1045 } while (isdigit(*bufp)); 1046 1047 if (*bufp != 'u') { 1048 continue; 1049 } 1050 1051 *bufp = '\0'; 1052 1053 vers = atoi(buf); 1054 if (vers > last) { 1055 last = vers; 1056 } 1057 } 1058 (void) fclose(fp); 1059 1060 *version = last; 1061 1062 return (st); 1063 } 1064 1065 static int 1066 mk_cmds_from_optfile(mmsdb_opts_t *opts, char *path, int vers, char cmdtype, 1067 int dopd, char **cmdfile) 1068 { 1069 int st = 0; 1070 int fd = -1; 1071 FILE *fp = NULL; 1072 FILE *ofp = NULL; 1073 char buf[MAXPATHLEN]; 1074 char *bufp; 1075 int started = 0; 1076 char *pass; 1077 1078 if (!opts || !path || !cmdfile) { 1079 return (MMS_MGMT_NOARG); 1080 } 1081 1082 st = access(path, R_OK); 1083 if (st != 0) { 1084 st = errno; 1085 return (st); 1086 } 1087 1088 fp = fopen(path, "r"); 1089 if (fp == NULL) { 1090 st = errno; 1091 return (errno); 1092 } 1093 1094 /* create our cmdfile */ 1095 (void) snprintf(buf, sizeof (buf), "%s/../mmsdbcmd-%c-%d", 1096 opts->path, cmdtype, time(NULL)); 1097 1098 fd = open(buf, O_CREAT|O_TRUNC|O_APPEND|O_WRONLY|O_NOFOLLOW|O_NOLINKS, 1099 0600); 1100 if (fd == -1) { 1101 st = errno; 1102 goto done; 1103 } 1104 1105 /* set this so the pguser can read it */ 1106 (void) fchown(fd, opts->dbuid, opts->dbgid); 1107 1108 ofp = fdopen(fd, "a"); 1109 if (ofp == NULL) { 1110 st = errno; 1111 (void) close(fd); 1112 goto done; 1113 } 1114 1115 *cmdfile = strdup(buf); 1116 1117 (void) fprintf(ofp, "BEGIN;\n"); 1118 1119 while ((bufp = fgets(buf, sizeof (buf), fp)) != NULL) { 1120 if (*bufp == '#') { 1121 continue; 1122 } 1123 1124 if (!isdigit(*bufp)) { 1125 if (started) { 1126 (void) fprintf(ofp, "%s", bufp); 1127 } 1128 continue; 1129 } 1130 1131 while (isdigit(*bufp)) { 1132 bufp++; 1133 } 1134 1135 if (*bufp++ == cmdtype) { 1136 started = 1; 1137 while (isspace(*buf)) { 1138 bufp++; 1139 } 1140 (void) fprintf(ofp, "%s", bufp); 1141 } else { 1142 started = 0; 1143 } 1144 } 1145 1146 if (dopd) { 1147 (void) fclose(fp); 1148 1149 /* override the junk password in the dbopts file */ 1150 pass = mms_net_cfg_read_pass_file(MMS_NET_CFG_HELLO_FILE); 1151 if (pass != NULL) { 1152 (void) fprintf(ofp, 1153 "UPDATE \"MMPASSWORD\" SET \"Password\" = '%s' " 1154 "WHERE \"ApplicationName\" = 'MMS';\n", 1155 pass); 1156 free(pass); 1157 } 1158 } 1159 1160 /* Set the version and add commit statement */ 1161 (void) fprintf(ofp, 1162 "UPDATE \"MM\" SET \"DBVersion\" = '%d';\nCOMMIT;\n", vers); 1163 1164 done: 1165 if (st != 0) { 1166 if (*cmdfile) { 1167 (void) unlink(*cmdfile); 1168 free(cmdfile); 1169 *cmdfile = NULL; 1170 } 1171 } 1172 (void) fclose(fp); 1173 (void) fclose(ofp); 1174 1175 return (st); 1176 } 1177 1178 static int 1179 mgmt_db_sql_exec(char *cmdfile, mmsdb_opts_t *opts) 1180 { 1181 int st; 1182 pid_t pid; 1183 FILE *dberr; 1184 char buf[MAXPATHLEN]; 1185 char *cmd[10]; 1186 char dbbuf[2048]; 1187 1188 if (!cmdfile || !opts) { 1189 return (MMS_MGMT_NOARG); 1190 } 1191 1192 (void) snprintf(dbbuf, sizeof (dbbuf), "%s/psql", opts->bindir); 1193 1194 cmd[0] = dbbuf; 1195 cmd[1] = "-a"; 1196 cmd[2] = "-h"; 1197 cmd[3] = opts->dbhost; 1198 cmd[4] = "-p"; 1199 cmd[5] = opts->port; 1200 cmd[6] = "-f"; 1201 cmd[7] = cmdfile; 1202 cmd[8] = opts->dbname; 1203 cmd[9] = NULL; 1204 1205 pid = exec_mgmt_cmd(NULL, &dberr, opts->dbuid, opts->dbgid, 1206 B_FALSE, cmd); 1207 mms_trace(MMS_DEBUG, "exec_mgmt_cmd: %s %s %s %s %s %s %s %s %s", 1208 cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], 1209 cmd[5], cmd[6], cmd[7], cmd[8]); 1210 1211 st = check_exit(pid, NULL); 1212 1213 if (st == 0) { 1214 while (fgets(buf, sizeof (buf), dberr) != NULL) { 1215 if ((strstr(buf, " ERROR: ") != NULL) || 1216 (strstr(buf, "ROLLBACK") != NULL)) { 1217 st = 1; 1218 break; 1219 } 1220 } 1221 } 1222 (void) fclose(dberr); 1223 1224 return (st); 1225 } 1226 1227 /* 1228 * this should probably move to a header somewhere, but for 1229 * now, leave it where it's directly mapped 1230 */ 1231 typedef struct { 1232 char *mm; 1233 char *ui; 1234 } mgmt_dbopt_map_t; 1235 1236 /* 1237 * map of MgmtUI-specified opts to MM options. NULL indicates 1238 * not exposed by MgmtUI 1239 */ 1240 static mgmt_dbopt_map_t mm_sys_opts[] = { 1241 {"AttendanceMode", O_ATTENDED}, 1242 {"SystemLogLevel", O_LOGLEVEL}, 1243 {"SystemLogFile", O_LOGFILE}, 1244 {"MessageLevel", O_MSGLEVEL}, 1245 {"TraceLevel", O_TRACELEVEL}, 1246 {"TraceFileSize", O_TRACESZ}, 1247 {"SocketFdLimit", O_NUMSOCKET}, 1248 {"SystemDiskMountTimeout", O_DKTIMEOUT}, 1249 {"WatcherStartsLimit", O_NUMRESTART}, 1250 {"SystemAcceptLevel", NULL}, 1251 {"SystemMessageLimit", NULL}, 1252 {"SystemMessageCount", NULL}, 1253 {"SystemRequestLimit", NULL}, 1254 {"SystemRequestCount", NULL}, 1255 {"SystemSyncLimit", NULL}, 1256 {"SystemDCALimit", NULL}, 1257 {"SystemDCACount", NULL}, 1258 {"ClearDriveAtLMConfig", NULL}, 1259 {"AskClearDriveAtLMConfig", NULL}, 1260 {"PreemptReservation", NULL}, 1261 {"SystemLogFileSize", NULL}, 1262 {"SystemName", NULL}, 1263 {"SystemInstance", NULL}, 1264 {"UnloadDelayTime", NULL}, 1265 {"DefaultBlocksize", NULL}, 1266 {"WatcherTimeLimit", NULL}, 1267 {"DriveRecordRetention", NULL}, 1268 {NULL, NULL} 1269 }; 1270 1271 /* add the MM options to the database before creation, if we know them */ 1272 static int 1273 set_mm_system_vars_db(nvlist_t *opts, char *cmdfile) 1274 { 1275 int st; 1276 char *val = NULL; 1277 int i; 1278 int fd = -1; 1279 FILE *ofp = NULL; 1280 struct stat sb; 1281 int changed = 0; 1282 1283 if (!opts) { 1284 return (0); 1285 } 1286 1287 if (!cmdfile) { 1288 return (MMS_MGMT_NOARG); 1289 } 1290 1291 fd = open(cmdfile, O_RDWR|O_NOFOLLOW|O_NOLINKS); 1292 if (fd == -1) { 1293 return (errno); 1294 } 1295 st = fstat(fd, &sb); 1296 if (st != 0) { 1297 st = errno; 1298 (void) close(fd); 1299 return (st); 1300 } 1301 1302 ofp = fdopen(fd, "a"); 1303 if (ofp == NULL) { 1304 st = errno; 1305 (void) close(fd); 1306 return (st); 1307 } 1308 1309 for (i = 0; mm_sys_opts[i].mm != NULL; i++) { 1310 if (mm_sys_opts[i].ui == NULL) { 1311 continue; 1312 } 1313 st = nvlist_lookup_string(opts, mm_sys_opts[i].ui, &val); 1314 if ((st == 0) && val) { 1315 if (!changed) { 1316 (void) fprintf(ofp, "BEGIN;\n"); 1317 } 1318 (void) fprintf(ofp, 1319 "UPDATE \"SYSTEM\" SET \"%s\" = '%s';\n", 1320 mm_sys_opts[i].mm, val); 1321 1322 changed++; 1323 } 1324 } 1325 1326 if (changed) { 1327 (void) fprintf(ofp, "COMMIT;\n"); 1328 } 1329 1330 (void) fclose(ofp); 1331 1332 return (0); 1333 } 1334 1335 int 1336 mgmt_set_db_pass(char *dbpass, nvlist_t *errs) 1337 { 1338 int st; 1339 mmsdb_opts_t opts; 1340 char buf[2048]; 1341 boolean_t ismd5 = B_FALSE; 1342 int fd = -1; 1343 int wr = 0; 1344 char file[MAXPATHLEN]; 1345 1346 /* no provided password means use 'trust' */ 1347 if (dbpass) { 1348 ismd5 = B_TRUE; 1349 } 1350 1351 st = mgmt_get_db_opts(&opts); 1352 if (st != 0) { 1353 return (st); 1354 } 1355 1356 /* tell Postgres to use the new password */ 1357 (void) snprintf(file, sizeof (file), "%s/../tsql", opts.path); 1358 fd = open64(file, O_CREAT|O_TRUNC|O_WRONLY, 0600); 1359 if (fd == -1) { 1360 st = errno; 1361 MGMT_ADD_ERR(errs, file, st); 1362 return (st); 1363 } 1364 1365 (void) fchown(fd, opts.dbuid, opts.dbgid); 1366 1367 (void) snprintf(buf, sizeof (buf), 1368 "alter user postgres with password '%s' valid until 'infinity';", 1369 dbpass); 1370 wr = write_buf(fd, buf, strlen(buf)); 1371 (void) close(fd); 1372 1373 if (wr == -1) { 1374 MGMT_ADD_ERR(errs, file, EIO); 1375 (void) unlink(file); 1376 return (EIO); 1377 } 1378 1379 st = mgmt_db_sql_exec(file, &opts); 1380 if (st != 0) { 1381 MGMT_ADD_ERR(errs, "postgres failure", st); 1382 (void) unlink(file); 1383 return (st); 1384 } 1385 1386 (void) unlink(file); 1387 1388 /* next, set up the conf file */ 1389 st = update_pghba(ismd5, &opts, errs); 1390 if (st != 0) { 1391 return (st); 1392 } 1393 1394 /* write the PGPASSFILE */ 1395 (void) snprintf(file, sizeof (file), "%s/../%s", 1396 opts.path, MMS_MGMT_PGA); 1397 fd = open64(file, O_CREAT|O_TRUNC|O_WRONLY, 0600); 1398 if (fd == -1) { 1399 st = errno; 1400 MGMT_ADD_ERR(errs, file, st); 1401 return (st); 1402 } 1403 (void) fchown(fd, opts.dbuid, opts.dbgid); 1404 1405 (void) snprintf(buf, sizeof (buf), "*:*:*:*:%s", dbpass); 1406 wr = write_buf(fd, buf, strlen(buf)); 1407 (void) close(fd); 1408 1409 if (wr == -1) { 1410 MGMT_ADD_ERR(errs, file, EIO); 1411 (void) unlink(file); 1412 return (EIO); 1413 } 1414 1415 st = mms_net_cfg_write_pass_file(MMS_NET_CFG_DB_FILE, dbpass); 1416 if (st != 0) { 1417 return (st); 1418 } 1419 1420 /* restart the db */ 1421 mms_trace(MMS_DEBUG, "restart db"); 1422 st = mgmt_set_svc_state(DBSVC, RESTART, NULL); 1423 1424 if (st == 0) { 1425 st = mgmt_db_ready(); 1426 if (st != 0) { 1427 mms_trace(MMS_ERR, 1428 "database did not go ready"); 1429 } 1430 } 1431 1432 return (st); 1433 } 1434 1435 static int 1436 update_pghba(boolean_t ismd5, mmsdb_opts_t *dbopts, nvlist_t *errs) 1437 { 1438 int st; 1439 char buf[2048]; 1440 char *bufp; 1441 int infd = -1; 1442 int outfd = -1; 1443 FILE *infp = NULL; 1444 FILE *outfp = NULL; 1445 struct stat64 statbuf; 1446 char confpath[2048]; 1447 char newconfpath[2048]; 1448 time_t now; 1449 struct tm usetime; 1450 static char datefmt[] = "%y""%m""%d""%H""%M""%S"; 1451 boolean_t changed = B_FALSE; 1452 char timebuf[256]; 1453 1454 if (!dbopts) { 1455 return (MMS_MGMT_NOARG); 1456 } 1457 1458 (void) snprintf(confpath, sizeof (confpath), "%s/pg_hba.conf", 1459 dbopts->path); 1460 1461 st = stat64(confpath, &statbuf); 1462 if (st != 0) { 1463 st = errno; 1464 MGMT_ADD_ERR(errs, confpath, st); 1465 return (st); 1466 } 1467 1468 /* construct the name of the new version of this file */ 1469 now = time(NULL); 1470 (void) localtime_r(&now, &usetime); 1471 (void) strftime(timebuf, sizeof (timebuf), datefmt, &usetime); 1472 (void) snprintf(newconfpath, sizeof (newconfpath), "%s_%s", confpath, 1473 timebuf); 1474 1475 /* open the original */ 1476 infd = open64(confpath, O_RDONLY); 1477 if (infd == -1) { 1478 st = errno; 1479 MGMT_ADD_ERR(errs, confpath, st); 1480 return (st); 1481 } 1482 1483 infp = fdopen(infd, "r"); 1484 if (infp == NULL) { 1485 st = errno; 1486 MGMT_ADD_ERR(errs, confpath, st); 1487 (void) close(infd); 1488 return (st); 1489 } 1490 1491 /* open the target file */ 1492 outfd = open64(newconfpath, O_CREAT|O_RDWR, 0600); 1493 if (outfd == -1) { 1494 st = errno; 1495 (void) close(infd); 1496 MGMT_ADD_ERR(errs, newconfpath, st); 1497 return (st); 1498 } 1499 1500 outfp = fdopen(outfd, "w"); 1501 if (outfp == NULL) { 1502 st = errno; 1503 (void) fclose(infp); 1504 (void) close(outfd); 1505 MGMT_ADD_ERR(errs, newconfpath, st); 1506 return (st); 1507 } 1508 1509 /* preserve, as much as possible, the existing format of the file */ 1510 while ((bufp = fgets(buf, sizeof (buf), infp)) != NULL) { 1511 while (isspace(*bufp)) { 1512 bufp++; 1513 } 1514 1515 if ((*bufp == '\0') || (*bufp == '#')) { 1516 (void) fprintf(outfp, "%s", buf); 1517 continue; 1518 } 1519 1520 /* look for 'trust' or 'md5' */ 1521 if (ismd5) { 1522 /* changing to password-protected */ 1523 bufp = strstr(buf, "trust"); 1524 if (bufp) { 1525 (void) strlcpy(bufp, "md5\n", 7); 1526 changed = B_TRUE; 1527 } 1528 } else { 1529 /* removing password protection */ 1530 bufp = strstr(buf, "md5"); 1531 if (bufp) { 1532 (void) strlcpy(bufp, "trust\n", 7); 1533 changed = B_TRUE; 1534 } 1535 } 1536 1537 (void) fprintf(outfp, "%s", buf); 1538 } 1539 1540 (void) fchown(outfd, dbopts->dbuid, dbopts->dbgid); 1541 (void) fclose(outfp); 1542 (void) fclose(infp); 1543 1544 /* if we didn't change anything, we're done */ 1545 if (!changed) { 1546 (void) unlink(newconfpath); 1547 return (0); 1548 } 1549 1550 /* construct the name of the backup copy of this file */ 1551 (void) localtime_r(&(statbuf.st_mtime), &usetime); 1552 (void) strftime(timebuf, sizeof (timebuf), datefmt, &usetime); 1553 1554 (void) snprintf(buf, sizeof (buf), "%s_%s", confpath, timebuf); 1555 1556 /* finally, swap em */ 1557 st = rename(confpath, buf); 1558 if (st != 0) { 1559 st = errno; 1560 (void) unlink(buf); 1561 MGMT_ADD_ERR(errs, confpath, st); 1562 } else { 1563 st = rename(newconfpath, confpath); 1564 if (st != 0) { 1565 st = errno; 1566 MGMT_ADD_ERR(errs, newconfpath, st); 1567 } 1568 } 1569 1570 return (st); 1571 } 1572