]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/dev/ppc/unix_signal.c
xnu-344.23.tar.gz
[apple/xnu.git] / bsd / dev / ppc / unix_signal.c
index 941ae0fe66d07ddab36b81c4c3b22550ebfa4020..bc2a1f20f14f0a556917cd9eac6246ea59df6efa 100644 (file)
@@ -3,22 +3,19 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
- * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
@@ -41,6 +38,7 @@
 #include <kern/thread.h>
 #include <kern/thread_act.h>
 #include <mach/ppc/thread_status.h>
+#define __ELF__ 0
 #include <ppc/proc_reg.h>
 
 #define        C_REDZONE_LEN           224
 #define        C_LINKAGE_LEN           48
 #define TRUNC_DOWN(a,b,c)  (((((unsigned)a)-(b))/(c)) * (c))
 
-/*
- * The stack layout possibilities (info style); This needs to mach with signal trampoline code
- *
- * Traditional:                        1
- * Traditional64:              20
- * Traditional64with vec:      25
- * 32bit context               30
- * 32bit context with vector   35
- * 64bit context               40
- * 64bit context with vector   45
- * Dual context                        50
- * Dual context with vector    55
- *
- */
-#define UC_TRAD                        1
-#define UC_TRAD64              20
-#define UC_TRAD64_VEC          25
-#define UC_FLAVOR              30
-#define UC_FLAVOR_VEC          35
-#define UC_FLAVOR64            40
-#define UC_FLAVOR64_VEC                45
-#define UC_DUAL                        50
-#define UC_DUAL_VEC            55
-
- /* The following are valid mcontext sizes */
-#define UC_FLAVOR_SIZE ((PPC_THREAD_STATE_COUNT + PPC_EXCEPTION_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int))
-
-#define UC_FLAVOR_VEC_SIZE ((PPC_THREAD_STATE_COUNT + PPC_EXCEPTION_STATE_COUNT + PPC_FLOAT_STATE_COUNT + PPC_VECTOR_STATE_COUNT) * sizeof(int))
-
-#define UC_FLAVOR64_SIZE ((PPC_THREAD_STATE64_COUNT + PPC_EXCEPTION_STATE64_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int))
-
-#define UC_FLAVOR64_VEC_SIZE ((PPC_THREAD_STATE64_COUNT + PPC_EXCEPTION_STATE64_COUNT + PPC_FLOAT_STATE_COUNT + PPC_VECTOR_STATE_COUNT) * sizeof(int))
-
-
 /*
  * Arrange for this process to run a signal handler
  */
@@ -96,7 +59,6 @@ sendsig(p, catcher, sig, mask, code)
        u_long code;
 {
        struct mcontext mctx, *p_mctx;
-       struct mcontext64 mctx64, *p_mctx64;
        struct ucontext uctx, *p_uctx;
        siginfo_t sinfo, *p_sinfo;
        struct sigacts *ps = p->p_sigacts;
@@ -107,115 +69,42 @@ sendsig(p, catcher, sig, mask, code)
        thread_act_t th_act;
        struct uthread *ut;
        unsigned long paramp,linkp;
-       int infostyle = UC_TRAD;
-       int dualcontext =0;
+       int infostyle = 1;
        sig_t trampact;
        int vec_used = 0;
        int stack_size = 0;
        int stack_flags = 0;
-       void * tstate;
-       int flavor;
-        int ctx32 = 1;
-       int is_64signalregset(void);
 
        th_act = current_act();
        ut = get_bsdthread_info(th_act);
 
-       
-       if (p->p_sigacts->ps_siginfo & sigmask(sig)) {
-               infostyle = UC_FLAVOR;
-        }
-       if(is_64signalregset() && (infostyle == UC_FLAVOR)) {
-               dualcontext = 1;
-               infostyle = UC_DUAL;    
-       }
-       if (p->p_sigacts->ps_64regset & sigmask(sig))  {
-               dualcontext = 0;
-                ctx32 = 0;
-               infostyle = UC_FLAVOR64;
-       }
-        if (is_64signalregset() && (infostyle == UC_TRAD)) {
-                ctx32=0;
-               infostyle = UC_TRAD64;
-       }
-       
-       /* I need this for SIGINFO anyway */
-       flavor = PPC_THREAD_STATE;
-       tstate = (void *)&mctx.ss;
+       state_count = PPC_EXCEPTION_STATE_COUNT;
+       if (act_machine_get_state(th_act, PPC_EXCEPTION_STATE, &mctx.es, &state_count)  != KERN_SUCCESS) {
+               goto bad;
+       }       
        state_count = PPC_THREAD_STATE_COUNT;
-       if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count)  != KERN_SUCCESS)
+       if (act_machine_get_state(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count)  != KERN_SUCCESS) {
                goto bad;
-
-       if ((ctx32 == 0) || dualcontext) {
-               flavor = PPC_THREAD_STATE64;
-               tstate = (void *)&mctx64.ss;
-               state_count = PPC_THREAD_STATE64_COUNT;
-                if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count)  != KERN_SUCCESS)
-                    goto bad;
-       }
-
-        if ((ctx32 == 1) || dualcontext) {
-                flavor = PPC_EXCEPTION_STATE;
-               tstate = (void *)&mctx.es;
-               state_count = PPC_EXCEPTION_STATE_COUNT;
-                if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count)  != KERN_SUCCESS)
-                    goto bad;
-       } 
-       
-       if ((ctx32 == 0) || dualcontext) {
-               flavor = PPC_EXCEPTION_STATE64;
-               tstate = (void *)&mctx64.es;
-               state_count = PPC_EXCEPTION_STATE64_COUNT;
-       
-                if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count)  != KERN_SUCCESS)
-                    goto bad;
-                
-        }
-       
-
-        if ((ctx32 == 1) || dualcontext) {
-                flavor = PPC_FLOAT_STATE;
-               tstate = (void *)&mctx.fs;
-               state_count = PPC_FLOAT_STATE_COUNT;
-                if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count)  != KERN_SUCCESS)
-                    goto bad;
-       } 
-       
-       if ((ctx32 == 0) || dualcontext) {
-               flavor = PPC_FLOAT_STATE;
-               tstate = (void *)&mctx64.fs;
-               state_count = PPC_FLOAT_STATE_COUNT;
-                       if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count)  != KERN_SUCCESS)
-                    goto bad;
-                
-        }
-
+       }       
+       state_count = PPC_FLOAT_STATE_COUNT;
+       if (act_machine_get_state(th_act, PPC_FLOAT_STATE, &mctx.fs, &state_count)  != KERN_SUCCESS) {
+               goto bad;
+       }       
 
        vec_save(th_act);
        if (find_user_vec(th_act)) {
                vec_used = 1;
-
-                if ((ctx32 == 1) || dualcontext) {
-                    flavor = PPC_VECTOR_STATE;
-                    tstate = (void *)&mctx.vs;
-                    state_count = PPC_VECTOR_STATE_COUNT;
-                    if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count)  != KERN_SUCCESS)
-                    goto bad;
-                    infostyle += 5;
-            } 
-       
-            if ((ctx32 == 0) || dualcontext) {
-                    flavor = PPC_VECTOR_STATE;
-                    tstate = (void *)&mctx64.vs;
-                    state_count = PPC_VECTOR_STATE_COUNT;
-                    if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count)  != KERN_SUCCESS)
-                        goto bad;
-                    infostyle += 5;
-           }
-       }  
+               state_count = PPC_VECTOR_STATE_COUNT;
+               if (act_machine_get_state(th_act, PPC_VECTOR_STATE, &mctx.vs, &state_count)  != KERN_SUCCESS) {
+                       goto bad;
+               }       
+               
+       }
 
        trampact = ps->ps_trampact[sig];
        oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK;
+       if (p->p_sigacts->ps_siginfo & sigmask(sig))
+               infostyle = 2;
 
        /* figure out where our new stack lives */
        if ((ps->ps_flags & SAS_ALTSTACK) && !oonstack &&
@@ -225,30 +114,13 @@ sendsig(p, catcher, sig, mask, code)
                stack_size = ps->ps_sigstk.ss_size;
                ps->ps_sigstk.ss_flags |= SA_ONSTACK;
        }
-       else {
-               if (ctx32 == 0)
-                       sp = (unsigned int)mctx64.ss.r1;
-               else
-                       sp = mctx.ss.r1;
-       }
+       else
+               sp = mctx.ss.r1;
 
-       
-       /* put siginfo on top */
-        
        /* preserve RED ZONE area */
        sp = TRUNC_DOWN(sp, C_REDZONE_LEN, C_STK_ALIGN);
 
-        /* next are the saved registers */
-        if ((ctx32 == 0) || dualcontext) {
-            sp -= sizeof(*p_mctx64);
-            p_mctx64 = (struct mcontext64 *)sp;
-        }
-        if ((ctx32 == 1) || dualcontext) {
-            sp -= sizeof(*p_mctx);
-            p_mctx = (struct mcontext *)sp;
-        }    
-        
-        /* context goes first on stack */
+       /* context goes first on stack */
        sp -= sizeof(*p_uctx);
        p_uctx = (struct ucontext *) sp;
 
@@ -256,9 +128,13 @@ sendsig(p, catcher, sig, mask, code)
        sp -= sizeof(*p_sinfo);
        p_sinfo = (siginfo_t *) sp;
 
+       /* next are the saved registers */
+       sp -= sizeof(*p_mctx);
+       p_mctx = (struct mcontext *)sp;
+
        /* C calling conventions, create param save and linkage
-       *  areas
-       */
+        *  areas
+        */
 
        sp = TRUNC_DOWN(sp, C_PARAMSAVE_LEN, C_STK_ALIGN);
        paramp = sp;
@@ -273,25 +149,14 @@ sendsig(p, catcher, sig, mask, code)
                uctx.uc_stack.ss_flags |= SS_ONSTACK;
                
        uctx.uc_link = 0;
-       if (ctx32 == 0)
-               uctx.uc_mcsize = (size_t)((PPC_EXCEPTION_STATE64_COUNT + PPC_THREAD_STATE64_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int));
-       else
-               uctx.uc_mcsize = (size_t)((PPC_EXCEPTION_STATE_COUNT + PPC_THREAD_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int));
-       
+       uctx.uc_mcsize = (size_t)((PPC_EXCEPTION_STATE_COUNT + PPC_THREAD_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int));
        if (vec_used) 
                uctx.uc_mcsize += (size_t)(PPC_VECTOR_STATE_COUNT * sizeof(int));
-        
-       if (ctx32 == 0)
-             uctx.uc_mcontext = (void *)p_mctx64;
-       else
-            uctx.uc_mcontext = (void *)p_mctx;
+       uctx.uc_mcontext = p_mctx;
 
        /* setup siginfo */
        bzero((caddr_t)&sinfo, sizeof(siginfo_t));
        sinfo.si_signo = sig;
-       sinfo.si_addr = (void *)mctx.ss.srr0;
-       sinfo.pad[0] = (unsigned int)mctx.ss.r1;
-
        switch (sig) {
                case SIGCHLD:
                        sinfo.si_pid = p->si_pid;
@@ -365,23 +230,13 @@ sendsig(p, catcher, sig, mask, code)
                        break;
        }
 
-
        /* copy info out to user space */
        if (copyout((caddr_t)&uctx, (caddr_t)p_uctx, sizeof(struct ucontext)))
                goto bad;
        if (copyout((caddr_t)&sinfo, (caddr_t)p_sinfo, sizeof(siginfo_t)))
                goto bad;
-        if ((ctx32 == 0) || dualcontext) {
-               tstate = &mctx64;
-            if (copyout((caddr_t)tstate, (caddr_t)p_mctx64, uctx.uc_mcsize))
+       if (copyout((caddr_t)&mctx, (caddr_t)p_mctx, uctx.uc_mcsize))
                goto bad;
-        }
-        if ((ctx32 == 1) || dualcontext) {
-               tstate = &mctx;
-            if (copyout((caddr_t)tstate, (caddr_t)p_mctx, uctx.uc_mcsize))
-               goto bad;
-        }    
-
 
        /* Place our arguments in arg registers: rtm dependent */
 
@@ -395,9 +250,10 @@ sendsig(p, catcher, sig, mask, code)
        mctx.ss.srr1 = get_msr_exportmask();    /* MSR_EXPORT_MASK_SET */
        mctx.ss.r1 = sp;
        state_count = PPC_THREAD_STATE_COUNT;
-       if (thread_setstatus(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count)  != KERN_SUCCESS) {
+       if (act_machine_set_state(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count)  != KERN_SUCCESS) {
                goto bad;
        }       
+
        return;
 
 bad:
@@ -421,121 +277,8 @@ bad:
  * psl to gain improper priviledges or to cause
  * a machine fault.
  */
-
-#define FOR64_TRANSITION 1
-
-#ifdef FOR64_TRANSITION
-
-struct osigreturn_args {
-       struct ucontext *uctx;
-};
-
-/* ARGSUSED */
-int
-osigreturn(p, uap, retval)
-       struct proc *p;
-       struct osigreturn_args *uap;
-       int *retval;
-{
-       struct ucontext uctx;
-       struct ucontext *p_uctx;
-       struct mcontext64 mctx64;
-       struct mcontext64 *p_64mctx;
-       struct mcontext  *p_mctx;
-       int error;
-       thread_act_t th_act;
-       struct sigacts *ps = p->p_sigacts;
-       sigset_t mask;  
-       register sig_t action;
-       unsigned long state_count;
-       unsigned int state_flavor;
-       struct uthread * ut;
-       int vec_used = 0;
-       void *tsptr, *fptr, *vptr, *mactx;
-       void ppc_checkthreadstate(void *, int);
-
-       th_act = current_act();
-       /* lets use the larger one */
-       mactx = (void *)&mctx64;
-
-       ut = (struct uthread *)get_bsdthread_info(th_act);
-       if (error = copyin(uap->uctx, &uctx, sizeof(struct ucontext))) {
-               return(error);
-       }
-       if (error = copyin(uctx.uc_mcontext, mactx, uctx.uc_mcsize)) {
-               return(error);
-       }
-       
-       if (uctx.uc_onstack & 01)
-                       p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK;
-       else
-               p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK;
-
-       ut->uu_sigmask = uctx.uc_sigmask & ~sigcantmask;
-       if (ut->uu_siglist & ~ut->uu_sigmask)
-               signal_setast(current_act());   
-
-       vec_used = 0;
-       switch (uctx.uc_mcsize)  {
-               case UC_FLAVOR64_VEC_SIZE :
-                       vec_used = 1;
-               case UC_FLAVOR64_SIZE : {
-                       p_64mctx = (struct mcontext64 *)mactx;  
-                       tsptr = (void *)&p_64mctx->ss;
-                       fptr = (void *)&p_64mctx->fs;
-                       vptr = (void *)&p_64mctx->vs;
-                       state_flavor = PPC_THREAD_STATE64;
-                       state_count = PPC_THREAD_STATE64_COUNT;
-                       }
-                       break;
-               case UC_FLAVOR_VEC_SIZE :
-                       vec_used = 1;
-               case UC_FLAVOR_SIZE:
-               default: {
-                       p_mctx = (struct mcontext *)mactx;      
-                       tsptr = (void *)&p_mctx->ss;
-                       fptr = (void *)&p_mctx->fs;
-                       vptr = (void *)&p_mctx->vs;
-                       state_flavor = PPC_THREAD_STATE;
-                       state_count = PPC_THREAD_STATE_COUNT;
-               }
-               break;
-       } /* switch () */
-
-       /* validate the thread state, set/reset appropriate mode bits in srr1 */
-       (void)ppc_checkthreadstate(tsptr, state_flavor);
-
-       if (thread_setstatus(th_act, state_flavor, tsptr, &state_count)  != KERN_SUCCESS) {
-               return(EINVAL);
-       }       
-
-       state_count = PPC_FLOAT_STATE_COUNT;
-       if (thread_setstatus(th_act, PPC_FLOAT_STATE, fptr, &state_count)  != KERN_SUCCESS) {
-               return(EINVAL);
-       }       
-
-       mask = sigmask(SIGFPE);
-       if (((ut->uu_sigmask & mask) == 0) && (p->p_sigcatch & mask) && ((p->p_sigignore & mask) == 0)) {
-               action = ps->ps_sigact[SIGFPE];
-               if((action != SIG_DFL) && (action != SIG_IGN)) {
-                       thread_enable_fpe(th_act, 1);
-               }
-       }
-
-       if (vec_used) {
-               state_count = PPC_VECTOR_STATE_COUNT;
-               if (thread_setstatus(th_act, PPC_VECTOR_STATE, vptr, &state_count)  != KERN_SUCCESS) {
-                       return(EINVAL);
-               }       
-       }
-       return (EJUSTRETURN);
-}
-
-#endif /* FOR64_TRANSITION */
-
 struct sigreturn_args {
        struct ucontext *uctx;
-        int infostyle;
 };
 
 /* ARGSUSED */
@@ -545,23 +288,19 @@ sigreturn(p, uap, retval)
        struct sigreturn_args *uap;
        int *retval;
 {
-       struct ucontext uctx;
-       struct ucontext *p_uctx;
-        char mactx[sizeof(struct mcontext64)];
-       struct mcontext  *p_mctx;
-       struct mcontext64 *p_64mctx;
+       struct ucontext uctx, *p_uctx;
+       struct mcontext mctx, *p_mctx;
        int error;
        thread_act_t th_act;
+       struct ppc_float_state fs;
+       struct ppc_exception_state es;
        struct sigacts *ps = p->p_sigacts;
        sigset_t mask;  
        register sig_t action;
        unsigned long state_count;
-       unsigned int state_flavor;
+       unsigned int nbits, rbits;
        struct uthread * ut;
        int vec_used = 0;
-       void *tsptr, *fptr, *vptr;
-        int infostyle = uap->infostyle;
-       void ppc_checkthreadstate(void *, int);
 
        th_act = current_act();
 
@@ -569,9 +308,7 @@ sigreturn(p, uap, retval)
        if (error = copyin(uap->uctx, &uctx, sizeof(struct ucontext))) {
                return(error);
        }
-        
-        
-       if (error = copyin(uctx.uc_mcontext, mactx, uctx.uc_mcsize)) {
+       if (error = copyin(uctx.uc_mcontext, &mctx, sizeof(struct mcontext))) {
                return(error);
        }
        
@@ -579,49 +316,32 @@ sigreturn(p, uap, retval)
                        p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK;
        else
                p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK;
-
        ut->uu_sigmask = uctx.uc_sigmask & ~sigcantmask;
+
+
        if (ut->uu_siglist & ~ut->uu_sigmask)
                signal_setast(current_act());   
 
-       vec_used = 0;
-       switch (infostyle)  {
-                case UC_FLAVOR64_VEC:
-                case UC_TRAD64_VEC:
-                                vec_used = 1;
-                case UC_TRAD64:
-               case UC_FLAVOR64:  {
-                            p_64mctx = (struct mcontext64 *)mactx;     
-                            tsptr = (void *)&p_64mctx->ss;
-                            fptr = (void *)&p_64mctx->fs;
-                            vptr = (void *)&p_64mctx->vs;
-                            state_flavor = PPC_THREAD_STATE64;
-                            state_count = PPC_THREAD_STATE64_COUNT;
-                    } 
-                    break;
-               case UC_FLAVOR_VEC :
-                                vec_used = 1;
-               case UC_FLAVOR :
-               default: {
-                       p_mctx = (struct mcontext *)mactx;      
-                       tsptr = (void *)&p_mctx->ss;
-                       fptr = (void *)&p_mctx->fs;
-                       vptr = (void *)&p_mctx->vs;
-                       state_flavor = PPC_THREAD_STATE;
-                       state_count = PPC_THREAD_STATE_COUNT;
-               }
-               break;
-       } /* switch () */
+       nbits = get_msr_nbits();
+       rbits = get_msr_rbits();
+       /* adjust the critical fields */
+       /* make sure naughty bits are off */
+       mctx.ss.srr1 &= ~(nbits);
+       /* make sure necessary bits are on */
+       mctx.ss.srr1 |= (rbits);
 
-       /* validate the thread state, set/reset appropriate mode bits in srr1 */
-       (void)ppc_checkthreadstate(tsptr, state_flavor);
+       state_count = (size_t)((PPC_EXCEPTION_STATE_COUNT + PPC_THREAD_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int));
 
-       if (thread_setstatus(th_act, state_flavor, tsptr, &state_count)  != KERN_SUCCESS) {
+       if (uctx.uc_mcsize > state_count)
+               vec_used = 1;
+
+       state_count = PPC_THREAD_STATE_COUNT;
+       if (act_machine_set_state(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count)  != KERN_SUCCESS) {
                return(EINVAL);
        }       
 
        state_count = PPC_FLOAT_STATE_COUNT;
-       if (thread_setstatus(th_act, PPC_FLOAT_STATE, fptr, &state_count)  != KERN_SUCCESS) {
+       if (act_machine_set_state(th_act, PPC_FLOAT_STATE, &mctx.fs, &state_count)  != KERN_SUCCESS) {
                return(EINVAL);
        }       
 
@@ -635,10 +355,11 @@ sigreturn(p, uap, retval)
 
        if (vec_used) {
                state_count = PPC_VECTOR_STATE_COUNT;
-               if (thread_setstatus(th_act, PPC_VECTOR_STATE, vptr, &state_count)  != KERN_SUCCESS) {
+               if (act_machine_set_state(th_act, PPC_VECTOR_STATE, &mctx.vs, &state_count)  != KERN_SUCCESS) {
                        return(EINVAL);
                }       
        }
+
        return (EJUSTRETURN);
 }