misc.c

Go to the documentation of this file.
00001 
00017 #include "pm.h"
00018 #include <minix/callnr.h>
00019 #include <signal.h>
00020 #include <sys/svrctl.h>
00021 #include <sys/resource.h>
00022 #include <minix/com.h>
00023 #include <minix/config.h>
00024 #include <minix/type.h>
00025 #include <string.h>
00026 #include <lib.h>
00027 #include "mproc.h"
00028 #include "param.h"
00029 #include "../../kernel/proc.h"
00030 
00031 /*===========================================================================*
00032  *                              do_allocmem                                  *
00033  *===========================================================================*/
00034 PUBLIC int do_allocmem()
00035 {
00036   vir_clicks mem_clicks;
00037   phys_clicks mem_base;
00038 
00039   mem_clicks = (m_in.memsize + CLICK_SIZE -1 ) >> CLICK_SHIFT;
00040   mem_base = alloc_mem(mem_clicks);
00041   if (mem_base == NO_MEM) return(ENOMEM);
00042   mp->mp_reply.membase =  (phys_bytes) (mem_base << CLICK_SHIFT);
00043   return(OK);
00044 }
00045 
00046 /*===========================================================================*
00047  *                              do_freemem                                   *
00048  *===========================================================================*/
00049 PUBLIC int do_freemem()
00050 {
00051   vir_clicks mem_clicks;
00052   phys_clicks mem_base;
00053 
00054   mem_clicks = (m_in.memsize + CLICK_SIZE -1 ) >> CLICK_SHIFT;
00055   mem_base = (m_in.membase + CLICK_SIZE -1 ) >> CLICK_SHIFT;
00056   free_mem(mem_base, mem_clicks);
00057   return(OK);
00058 }
00059 
00060 /*===========================================================================*
00061  *                              do_procstat                                  *
00062  *===========================================================================*/
00063 PUBLIC int do_procstat()
00064 { 
00065   /* For the moment, this is only used to return pending signals to 
00066    * system processes that request the PM for their own status. 
00067    *
00068    * Future use might include the FS requesting for process status of
00069    * any user process. 
00070    */
00071   if (m_in.stat_nr == SELF) {
00072       mp->mp_reply.sig_set = mp->mp_sigpending;
00073       sigemptyset(&mp->mp_sigpending);
00074   } 
00075   else {
00076       return(ENOSYS);
00077   }
00078   return(OK);
00079 }
00080 
00081 /*===========================================================================*
00082  *                              do_getsysinfo                                *
00083  *===========================================================================*/
00084 PUBLIC int do_getsysinfo()
00085 {
00086   struct mproc *proc_addr;
00087   vir_bytes src_addr, dst_addr;
00088   struct kinfo kinfo;
00089   struct loadinfo loadinfo;
00090   static struct proc proctab[NR_PROCS+NR_TASKS];
00091   size_t len;
00092   static struct pm_mem_info pmi;
00093   int s, r;
00094   size_t holesize;
00095 
00096   switch(m_in.info_what) {
00097   case SI_KINFO:                        /* kernel info is obtained via PM */
00098         sys_getkinfo(&kinfo);
00099         src_addr = (vir_bytes) &kinfo;
00100         len = sizeof(struct kinfo);
00101         break;
00102   case SI_PROC_ADDR:                    /* get address of PM process table */
00103         proc_addr = &mproc[0];
00104         src_addr = (vir_bytes) &proc_addr;
00105         len = sizeof(struct mproc *);
00106         break; 
00107   case SI_PROC_TAB:                     /* copy entire process table */
00108         src_addr = (vir_bytes) mproc;
00109         len = sizeof(struct mproc) * NR_PROCS;
00110         break;
00111   case SI_KPROC_TAB:                    /* copy entire process table */
00112         if((r=sys_getproctab(proctab)) != OK)
00113                 return r;
00114         src_addr = (vir_bytes) proctab;
00115         len = sizeof(proctab);
00116         break;
00117   case SI_MEM_ALLOC:
00118         holesize = sizeof(pmi.pmi_holes);
00119         if((r=mem_holes_copy(pmi.pmi_holes, &holesize,
00120            &pmi.pmi_hi_watermark)) != OK)
00121                 return r;
00122         src_addr = (vir_bytes) &pmi;
00123         len = sizeof(pmi);
00124         break;
00125   case SI_LOADINFO:                     /* loadinfo is obtained via PM */
00126         sys_getloadinfo(&loadinfo);
00127         src_addr = (vir_bytes) &loadinfo;
00128         len = sizeof(struct loadinfo);
00129         break;
00130   default:
00131         return(EINVAL);
00132   }
00133 
00134   dst_addr = (vir_bytes) m_in.info_where;
00135   if (OK != (s=sys_datacopy(SELF, src_addr, who_e, dst_addr, len)))
00136         return(s);
00137   return(OK);
00138 }
00139 
00140 /*===========================================================================*
00141  *                              do_getprocnr                                 *
00142  *===========================================================================*/
00143 PUBLIC int do_getprocnr()
00144 {
00145   register struct mproc *rmp;
00146   static char search_key[PROC_NAME_LEN+1];
00147   int key_len;
00148   int s;
00149 
00150   if (m_in.pid >= 0) {                  /* lookup process by pid */
00151         for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
00152                 if ((rmp->mp_flags & IN_USE) && (rmp->mp_pid==m_in.pid)) {
00153                         mp->mp_reply.endpt = rmp->mp_endpoint;
00154                         return(OK);
00155                 } 
00156         }
00157         return(ESRCH);                  
00158   } else if (m_in.namelen > 0) {        /* lookup process by name */
00159         key_len = MIN(m_in.namelen, PROC_NAME_LEN);
00160         if (OK != (s=sys_datacopy(who_e, (vir_bytes) m_in.addr, 
00161                         SELF, (vir_bytes) search_key, key_len))) 
00162                 return(s);
00163         search_key[key_len] = '\0';     /* terminate for safety */
00164         for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
00165                 if (((rmp->mp_flags & (IN_USE | ZOMBIE)) == IN_USE) && 
00166                         strncmp(rmp->mp_name, search_key, key_len)==0) {
00167                         mp->mp_reply.endpt = rmp->mp_endpoint;
00168                         return(OK);
00169                 } 
00170         }
00171         return(ESRCH);                  
00172   } else {                      /* return own/parent process number */
00173         mp->mp_reply.endpt = who_e;
00174         mp->mp_reply.pendpt = mproc[mp->mp_parent].mp_endpoint;
00175   }
00176 
00177   return(OK);
00178 }
00179 
00180 /*===========================================================================*
00181  *                              do_reboot                                    *
00182  *===========================================================================*/
00183 PUBLIC int do_reboot()
00184 {
00185   char monitor_code[256];               
00186   vir_bytes code_addr;
00187   int code_size;
00188   int abort_flag;
00189 
00190   /* Check permission to abort the system. */
00191   if (mp->mp_effuid != SUPER_USER) return(EPERM);
00192 
00193   /* See how the system should be aborted. */
00194   abort_flag = (unsigned) m_in.reboot_flag;
00195   if (abort_flag >= RBT_INVALID) return(EINVAL); 
00196   if (RBT_MONITOR == abort_flag) {
00197         int r;
00198         if(m_in.reboot_strlen >= sizeof(monitor_code))
00199                 return EINVAL;
00200         if((r = sys_datacopy(who_e, (vir_bytes) m_in.reboot_code,
00201                 SELF, (vir_bytes) monitor_code, m_in.reboot_strlen)) != OK)
00202                 return r;
00203         code_addr = (vir_bytes) monitor_code;
00204         monitor_code[m_in.reboot_strlen] = '\0';
00205         code_size = m_in.reboot_strlen + 1;
00206   }
00207 
00208   /* Order matters here. When FS is told to reboot, it exits all its
00209    * processes, and then would be confused if they're exited again by
00210    * SIGKILL. So first kill, then reboot. 
00211    */
00212 
00213   check_sig(-1, SIGKILL);               /* kill all users except init */
00214   sys_nice(INIT_PROC_NR, PRIO_STOP);    /* stop init, but keep it around */
00215   tell_fs(REBOOT, 0, 0, 0);             /* tell FS to synchronize */
00216 
00217   /* Ask the kernel to abort. All system services, including the PM, will 
00218    * get a HARD_STOP notification. Await the notification in the main loop.
00219    */
00220   sys_abort(abort_flag, PM_PROC_NR, code_addr, code_size);
00221   return(SUSPEND);                      /* don't reply to caller */
00222 }
00223 
00224 /*===========================================================================*
00225  *                              do_getsetpriority                            *
00226  *===========================================================================*/
00227 PUBLIC int do_getsetpriority()
00228 {
00229         int arg_which, arg_who, arg_pri;
00230         int rmp_nr;
00231         struct mproc *rmp;
00232 
00233         arg_which = m_in.m1_i1;
00234         arg_who = m_in.m1_i2;
00235         arg_pri = m_in.m1_i3;   /* for SETPRIORITY */
00236 
00237         /* Code common to GETPRIORITY and SETPRIORITY. */
00238 
00239         /* Only support PRIO_PROCESS for now. */
00240         if (arg_which != PRIO_PROCESS)
00241                 return(EINVAL);
00242 
00243         if (arg_who == 0)
00244                 rmp_nr = who_p;
00245         else
00246                 if ((rmp_nr = proc_from_pid(arg_who)) < 0)
00247                         return(ESRCH);
00248 
00249         rmp = &mproc[rmp_nr];
00250 
00251         if (mp->mp_effuid != SUPER_USER &&
00252            mp->mp_effuid != rmp->mp_effuid && mp->mp_effuid != rmp->mp_realuid)
00253                 return EPERM;
00254 
00255         /* If GET, that's it. */
00256         if (call_nr == GETPRIORITY) {
00257                 return(rmp->mp_nice - PRIO_MIN);
00258         }
00259 
00260         /* Only root is allowed to reduce the nice level. */
00261         if (rmp->mp_nice > arg_pri && mp->mp_effuid != SUPER_USER)
00262                 return(EACCES);
00263         
00264         /* We're SET, and it's allowed. Do it and tell kernel. */
00265         rmp->mp_nice = arg_pri;
00266         return sys_nice(rmp->mp_endpoint, arg_pri);
00267 }
00268 
00269 /*===========================================================================*
00270  *                              do_svrctl                                    *
00271  *===========================================================================*/
00272 PUBLIC int do_svrctl()
00273 {
00274   int s, req;
00275   vir_bytes ptr;
00276 #define MAX_LOCAL_PARAMS 2
00277   static struct {
00278         char name[30];
00279         char value[30];
00280   } local_param_overrides[MAX_LOCAL_PARAMS];
00281   static int local_params = 0;
00282 
00283   req = m_in.svrctl_req;
00284   ptr = (vir_bytes) m_in.svrctl_argp;
00285 
00286   /* Is the request indeed for the MM? */
00287   if (((req >> 8) & 0xFF) != 'M') return(EINVAL);
00288 
00289   /* Control operations local to the PM. */
00290   switch(req) {
00291   case MMSETPARAM:
00292   case MMGETPARAM: {
00293       struct sysgetenv sysgetenv;
00294       char search_key[64];
00295       char *val_start;
00296       size_t val_len;
00297       size_t copy_len;
00298 
00299       /* Copy sysgetenv structure to PM. */
00300       if (sys_datacopy(who_e, ptr, SELF, (vir_bytes) &sysgetenv, 
00301               sizeof(sysgetenv)) != OK) return(EFAULT);  
00302 
00303       /* Set a param override? */
00304       if (req == MMSETPARAM) {
00305         if (local_params >= MAX_LOCAL_PARAMS) return ENOSPC;
00306         if (sysgetenv.keylen <= 0
00307          || sysgetenv.keylen >=
00308                  sizeof(local_param_overrides[local_params].name)
00309          || sysgetenv.vallen <= 0
00310          || sysgetenv.vallen >=
00311                  sizeof(local_param_overrides[local_params].value))
00312                 return EINVAL;
00313                 
00314           if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key,
00315             SELF, (vir_bytes) local_param_overrides[local_params].name,
00316                sysgetenv.keylen)) != OK)
00317                 return s;
00318           if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.val,
00319             SELF, (vir_bytes) local_param_overrides[local_params].value,
00320               sysgetenv.keylen)) != OK)
00321                 return s;
00322             local_param_overrides[local_params].name[sysgetenv.keylen] = '\0';
00323             local_param_overrides[local_params].value[sysgetenv.vallen] = '\0';
00324 
00325         local_params++;
00326 
00327         return OK;
00328       }
00329 
00330       if (sysgetenv.keylen == 0) {      /* copy all parameters */
00331           val_start = monitor_params;
00332           val_len = sizeof(monitor_params);
00333       } 
00334       else {                            /* lookup value for key */
00335           int p;
00336           /* Try to get a copy of the requested key. */
00337           if (sysgetenv.keylen > sizeof(search_key)) return(EINVAL);
00338           if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key,
00339                   SELF, (vir_bytes) search_key, sysgetenv.keylen)) != OK)
00340               return(s);
00341 
00342           /* Make sure key is null-terminated and lookup value.
00343            * First check local overrides.
00344            */
00345           search_key[sysgetenv.keylen-1]= '\0';
00346           for(p = 0; p < local_params; p++) {
00347                 if (!strcmp(search_key, local_param_overrides[p].name)) {
00348                         val_start = local_param_overrides[p].value;
00349                         break;
00350                 }
00351           }
00352           if (p >= local_params && (val_start = find_param(search_key)) == NULL)
00353                return(ESRCH);
00354           val_len = strlen(val_start) + 1;
00355       }
00356 
00357       /* See if it fits in the client's buffer. */
00358       if (val_len > sysgetenv.vallen)
00359         return E2BIG;
00360 
00361       /* Value found, make the actual copy (as far as possible). */
00362       copy_len = MIN(val_len, sysgetenv.vallen); 
00363       if ((s=sys_datacopy(SELF, (vir_bytes) val_start, 
00364               who_e, (vir_bytes) sysgetenv.val, copy_len)) != OK)
00365           return(s);
00366 
00367       return OK;
00368   }
00369 
00370 #if ENABLE_SWAP
00371   case MMSWAPON: {
00372         struct mmswapon swapon;
00373 
00374         if (mp->mp_effuid != SUPER_USER) return(EPERM);
00375 
00376         if (sys_datacopy(who_e, (phys_bytes) ptr,
00377                 PM_PROC_NR, (phys_bytes) &swapon,
00378                 (phys_bytes) sizeof(swapon)) != OK) return(EFAULT);
00379 
00380         return(swap_on(swapon.file, swapon.offset, swapon.size)); }
00381 
00382   case MMSWAPOFF: {
00383         if (mp->mp_effuid != SUPER_USER) return(EPERM);
00384 
00385         return(swap_off()); }
00386 #endif /* SWAP */
00387 
00388   default:
00389         return(EINVAL);
00390   }
00391 }
00392 
00393 /*===========================================================================*
00394  *                              _read_pm                                     *
00395  *===========================================================================*/
00396 PUBLIC ssize_t _read_pm(fd, buffer, nbytes, seg, ep)
00397 int fd;
00398 void *buffer;
00399 size_t nbytes;
00400 int seg;
00401 int ep;
00402 {
00403   message m;
00404 
00405   m.m1_i1 = _PM_SEG_FLAG | fd;
00406   m.m1_i2 = nbytes;
00407   m.m1_p1 = (char *) buffer;
00408   m.m1_p2 = (char *) seg;
00409   m.m1_p3 = (char *) ep;
00410   return(_syscall(FS_PROC_NR, READ, &m));
00411 }
00412 
00413 /*===========================================================================*
00414  *                              _write_pm                                    *
00415  *===========================================================================*/
00416 PUBLIC ssize_t _write_pm(fd, buffer, nbytes, seg, ep)
00417 int fd;
00418 void *buffer;
00419 size_t nbytes;
00420 int seg;
00421 int ep;
00422 {
00423   message m;
00424 
00425   m.m1_i1 = _PM_SEG_FLAG | fd;
00426   m.m1_i2 = nbytes;
00427   m.m1_p1 = (char *) buffer;
00428   m.m1_p2 = (char *) seg;
00429   m.m1_p3 = (char *) ep;
00430   return(_syscall(FS_PROC_NR, WRITE, &m));
00431 }
00432 

Generated on Fri Apr 14 22:56:47 2006 for minix by  doxygen 1.4.6