10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52267Sdp * Common Development and Distribution License (the "License").
62267Sdp * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
21390Sraf
220Sstevel@tonic-gate /*
239160SSherry.Moore@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #include <sys/param.h>
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #include <sys/sysmacros.h>
300Sstevel@tonic-gate #include <sys/systm.h>
310Sstevel@tonic-gate #include <sys/errno.h>
320Sstevel@tonic-gate #include <sys/vfs.h>
330Sstevel@tonic-gate #include <sys/vnode.h>
340Sstevel@tonic-gate #include <sys/swap.h>
350Sstevel@tonic-gate #include <sys/file.h>
360Sstevel@tonic-gate #include <sys/proc.h>
370Sstevel@tonic-gate #include <sys/var.h>
380Sstevel@tonic-gate #include <sys/uadmin.h>
390Sstevel@tonic-gate #include <sys/signal.h>
400Sstevel@tonic-gate #include <sys/time.h>
410Sstevel@tonic-gate #include <vm/seg_kmem.h>
420Sstevel@tonic-gate #include <sys/modctl.h>
430Sstevel@tonic-gate #include <sys/callb.h>
440Sstevel@tonic-gate #include <sys/dumphdr.h>
450Sstevel@tonic-gate #include <sys/debug.h>
460Sstevel@tonic-gate #include <sys/ftrace.h>
470Sstevel@tonic-gate #include <sys/cmn_err.h>
480Sstevel@tonic-gate #include <sys/panic.h>
490Sstevel@tonic-gate #include <sys/ddi.h>
500Sstevel@tonic-gate #include <sys/sunddi.h>
510Sstevel@tonic-gate #include <sys/policy.h>
520Sstevel@tonic-gate #include <sys/zone.h>
534579Scg209009 #include <sys/condvar.h>
544579Scg209009 #include <sys/thread.h>
556878Sbrendan #include <sys/sdt.h>
560Sstevel@tonic-gate
570Sstevel@tonic-gate /*
580Sstevel@tonic-gate * Administrivia system call. We provide this in two flavors: one for calling
590Sstevel@tonic-gate * from the system call path (uadmin), and the other for calling from elsewhere
600Sstevel@tonic-gate * within the kernel (kadmin). Callers must beware that certain uadmin cmd
610Sstevel@tonic-gate * values (specifically A_SWAPCTL) are only supported by uadmin and not kadmin.
620Sstevel@tonic-gate */
630Sstevel@tonic-gate
640Sstevel@tonic-gate extern ksema_t fsflush_sema;
650Sstevel@tonic-gate kmutex_t ualock;
664579Scg209009 kcondvar_t uacond;
674579Scg209009 kthread_t *ua_shutdown_thread = NULL;
680Sstevel@tonic-gate
692621Sllai1 int sys_shutdown = 0;
707656SSherry.Moore@Sun.COM volatile int fastreboot_dryrun = 0;
710Sstevel@tonic-gate
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate * Kill all user processes in said zone. A special argument of ALL_ZONES is
740Sstevel@tonic-gate * passed in when the system as a whole is shutting down. The lack of per-zone
750Sstevel@tonic-gate * process lists is likely to make the following a performance bottleneck on a
760Sstevel@tonic-gate * system with many zones.
770Sstevel@tonic-gate */
780Sstevel@tonic-gate void
killall(zoneid_t zoneid)790Sstevel@tonic-gate killall(zoneid_t zoneid)
800Sstevel@tonic-gate {
810Sstevel@tonic-gate proc_t *p;
820Sstevel@tonic-gate
830Sstevel@tonic-gate ASSERT(zoneid != GLOBAL_ZONEID);
840Sstevel@tonic-gate /*
850Sstevel@tonic-gate * Kill all processes except kernel daemons and ourself.
860Sstevel@tonic-gate * Make a first pass to stop all processes so they won't
870Sstevel@tonic-gate * be trying to restart children as we kill them.
880Sstevel@tonic-gate */
890Sstevel@tonic-gate mutex_enter(&pidlock);
900Sstevel@tonic-gate for (p = practive; p != NULL; p = p->p_next) {
910Sstevel@tonic-gate if ((zoneid == ALL_ZONES || p->p_zone->zone_id == zoneid) &&
920Sstevel@tonic-gate p->p_exec != NULLVP && /* kernel daemons */
930Sstevel@tonic-gate p->p_as != &kas &&
940Sstevel@tonic-gate p->p_stat != SZOMB) {
950Sstevel@tonic-gate mutex_enter(&p->p_lock);
960Sstevel@tonic-gate p->p_flag |= SNOWAIT;
970Sstevel@tonic-gate sigtoproc(p, NULL, SIGSTOP);
980Sstevel@tonic-gate mutex_exit(&p->p_lock);
990Sstevel@tonic-gate }
1000Sstevel@tonic-gate }
1010Sstevel@tonic-gate p = practive;
1020Sstevel@tonic-gate while (p != NULL) {
1030Sstevel@tonic-gate if ((zoneid == ALL_ZONES || p->p_zone->zone_id == zoneid) &&
1040Sstevel@tonic-gate p->p_exec != NULLVP && /* kernel daemons */
1050Sstevel@tonic-gate p->p_as != &kas &&
1060Sstevel@tonic-gate p->p_stat != SIDL &&
1070Sstevel@tonic-gate p->p_stat != SZOMB) {
1080Sstevel@tonic-gate mutex_enter(&p->p_lock);
1090Sstevel@tonic-gate if (sigismember(&p->p_sig, SIGKILL)) {
1100Sstevel@tonic-gate mutex_exit(&p->p_lock);
1110Sstevel@tonic-gate p = p->p_next;
1120Sstevel@tonic-gate } else {
1130Sstevel@tonic-gate sigtoproc(p, NULL, SIGKILL);
1140Sstevel@tonic-gate mutex_exit(&p->p_lock);
115*11066Srafael.vanoni@sun.com (void) cv_reltimedwait(&p->p_srwchan_cv,
116*11066Srafael.vanoni@sun.com &pidlock, hz, TR_CLOCK_TICK);
1170Sstevel@tonic-gate p = practive;
1180Sstevel@tonic-gate }
1190Sstevel@tonic-gate } else {
1200Sstevel@tonic-gate p = p->p_next;
1210Sstevel@tonic-gate }
1220Sstevel@tonic-gate }
1230Sstevel@tonic-gate mutex_exit(&pidlock);
1240Sstevel@tonic-gate }
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate int
kadmin(int cmd,int fcn,void * mdep,cred_t * credp)1270Sstevel@tonic-gate kadmin(int cmd, int fcn, void *mdep, cred_t *credp)
1280Sstevel@tonic-gate {
1290Sstevel@tonic-gate int error = 0;
1300Sstevel@tonic-gate char *buf;
1310Sstevel@tonic-gate size_t buflen = 0;
132136Sachartre boolean_t invoke_cb = B_FALSE;
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate /*
1350Sstevel@tonic-gate * We might be called directly by the kernel's fault-handling code, so
1360Sstevel@tonic-gate * we can't assert that the caller is in the global zone.
1370Sstevel@tonic-gate */
1380Sstevel@tonic-gate
1390Sstevel@tonic-gate /*
1400Sstevel@tonic-gate * Make sure that cmd is one of the valid <sys/uadmin.h> command codes
1410Sstevel@tonic-gate * and that we have appropriate privileges for this action.
1420Sstevel@tonic-gate */
1430Sstevel@tonic-gate switch (cmd) {
1440Sstevel@tonic-gate case A_FTRACE:
1450Sstevel@tonic-gate case A_SHUTDOWN:
1460Sstevel@tonic-gate case A_REBOOT:
1470Sstevel@tonic-gate case A_REMOUNT:
1480Sstevel@tonic-gate case A_FREEZE:
1490Sstevel@tonic-gate case A_DUMP:
1506878Sbrendan case A_SDTTEST:
1519160SSherry.Moore@Sun.COM case A_CONFIG:
1520Sstevel@tonic-gate if (secpolicy_sys_config(credp, B_FALSE) != 0)
1530Sstevel@tonic-gate return (EPERM);
1540Sstevel@tonic-gate break;
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate default:
1570Sstevel@tonic-gate return (EINVAL);
1580Sstevel@tonic-gate }
1590Sstevel@tonic-gate
1600Sstevel@tonic-gate /*
1614579Scg209009 * Serialize these operations on ualock. If it is held, the
1624579Scg209009 * system should shutdown, reboot, or remount shortly, unless there is
1634579Scg209009 * an error. We need a cv rather than just a mutex because proper
1644579Scg209009 * functioning of A_REBOOT relies on being able to interrupt blocked
1654579Scg209009 * userland callers.
1664579Scg209009 *
1679160SSherry.Moore@Sun.COM * We only clear ua_shutdown_thread after A_REMOUNT or A_CONFIG.
1689160SSherry.Moore@Sun.COM * Other commands should never return.
1690Sstevel@tonic-gate */
1709160SSherry.Moore@Sun.COM if (cmd == A_SHUTDOWN || cmd == A_REBOOT || cmd == A_REMOUNT ||
1719160SSherry.Moore@Sun.COM cmd == A_CONFIG) {
1724579Scg209009 mutex_enter(&ualock);
1734579Scg209009 while (ua_shutdown_thread != NULL) {
1744579Scg209009 if (cv_wait_sig(&uacond, &ualock) == 0) {
1754579Scg209009 /*
1764579Scg209009 * If we were interrupted, leave, and handle
1774579Scg209009 * the signal (or exit, depending on what
1784579Scg209009 * happened)
1794579Scg209009 */
1804579Scg209009 mutex_exit(&ualock);
1814579Scg209009 return (EINTR);
1824579Scg209009 }
1834579Scg209009 }
1844579Scg209009 ua_shutdown_thread = curthread;
1854579Scg209009 mutex_exit(&ualock);
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate switch (cmd) {
1890Sstevel@tonic-gate case A_SHUTDOWN:
1900Sstevel@tonic-gate {
1910Sstevel@tonic-gate proc_t *p = ttoproc(curthread);
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate /*
1940Sstevel@tonic-gate * Release (almost) all of our own resources if we are called
1950Sstevel@tonic-gate * from a user context, however if we are calling kadmin() from
1960Sstevel@tonic-gate * a kernel context then we do not release these resources.
1970Sstevel@tonic-gate */
198390Sraf if (p != &p0) {
199390Sraf proc_is_exiting(p);
2004434Scg209009 if ((error = exitlwps(0)) != 0) {
2014579Scg209009 /*
2024579Scg209009 * Another thread in this process also called
2034579Scg209009 * exitlwps().
2044579Scg209009 */
2054579Scg209009 mutex_enter(&ualock);
2064579Scg209009 ua_shutdown_thread = NULL;
2074579Scg209009 cv_signal(&uacond);
2084434Scg209009 mutex_exit(&ualock);
2090Sstevel@tonic-gate return (error);
2104434Scg209009 }
2110Sstevel@tonic-gate mutex_enter(&p->p_lock);
2120Sstevel@tonic-gate p->p_flag |= SNOWAIT;
2130Sstevel@tonic-gate sigfillset(&p->p_ignore);
2140Sstevel@tonic-gate curthread->t_lwp->lwp_cursig = 0;
2150Sstevel@tonic-gate curthread->t_lwp->lwp_extsig = 0;
2160Sstevel@tonic-gate if (p->p_exec) {
2170Sstevel@tonic-gate vnode_t *exec_vp = p->p_exec;
2180Sstevel@tonic-gate p->p_exec = NULLVP;
2190Sstevel@tonic-gate mutex_exit(&p->p_lock);
2200Sstevel@tonic-gate VN_RELE(exec_vp);
2210Sstevel@tonic-gate } else {
2220Sstevel@tonic-gate mutex_exit(&p->p_lock);
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate
2250Sstevel@tonic-gate pollcleanup();
2260Sstevel@tonic-gate closeall(P_FINFO(curproc));
2270Sstevel@tonic-gate relvm();
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate } else {
2300Sstevel@tonic-gate /*
2310Sstevel@tonic-gate * Reset t_cred if not set because much of the
2320Sstevel@tonic-gate * filesystem code depends on CRED() being valid.
2330Sstevel@tonic-gate */
2340Sstevel@tonic-gate if (curthread->t_cred == NULL)
2350Sstevel@tonic-gate curthread->t_cred = kcred;
2360Sstevel@tonic-gate }
2370Sstevel@tonic-gate
2382621Sllai1 /* indicate shutdown in progress */
2392621Sllai1 sys_shutdown = 1;
2402621Sllai1
2410Sstevel@tonic-gate /*
2420Sstevel@tonic-gate * Communcate that init shouldn't be restarted.
2430Sstevel@tonic-gate */
2440Sstevel@tonic-gate zone_shutdown_global();
2450Sstevel@tonic-gate
2460Sstevel@tonic-gate killall(ALL_ZONES);
2470Sstevel@tonic-gate /*
2480Sstevel@tonic-gate * If we are calling kadmin() from a kernel context then we
2490Sstevel@tonic-gate * do not release these resources.
2500Sstevel@tonic-gate */
2510Sstevel@tonic-gate if (ttoproc(curthread) != &p0) {
2523446Smrj VN_RELE(PTOU(curproc)->u_cdir);
2533446Smrj if (PTOU(curproc)->u_rdir)
2543446Smrj VN_RELE(PTOU(curproc)->u_rdir);
2553446Smrj if (PTOU(curproc)->u_cwd)
2563446Smrj refstr_rele(PTOU(curproc)->u_cwd);
2570Sstevel@tonic-gate
2583446Smrj PTOU(curproc)->u_cdir = rootdir;
2593446Smrj PTOU(curproc)->u_rdir = NULL;
2603446Smrj PTOU(curproc)->u_cwd = NULL;
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate /*
2640Sstevel@tonic-gate * Allow the reboot/halt/poweroff code a chance to do
2650Sstevel@tonic-gate * anything it needs to whilst we still have filesystems
2660Sstevel@tonic-gate * mounted, like loading any modules necessary for later
2670Sstevel@tonic-gate * performing the actual poweroff.
2680Sstevel@tonic-gate */
2690Sstevel@tonic-gate if ((mdep != NULL) && (*(char *)mdep == '/')) {
2700Sstevel@tonic-gate buf = i_convert_boot_device_name(mdep, NULL, &buflen);
2710Sstevel@tonic-gate mdpreboot(cmd, fcn, buf);
2720Sstevel@tonic-gate } else
2730Sstevel@tonic-gate mdpreboot(cmd, fcn, mdep);
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate /*
2760Sstevel@tonic-gate * Allow fsflush to finish running and then prevent it
2770Sstevel@tonic-gate * from ever running again so that vfs_unmountall() and
2780Sstevel@tonic-gate * vfs_syncall() can acquire the vfs locks they need.
2790Sstevel@tonic-gate */
2800Sstevel@tonic-gate sema_p(&fsflush_sema);
2810Sstevel@tonic-gate (void) callb_execute_class(CB_CL_UADMIN_PRE_VFS, NULL);
2820Sstevel@tonic-gate
2830Sstevel@tonic-gate vfs_unmountall();
2840Sstevel@tonic-gate (void) VFS_MOUNTROOT(rootvfs, ROOT_UNMOUNT);
2850Sstevel@tonic-gate vfs_syncall();
2860Sstevel@tonic-gate
2870Sstevel@tonic-gate dump_ereports();
2880Sstevel@tonic-gate dump_messages();
2890Sstevel@tonic-gate
290136Sachartre invoke_cb = B_TRUE;
291136Sachartre
2920Sstevel@tonic-gate /* FALLTHROUGH */
2930Sstevel@tonic-gate }
2940Sstevel@tonic-gate
2950Sstevel@tonic-gate case A_REBOOT:
2960Sstevel@tonic-gate if ((mdep != NULL) && (*(char *)mdep == '/')) {
2970Sstevel@tonic-gate buf = i_convert_boot_device_name(mdep, NULL, &buflen);
298136Sachartre mdboot(cmd, fcn, buf, invoke_cb);
2990Sstevel@tonic-gate } else
300136Sachartre mdboot(cmd, fcn, mdep, invoke_cb);
3010Sstevel@tonic-gate /* no return expected */
3020Sstevel@tonic-gate break;
3030Sstevel@tonic-gate
3049160SSherry.Moore@Sun.COM case A_CONFIG:
3059160SSherry.Moore@Sun.COM switch (fcn) {
3069160SSherry.Moore@Sun.COM case AD_UPDATE_BOOT_CONFIG:
3079160SSherry.Moore@Sun.COM #ifndef __sparc
3089160SSherry.Moore@Sun.COM {
3099160SSherry.Moore@Sun.COM extern void fastboot_update_config(const char *);
3109160SSherry.Moore@Sun.COM
31110559SSherry.Moore@Sun.COM fastboot_update_config(mdep);
3129160SSherry.Moore@Sun.COM }
3139160SSherry.Moore@Sun.COM #endif
3149160SSherry.Moore@Sun.COM
3159160SSherry.Moore@Sun.COM break;
3169160SSherry.Moore@Sun.COM }
3179160SSherry.Moore@Sun.COM /* Let other threads enter the shutdown path now */
3189160SSherry.Moore@Sun.COM mutex_enter(&ualock);
3199160SSherry.Moore@Sun.COM ua_shutdown_thread = NULL;
3209160SSherry.Moore@Sun.COM cv_signal(&uacond);
3219160SSherry.Moore@Sun.COM mutex_exit(&ualock);
3229160SSherry.Moore@Sun.COM break;
3239160SSherry.Moore@Sun.COM
3240Sstevel@tonic-gate case A_REMOUNT:
3250Sstevel@tonic-gate (void) VFS_MOUNTROOT(rootvfs, ROOT_REMOUNT);
3264579Scg209009 /* Let other threads enter the shutdown path now */
3274579Scg209009 mutex_enter(&ualock);
3284579Scg209009 ua_shutdown_thread = NULL;
3294579Scg209009 cv_signal(&uacond);
3304579Scg209009 mutex_exit(&ualock);
3310Sstevel@tonic-gate break;
3320Sstevel@tonic-gate
3330Sstevel@tonic-gate case A_FREEZE:
3340Sstevel@tonic-gate {
3355295Srandyf /*
3365295Srandyf * This is the entrypoint for all suspend/resume actions.
3375295Srandyf */
3385295Srandyf extern int cpr(int, void *);
3390Sstevel@tonic-gate
3400Sstevel@tonic-gate if (modload("misc", "cpr") == -1)
3410Sstevel@tonic-gate return (ENOTSUP);
3425295Srandyf /* Let the CPR module decide what to do with mdep */
3435295Srandyf error = cpr(fcn, mdep);
3440Sstevel@tonic-gate break;
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate case A_FTRACE:
3480Sstevel@tonic-gate {
3490Sstevel@tonic-gate switch (fcn) {
3500Sstevel@tonic-gate case AD_FTRACE_START:
3510Sstevel@tonic-gate (void) FTRACE_START();
3520Sstevel@tonic-gate break;
3530Sstevel@tonic-gate case AD_FTRACE_STOP:
3540Sstevel@tonic-gate (void) FTRACE_STOP();
3550Sstevel@tonic-gate break;
3560Sstevel@tonic-gate default:
3570Sstevel@tonic-gate error = EINVAL;
3580Sstevel@tonic-gate }
3590Sstevel@tonic-gate break;
3600Sstevel@tonic-gate }
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate case A_DUMP:
3630Sstevel@tonic-gate {
3640Sstevel@tonic-gate if (fcn == AD_NOSYNC) {
3650Sstevel@tonic-gate in_sync = 1;
3660Sstevel@tonic-gate break;
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate
3690Sstevel@tonic-gate panic_bootfcn = fcn;
3700Sstevel@tonic-gate panic_forced = 1;
3710Sstevel@tonic-gate
3720Sstevel@tonic-gate if ((mdep != NULL) && (*(char *)mdep == '/')) {
3730Sstevel@tonic-gate panic_bootstr = i_convert_boot_device_name(mdep,
3742267Sdp NULL, &buflen);
3750Sstevel@tonic-gate } else
3760Sstevel@tonic-gate panic_bootstr = mdep;
3770Sstevel@tonic-gate
3789160SSherry.Moore@Sun.COM #ifndef __sparc
37910559SSherry.Moore@Sun.COM extern void fastboot_update_and_load(int, char *);
3809160SSherry.Moore@Sun.COM
38110559SSherry.Moore@Sun.COM fastboot_update_and_load(fcn, mdep);
3829160SSherry.Moore@Sun.COM #endif
3839160SSherry.Moore@Sun.COM
3840Sstevel@tonic-gate panic("forced crash dump initiated at user request");
3850Sstevel@tonic-gate /*NOTREACHED*/
3860Sstevel@tonic-gate }
3870Sstevel@tonic-gate
3886878Sbrendan case A_SDTTEST:
3896878Sbrendan {
3906878Sbrendan DTRACE_PROBE7(test, int, 1, int, 2, int, 3, int, 4, int, 5,
3916878Sbrendan int, 6, int, 7);
3926878Sbrendan break;
3936878Sbrendan }
3946878Sbrendan
3950Sstevel@tonic-gate default:
3960Sstevel@tonic-gate error = EINVAL;
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate
3990Sstevel@tonic-gate return (error);
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate
4020Sstevel@tonic-gate int
uadmin(int cmd,int fcn,uintptr_t mdep)4030Sstevel@tonic-gate uadmin(int cmd, int fcn, uintptr_t mdep)
4040Sstevel@tonic-gate {
4050Sstevel@tonic-gate int error = 0, rv = 0;
4060Sstevel@tonic-gate size_t nbytes = 0;
4070Sstevel@tonic-gate cred_t *credp = CRED();
4082267Sdp char *bootargs = NULL;
4097656SSherry.Moore@Sun.COM int reset_status = 0;
4107656SSherry.Moore@Sun.COM
4117656SSherry.Moore@Sun.COM if (cmd == A_SHUTDOWN && fcn == AD_FASTREBOOT_DRYRUN) {
4127656SSherry.Moore@Sun.COM ddi_walk_devs(ddi_root_node(), check_driver_quiesce,
4137656SSherry.Moore@Sun.COM &reset_status);
4147656SSherry.Moore@Sun.COM if (reset_status != 0)
4157656SSherry.Moore@Sun.COM return (EIO);
4167656SSherry.Moore@Sun.COM else
4177656SSherry.Moore@Sun.COM return (0);
4187656SSherry.Moore@Sun.COM }
4190Sstevel@tonic-gate
4200Sstevel@tonic-gate /*
4210Sstevel@tonic-gate * The swapctl system call doesn't have its own entry point: it uses
4220Sstevel@tonic-gate * uadmin as a wrapper so we just call it directly from here.
4230Sstevel@tonic-gate */
4240Sstevel@tonic-gate if (cmd == A_SWAPCTL) {
4250Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE)
4260Sstevel@tonic-gate error = swapctl(fcn, (void *)mdep, &rv);
4270Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL)
4280Sstevel@tonic-gate else
4290Sstevel@tonic-gate error = swapctl32(fcn, (void *)mdep, &rv);
4300Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
4310Sstevel@tonic-gate return (error ? set_errno(error) : rv);
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate /*
4352267Sdp * Certain subcommands intepret a non-NULL mdep value as a pointer to
4362267Sdp * a boot string. We pull that in as bootargs, if applicable.
4370Sstevel@tonic-gate */
4382267Sdp if (mdep != NULL &&
4395295Srandyf (cmd == A_SHUTDOWN || cmd == A_REBOOT || cmd == A_DUMP ||
4409160SSherry.Moore@Sun.COM cmd == A_FREEZE || cmd == A_CONFIG)) {
4412267Sdp bootargs = kmem_zalloc(BOOTARGS_MAX, KM_SLEEP);
4422267Sdp if ((error = copyinstr((const char *)mdep, bootargs,
4432267Sdp BOOTARGS_MAX, &nbytes)) != 0) {
4442267Sdp kmem_free(bootargs, BOOTARGS_MAX);
4452267Sdp return (set_errno(error));
4462267Sdp }
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate
4490Sstevel@tonic-gate /*
4502267Sdp * Invoke the appropriate kadmin() routine.
4510Sstevel@tonic-gate */
4522267Sdp if (getzoneid() != GLOBAL_ZONEID)
4532267Sdp error = zone_kadmin(cmd, fcn, bootargs, credp);
4542267Sdp else
4552267Sdp error = kadmin(cmd, fcn, bootargs, credp);
4560Sstevel@tonic-gate
4572267Sdp if (bootargs != NULL)
4582267Sdp kmem_free(bootargs, BOOTARGS_MAX);
4592267Sdp return (error ? set_errno(error) : 0);
4600Sstevel@tonic-gate }
461