BOOK.TXT
上传用户:datang2001
上传日期:2007-02-01
资源大小:53269k
文件大小:999k
源码类别:

操作系统开发

开发平台:

C/C++

  1. 24310  *   release:     check to see if a suspended process can be released and do it
  2. 24311  *   revive:      mark a suspended process as able to run again
  3. 24312  *   do_unpause:  a signal has been sent to a process; see if it suspended
  4. 24313  */
  5. 24314
  6. 24315 #include "fs.h"
  7. 24316 #include <fcntl.h>
  8. 24317 #include <signal.h>
  9. 24318 #include <minix/boot.h>
  10. 24319 #include <minix/callnr.h>
  11. 24320 #include <minix/com.h>
  12. 24321 #include "dev.h"
  13. 24322 #include "file.h"
  14. 24323 #include "fproc.h"
  15. 24324 #include "inode.h"
  16. 24325 #include "param.h"
  17. 24326
  18. 24327 PRIVATE message mess;
  19. 24328
  20. 24329 /*===========================================================================*
  21. 24330  *                              do_pipe                                      *
  22. 24331  *===========================================================================*/
  23. 24332 PUBLIC int do_pipe()
  24. 24333 {
  25. 24334 /* Perform the pipe(fil_des) system call. */
  26. 24335
  27. 24336   register struct fproc *rfp;
  28. 24337   register struct inode *rip;
  29. 24338   int r;
  30. 24339   struct filp *fil_ptr0, *fil_ptr1;
  31. 24340   int fil_des[2];               /* reply goes here */
  32. 24341
  33. 24342   /* Acquire two file descriptors. */
  34. 24343   rfp = fp;
  35. 24344   if ( (r = get_fd(0, R_BIT, &fil_des[0], &fil_ptr0)) != OK) return(r);
  36. 24345   rfp->fp_filp[fil_des[0]] = fil_ptr0;
  37. 24346   fil_ptr0->filp_count = 1;
  38. 24347   if ( (r = get_fd(0, W_BIT, &fil_des[1], &fil_ptr1)) != OK) {
  39. 24348         rfp->fp_filp[fil_des[0]] = NIL_FILP;
  40. 24349         fil_ptr0->filp_count = 0;
  41. 24350         return(r);
  42. 24351   }
  43. 24352   rfp->fp_filp[fil_des[1]] = fil_ptr1;
  44. 24353   fil_ptr1->filp_count = 1;
  45. 24354
  46. 24355   /* Make the inode on the pipe device. */
  47. 24356   if ( (rip = alloc_inode(PIPE_DEV, I_REGULAR) ) == NIL_INODE) {
  48. 24357         rfp->fp_filp[fil_des[0]] = NIL_FILP;
  49. 24358         fil_ptr0->filp_count = 0;
  50. 24359         rfp->fp_filp[fil_des[1]] = NIL_FILP;
  51. 24360         fil_ptr1->filp_count = 0;
  52. 24361         return(err_code);
  53. 24362   }
  54. 24363
  55. 24364   if (read_only(rip) != OK) panic("pipe device is read only", NO_NUM);
  56. 24365  
  57. 24366   rip->i_pipe = I_PIPE;
  58. 24367   rip->i_mode &= ~I_REGULAR;
  59. 24368   rip->i_mode |= I_NAMED_PIPE;  /* pipes and FIFOs have this bit set */
  60. 24369   fil_ptr0->filp_ino = rip;
  61. 24370   fil_ptr0->filp_flags = O_RDONLY;
  62. 24371   dup_inode(rip);               /* for double usage */
  63. 24372   fil_ptr1->filp_ino = rip;
  64. 24373   fil_ptr1->filp_flags = O_WRONLY;
  65. 24374   rw_inode(rip, WRITING);       /* mark inode as allocated */
  66. 24375   reply_i1 = fil_des[0];
  67. 24376   reply_i2 = fil_des[1];
  68. 24377   rip->i_update = ATIME | CTIME | MTIME;
  69. 24378   return(OK);
  70. 24379 }
  71. 24382 /*===========================================================================*
  72. 24383  *                              pipe_check                                   *
  73. 24384  *===========================================================================*/
  74. 24385 PUBLIC int pipe_check(rip, rw_flag, oflags, bytes, position, canwrite)
  75. 24386 register struct inode *rip;     /* the inode of the pipe */
  76. 24387 int rw_flag;                    /* READING or WRITING */
  77. 24388 int oflags;                     /* flags set by open or fcntl */
  78. 24389 register int bytes;             /* bytes to be read or written (all chunks) */
  79. 24390 register off_t position;        /* current file position */
  80. 24391 int *canwrite;                  /* return: number of bytes we can write */
  81. 24392 {
  82. 24393 /* Pipes are a little different.  If a process reads from an empty pipe for
  83. 24394  * which a writer still exists, suspend the reader.  If the pipe is empty
  84. 24395  * and there is no writer, return 0 bytes.  If a process is writing to a
  85. 24396  * pipe and no one is reading from it, give a broken pipe error.
  86. 24397  */
  87. 24398
  88. 24399   int r = 0;
  89. 24400
  90. 24401   /* If reading, check for empty pipe. */
  91. 24402   if (rw_flag == READING) {
  92. 24403         if (position >= rip->i_size) {
  93. 24404                 /* Process is reading from an empty pipe. */
  94. 24405                 if (find_filp(rip, W_BIT) != NIL_FILP) {
  95. 24406                         /* Writer exists */
  96. 24407                         if (oflags & O_NONBLOCK) 
  97. 24408                                 r = EAGAIN;
  98. 24409                         else 
  99. 24410                                 suspend(XPIPE); /* block reader */
  100. 24411
  101. 24412                         /* If need be, activate sleeping writers. */
  102. 24413                         if (susp_count > 0) release(rip, WRITE, susp_count);
  103. 24414                 }
  104. 24415                 return(r);
  105. 24416         }
  106. 24417   } else {
  107. 24418         /* Process is writing to a pipe. */
  108. 24419 /*      if (bytes > PIPE_SIZE) return(EFBIG); */
  109. 24420         if (find_filp(rip, R_BIT) == NIL_FILP) {
  110. 24421                 /* Tell kernel to generate a SIGPIPE signal. */
  111. 24422                 sys_kill((int)(fp - fproc), SIGPIPE);
  112. 24423                 return(EPIPE);
  113. 24424         }
  114. 24425
  115. 24426         if (position + bytes > PIPE_SIZE) {
  116. 24427                 if ((oflags & O_NONBLOCK) && bytes < PIPE_SIZE) 
  117. 24428                         return(EAGAIN);
  118. 24429                 else if ((oflags & O_NONBLOCK) && bytes > PIPE_SIZE) {
  119. 24430                         if ( (*canwrite = (PIPE_SIZE - position)) > 0)  {
  120. 24431                                 /* Do a partial write. Need to wakeup reader */
  121. 24432                                 release(rip, READ, susp_count);
  122. 24433                                 return(1);
  123. 24434                         } else {
  124. 24435                                 return(EAGAIN);
  125. 24436                         }
  126. 24437                      }
  127. 24438                 if (bytes > PIPE_SIZE) {
  128. 24439                         if ((*canwrite = PIPE_SIZE - position) > 0) {
  129. 24440                                 /* Do a partial write. Need to wakeup reader
  130. 24441                                  * since we'll suspend ourself in read_write()
  131. 24442                                  */
  132. 24443                                 release(rip, READ, susp_count);
  133. 24444                                 return(1);
  134. 24445                         }
  135. 24446                 }
  136. 24447                 suspend(XPIPE); /* stop writer -- pipe full */
  137. 24448                 return(0);
  138. 24449         }
  139. 24450
  140. 24451         /* Writing to an empty pipe.  Search for suspended reader. */
  141. 24452         if (position == 0) release(rip, READ, susp_count);
  142. 24453   }
  143. 24454
  144. 24455   *canwrite = 0;
  145. 24456   return(1);
  146. 24457 }
  147. 24460 /*===========================================================================*
  148. 24461  *                              suspend                                      *
  149. 24462  *===========================================================================*/
  150. 24463 PUBLIC void suspend(task)
  151. 24464 int task;                       /* who is proc waiting for? (PIPE = pipe) */
  152. 24465 {
  153. 24466 /* Take measures to suspend the processing of the present system call.
  154. 24467  * Store the parameters to be used upon resuming in the process table.
  155. 24468  * (Actually they are not used when a process is waiting for an I/O device,
  156. 24469  * but they are needed for pipes, and it is not worth making the distinction.)
  157. 24470  */
  158. 24471
  159. 24472   if (task == XPIPE || task == XPOPEN) susp_count++;/* #procs susp'ed on pipe*/
  160. 24473   fp->fp_suspended = SUSPENDED;
  161. 24474   fp->fp_fd = fd << 8 | fs_call;
  162. 24475   fp->fp_task = -task;
  163. 24476   if (task == XLOCK) {
  164. 24477         fp->fp_buffer = (char *) name1; /*  third arg to fcntl() */
  165. 24478         fp->fp_nbytes =request;         /* second arg to fcntl() */
  166. 24479   } else {
  167. 24480         fp->fp_buffer = buffer;         /* for reads and writes */
  168. 24481         fp->fp_nbytes = nbytes;
  169. 24482   }
  170. 24483   dont_reply = TRUE;            /* do not send caller a reply message now */
  171. 24484 }
  172. 24487 /*===========================================================================*
  173. 24488  *                              release                                      *
  174. 24489  *===========================================================================*/
  175. 24490 PUBLIC void release(ip, call_nr, count)
  176. 24491 register struct inode *ip;      /* inode of pipe */
  177. 24492 int call_nr;                    /* READ, WRITE, OPEN or CREAT */
  178. 24493 int count;                      /* max number of processes to release */
  179. 24494 {
  180. 24495 /* Check to see if any process is hanging on the pipe whose inode is in 'ip'.
  181. 24496  * If one is, and it was trying to perform the call indicated by 'call_nr',
  182. 24497  * release it.
  183. 24498  */
  184. 24499
  185. 24500   register struct fproc *rp;
  186. 24501
  187. 24502   /* Search the proc table. */
  188. 24503   for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) {
  189. 24504         if (rp->fp_suspended == SUSPENDED &&
  190. 24505                         rp->fp_revived == NOT_REVIVING &&
  191. 24506                         (rp->fp_fd & BYTE) == call_nr &&
  192. 24507                         rp->fp_filp[rp->fp_fd>>8]->filp_ino == ip) {
  193. 24508                 revive((int)(rp - fproc), 0);
  194. 24509                 susp_count--;   /* keep track of who is suspended */
  195. 24510                 if (--count == 0) return;
  196. 24511         }
  197. 24512   }
  198. 24513 }
  199. 24516 /*===========================================================================*
  200. 24517  *                              revive                                       *
  201. 24518  *===========================================================================*/
  202. 24519 PUBLIC void revive(proc_nr, bytes)
  203. 24520 int proc_nr;                    /* process to revive */
  204. 24521 int bytes;                      /* if hanging on task, how many bytes read */
  205. 24522 {
  206. 24523 /* Revive a previously blocked process. When a process hangs on tty, this
  207. 24524  * is the way it is eventually released.
  208. 24525  */
  209. 24526
  210. 24527   register struct fproc *rfp;
  211. 24528   register int task;
  212. 24529
  213. 24530   if (proc_nr < 0 || proc_nr >= NR_PROCS) panic("revive err", proc_nr);
  214. 24531   rfp = &fproc[proc_nr];
  215. 24532   if (rfp->fp_suspended == NOT_SUSPENDED || rfp->fp_revived == REVIVING)return;
  216. 24533
  217. 24534   /* The 'reviving' flag only applies to pipes.  Processes waiting for TTY get
  218. 24535    * a message right away.  The revival process is different for TTY and pipes.
  219. 24536    * For TTY revival, the work is already done, for pipes it is not: the proc
  220. 24537    * must be restarted so it can try again.
  221. 24538    */
  222. 24539   task = -rfp->fp_task;
  223. 24540   if (task == XPIPE || task == XLOCK) {
  224. 24541         /* Revive a process suspended on a pipe or lock. */
  225. 24542         rfp->fp_revived = REVIVING;
  226. 24543         reviving++;             /* process was waiting on pipe or lock */
  227. 24544   } else {
  228. 24545         rfp->fp_suspended = NOT_SUSPENDED;
  229. 24546         if (task == XPOPEN) /* process blocked in open or create */
  230. 24547                 reply(proc_nr, rfp->fp_fd>>8);
  231. 24548         else {
  232. 24549                 /* Revive a process suspended on TTY or other device. */
  233. 24550                 rfp->fp_nbytes = bytes; /*pretend it wants only what there is*/
  234. 24551                 reply(proc_nr, bytes);  /* unblock the process */
  235. 24552         }
  236. 24553   }
  237. 24554 }
  238. 24557 /*===========================================================================*
  239. 24558  *                              do_unpause                                   *
  240. 24559  *===========================================================================*/
  241. 24560 PUBLIC int do_unpause()
  242. 24561 {
  243. 24562 /* A signal has been sent to a user who is paused on the file system.
  244. 24563  * Abort the system call with the EINTR error message.
  245. 24564  */
  246. 24565
  247. 24566   register struct fproc *rfp;
  248. 24567   int proc_nr, task, fild;
  249. 24568   struct filp *f;
  250. 24569   dev_t dev;
  251. 24570
  252. 24571   if (who > MM_PROC_NR) return(EPERM);
  253. 24572   proc_nr = pro;
  254. 24573   if (proc_nr < 0 || proc_nr >= NR_PROCS) panic("unpause err 1", proc_nr);
  255. 24574   rfp = &fproc[proc_nr];
  256. 24575   if (rfp->fp_suspended == NOT_SUSPENDED) return(OK);
  257. 24576   task = -rfp->fp_task;
  258. 24577
  259. 24578   switch(task) {
  260. 24579         case XPIPE:             /* process trying to read or write a pipe */
  261. 24580                 break;
  262. 24581
  263. 24582         case XOPEN:             /* process trying to open a special file */
  264. 24583                 panic ("fs/do_unpause called with XOPENn", NO_NUM);
  265. 24584
  266. 24585         case XLOCK:             /* process trying to set a lock with FCNTL */
  267. 24586                 break;
  268. 24587
  269. 24588         case XPOPEN:            /* process trying to open a fifo */
  270. 24589                 break;
  271. 24590
  272. 24591         default:                /* process trying to do device I/O (e.g. tty)*/
  273. 24592                 fild = (rfp->fp_fd >> 8) & BYTE;/* extract file descriptor */
  274. 24593                 if (fild < 0 || fild >= OPEN_MAX)panic("unpause err 2",NO_NUM);
  275. 24594                 f = rfp->fp_filp[fild];
  276. 24595                 dev = (dev_t) f->filp_ino->i_zone[0];   /* device hung on */
  277. 24596                 mess.TTY_LINE = (dev >> MINOR) & BYTE;
  278. 24597                 mess.PROC_NR = proc_nr;
  279. 24598
  280. 24599                 /* Tell kernel R or W. Mode is from current call, not open. */
  281. 24600                 mess.COUNT = (rfp->fp_fd & BYTE) == READ ? R_BIT : W_BIT;
  282. 24601                 mess.m_type = CANCEL;
  283. 24602                 fp = rfp;       /* hack - call_ctty uses fp */
  284. 24603                 (*dmap[(dev >> MAJOR) & BYTE].dmap_rw)(task, &mess);
  285. 24604   }
  286. 24605
  287. 24606   rfp->fp_suspended = NOT_SUSPENDED;
  288. 24607   reply(proc_nr, EINTR);        /* signal interrupted call */
  289. 24608   return(OK);
  290. 24609 }
  291. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  292. src/fs/path.c    
  293. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  294. 24700 /* This file contains the procedures that look up path names in the directory
  295. 24701  * system and determine the inode number that goes with a given path name.
  296. 24702  *
  297. 24703  *  The entry points into this file are
  298. 24704  *   eat_path:   the 'main' routine of the path-to-inode conversion mechanism
  299. 24705  *   last_dir:   find the final directory on a given path
  300. 24706  *   advance:    parse one component of a path name
  301. 24707  *   search_dir: search a directory for a string and return its inode number
  302. 24708  */
  303. 24709
  304. 24710 #include "fs.h"
  305. 24711 #include <string.h>
  306. 24712 #include <minix/callnr.h>
  307. 24713 #include "buf.h"
  308. 24714 #include "file.h"
  309. 24715 #include "fproc.h"
  310. 24716 #include "inode.h"
  311. 24717 #include "super.h"
  312. 24718
  313. 24719 PUBLIC char dot1[2] = ".";      /* used for search_dir to bypass the access */
  314. 24720 PUBLIC char dot2[3] = "..";     /* permissions for . and ..                 */
  315. 24721
  316. 24722 FORWARD _PROTOTYPE( char *get_name, (char *old_name, char string [NAME_MAX]) );
  317. 24723
  318. 24724 /*===========================================================================*
  319. 24725  *                              eat_path                                     *
  320. 24726  *===========================================================================*/
  321. 24727 PUBLIC struct inode *eat_path(path)
  322. 24728 char *path;                     /* the path name to be parsed */
  323. 24729 {
  324. 24730 /* Parse the path 'path' and put its inode in the inode table. If not possible,
  325. 24731  * return NIL_INODE as function value and an error code in 'err_code'.
  326. 24732  */
  327. 24733
  328. 24734   register struct inode *ldip, *rip;
  329. 24735   char string[NAME_MAX];        /* hold 1 path component name here */
  330. 24736
  331. 24737   /* First open the path down to the final directory. */
  332. 24738   if ( (ldip = last_dir(path, string)) == NIL_INODE)
  333. 24739         return(NIL_INODE);      /* we couldn't open final directory */
  334. 24740
  335. 24741   /* The path consisting only of "/" is a special case, check for it. */
  336. 24742   if (string[0] == '') return(ldip);
  337. 24743
  338. 24744   /* Get final component of the path. */
  339. 24745   rip = advance(ldip, string);
  340. 24746   put_inode(ldip);
  341. 24747   return(rip);
  342. 24748 }
  343. 24751 /*===========================================================================*
  344. 24752  *                              last_dir                                     *
  345. 24753  *===========================================================================*/
  346. 24754 PUBLIC struct inode *last_dir(path, string)
  347. 24755 char *path;                     /* the path name to be parsed */
  348. 24756 char string[NAME_MAX];          /* the final component is returned here */
  349. 24757 {
  350. 24758 /* Given a path, 'path', located in the fs address space, parse it as
  351. 24759  * far as the last directory, fetch the inode for the last directory into
  352. 24760  * the inode table, and return a pointer to the inode.  In
  353. 24761  * addition, return the final component of the path in 'string'.
  354. 24762  * If the last directory can't be opened, return NIL_INODE and
  355. 24763  * the reason for failure in 'err_code'.
  356. 24764  */
  357. 24765
  358. 24766   register struct inode *rip;
  359. 24767   register char *new_name;
  360. 24768   register struct inode *new_ip;
  361. 24769
  362. 24770   /* Is the path absolute or relative?  Initialize 'rip' accordingly. */
  363. 24771   rip = (*path == '/' ? fp->fp_rootdir : fp->fp_workdir);
  364. 24772
  365. 24773   /* If dir has been removed or path is empty, return ENOENT. */
  366. 24774   if (rip->i_nlinks == 0 || *path == '') {
  367. 24775         err_code = ENOENT;
  368. 24776         return(NIL_INODE);
  369. 24777   }
  370. 24778
  371. 24779   dup_inode(rip);               /* inode will be returned with put_inode */
  372. 24780
  373. 24781   /* Scan the path component by component. */
  374. 24782   while (TRUE) {
  375. 24783         /* Extract one component. */
  376. 24784         if ( (new_name = get_name(path, string)) == (char*) 0) {
  377. 24785                 put_inode(rip); /* bad path in user space */
  378. 24786                 return(NIL_INODE);
  379. 24787         }
  380. 24788         if (*new_name == '')
  381. 24789                 if ( (rip->i_mode & I_TYPE) == I_DIRECTORY)
  382. 24790                         return(rip);    /* normal exit */
  383. 24791                 else {
  384. 24792                         /* last file of path prefix is not a directory */
  385. 24793                         put_inode(rip);
  386. 24794                         err_code = ENOTDIR;                     
  387. 24795                         return(NIL_INODE);
  388. 24796                 }
  389. 24797
  390. 24798         /* There is more path.  Keep parsing. */
  391. 24799         new_ip = advance(rip, string);
  392. 24800         put_inode(rip);         /* rip either obsolete or irrelevant */
  393. 24801         if (new_ip == NIL_INODE) return(NIL_INODE);
  394. 24802
  395. 24803         /* The call to advance() succeeded.  Fetch next component. */
  396. 24804         path = new_name;
  397. 24805         rip = new_ip;
  398. 24806   }
  399. 24807 }
  400. 24810 /*===========================================================================*
  401. 24811  *                              get_name                                     *
  402. 24812  *===========================================================================*/
  403. 24813 PRIVATE char *get_name(old_name, string)
  404. 24814 char *old_name;                 /* path name to parse */
  405. 24815 char string[NAME_MAX];          /* component extracted from 'old_name' */
  406. 24816 {
  407. 24817 /* Given a pointer to a path name in fs space, 'old_name', copy the next
  408. 24818  * component to 'string' and pad with zeros.  A pointer to that part of
  409. 24819  * the name as yet unparsed is returned.  Roughly speaking,
  410. 24820  * 'get_name' = 'old_name' - 'string'.
  411. 24821  *
  412. 24822  * This routine follows the standard convention that /usr/ast, /usr//ast,
  413. 24823  * //usr///ast and /usr/ast/ are all equivalent.
  414. 24824  */
  415. 24825
  416. 24826   register int c;
  417. 24827   register char *np, *rnp;
  418. 24828
  419. 24829   np = string;                  /* 'np' points to current position */
  420. 24830   rnp = old_name;               /* 'rnp' points to unparsed string */
  421. 24831   while ( (c = *rnp) == '/') rnp++;     /* skip leading slashes */
  422. 24832
  423. 24833   /* Copy the unparsed path, 'old_name', to the array, 'string'. */
  424. 24834   while ( rnp < &old_name[PATH_MAX]  &&  c != '/'   &&  c != '') {
  425. 24835         if (np < &string[NAME_MAX]) *np++ = c;
  426. 24836         c = *++rnp;             /* advance to next character */
  427. 24837   }
  428. 24838
  429. 24839   /* To make /usr/ast/ equivalent to /usr/ast, skip trailing slashes. */
  430. 24840   while (c == '/' && rnp < &old_name[PATH_MAX]) c = *++rnp;
  431. 24841
  432. 24842   if (np < &string[NAME_MAX]) *np = '';       /* Terminate string */
  433. 24843
  434. 24844   if (rnp >= &old_name[PATH_MAX]) {
  435. 24845         err_code = ENAMETOOLONG;
  436. 24846         return((char *) 0);
  437. 24847   }
  438. 24848   return(rnp);
  439. 24849 }
  440. 24852 /*===========================================================================*
  441. 24853  *                              advance                                      *
  442. 24854  *===========================================================================*/
  443. 24855 PUBLIC struct inode *advance(dirp, string)
  444. 24856 struct inode *dirp;             /* inode for directory to be searched */
  445. 24857 char string[NAME_MAX];          /* component name to look for */
  446. 24858 {
  447. 24859 /* Given a directory and a component of a path, look up the component in
  448. 24860  * the directory, find the inode, open it, and return a pointer to its inode
  449. 24861  * slot.  If it can't be done, return NIL_INODE.
  450. 24862  */
  451. 24863
  452. 24864   register struct inode *rip;
  453. 24865   struct inode *rip2;
  454. 24866   register struct super_block *sp;
  455. 24867   int r, inumb;
  456. 24868   dev_t mnt_dev;
  457. 24869   ino_t numb;
  458. 24870
  459. 24871   /* If 'string' is empty, yield same inode straight away. */
  460. 24872   if (string[0] == '') return(get_inode(dirp->i_dev, (int) dirp->i_num));
  461. 24873
  462. 24874   /* Check for NIL_INODE. */
  463. 24875   if (dirp == NIL_INODE) return(NIL_INODE);
  464. 24876
  465. 24877   /* If 'string' is not present in the directory, signal error. */
  466. 24878   if ( (r = search_dir(dirp, string, &numb, LOOK_UP)) != OK) {
  467. 24879         err_code = r;
  468. 24880         return(NIL_INODE);
  469. 24881   }
  470. 24882
  471. 24883   /* Don't go beyond the current root directory, unless the string is dot2. */
  472. 24884   if (dirp == fp->fp_rootdir && strcmp(string, "..") == 0 && string != dot2)
  473. 24885                 return(get_inode(dirp->i_dev, (int) dirp->i_num));
  474. 24886
  475. 24887   /* The component has been found in the directory.  Get inode. */
  476. 24888   if ( (rip = get_inode(dirp->i_dev, (int) numb)) == NIL_INODE) 
  477. 24889         return(NIL_INODE);
  478. 24890
  479. 24891   if (rip->i_num == ROOT_INODE)
  480. 24892         if (dirp->i_num == ROOT_INODE) {
  481. 24893             if (string[1] == '.') {
  482. 24894                 for (sp = &super_block[1]; sp < &super_block[NR_SUPERS]; sp++){
  483. 24895                         if (sp->s_dev == rip->i_dev) {
  484. 24896                                 /* Release the root inode.  Replace by the
  485. 24897                                  * inode mounted on.
  486. 24898                                  */
  487. 24899                                 put_inode(rip);
  488. 24900                                 mnt_dev = sp->s_imount->i_dev;
  489. 24901                                 inumb = (int) sp->s_imount->i_num;
  490. 24902                                 rip2 = get_inode(mnt_dev, inumb);
  491. 24903                                 rip = advance(rip2, string);
  492. 24904                                 put_inode(rip2);
  493. 24905                                 break;
  494. 24906                         }
  495. 24907                 }
  496. 24908             }
  497. 24909         }
  498. 24910   if (rip == NIL_INODE) return(NIL_INODE);
  499. 24911
  500. 24912   /* See if the inode is mounted on.  If so, switch to root directory of the
  501. 24913    * mounted file system.  The super_block provides the linkage between the
  502. 24914    * inode mounted on and the root directory of the mounted file system.
  503. 24915    */
  504. 24916   while (rip != NIL_INODE && rip->i_mount == I_MOUNT) {
  505. 24917         /* The inode is indeed mounted on. */
  506. 24918         for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) {
  507. 24919                 if (sp->s_imount == rip) {
  508. 24920                         /* Release the inode mounted on.  Replace by the
  509. 24921                          * inode of the root inode of the mounted device.
  510. 24922                          */
  511. 24923                         put_inode(rip);
  512. 24924                         rip = get_inode(sp->s_dev, ROOT_INODE);
  513. 24925                         break;
  514. 24926                 }
  515. 24927         }
  516. 24928   }
  517. 24929   return(rip);          /* return pointer to inode's component */
  518. 24930 }
  519. 24933 /*===========================================================================*
  520. 24934  *                              search_dir                                   *
  521. 24935  *===========================================================================*/
  522. 24936 PUBLIC int search_dir(ldir_ptr, string, numb, flag)
  523. 24937 register struct inode *ldir_ptr;        /* ptr to inode for dir to search */
  524. 24938 char string[NAME_MAX];          /* component to search for */
  525. 24939 ino_t *numb;                    /* pointer to inode number */
  526. 24940 int flag;                       /* LOOK_UP, ENTER, DELETE or IS_EMPTY */
  527. 24941 {
  528. 24942 /* This function searches the directory whose inode is pointed to by 'ldip':
  529. 24943  * if (flag == ENTER)  enter 'string' in the directory with inode # '*numb';
  530. 24944  * if (flag == DELETE) delete 'string' from the directory;
  531. 24945  * if (flag == LOOK_UP) search for 'string' and return inode # in 'numb';
  532. 24946  * if (flag == IS_EMPTY) return OK if only . and .. in dir else ENOTEMPTY;
  533. 24947  *
  534. 24948  *    if 'string' is dot1 or dot2, no access permissions are checked.
  535. 24949  */
  536. 24950
  537. 24951   register struct direct *dp;
  538. 24952   register struct buf *bp;
  539. 24953   int i, r, e_hit, t, match;
  540. 24954   mode_t bits;
  541. 24955   off_t pos;
  542. 24956   unsigned new_slots, old_slots;
  543. 24957   block_t b;
  544. 24958   struct super_block *sp;
  545. 24959   int extended = 0;
  546. 24960
  547. 24961   /* If 'ldir_ptr' is not a pointer to a dir inode, error. */
  548. 24962   if ( (ldir_ptr->i_mode & I_TYPE) != I_DIRECTORY) return(ENOTDIR);
  549. 24963
  550. 24964   r = OK;
  551. 24965
  552. 24966   if (flag != IS_EMPTY) {
  553. 24967         bits = (flag == LOOK_UP ? X_BIT : W_BIT | X_BIT);
  554. 24968
  555. 24969         if (string == dot1 || string == dot2) {
  556. 24970                 if (flag != LOOK_UP) r = read_only(ldir_ptr);
  557. 24971                                      /* only a writable device is required. */
  558. 24972         }
  559. 24973         else r = forbidden(ldir_ptr, bits); /* check access permissions */
  560. 24974   }
  561. 24975   if (r != OK) return(r);
  562. 24976   
  563. 24977   /* Step through the directory one block at a time. */
  564. 24978   old_slots = (unsigned) (ldir_ptr->i_size/DIR_ENTRY_SIZE);
  565. 24979   new_slots = 0;
  566. 24980   e_hit = FALSE;
  567. 24981   match = 0;                    /* set when a string match occurs */
  568. 24982
  569. 24983   for (pos = 0; pos < ldir_ptr->i_size; pos += BLOCK_SIZE) {
  570. 24984         b = read_map(ldir_ptr, pos);    /* get block number */
  571. 24985
  572. 24986         /* Since directories don't have holes, 'b' cannot be NO_BLOCK. */
  573. 24987         bp = get_block(ldir_ptr->i_dev, b, NORMAL);     /* get a dir block */
  574. 24988
  575. 24989         /* Search a directory block. */
  576. 24990         for (dp = &bp->b_dir[0]; dp < &bp->b_dir[NR_DIR_ENTRIES]; dp++) {
  577. 24991                 if (++new_slots > old_slots) { /* not found, but room left */
  578. 24992                         if (flag == ENTER) e_hit = TRUE;
  579. 24993                         break;
  580. 24994                 }
  581. 24995
  582. 24996                 /* Match occurs if string found. */
  583. 24997                 if (flag != ENTER && dp->d_ino != 0) {
  584. 24998                         if (flag == IS_EMPTY) {
  585. 24999                                 /* If this test succeeds, dir is not empty. */
  586. 25000                                 if (strcmp(dp->d_name, "." ) != 0 &&
  587. 25001                                     strcmp(dp->d_name, "..") != 0) match = 1;
  588. 25002                         } else {
  589. 25003                                 if (strncmp(dp->d_name, string, NAME_MAX) == 0)
  590. 25004                                         match = 1;
  591. 25005                         }
  592. 25006                 }
  593. 25007
  594. 25008                 if (match) {
  595. 25009                         /* LOOK_UP or DELETE found what it wanted. */
  596. 25010                         r = OK;
  597. 25011                         if (flag == IS_EMPTY) r = ENOTEMPTY;
  598. 25012                         else if (flag == DELETE) {
  599. 25013                                 /* Save d_ino for recovery. */
  600. 25014                                 t = NAME_MAX - sizeof(ino_t);
  601. 25015                                 *((ino_t *) &dp->d_name[t]) = dp->d_ino;
  602. 25016                                 dp->d_ino = 0;  /* erase entry */
  603. 25017                                 bp->b_dirt = DIRTY;
  604. 25018                                 ldir_ptr->i_update |= CTIME | MTIME;
  605. 25019                                 ldir_ptr->i_dirt = DIRTY;
  606. 25020                         } else {
  607. 25021                                 sp = ldir_ptr->i_sp;    /* 'flag' is LOOK_UP */
  608. 25022                                 *numb = conv2(sp->s_native, (int) dp->d_ino);
  609. 25023                         }
  610. 25024                         put_block(bp, DIRECTORY_BLOCK);
  611. 25025                         return(r);
  612. 25026                 }
  613. 25027
  614. 25028
  615. 25029                 /* Check for free slot for the benefit of ENTER. */
  616. 25030                 if (flag == ENTER && dp->d_ino == 0) {
  617. 25031                         e_hit = TRUE;   /* we found a free slot */
  618. 25032                         break;
  619. 25033                 }
  620. 25034         }
  621. 25035
  622. 25036         /* The whole block has been searched or ENTER has a free slot. */
  623. 25037         if (e_hit) break;       /* e_hit set if ENTER can be performed now */
  624. 25038         put_block(bp, DIRECTORY_BLOCK); /* otherwise, continue searching dir */
  625. 25039   }
  626. 25040
  627. 25041   /* The whole directory has now been searched. */
  628. 25042   if (flag != ENTER) return(flag == IS_EMPTY ? OK : ENOENT);
  629. 25043
  630. 25044   /* This call is for ENTER.  If no free slot has been found so far, try to
  631. 25045    * extend directory.
  632. 25046    */
  633. 25047   if (e_hit == FALSE) { /* directory is full and no room left in last block */
  634. 25048         new_slots++;            /* increase directory size by 1 entry */
  635. 25049         if (new_slots == 0) return(EFBIG); /* dir size limited by slot count */
  636. 25050         if ( (bp = new_block(ldir_ptr, ldir_ptr->i_size)) == NIL_BUF)
  637. 25051                 return(err_code);
  638. 25052         dp = &bp->b_dir[0];
  639. 25053         extended = 1;
  640. 25054   }
  641. 25055
  642. 25056   /* 'bp' now points to a directory block with space. 'dp' points to slot. */
  643. 25057   (void) memset(dp->d_name, 0, (size_t) NAME_MAX); /* clear entry */
  644. 25058   for (i = 0; string[i] && i < NAME_MAX; i++) dp->d_name[i] = string[i];
  645. 25059   sp = ldir_ptr->i_sp; 
  646. 25060   dp->d_ino = conv2(sp->s_native, (int) *numb);
  647. 25061   bp->b_dirt = DIRTY;
  648. 25062   put_block(bp, DIRECTORY_BLOCK);
  649. 25063   ldir_ptr->i_update |= CTIME | MTIME;  /* mark mtime for update later */
  650. 25064   ldir_ptr->i_dirt = DIRTY;
  651. 25065   if (new_slots > old_slots) {
  652. 25066         ldir_ptr->i_size = (off_t) new_slots * DIR_ENTRY_SIZE;
  653. 25067         /* Send the change to disk if the directory is extended. */
  654. 25068         if (extended) rw_inode(ldir_ptr, WRITING);
  655. 25069   }
  656. 25070   return(OK);
  657. 25071 }
  658. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  659. src/fs/mount.c    
  660. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  661. 25100 /* This file performs the MOUNT and UMOUNT system calls.
  662. 25101  *
  663. 25102  * The entry points into this file are
  664. 25103  *   do_mount:  perform the MOUNT system call
  665. 25104  *   do_umount: perform the UMOUNT system call
  666. 25105  */
  667. 25106
  668. 25107 #include "fs.h"
  669. 25108 #include <fcntl.h>
  670. 25109 #include <minix/com.h>
  671. 25110 #include <sys/stat.h>
  672. 25111 #include "buf.h"
  673. 25112 #include "dev.h"
  674. 25113 #include "file.h"
  675. 25114 #include "fproc.h"
  676. 25115 #include "inode.h"
  677. 25116 #include "param.h"
  678. 25117 #include "super.h"
  679. 25118
  680. 25119 PRIVATE message dev_mess;
  681. 25120
  682. 25121 FORWARD _PROTOTYPE( dev_t name_to_dev, (char *path)                     );
  683. 25122
  684. 25123 /*===========================================================================*
  685. 25124  *                              do_mount                                     *
  686. 25125  *===========================================================================*/
  687. 25126 PUBLIC int do_mount()
  688. 25127 {
  689. 25128 /* Perform the mount(name, mfile, rd_only) system call. */
  690. 25129
  691. 25130   register struct inode *rip, *root_ip;
  692. 25131   struct super_block *xp, *sp;
  693. 25132   dev_t dev;
  694. 25133   mode_t bits;
  695. 25134   int rdir, mdir;               /* TRUE iff {root|mount} file is dir */
  696. 25135   int r, found, major, task;
  697. 25136
  698. 25137   /* Only the super-user may do MOUNT. */
  699. 25138   if (!super_user) return(EPERM);
  700. 25139
  701. 25140   /* If 'name' is not for a block special file, return error. */
  702. 25141   if (fetch_name(name1, name1_length, M1) != OK) return(err_code);
  703. 25142   if ( (dev = name_to_dev(user_path)) == NO_DEV) return(err_code);
  704. 25143
  705. 25144   /* Scan super block table to see if dev already mounted & find a free slot.*/
  706. 25145   sp = NIL_SUPER;
  707. 25146   found = FALSE;
  708. 25147   for (xp = &super_block[0]; xp < &super_block[NR_SUPERS]; xp++) {
  709. 25148         if (xp->s_dev == dev) found = TRUE;     /* is it mounted already? */
  710. 25149         if (xp->s_dev == NO_DEV) sp = xp;       /* record free slot */
  711. 25150   }
  712. 25151   if (found) return(EBUSY);     /* already mounted */
  713. 25152   if (sp == NIL_SUPER) return(ENFILE);  /* no super block available */
  714. 25153
  715. 25154   dev_mess.m_type = DEV_OPEN;           /* distinguish from close */
  716. 25155   dev_mess.DEVICE = dev;                /* Touch the device. */  
  717. 25156   if (rd_only) dev_mess.COUNT = R_BIT;
  718. 25157   else  dev_mess.COUNT = R_BIT|W_BIT;
  719. 25158
  720. 25159   major = (dev >> MAJOR) & BYTE;
  721. 25160   if (major <= 0 || major >= max_major) return(ENODEV);
  722. 25161   task = dmap[major].dmap_task;         /* device task nr */
  723. 25162   (*dmap[major].dmap_open)(task, &dev_mess);
  724. 25163   if (dev_mess.REP_STATUS != OK) return(EINVAL);
  725. 25164
  726. 25165   /* Fill in the super block. */
  727. 25166   sp->s_dev = dev;              /* read_super() needs to know which dev */
  728. 25167   r = read_super(sp);
  729. 25168
  730. 25169   /* Is it recognized as a Minix filesystem? */
  731. 25170   if (r != OK) {
  732. 25171         dev_mess.m_type = DEV_CLOSE;
  733. 25172         dev_mess.DEVICE = dev;
  734. 25173         (*dmap[major].dmap_close)(task, &dev_mess);
  735. 25174         return(r);
  736. 25175   }
  737. 25176
  738. 25177   /* Now get the inode of the file to be mounted on. */
  739. 25178   if (fetch_name(name2, name2_length, M1) != OK) {
  740. 25179         sp->s_dev = NO_DEV;
  741. 25180         dev_mess.m_type = DEV_CLOSE;
  742. 25181         dev_mess.DEVICE = dev;
  743. 25182         (*dmap[major].dmap_close)(task, &dev_mess);
  744. 25183         return(err_code);
  745. 25184   }
  746. 25185   if ( (rip = eat_path(user_path)) == NIL_INODE) {
  747. 25186         sp->s_dev = NO_DEV;
  748. 25187         dev_mess.m_type = DEV_CLOSE;
  749. 25188         dev_mess.DEVICE = dev;
  750. 25189         (*dmap[major].dmap_close)(task, &dev_mess);
  751. 25190         return(err_code);
  752. 25191   }
  753. 25192
  754. 25193   /* It may not be busy. */
  755. 25194   r = OK;
  756. 25195   if (rip->i_count > 1) r = EBUSY;
  757. 25196
  758. 25197   /* It may not be special. */
  759. 25198   bits = rip->i_mode & I_TYPE;
  760. 25199   if (bits == I_BLOCK_SPECIAL || bits == I_CHAR_SPECIAL) r = ENOTDIR;
  761. 25200
  762. 25201   /* Get the root inode of the mounted file system. */
  763. 25202   root_ip = NIL_INODE;          /* if 'r' not OK, make sure this is defined */
  764. 25203   if (r == OK) {
  765. 25204         if ( (root_ip = get_inode(dev, ROOT_INODE)) == NIL_INODE) r = err_code;
  766. 25205   }
  767. 25206   if (root_ip != NIL_INODE && root_ip->i_mode == 0) r = EINVAL;
  768. 25207
  769. 25208   /* File types of 'rip' and 'root_ip' may not conflict. */
  770. 25209   if (r == OK) {
  771. 25210         mdir = ((rip->i_mode & I_TYPE) == I_DIRECTORY);  /* TRUE iff dir */
  772. 25211         rdir = ((root_ip->i_mode & I_TYPE) == I_DIRECTORY);
  773. 25212         if (!mdir && rdir) r = EISDIR;
  774. 25213   }
  775. 25214
  776. 25215   /* If error, return the super block and both inodes; release the maps. */
  777. 25216   if (r != OK) {
  778. 25217         put_inode(rip);
  779. 25218         put_inode(root_ip);
  780. 25219         (void) do_sync();
  781. 25220         invalidate(dev);
  782. 25221
  783. 25222         sp->s_dev = NO_DEV;
  784. 25223         dev_mess.m_type = DEV_CLOSE;
  785. 25224         dev_mess.DEVICE = dev;
  786. 25225         (*dmap[major].dmap_close)(task, &dev_mess);
  787. 25226         return(r);
  788. 25227   }
  789. 25228
  790. 25229   /* Nothing else can go wrong.  Perform the mount. */
  791. 25230   rip->i_mount = I_MOUNT;       /* this bit says the inode is mounted on */
  792. 25231   sp->s_imount = rip;
  793. 25232   sp->s_isup = root_ip;
  794. 25233   sp->s_rd_only = rd_only;
  795. 25234   return(OK);
  796. 25235 }
  797. 25238 /*===========================================================================*
  798. 25239  *                              do_umount                                    *
  799. 25240  *===========================================================================*/
  800. 25241 PUBLIC int do_umount()
  801. 25242 {
  802. 25243 /* Perform the umount(name) system call. */
  803. 25244
  804. 25245   register struct inode *rip;
  805. 25246   struct super_block *sp, *sp1;
  806. 25247   dev_t dev;
  807. 25248   int count;
  808. 25249   int major, task;
  809. 25250
  810. 25251   /* Only the super-user may do UMOUNT. */
  811. 25252   if (!super_user) return(EPERM);
  812. 25253
  813. 25254   /* If 'name' is not for a block special file, return error. */
  814. 25255   if (fetch_name(name, name_length, M3) != OK) return(err_code);
  815. 25256   if ( (dev = name_to_dev(user_path)) == NO_DEV) return(err_code);
  816. 25257
  817. 25258   /* See if the mounted device is busy.  Only 1 inode using it should be
  818. 25259    * open -- the root inode -- and that inode only 1 time.
  819. 25260    */
  820. 25261   count = 0;
  821. 25262   for (rip = &inode[0]; rip< &inode[NR_INODES]; rip++)
  822. 25263         if (rip->i_count > 0 && rip->i_dev == dev) count += rip->i_count;
  823. 25264   if (count > 1) return(EBUSY); /* can't umount a busy file system */
  824. 25265
  825. 25266   /* Find the super block. */
  826. 25267   sp = NIL_SUPER;
  827. 25268   for (sp1 = &super_block[0]; sp1 < &super_block[NR_SUPERS]; sp1++) {
  828. 25269         if (sp1->s_dev == dev) {
  829. 25270                 sp = sp1;
  830. 25271                 break;
  831. 25272         }
  832. 25273   }
  833. 25274
  834. 25275   /* Sync the disk, and invalidate cache. */
  835. 25276   (void) do_sync();             /* force any cached blocks out of memory */
  836. 25277   invalidate(dev);              /* invalidate cache entries for this dev */
  837. 25278   if (sp == NIL_SUPER) return(EINVAL);
  838. 25279
  839. 25280   major = (dev >> MAJOR) & BYTE;        /* major device nr */
  840. 25281   task = dmap[major].dmap_task; /* device task nr */
  841. 25282   dev_mess.m_type = DEV_CLOSE;          /* distinguish from open */
  842. 25283   dev_mess.DEVICE = dev;
  843. 25284   (*dmap[major].dmap_close)(task, &dev_mess);
  844. 25285
  845. 25286   /* Finish off the unmount. */
  846. 25287   sp->s_imount->i_mount = NO_MOUNT;     /* inode returns to normal */
  847. 25288   put_inode(sp->s_imount);      /* release the inode mounted on */
  848. 25289   put_inode(sp->s_isup);        /* release the root inode of the mounted fs */
  849. 25290   sp->s_imount = NIL_INODE;
  850. 25291   sp->s_dev = NO_DEV;
  851. 25292   return(OK);
  852. 25293 }
  853. 25296 /*===========================================================================*
  854. 25297  *                              name_to_dev                                  *
  855. 25298  *===========================================================================*/
  856. 25299 PRIVATE dev_t name_to_dev(path)
  857. 25300 char *path;                     /* pointer to path name */
  858. 25301 {
  859. 25302 /* Convert the block special file 'path' to a device number.  If 'path'
  860. 25303  * is not a block special file, return error code in 'err_code'.
  861. 25304  */
  862. 25305
  863. 25306   register struct inode *rip;
  864. 25307   register dev_t dev;
  865. 25308
  866. 25309   /* If 'path' can't be opened, give up immediately. */
  867. 25310   if ( (rip = eat_path(path)) == NIL_INODE) return(NO_DEV);
  868. 25311
  869. 25312   /* If 'path' is not a block special file, return error. */
  870. 25313   if ( (rip->i_mode & I_TYPE) != I_BLOCK_SPECIAL) {
  871. 25314         err_code = ENOTBLK;
  872. 25315         put_inode(rip);
  873. 25316         return(NO_DEV);
  874. 25317   }
  875. 25318
  876. 25319   /* Extract the device number. */
  877. 25320   dev = (dev_t) rip->i_zone[0];
  878. 25321   put_inode(rip);
  879. 25322   return(dev);
  880. 25323 }
  881. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  882. src/fs/link.c    
  883. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  884. 25400 /* This file handles the LINK and UNLINK system calls.  It also deals with
  885. 25401  * deallocating the storage used by a file when the last UNLINK is done to a
  886. 25402  * file and the blocks must be returned to the free block pool.
  887. 25403  *
  888. 25404  * The entry points into this file are
  889. 25405  *   do_link:   perform the LINK system call
  890. 25406  *   do_unlink: perform the UNLINK and RMDIR system calls
  891. 25407  *   do_rename: perform the RENAME system call
  892. 25408  *   truncate:  release all the blocks associated with an inode
  893. 25409  */
  894. 25410
  895. 25411 #include "fs.h"
  896. 25412 #include <sys/stat.h>
  897. 25413 #include <string.h>
  898. 25414 #include <minix/callnr.h>
  899. 25415 #include "buf.h"
  900. 25416 #include "file.h"
  901. 25417 #include "fproc.h"
  902. 25418 #include "inode.h"
  903. 25419 #include "param.h"
  904. 25420 #include "super.h"
  905. 25421
  906. 25422 #define SAME 1000
  907. 25423
  908. 25424 FORWARD _PROTOTYPE( int remove_dir, (struct inode *rldirp, struct inode *rip,
  909. 25425                         char dir_name[NAME_MAX])                        );
  910. 25426
  911. 25427 FORWARD _PROTOTYPE( int unlink_file, (struct inode *dirp, struct inode *rip,
  912. 25428                         char file_name[NAME_MAX])                       );
  913. 25429
  914. 25430
  915. 25431 /*===========================================================================*
  916. 25432  *                              do_link                                      *
  917. 25433  *===========================================================================*/
  918. 25434 PUBLIC int do_link()
  919. 25435 {
  920. 25436 /* Perform the link(name1, name2) system call. */
  921. 25437
  922. 25438   register struct inode *ip, *rip;
  923. 25439   register int r;
  924. 25440   char string[NAME_MAX];
  925. 25441   struct inode *new_ip;
  926. 25442
  927. 25443   /* See if 'name' (file to be linked) exists. */
  928. 25444   if (fetch_name(name1, name1_length, M1) != OK) return(err_code);
  929. 25445   if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
  930. 25446
  931. 25447   /* Check to see if the file has maximum number of links already. */
  932. 25448   r = OK;
  933. 25449   if ( (rip->i_nlinks & BYTE) >= LINK_MAX) r = EMLINK;
  934. 25450
  935. 25451   /* Only super_user may link to directories. */
  936. 25452   if (r == OK)
  937. 25453         if ( (rip->i_mode & I_TYPE) == I_DIRECTORY && !super_user) r = EPERM;
  938. 25454
  939. 25455   /* If error with 'name', return the inode. */
  940. 25456   if (r != OK) {
  941. 25457         put_inode(rip);
  942. 25458         return(r);
  943. 25459   }
  944. 25460
  945. 25461   /* Does the final directory of 'name2' exist? */
  946. 25462   if (fetch_name(name2, name2_length, M1) != OK) {
  947. 25463         put_inode(rip);
  948. 25464         return(err_code);
  949. 25465   }
  950. 25466   if ( (ip = last_dir(user_path, string)) == NIL_INODE) r = err_code;
  951. 25467
  952. 25468   /* If 'name2' exists in full (even if no space) set 'r' to error. */
  953. 25469   if (r == OK) {
  954. 25470         if ( (new_ip = advance(ip, string)) == NIL_INODE) {
  955. 25471                 r = err_code;
  956. 25472                 if (r == ENOENT) r = OK;
  957. 25473         } else {
  958. 25474                 put_inode(new_ip);
  959. 25475                 r = EEXIST;
  960. 25476         }
  961. 25477   }
  962. 25478
  963. 25479   /* Check for links across devices. */
  964. 25480   if (r == OK)
  965. 25481         if (rip->i_dev != ip->i_dev) r = EXDEV;
  966. 25482
  967. 25483   /* Try to link. */
  968. 25484   if (r == OK)
  969. 25485         r = search_dir(ip, string, &rip->i_num, ENTER);
  970. 25486
  971. 25487   /* If success, register the linking. */
  972. 25488   if (r == OK) {
  973. 25489         rip->i_nlinks++;
  974. 25490         rip->i_update |= CTIME;
  975. 25491         rip->i_dirt = DIRTY;
  976. 25492   }
  977. 25493
  978. 25494   /* Done.  Release both inodes. */
  979. 25495   put_inode(rip);
  980. 25496   put_inode(ip);
  981. 25497   return(r);
  982. 25498 }
  983. 25501 /*===========================================================================*
  984. 25502  *                              do_unlink                                    *
  985. 25503  *===========================================================================*/
  986. 25504 PUBLIC int do_unlink()
  987. 25505 {
  988. 25506 /* Perform the unlink(name) or rmdir(name) system call. The code for these two
  989. 25507  * is almost the same.  They differ only in some condition testing.  Unlink()
  990. 25508  * may be used by the superuser to do dangerous things; rmdir() may not.
  991. 25509  */
  992. 25510
  993. 25511   register struct inode *rip;
  994. 25512   struct inode *rldirp;
  995. 25513   int r;
  996. 25514   char string[NAME_MAX];
  997. 25515
  998. 25516   /* Get the last directory in the path. */
  999. 25517   if (fetch_name(name, name_length, M3) != OK) return(err_code);
  1000. 25518   if ( (rldirp = last_dir(user_path, string)) == NIL_INODE)
  1001. 25519         return(err_code);
  1002. 25520
  1003. 25521   /* The last directory exists.  Does the file also exist? */
  1004. 25522   r = OK;
  1005. 25523   if ( (rip = advance(rldirp, string)) == NIL_INODE) r = err_code;
  1006. 25524
  1007. 25525   /* If error, return inode. */
  1008. 25526   if (r != OK) {
  1009. 25527         put_inode(rldirp);
  1010. 25528         return(r);
  1011. 25529   }
  1012. 25530
  1013. 25531   /* Do not remove a mount point. */
  1014. 25532   if (rip->i_num == ROOT_INODE) {
  1015. 25533         put_inode(rldirp);
  1016. 25534         put_inode(rip);
  1017. 25535         return(EBUSY);
  1018. 25536   }
  1019. 25537
  1020. 25538   /* Now test if the call is allowed, separately for unlink() and rmdir(). */
  1021. 25539   if (fs_call == UNLINK) {
  1022. 25540         /* Only the su may unlink directories, but the su can unlink any dir.*/
  1023. 25541         if ( (rip->i_mode & I_TYPE) == I_DIRECTORY && !super_user) r = EPERM;
  1024. 25542
  1025. 25543         /* Don't unlink a file if it is the root of a mounted file system. */
  1026. 25544         if (rip->i_num == ROOT_INODE) r = EBUSY;
  1027. 25545
  1028. 25546         /* Actually try to unlink the file; fails if parent is mode 0 etc. */
  1029. 25547         if (r == OK) r = unlink_file(rldirp, rip, string);
  1030. 25548
  1031. 25549   } else {
  1032. 25550         r = remove_dir(rldirp, rip, string); /* call is RMDIR */
  1033. 25551   }
  1034. 25552
  1035. 25553   /* If unlink was possible, it has been done, otherwise it has not. */
  1036. 25554   put_inode(rip);
  1037. 25555   put_inode(rldirp);
  1038. 25556   return(r);
  1039. 25557 }
  1040. 25560 /*===========================================================================*
  1041. 25561  *                              do_rename                                    *
  1042. 25562  *===========================================================================*/
  1043. 25563 PUBLIC int do_rename()
  1044. 25564 {
  1045. 25565 /* Perform the rename(name1, name2) system call. */
  1046. 25566
  1047. 25567   struct inode *old_dirp, *old_ip;      /* ptrs to old dir, file inodes */
  1048. 25568   struct inode *new_dirp, *new_ip;      /* ptrs to new dir, file inodes */
  1049. 25569   struct inode *new_superdirp, *next_new_superdirp;
  1050. 25570   int r = OK;                           /* error flag; initially no error */
  1051. 25571   int odir, ndir;                       /* TRUE iff {old|new} file is dir */
  1052. 25572   int same_pdir;                        /* TRUE iff parent dirs are the same */
  1053. 25573   char old_name[NAME_MAX], new_name[NAME_MAX];
  1054. 25574   ino_t numb;
  1055. 25575   int r1;
  1056. 25576   
  1057. 25577   /* See if 'name1' (existing file) exists.  Get dir and file inodes. */
  1058. 25578   if (fetch_name(name1, name1_length, M1) != OK) return(err_code);
  1059. 25579   if ( (old_dirp = last_dir(user_path, old_name))==NIL_INODE) return(err_code);
  1060. 25580
  1061. 25581   if ( (old_ip = advance(old_dirp, old_name)) == NIL_INODE) r = err_code;
  1062. 25582
  1063. 25583   /* See if 'name2' (new name) exists.  Get dir and file inodes. */
  1064. 25584   if (fetch_name(name2, name2_length, M1) != OK) r = err_code;
  1065. 25585   if ( (new_dirp = last_dir(user_path, new_name)) == NIL_INODE) r = err_code;
  1066. 25586   new_ip = advance(new_dirp, new_name); /* not required to exist */
  1067. 25587
  1068. 25588   if (old_ip != NIL_INODE)
  1069. 25589         odir = ((old_ip->i_mode & I_TYPE) == I_DIRECTORY);  /* TRUE iff dir */
  1070. 25590
  1071. 25591   /* If it is ok, check for a variety of possible errors. */
  1072. 25592   if (r == OK) {
  1073. 25593         same_pdir = (old_dirp == new_dirp);
  1074. 25594
  1075. 25595         /* The old inode must not be a superdirectory of the new last dir. */
  1076. 25596         if (odir && !same_pdir) {
  1077. 25597                 dup_inode(new_superdirp = new_dirp);
  1078. 25598                 while (TRUE) {          /* may hang in a file system loop */
  1079. 25599                         if (new_superdirp == old_ip) {
  1080. 25600                                 r = EINVAL;
  1081. 25601                                 break;
  1082. 25602                         }
  1083. 25603                         next_new_superdirp = advance(new_superdirp, dot2);
  1084. 25604                         put_inode(new_superdirp);
  1085. 25605                         if (next_new_superdirp == new_superdirp)
  1086. 25606                                 break;  /* back at system root directory */
  1087. 25607                         new_superdirp = next_new_superdirp;
  1088. 25608                         if (new_superdirp == NIL_INODE) {
  1089. 25609                                 /* Missing ".." entry.  Assume the worst. */
  1090. 25610                                 r = EINVAL;
  1091. 25611                                 break;
  1092. 25612                         }
  1093. 25613                 }       
  1094. 25614                 put_inode(new_superdirp);
  1095. 25615         }       
  1096. 25616
  1097. 25617         /* The old or new name must not be . or .. */
  1098. 25618         if (strcmp(old_name, ".")==0 || strcmp(old_name, "..")==0 ||
  1099. 25619             strcmp(new_name, ".")==0 || strcmp(new_name, "..")==0) r = EINVAL;
  1100. 25620
  1101. 25621         /* Both parent directories must be on the same device. */
  1102. 25622         if (old_dirp->i_dev != new_dirp->i_dev) r = EXDEV;
  1103. 25623
  1104. 25624         /* Parent dirs must be writable, searchable and on a writable device */
  1105. 25625         if ((r1 = forbidden(old_dirp, W_BIT | X_BIT)) != OK ||
  1106. 25626             (r1 = forbidden(new_dirp, W_BIT | X_BIT)) != OK) r = r1;
  1107. 25627
  1108. 25628         /* Some tests apply only if the new path exists. */
  1109. 25629         if (new_ip == NIL_INODE) {
  1110. 25630                 /* don't rename a file with a file system mounted on it. */
  1111. 25631                 if (old_ip->i_dev != old_dirp->i_dev) r = EXDEV;
  1112. 25632                 if (odir && (new_dirp->i_nlinks & BYTE) >= LINK_MAX &&
  1113. 25633                     !same_pdir && r == OK) r = EMLINK;
  1114. 25634         } else {
  1115. 25635                 if (old_ip == new_ip) r = SAME; /* old=new */
  1116. 25636
  1117. 25637                 /* has the old file or new file a file system mounted on it? */
  1118. 25638                 if (old_ip->i_dev != new_ip->i_dev) r = EXDEV;
  1119. 25639
  1120. 25640                 ndir = ((new_ip->i_mode & I_TYPE) == I_DIRECTORY); /* dir ? */
  1121. 25641                 if (odir == TRUE && ndir == FALSE) r = ENOTDIR;
  1122. 25642                 if (odir == FALSE && ndir == TRUE) r = EISDIR;
  1123. 25643         }
  1124. 25644   }
  1125. 25645
  1126. 25646   /* If a process has another root directory than the system root, we might
  1127. 25647    * "accidently" be moving it's working directory to a place where it's
  1128. 25648    * root directory isn't a super directory of it anymore. This can make
  1129. 25649    * the function chroot useless. If chroot will be used often we should
  1130. 25650    * probably check for it here.
  1131. 25651    */
  1132. 25652
  1133. 25653   /* The rename will probably work. Only two things can go wrong now:
  1134. 25654    * 1. being unable to remove the new file. (when new file already exists)
  1135. 25655    * 2. being unable to make the new directory entry. (new file doesn't exists)
  1136. 25656    *     [directory has to grow by one block and cannot because the disk
  1137. 25657    *      is completely full].
  1138. 25658    */
  1139. 25659   if (r == OK) {
  1140. 25660         if (new_ip != NIL_INODE) {
  1141. 25661                   /* There is already an entry for 'new'. Try to remove it. */
  1142. 25662                 if (odir) 
  1143. 25663                         r = remove_dir(new_dirp, new_ip, new_name);
  1144. 25664                 else 
  1145. 25665                         r = unlink_file(new_dirp, new_ip, new_name);
  1146. 25666         }
  1147. 25667         /* if r is OK, the rename will succeed, while there is now an
  1148. 25668          * unused entry in the new parent directory.
  1149. 25669          */
  1150. 25670   }
  1151. 25671
  1152. 25672   if (r == OK) {
  1153. 25673         /* If the new name will be in the same parent directory as the old one,
  1154. 25674          * first remove the old name to free an entry for the new name,
  1155. 25675          * otherwise first try to create the new name entry to make sure
  1156. 25676          * the rename will succeed.
  1157. 25677          */
  1158. 25678         numb = old_ip->i_num;           /* inode number of old file */
  1159. 25679
  1160. 25680         if (same_pdir) {
  1161. 25681                 r = search_dir(old_dirp, old_name, (ino_t *) 0, DELETE);
  1162. 25682                                                 /* shouldn't go wrong. */
  1163. 25683                 if (r==OK) (void) search_dir(old_dirp, new_name, &numb, ENTER);
  1164. 25684         } else {
  1165. 25685                 r = search_dir(new_dirp, new_name, &numb, ENTER);
  1166. 25686                 if (r == OK)
  1167. 25687                     (void) search_dir(old_dirp, old_name, (ino_t *) 0, DELETE);
  1168. 25688         }
  1169. 25689   }
  1170. 25690   /* If r is OK, the ctime and mtime of old_dirp and new_dirp have been marked
  1171. 25691    * for update in search_dir.
  1172. 25692    */
  1173. 25693
  1174. 25694   if (r == OK && odir && !same_pdir) {
  1175. 25695         /* Update the .. entry in the directory (still points to old_dirp). */
  1176. 25696         numb = new_dirp->i_num;
  1177. 25697         (void) unlink_file(old_ip, NIL_INODE, dot2);
  1178. 25698         if (search_dir(old_ip, dot2, &numb, ENTER) == OK) {
  1179. 25699                 /* New link created. */
  1180. 25700                 new_dirp->i_nlinks++;
  1181. 25701                 new_dirp->i_dirt = DIRTY;
  1182. 25702         }
  1183. 25703   }
  1184. 25704         
  1185. 25705   /* Release the inodes. */
  1186. 25706   put_inode(old_dirp);
  1187. 25707   put_inode(old_ip);
  1188. 25708   put_inode(new_dirp);
  1189. 25709   put_inode(new_ip);
  1190. 25710   return(r == SAME ? OK : r);
  1191. 25711 }
  1192. 25714 /*===========================================================================*
  1193. 25715  *                              truncate                                     *
  1194. 25716  *===========================================================================*/
  1195. 25717 PUBLIC void truncate(rip)
  1196. 25718 register struct inode *rip;     /* pointer to inode to be truncated */
  1197. 25719 {
  1198. 25720 /* Remove all the zones from the inode 'rip' and mark it dirty. */
  1199. 25721
  1200. 25722   register block_t b;
  1201. 25723   zone_t z, zone_size, z1;
  1202. 25724   off_t position;
  1203. 25725   int i, scale, file_type, waspipe, single, nr_indirects;
  1204. 25726   struct buf *bp;
  1205. 25727   dev_t dev;
  1206. 25728
  1207. 25729   file_type = rip->i_mode & I_TYPE;     /* check to see if file is special */
  1208. 25730   if (file_type == I_CHAR_SPECIAL || file_type == I_BLOCK_SPECIAL) return;
  1209. 25731   dev = rip->i_dev;             /* device on which inode resides */
  1210. 25732   scale = rip->i_sp->s_log_zone_size;
  1211. 25733   zone_size = (zone_t) BLOCK_SIZE << scale;
  1212. 25734   nr_indirects = rip->i_nindirs;
  1213. 25735
  1214. 25736   /* Pipes can shrink, so adjust size to make sure all zones are removed. */
  1215. 25737   waspipe = rip->i_pipe == I_PIPE;      /* TRUE is this was a pipe */
  1216. 25738   if (waspipe) rip->i_size = PIPE_SIZE;
  1217. 25739
  1218. 25740   /* Step through the file a zone at a time, finding and freeing the zones. */
  1219. 25741   for (position = 0; position < rip->i_size; position += zone_size) {
  1220. 25742         if ( (b = read_map(rip, position)) != NO_BLOCK) {
  1221. 25743                 z = (zone_t) b >> scale;
  1222. 25744                 free_zone(dev, z);
  1223. 25745         }
  1224. 25746   }
  1225. 25747
  1226. 25748   /* All the data zones have been freed.  Now free the indirect zones. */
  1227. 25749   rip->i_dirt = DIRTY;
  1228. 25750   if (waspipe) {
  1229. 25751         wipe_inode(rip);        /* clear out inode for pipes */
  1230. 25752         return;                 /* indirect slots contain file positions */
  1231. 25753   }
  1232. 25754   single = rip->i_ndzones;
  1233. 25755   free_zone(dev, rip->i_zone[single]);  /* single indirect zone */
  1234. 25756   if ( (z = rip->i_zone[single+1]) != NO_ZONE) {
  1235. 25757         /* Free all the single indirect zones pointed to by the double. */
  1236. 25758         b = (block_t) z << scale;
  1237. 25759         bp = get_block(dev, b, NORMAL); /* get double indirect zone */
  1238. 25760         for (i = 0; i < nr_indirects; i++) {
  1239. 25761                 z1 = rd_indir(bp, i);
  1240. 25762                 free_zone(dev, z1);
  1241. 25763         }
  1242. 25764
  1243. 25765         /* Now free the double indirect zone itself. */
  1244. 25766         put_block(bp, INDIRECT_BLOCK);
  1245. 25767         free_zone(dev, z);
  1246. 25768   }
  1247. 25769
  1248. 25770   /* Leave zone numbers for de(1) to recover file after an unlink(2).  */
  1249. 25771 }
  1250. 25774 /*===========================================================================*
  1251. 25775  *                              remove_dir                                   *
  1252. 25776  *===========================================================================*/
  1253. 25777 PRIVATE int remove_dir(rldirp, rip, dir_name)
  1254. 25778 struct inode *rldirp;                   /* parent directory */
  1255. 25779 struct inode *rip;                      /* directory to be removed */
  1256. 25780 char dir_name[NAME_MAX];                /* name of directory to be removed */
  1257. 25781 {
  1258. 25782   /* A directory file has to be removed. Five conditions have to met:
  1259. 25783    *    - The file must be a directory
  1260. 25784    *    - The directory must be empty (except for . and ..)
  1261. 25785    *    - The final component of the path must not be . or ..
  1262. 25786    *    - The directory must not be the root of a mounted file system
  1263. 25787    *    - The directory must not be anybody's root/working directory
  1264. 25788    */
  1265. 25789
  1266. 25790   int r;
  1267. 25791   register struct fproc *rfp;
  1268. 25792
  1269. 25793   /* search_dir checks that rip is a directory too. */
  1270. 25794   if ((r = search_dir(rip, "", (ino_t *) 0, IS_EMPTY)) != OK) return r;
  1271. 25795
  1272. 25796   if (strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0)return(EINVAL);
  1273. 25797   if (rip->i_num == ROOT_INODE) return(EBUSY); /* can't remove 'root' */
  1274. 25798   
  1275. 25799   for (rfp = &fproc[INIT_PROC_NR + 1]; rfp < &fproc[NR_PROCS]; rfp++)
  1276. 25800         if (rfp->fp_workdir == rip || rfp->fp_rootdir == rip) return(EBUSY);
  1277. 25801                                 /* can't remove anybody's working dir */
  1278. 25802
  1279. 25803   /* Actually try to unlink the file; fails if parent is mode 0 etc. */
  1280. 25804   if ((r = unlink_file(rldirp, rip, dir_name)) != OK) return r;
  1281. 25805
  1282. 25806   /* Unlink . and .. from the dir. The super user can link and unlink any dir,
  1283. 25807    * so don't make too many assumptions about them.
  1284. 25808    */
  1285. 25809   (void) unlink_file(rip, NIL_INODE, dot1);
  1286. 25810   (void) unlink_file(rip, NIL_INODE, dot2);
  1287. 25811   return(OK);
  1288. 25812 }
  1289. 25815 /*===========================================================================*
  1290. 25816  *                              unlink_file                                  *
  1291. 25817  *===========================================================================*/
  1292. 25818 PRIVATE int unlink_file(dirp, rip, file_name)
  1293. 25819 struct inode *dirp;             /* parent directory of file */
  1294. 25820 struct inode *rip;              /* inode of file, may be NIL_INODE too. */
  1295. 25821 char file_name[NAME_MAX];       /* name of file to be removed */
  1296. 25822 {
  1297. 25823 /* Unlink 'file_name'; rip must be the inode of 'file_name' or NIL_INODE. */
  1298. 25824
  1299. 25825   ino_t numb;                   /* inode number */
  1300. 25826   int   r;
  1301. 25827
  1302. 25828   /* If rip is not NIL_INODE, it is used to get faster access to the inode. */
  1303. 25829   if (rip == NIL_INODE) {
  1304. 25830         /* Search for file in directory and try to get its inode. */
  1305. 25831         err_code = search_dir(dirp, file_name, &numb, LOOK_UP);
  1306. 25832         if (err_code == OK) rip = get_inode(dirp->i_dev, (int) numb);
  1307. 25833         if (err_code != OK || rip == NIL_INODE) return(err_code);
  1308. 25834   } else {
  1309. 25835         dup_inode(rip);         /* inode will be returned with put_inode */
  1310. 25836   }
  1311. 25837
  1312. 25838   r = search_dir(dirp, file_name, (ino_t *) 0, DELETE);
  1313. 25839
  1314. 25840   if (r == OK) {
  1315. 25841         rip->i_nlinks--;        /* entry deleted from parent's dir */
  1316. 25842         rip->i_update |= CTIME;
  1317. 25843         rip->i_dirt = DIRTY;
  1318. 25844   }
  1319. 25845
  1320. 25846   put_inode(rip);
  1321. 25847   return(r);
  1322. 25848 }
  1323. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1324. src/fs/stadir.c    
  1325. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1326. 25900 /* This file contains the code for performing four system calls relating to
  1327. 25901  * status and directories.
  1328. 25902  *
  1329. 25903  * The entry points into this file are
  1330. 25904  *   do_chdir:  perform the CHDIR system call
  1331. 25905  *   do_chroot: perform the CHROOT system call
  1332. 25906  *   do_stat:   perform the STAT system call
  1333. 25907  *   do_fstat:  perform the FSTAT system call
  1334. 25908  */
  1335. 25909
  1336. 25910 #include "fs.h"
  1337. 25911 #include <sys/stat.h>
  1338. 25912 #include "file.h"
  1339. 25913 #include "fproc.h"
  1340. 25914 #include "inode.h"
  1341. 25915 #include "param.h"
  1342. 25916
  1343. 25917 FORWARD _PROTOTYPE( int change, (struct inode **iip, char *name_ptr, int len));
  1344. 25918 FORWARD _PROTOTYPE( int stat_inode, (struct inode *rip, struct filp *fil_ptr,
  1345. 25919                         char *user_addr)                                );
  1346. 25920
  1347. 25921 /*===========================================================================*
  1348. 25922  *                              do_chdir                                     *
  1349. 25923  *===========================================================================*/
  1350. 25924 PUBLIC int do_chdir()
  1351. 25925 {
  1352. 25926 /* Change directory.  This function is  also called by MM to simulate a chdir
  1353. 25927  * in order to do EXEC, etc.  It also changes the root directory, the uids and
  1354. 25928  * gids, and the umask. 
  1355. 25929  */
  1356. 25930
  1357. 25931   int r;
  1358. 25932   register struct fproc *rfp;
  1359. 25933
  1360. 25934   if (who == MM_PROC_NR) {
  1361. 25935         rfp = &fproc[slot1];
  1362. 25936         put_inode(fp->fp_rootdir);
  1363. 25937         dup_inode(fp->fp_rootdir = rfp->fp_rootdir);
  1364. 25938         put_inode(fp->fp_workdir);
  1365. 25939         dup_inode(fp->fp_workdir = rfp->fp_workdir);
  1366. 25940
  1367. 25941         /* MM uses access() to check permissions.  To make this work, pretend
  1368. 25942          * that the user's real ids are the same as the user's effective ids.
  1369. 25943          * FS calls other than access() do not use the real ids, so are not
  1370. 25944          * affected.
  1371. 25945          */
  1372. 25946         fp->fp_realuid =
  1373. 25947         fp->fp_effuid = rfp->fp_effuid;
  1374. 25948         fp->fp_realgid =
  1375. 25949         fp->fp_effgid = rfp->fp_effgid;
  1376. 25950         fp->fp_umask = rfp->fp_umask;
  1377. 25951         return(OK);
  1378. 25952   }
  1379. 25953
  1380. 25954   /* Perform the chdir(name) system call. */
  1381. 25955   r = change(&fp->fp_workdir, name, name_length);
  1382. 25956   return(r);
  1383. 25957 }
  1384. 25960 /*===========================================================================*
  1385. 25961  *                              do_chroot                                    *
  1386. 25962  *===========================================================================*/
  1387. 25963 PUBLIC int do_chroot()
  1388. 25964 {
  1389. 25965 /* Perform the chroot(name) system call. */
  1390. 25966
  1391. 25967   register int r;
  1392. 25968
  1393. 25969   if (!super_user) return(EPERM);       /* only su may chroot() */
  1394. 25970   r = change(&fp->fp_rootdir, name, name_length);
  1395. 25971   return(r);
  1396. 25972 }
  1397. 25975 /*===========================================================================*
  1398. 25976  *                              change                                       *
  1399. 25977  *===========================================================================*/
  1400. 25978 PRIVATE int change(iip, name_ptr, len)
  1401. 25979 struct inode **iip;             /* pointer to the inode pointer for the dir */
  1402. 25980 char *name_ptr;                 /* pointer to the directory name to change to */
  1403. 25981 int len;                        /* length of the directory name string */
  1404. 25982 {
  1405. 25983 /* Do the actual work for chdir() and chroot(). */
  1406. 25984
  1407. 25985   struct inode *rip;
  1408. 25986   register int r;
  1409. 25987
  1410. 25988   /* Try to open the new directory. */
  1411. 25989   if (fetch_name(name_ptr, len, M3) != OK) return(err_code);
  1412. 25990   if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
  1413. 25991
  1414. 25992   /* It must be a directory and also be searchable. */
  1415. 25993   if ( (rip->i_mode & I_TYPE) != I_DIRECTORY)
  1416. 25994         r = ENOTDIR;
  1417. 25995   else
  1418. 25996         r = forbidden(rip, X_BIT);      /* check if dir is searchable */
  1419. 25997
  1420. 25998   /* If error, return inode. */
  1421. 25999   if (r != OK) {
  1422. 26000         put_inode(rip);
  1423. 26001         return(r);
  1424. 26002   }
  1425. 26003
  1426. 26004   /* Everything is OK.  Make the change. */
  1427. 26005   put_inode(*iip);              /* release the old directory */
  1428. 26006   *iip = rip;                   /* acquire the new one */
  1429. 26007   return(OK);
  1430. 26008 }
  1431. 26011 /*===========================================================================*
  1432. 26012  *                              do_stat                                      *
  1433. 26013  *===========================================================================*/
  1434. 26014 PUBLIC int do_stat()
  1435. 26015 {
  1436. 26016 /* Perform the stat(name, buf) system call. */
  1437. 26017
  1438. 26018   register struct inode *rip;
  1439. 26019   register int r;
  1440. 26020
  1441. 26021   /* Both stat() and fstat() use the same routine to do the real work.  That
  1442. 26022    * routine expects an inode, so acquire it temporarily.
  1443. 26023    */
  1444. 26024   if (fetch_name(name1, name1_length, M1) != OK) return(err_code);
  1445. 26025   if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
  1446. 26026   r = stat_inode(rip, NIL_FILP, name2); /* actually do the work.*/
  1447. 26027   put_inode(rip);               /* release the inode */
  1448. 26028   return(r);
  1449. 26029 }
  1450. 26032 /*===========================================================================*
  1451. 26033  *                              do_fstat                                     *
  1452. 26034  *===========================================================================*/
  1453. 26035 PUBLIC int do_fstat()
  1454. 26036 {
  1455. 26037 /* Perform the fstat(fd, buf) system call. */
  1456. 26038
  1457. 26039   register struct filp *rfilp;
  1458. 26040
  1459. 26041   /* Is the file descriptor valid? */
  1460. 26042   if ( (rfilp = get_filp(fd)) == NIL_FILP) return(err_code);
  1461. 26043
  1462. 26044   return(stat_inode(rfilp->filp_ino, rfilp, buffer));
  1463. 26045 }
  1464. 26048 /*===========================================================================*
  1465. 26049  *                              stat_inode                                   *
  1466. 26050  *===========================================================================*/
  1467. 26051 PRIVATE int stat_inode(rip, fil_ptr, user_addr)
  1468. 26052 register struct inode *rip;     /* pointer to inode to stat */
  1469. 26053 struct filp *fil_ptr;           /* filp pointer, supplied by 'fstat' */
  1470. 26054 char *user_addr;                /* user space address where stat buf goes */
  1471. 26055 {
  1472. 26056 /* Common code for stat and fstat system calls. */
  1473. 26057
  1474. 26058   struct stat statbuf;
  1475. 26059   mode_t mo;
  1476. 26060   int r, s;
  1477. 26061
  1478. 26062   /* Update the atime, ctime, and mtime fields in the inode, if need be. */
  1479. 26063   if (rip->i_update) update_times(rip);
  1480. 26064
  1481. 26065   /* Fill in the statbuf struct. */
  1482. 26066   mo = rip->i_mode & I_TYPE;
  1483. 26067   s = (mo == I_CHAR_SPECIAL || mo == I_BLOCK_SPECIAL);  /* true iff special */
  1484. 26068   statbuf.st_dev = rip->i_dev;
  1485. 26069   statbuf.st_ino = rip->i_num;
  1486. 26070   statbuf.st_mode = rip->i_mode;
  1487. 26071   statbuf.st_nlink = rip->i_nlinks & BYTE;
  1488. 26072   statbuf.st_uid = rip->i_uid;
  1489. 26073   statbuf.st_gid = rip->i_gid & BYTE;
  1490. 26074   statbuf.st_rdev = (dev_t) (s ? rip->i_zone[0] : NO_DEV);
  1491. 26075   statbuf.st_size = rip->i_size;
  1492. 26076
  1493. 26077   if (rip->i_pipe == I_PIPE) {
  1494. 26078         statbuf.st_mode &= ~I_REGULAR;  /* wipe out I_REGULAR bit for pipes */
  1495. 26079         if (fil_ptr != NIL_FILP && fil_ptr->filp_mode & R_BIT) 
  1496. 26080                 statbuf.st_size -= fil_ptr->filp_pos;
  1497. 26081   }
  1498. 26082
  1499. 26083   statbuf.st_atime = rip->i_atime;
  1500. 26084   statbuf.st_mtime = rip->i_mtime;
  1501. 26085   statbuf.st_ctime = rip->i_ctime;
  1502. 26086
  1503. 26087   /* Copy the struct to user space. */
  1504. 26088   r = sys_copy(FS_PROC_NR, D, (phys_bytes) &statbuf,
  1505. 26089                 who, D, (phys_bytes) user_addr, (phys_bytes) sizeof(statbuf));
  1506. 26090   return(r);
  1507. 26091 }
  1508. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1509. src/fs/protect.c    
  1510. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1511. 26100 /* This file deals with protection in the file system.  It contains the code
  1512. 26101  * for four system calls that relate to protection.
  1513. 26102  *
  1514. 26103  * The entry points into this file are
  1515. 26104  *   do_chmod:  perform the CHMOD system call
  1516. 26105  *   do_chown:  perform the CHOWN system call
  1517. 26106  *   do_umask:  perform the UMASK system call
  1518. 26107  *   do_access: perform the ACCESS system call
  1519. 26108  *   forbidden: check to see if a given access is allowed on a given inode
  1520. 26109  */
  1521. 26110
  1522. 26111 #include "fs.h"
  1523. 26112 #include <unistd.h>
  1524. 26113 #include <minix/callnr.h>
  1525. 26114 #include "buf.h"
  1526. 26115 #include "file.h"
  1527. 26116 #include "fproc.h"
  1528. 26117 #include "inode.h"
  1529. 26118 #include "param.h"
  1530. 26119 #include "super.h"
  1531. 26120
  1532. 26121 /*===========================================================================*
  1533. 26122  *                              do_chmod                                     *
  1534. 26123  *===========================================================================*/
  1535. 26124 PUBLIC int do_chmod()
  1536. 26125 {
  1537. 26126 /* Perform the chmod(name, mode) system call. */
  1538. 26127
  1539. 26128   register struct inode *rip;
  1540. 26129   register int r;
  1541. 26130
  1542. 26131   /* Temporarily open the file. */
  1543. 26132   if (fetch_name(name, name_length, M3) != OK) return(err_code);
  1544. 26133   if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
  1545. 26134
  1546. 26135   /* Only the owner or the super_user may change the mode of a file.
  1547. 26136    * No one may change the mode of a file on a read-only file system.
  1548. 26137    */
  1549. 26138   if (rip->i_uid != fp->fp_effuid && !super_user)
  1550. 26139         r = EPERM;
  1551. 26140   else
  1552. 26141         r = read_only(rip);
  1553. 26142
  1554. 26143   /* If error, return inode. */
  1555. 26144   if (r != OK)  {
  1556. 26145         put_inode(rip);
  1557. 26146         return(r);
  1558. 26147   }
  1559. 26148
  1560. 26149   /* Now make the change. Clear setgid bit if file is not in caller's grp */
  1561. 26150   rip->i_mode = (rip->i_mode & ~ALL_MODES) | (mode & ALL_MODES);
  1562. 26151   if (!super_user && rip->i_gid != fp->fp_effgid)rip->i_mode &= ~I_SET_GID_BIT;
  1563. 26152   rip->i_update |= CTIME;
  1564. 26153   rip->i_dirt = DIRTY;
  1565. 26154
  1566. 26155   put_inode(rip);
  1567. 26156   return(OK);
  1568. 26157 }
  1569. 26160 /*===========================================================================*
  1570. 26161  *                              do_chown                                     *
  1571. 26162  *===========================================================================*/
  1572. 26163 PUBLIC int do_chown()
  1573. 26164 {
  1574. 26165 /* Perform the chown(name, owner, group) system call. */
  1575. 26166
  1576. 26167   register struct inode *rip;
  1577. 26168   register int r;
  1578. 26169
  1579. 26170   /* Temporarily open the file. */
  1580. 26171   if (fetch_name(name1, name1_length, M1) != OK) return(err_code);
  1581. 26172   if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
  1582. 26173
  1583. 26174   /* Not permitted to change the owner of a file on a read-only file sys. */
  1584. 26175   r = read_only(rip);
  1585. 26176   if (r == OK) {
  1586. 26177         /* FS is R/W.  Whether call is allowed depends on ownership, etc. */
  1587. 26178         if (super_user) {
  1588. 26179                 /* The super user can do anything. */
  1589. 26180                 rip->i_uid = owner;     /* others later */
  1590. 26181         } else {
  1591. 26182                 /* Regular users can only change groups of their own files. */
  1592. 26183                 if (rip->i_uid != fp->fp_effuid) r = EPERM;
  1593. 26184                 if (rip->i_uid != owner) r = EPERM;     /* no giving away */
  1594. 26185                 if (fp->fp_effgid != group) r = EPERM;
  1595. 26186         }
  1596. 26187   }
  1597. 26188   if (r == OK) {
  1598. 26189         rip->i_gid = group;
  1599. 26190         rip->i_mode &= ~(I_SET_UID_BIT | I_SET_GID_BIT);
  1600. 26191         rip->i_update |= CTIME;
  1601. 26192         rip->i_dirt = DIRTY;
  1602. 26193   }
  1603. 26194
  1604. 26195   put_inode(rip);
  1605. 26196   return(r);
  1606. 26197 }
  1607. 26200 /*===========================================================================*
  1608. 26201  *                              do_umask                                     *
  1609. 26202  *===========================================================================*/
  1610. 26203 PUBLIC int do_umask()
  1611. 26204 {
  1612. 26205 /* Perform the umask(co_mode) system call. */
  1613. 26206   register mode_t r;
  1614. 26207
  1615. 26208   r = ~fp->fp_umask;            /* set 'r' to complement of old mask */
  1616. 26209   fp->fp_umask = ~(co_mode & RWX_MODES);
  1617. 26210   return(r);                    /* return complement of old mask */
  1618. 26211 }
  1619. 26214 /*===========================================================================*
  1620. 26215  *                              do_access                                    *
  1621. 26216  *===========================================================================*/
  1622. 26217 PUBLIC int do_access()
  1623. 26218 {
  1624. 26219 /* Perform the access(name, mode) system call. */
  1625. 26220
  1626. 26221   struct inode *rip;
  1627. 26222   register int r;
  1628. 26223
  1629. 26224   /* First check to see if the mode is correct. */
  1630. 26225   if ( (mode & ~(R_OK | W_OK | X_OK)) != 0 && mode != F_OK)
  1631. 26226         return(EINVAL);
  1632. 26227
  1633. 26228   /* Temporarily open the file whose access is to be checked. */
  1634. 26229   if (fetch_name(name, name_length, M3) != OK) return(err_code);
  1635. 26230   if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
  1636. 26231
  1637. 26232   /* Now check the permissions. */
  1638. 26233   r = forbidden(rip, (mode_t) mode);
  1639. 26234   put_inode(rip);
  1640. 26235   return(r);
  1641. 26236 }
  1642. 26239 /*===========================================================================*
  1643. 26240  *                              forbidden                                    *
  1644. 26241  *===========================================================================*/
  1645. 26242 PUBLIC int forbidden(rip, access_desired)
  1646. 26243 register struct inode *rip;     /* pointer to inode to be checked */
  1647. 26244 mode_t access_desired;  /* RWX bits */
  1648. 26245 {
  1649. 26246 /* Given a pointer to an inode, 'rip', and the access desired, determine
  1650. 26247  * if the access is allowed, and if not why not.  The routine looks up the
  1651. 26248  * caller's uid in the 'fproc' table.  If access is allowed, OK is returned
  1652. 26249  * if it is forbidden, EACCES is returned.
  1653. 26250  */
  1654. 26251
  1655. 26252   register struct inode *old_rip = rip;
  1656. 26253   register struct super_block *sp;
  1657. 26254   register mode_t bits, perm_bits;
  1658. 26255   int r, shift, test_uid, test_gid;
  1659. 26256
  1660. 26257   if (rip->i_mount == I_MOUNT)  /* The inode is mounted on. */
  1661. 26258         for (sp = &super_block[1]; sp < &super_block[NR_SUPERS]; sp++)
  1662. 26259                 if (sp->s_imount == rip) {
  1663. 26260                         rip = get_inode(sp->s_dev, ROOT_INODE);
  1664. 26261                         break;
  1665. 26262                 } /* if */
  1666. 26263
  1667. 26264   /* Isolate the relevant rwx bits from the mode. */
  1668. 26265   bits = rip->i_mode;
  1669. 26266   test_uid = (fs_call == ACCESS ? fp->fp_realuid : fp->fp_effuid);
  1670. 26267   test_gid = (fs_call == ACCESS ? fp->fp_realgid : fp->fp_effgid);
  1671. 26268   if (test_uid == SU_UID) {
  1672. 26269         /* Grant read and write permission.  Grant search permission for
  1673. 26270          * directories.  Grant execute permission (for non-directories) if
  1674. 26271          * and only if one of the 'X' bits is set.
  1675. 26272          */
  1676. 26273         if ( (bits & I_TYPE) == I_DIRECTORY ||
  1677. 26274              bits & ((X_BIT << 6) | (X_BIT << 3) | X_BIT))
  1678. 26275                 perm_bits = R_BIT | W_BIT | X_BIT;
  1679. 26276         else
  1680. 26277                 perm_bits = R_BIT | W_BIT;
  1681. 26278   } else {
  1682. 26279         if (test_uid == rip->i_uid) shift = 6;          /* owner */
  1683. 26280         else if (test_gid == rip->i_gid ) shift = 3;    /* group */
  1684. 26281         else shift = 0;                                 /* other */
  1685. 26282         perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT);
  1686. 26283   }
  1687. 26284
  1688. 26285   /* If access desired is not a subset of what is allowed, it is refused. */
  1689. 26286   r = OK;
  1690. 26287   if ((perm_bits | access_desired) != perm_bits) r = EACCES;
  1691. 26288
  1692. 26289   /* Check to see if someone is trying to write on a file system that is
  1693. 26290    * mounted read-only.
  1694. 26291    */
  1695. 26292   if (r == OK)
  1696. 26293         if (access_desired & W_BIT) r = read_only(rip);
  1697. 26294
  1698. 26295   if (rip != old_rip) put_inode(rip);
  1699. 26296
  1700. 26297   return(r);
  1701. 26298 }
  1702. 26301 /*===========================================================================*
  1703. 26302  *                              read_only                                    *
  1704. 26303  *===========================================================================*/
  1705. 26304 PUBLIC int read_only(ip)
  1706. 26305 struct inode *ip;               /* ptr to inode whose file sys is to be cked */
  1707. 26306 {
  1708. 26307 /* Check to see if the file system on which the inode 'ip' resides is mounted
  1709. 26308  * read only.  If so, return EROFS, else return OK.
  1710. 26309  */
  1711. 26310
  1712. 26311   register struct super_block *sp;
  1713. 26312
  1714. 26313   sp = ip->i_sp;
  1715. 26314   return(sp->s_rd_only ? EROFS : OK);
  1716. 26315 }
  1717. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1718. src/fs/time.c    
  1719. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1720. 26400 /* This file takes care of those system calls that deal with time.
  1721. 26401  *
  1722. 26402  * The entry points into this file are
  1723. 26403  *   do_utime:  perform the UTIME system call
  1724. 26404  *   do_time:   perform the TIME system call
  1725. 26405  *   do_stime:  perform the STIME system call
  1726. 26406  *   do_tims:   perform the TIMES system call
  1727. 26407  */
  1728. 26408
  1729. 26409 #include "fs.h"
  1730. 26410 #include <minix/callnr.h>
  1731. 26411 #include <minix/com.h>
  1732. 26412 #include "file.h"
  1733. 26413 #include "fproc.h"
  1734. 26414 #include "inode.h"
  1735. 26415 #include "param.h"
  1736. 26416
  1737. 26417 PRIVATE message clock_mess;
  1738. 26418
  1739. 26419 /*===========================================================================*
  1740. 26420  *                              do_utime                                     *
  1741. 26421  *===========================================================================*/
  1742. 26422 PUBLIC int do_utime()
  1743. 26423 {
  1744. 26424 /* Perform the utime(name, timep) system call. */
  1745. 26425
  1746. 26426   register struct inode *rip;
  1747. 26427   register int len, r;
  1748. 26428
  1749. 26429   /* Adjust for case of NULL 'timep'. */
  1750. 26430   len = utime_length;
  1751. 26431   if (len == 0) len = m.m2_i2;
  1752. 26432
  1753. 26433   /* Temporarily open the file. */
  1754. 26434   if (fetch_name(utime_file, len, M1) != OK) return(err_code);
  1755. 26435   if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
  1756. 26436
  1757. 26437   /* Only the owner of a file or the super_user can change its time. */
  1758. 26438   r = OK;
  1759. 26439   if (rip->i_uid != fp->fp_effuid && !super_user) r = EPERM;
  1760. 26440   if (utime_length == 0 && r != OK) r = forbidden(rip, W_BIT);
  1761. 26441   if (read_only(rip) != OK) r = EROFS;  /* not even su can touch if R/O */
  1762. 26442   if (r == OK) {
  1763. 26443         if (utime_length == 0) {
  1764. 26444                 rip->i_atime = clock_time();
  1765. 26445                 rip->i_mtime = rip->i_atime;
  1766. 26446         } else {
  1767. 26447                 rip->i_atime = utime_actime;
  1768. 26448                 rip->i_mtime = utime_modtime;
  1769. 26449         }
  1770. 26450         rip->i_update = CTIME;  /* discard any stale ATIME and MTIME flags */
  1771. 26451         rip->i_dirt = DIRTY;
  1772. 26452   }
  1773. 26453
  1774. 26454   put_inode(rip);
  1775. 26455   return(r);
  1776. 26456 }
  1777. 26459 /*===========================================================================*
  1778. 26460  *                              do_time                                      *
  1779. 26461  *===========================================================================*/
  1780. 26462 PUBLIC int do_time()
  1781. 26463
  1782. 26464 {
  1783. 26465 /* Perform the time(tp) system call. */
  1784. 26466
  1785. 26467   reply_l1 = clock_time();      /* return time in seconds */
  1786. 26468   return(OK);
  1787. 26469 }
  1788. 26472 /*===========================================================================*
  1789. 26473  *                              do_stime                                     *
  1790. 26474  *===========================================================================*/
  1791. 26475 PUBLIC int do_stime()
  1792. 26476 {
  1793. 26477 /* Perform the stime(tp) system call. */
  1794. 26478
  1795. 26479   register int k;
  1796. 26480
  1797. 26481   if (!super_user) return(EPERM);
  1798. 26482   clock_mess.m_type = SET_TIME;
  1799. 26483   clock_mess.NEW_TIME = (long) tp;
  1800. 26484   if ( (k = sendrec(CLOCK, &clock_mess)) != OK) panic("do_stime error", k);
  1801. 26485   return(OK);
  1802. 26486 }
  1803. 26489 /*===========================================================================*
  1804. 26490  *                              do_tims                                      *
  1805. 26491  *===========================================================================*/
  1806. 26492 PUBLIC int do_tims()
  1807. 26493 {
  1808. 26494 /* Perform the times(buffer) system call. */
  1809. 26495
  1810. 26496   clock_t t[5];
  1811. 26497
  1812. 26498   sys_times(who, t);
  1813. 26499   reply_t1 = t[0];
  1814. 26500   reply_t2 = t[1];
  1815. 26501   reply_t3 = t[2];
  1816. 26502   reply_t4 = t[3];
  1817. 26503   reply_t5 = t[4];
  1818. 26504   return(OK);
  1819. 26505 }
  1820. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1821. src/fs/misc.c    
  1822. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1823. 26600 /* This file contains a collection of miscellaneous procedures.  Some of them
  1824. 26601  * perform simple system calls.  Some others do a little part of system calls
  1825. 26602  * that are mostly performed by the Memory Manager.
  1826. 26603  *
  1827. 26604  * The entry points into this file are
  1828. 26605  *   do_dup:      perform the DUP system call
  1829. 26606  *   do_fcntl:    perform the FCNTL system call
  1830. 26607  *   do_sync:     perform the SYNC system call
  1831. 26608  *   do_fork:     adjust the tables after MM has performed a FORK system call
  1832. 26609  *   do_exec:     handle files with FD_CLOEXEC on after MM has done an EXEC
  1833. 26610  *   do_exit:     a process has exited; note that in the tables
  1834. 26611  *   do_set:      set uid or gid for some process
  1835. 26612  *   do_revive:   revive a process that was waiting for something (e.g. TTY)
  1836. 26613  */
  1837. 26614
  1838. 26615 #include "fs.h"
  1839. 26616 #include <fcntl.h>
  1840. 26617 #include <unistd.h>     /* cc runs out of memory with unistd.h :-( */
  1841. 26618 #include <minix/callnr.h>
  1842. 26619 #include <minix/com.h>
  1843. 26620 #include <minix/boot.h>
  1844. 26621 #include "buf.h"
  1845. 26622 #include "file.h"
  1846. 26623 #include "fproc.h"
  1847. 26624 #include "inode.h"
  1848. 26625 #include "dev.h"
  1849. 26626 #include "param.h"
  1850. 26627
  1851. 26628
  1852. 26629 /*===========================================================================*
  1853. 26630  *                              do_dup                                       *
  1854. 26631  *===========================================================================*/
  1855. 26632 PUBLIC int do_dup()
  1856. 26633 {
  1857. 26634 /* Perform the dup(fd) or dup2(fd,fd2) system call. These system calls are
  1858. 26635  * obsolete.  In fact, it is not even possible to invoke them using the
  1859. 26636  * current library because the library routines call fcntl().  They are
  1860. 26637  * provided to permit old binary programs to continue to run.
  1861. 26638  */
  1862. 26639
  1863. 26640   register int rfd;
  1864. 26641   register struct filp *f;
  1865. 26642   struct filp *dummy;
  1866. 26643   int r;
  1867. 26644
  1868. 26645   /* Is the file descriptor valid? */
  1869. 26646   rfd = fd & ~DUP_MASK;         /* kill off dup2 bit, if on */
  1870. 26647   if ((f = get_filp(rfd)) == NIL_FILP) return(err_code);
  1871. 26648
  1872. 26649   /* Distinguish between dup and dup2. */
  1873. 26650   if (fd == rfd) {                      /* bit not on */
  1874. 26651         /* dup(fd) */
  1875. 26652         if ( (r = get_fd(0, 0, &fd2, &dummy)) != OK) return(r);
  1876. 26653   } else {
  1877. 26654         /* dup2(fd, fd2) */
  1878. 26655         if (fd2 < 0 || fd2 >= OPEN_MAX) return(EBADF);
  1879. 26656         if (rfd == fd2) return(fd2);    /* ignore the call: dup2(x, x) */
  1880. 26657         fd = fd2;               /* prepare to close fd2 */
  1881. 26658         (void) do_close();      /* cannot fail */
  1882. 26659   }
  1883. 26660
  1884. 26661   /* Success. Set up new file descriptors. */
  1885. 26662   f->filp_count++;
  1886. 26663   fp->fp_filp[fd2] = f;
  1887. 26664   return(fd2);
  1888. 26665 }
  1889. 26667 /*===========================================================================*
  1890. 26668  *                              do_fcntl                                     *
  1891. 26669  *===========================================================================*/
  1892. 26670 PUBLIC int do_fcntl()
  1893. 26671 {
  1894. 26672 /* Perform the fcntl(fd, request, ...) system call. */
  1895. 26673
  1896. 26674   register struct filp *f;
  1897. 26675   int new_fd, r, fl;
  1898. 26676   long cloexec_mask;            /* bit map for the FD_CLOEXEC flag */
  1899. 26677   long clo_value;               /* FD_CLOEXEC flag in proper position */
  1900. 26678   struct filp *dummy;
  1901. 26679
  1902. 26680   /* Is the file descriptor valid? */
  1903. 26681   if ((f = get_filp(fd)) == NIL_FILP) return(err_code);
  1904. 26682
  1905. 26683   switch (request) {
  1906. 26684      case F_DUPFD: 
  1907. 26685         /* This replaces the old dup() system call. */
  1908. 26686         if (addr < 0 || addr >= OPEN_MAX) return(EINVAL);
  1909. 26687         if ((r = get_fd(addr, 0, &new_fd, &dummy)) != OK) return(r);
  1910. 26688         f->filp_count++;
  1911. 26689         fp->fp_filp[new_fd] = f;
  1912. 26690         return(new_fd);
  1913. 26691
  1914. 26692      case F_GETFD: 
  1915. 26693         /* Get close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */
  1916. 26694         return( ((fp->fp_cloexec >> fd) & 01) ? FD_CLOEXEC : 0);
  1917. 26695
  1918. 26696      case F_SETFD: 
  1919. 26697         /* Set close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */
  1920. 26698         cloexec_mask = 1L << fd;        /* singleton set position ok */
  1921. 26699         clo_value = (addr & FD_CLOEXEC ? cloexec_mask : 0L);
  1922. 26700         fp->fp_cloexec = (fp->fp_cloexec & ~cloexec_mask) | clo_value;
  1923. 26701         return(OK);
  1924. 26702
  1925. 26703      case F_GETFL: 
  1926. 26704         /* Get file status flags (O_NONBLOCK and O_APPEND). */
  1927. 26705         fl = f->filp_flags & (O_NONBLOCK | O_APPEND | O_ACCMODE);
  1928. 26706         return(fl);     
  1929. 26707
  1930. 26708      case F_SETFL: 
  1931. 26709         /* Set file status flags (O_NONBLOCK and O_APPEND). */
  1932. 26710         fl = O_NONBLOCK | O_APPEND;
  1933. 26711         f->filp_flags = (f->filp_flags & ~fl) | (addr & fl);
  1934. 26712         return(OK);
  1935. 26713
  1936. 26714      case F_GETLK:
  1937. 26715      case F_SETLK:
  1938. 26716      case F_SETLKW:
  1939. 26717         /* Set or clear a file lock. */
  1940. 26718         r = lock_op(f, request);
  1941. 26719         return(r);
  1942. 26720
  1943. 26721      default:
  1944. 26722         return(EINVAL);
  1945. 26723   }
  1946. 26724 }
  1947. 26727 /*===========================================================================*
  1948. 26728  *                              do_sync                                      *
  1949. 26729  *===========================================================================*/
  1950. 26730 PUBLIC int do_sync()
  1951. 26731 {
  1952. 26732 /* Perform the sync() system call.  Flush all the tables. */
  1953. 26733
  1954. 26734   register struct inode *rip;
  1955. 26735   register struct buf *bp;
  1956. 26736
  1957. 26737   /* The order in which the various tables are flushed is critical.  The
  1958. 26738    * blocks must be flushed last, since rw_inode() leaves its results in
  1959. 26739    * the block cache.
  1960. 26740    */
  1961. 26741
  1962. 26742   /* Write all the dirty inodes to the disk. */
  1963. 26743   for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++)
  1964. 26744         if (rip->i_count > 0 && rip->i_dirt == DIRTY) rw_inode(rip, WRITING);
  1965. 26745
  1966. 26746   /* Write all the dirty blocks to the disk, one drive at a time. */
  1967. 26747   for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++)
  1968. 26748         if (bp->b_dev != NO_DEV && bp->b_dirt == DIRTY) flushall(bp->b_dev);
  1969. 26749
  1970. 26750   return(OK);           /* sync() can't fail */
  1971. 26751 }
  1972. 26754 /*===========================================================================*
  1973. 26755  *                              do_fork                                      *
  1974. 26756  *===========================================================================*/
  1975. 26757 PUBLIC int do_fork()
  1976. 26758 {
  1977. 26759 /* Perform those aspects of the fork() system call that relate to files.
  1978. 26760  * In particular, let the child inherit its parent's file descriptors.
  1979. 26761  * The parent and child parameters tell who forked off whom. The file
  1980. 26762  * system uses the same slot numbers as the kernel.  Only MM makes this call.
  1981. 26763  */
  1982. 26764
  1983. 26765   register struct fproc *cp;
  1984. 26766   int i;
  1985. 26767
  1986. 26768   /* Only MM may make this call directly. */
  1987. 26769   if (who != MM_PROC_NR) return(EGENERIC);
  1988. 26770
  1989. 26771   /* Copy the parent's fproc struct to the child. */
  1990. 26772   fproc[child] = fproc[parent];
  1991. 26773
  1992. 26774   /* Increase the counters in the 'filp' table. */
  1993. 26775   cp = &fproc[child];
  1994. 26776   for (i = 0; i < OPEN_MAX; i++)
  1995. 26777         if (cp->fp_filp[i] != NIL_FILP) cp->fp_filp[i]->filp_count++;
  1996. 26778
  1997. 26779   /* Fill in new process id. */
  1998. 26780   cp->fp_pid = pid;
  1999. 26781
  2000. 26782   /* A child is not a process leader. */
  2001. 26783   cp->fp_sesldr = 0;
  2002. 26784
  2003. 26785   /* Record the fact that both root and working dir have another user. */
  2004. 26786   dup_inode(cp->fp_rootdir);
  2005. 26787   dup_inode(cp->fp_workdir);
  2006. 26788   return(OK);
  2007. 26789 }
  2008. 26792 /*===========================================================================*
  2009. 26793  *                              do_exec                                      *
  2010. 26794  *===========================================================================*/
  2011. 26795 PUBLIC int do_exec()
  2012. 26796 {
  2013. 26797 /* Files can be marked with the FD_CLOEXEC bit (in fp->fp_cloexec).  When
  2014. 26798  * MM does an EXEC, it calls FS to allow FS to find these files and close them.
  2015. 26799  */
  2016. 26800
  2017. 26801   register int i;
  2018. 26802   long bitmap;
  2019. 26803
  2020. 26804   /* Only MM may make this call directly. */
  2021. 26805   if (who != MM_PROC_NR) return(EGENERIC);
  2022. 26806
  2023. 26807   /* The array of FD_CLOEXEC bits is in the fp_cloexec bit map. */
  2024. 26808   fp = &fproc[slot1];           /* get_filp() needs 'fp' */
  2025. 26809   bitmap = fp->fp_cloexec;
  2026. 26810   if (bitmap == 0) return(OK);  /* normal case, no FD_CLOEXECs */
  2027. 26811
  2028. 26812   /* Check the file desriptors one by one for presence of FD_CLOEXEC. */
  2029. 26813   for (i = 0; i < OPEN_MAX; i++) {
  2030. 26814         fd = i;
  2031. 26815         if ( (bitmap >> i) & 01) (void) do_close();
  2032. 26816   }
  2033. 26817
  2034. 26818   return(OK);
  2035. 26819 }
  2036. 26822 /*===========================================================================*
  2037. 26823  *                              do_exit                                      *
  2038. 26824  *===========================================================================*/
  2039. 26825 PUBLIC int do_exit()
  2040. 26826 {
  2041. 26827 /* Perform the file system portion of the exit(status) system call. */
  2042. 26828
  2043. 26829   register int i, exitee, task;
  2044. 26830   register struct fproc *rfp;
  2045. 26831   register struct filp *rfilp;
  2046. 26832   register struct inode *rip;
  2047. 26833   int major;
  2048. 26834   dev_t dev;
  2049. 26835   message dev_mess;
  2050. 26836
  2051. 26837   /* Only MM may do the EXIT call directly. */
  2052. 26838   if (who != MM_PROC_NR) return(EGENERIC);
  2053. 26839
  2054. 26840   /* Nevertheless, pretend that the call came from the user. */
  2055. 26841   fp = &fproc[slot1];           /* get_filp() needs 'fp' */
  2056. 26842   exitee = slot1;
  2057. 26843
  2058. 26844   if (fp->fp_suspended == SUSPENDED) {
  2059. 26845         task = -fp->fp_task;
  2060. 26846         if (task == XPIPE || task == XPOPEN) susp_count--;
  2061. 26847         pro = exitee;
  2062. 26848         (void) do_unpause();    /* this always succeeds for MM */
  2063. 26849         fp->fp_suspended = NOT_SUSPENDED;
  2064. 26850   }
  2065. 26851
  2066. 26852   /* Loop on file descriptors, closing any that are open. */
  2067. 26853   for (i = 0; i < OPEN_MAX; i++) {
  2068. 26854         fd = i;
  2069. 26855         (void) do_close();
  2070. 26856   }
  2071. 26857
  2072. 26858   /* Release root and working directories. */
  2073. 26859   put_inode(fp->fp_rootdir);
  2074. 26860   put_inode(fp->fp_workdir);
  2075. 26861   fp->fp_rootdir = NIL_INODE;
  2076. 26862   fp->fp_workdir = NIL_INODE;
  2077. 26863
  2078. 26864   /* If a session leader exits then revoke access to its controlling tty from
  2079. 26865    * all other processes using it.
  2080. 26866    */
  2081. 26867   if (!fp->fp_sesldr) return(OK);               /* not a session leader */
  2082. 26868   fp->fp_sesldr = FALSE;
  2083. 26869   if (fp->fp_tty == 0) return(OK);              /* no controlling tty */
  2084. 26870   dev = fp->fp_tty;
  2085. 26871
  2086. 26872   for (rfp = &fproc[LOW_USER]; rfp < &fproc[NR_PROCS]; rfp++) {
  2087. 26873         if (rfp->fp_tty == dev) rfp->fp_tty = 0;
  2088. 26874
  2089. 26875         for (i = 0; i < OPEN_MAX; i++) {
  2090. 26876                 if ((rfilp = rfp->fp_filp[i]) == NIL_FILP) continue;
  2091. 26877                 if (rfilp->filp_mode == FILP_CLOSED) continue;
  2092. 26878                 rip = rfilp->filp_ino;
  2093. 26879                 if ((rip->i_mode & I_TYPE) != I_CHAR_SPECIAL) continue;
  2094. 26880                 if ((dev_t) rip->i_zone[0] != dev) continue;
  2095. 26881                 dev_mess.m_type = DEV_CLOSE;
  2096. 26882                 dev_mess.DEVICE = dev;
  2097. 26883                 major = (dev >> MAJOR) & BYTE;  /* major device nr */
  2098. 26884                 task = dmap[major].dmap_task;   /* device task nr */
  2099. 26885                 (*dmap[major].dmap_close)(task, &dev_mess);
  2100. 26886                 rfilp->filp_mode = FILP_CLOSED;
  2101. 26887         }
  2102. 26888   }
  2103. 26889   return(OK);
  2104. 26890 }
  2105. 26893 /*===========================================================================*
  2106. 26894  *                              do_set                                       *
  2107. 26895  *===========================================================================*/
  2108. 26896 PUBLIC int do_set()
  2109. 26897 {
  2110. 26898 /* Set uid_t or gid_t field. */
  2111. 26899
  2112. 26900   register struct fproc *tfp;
  2113. 26901
  2114. 26902   /* Only MM may make this call directly. */
  2115. 26903   if (who != MM_PROC_NR) return(EGENERIC);
  2116. 26904
  2117. 26905   tfp = &fproc[slot1];
  2118. 26906   if (fs_call == SETUID) {
  2119. 26907         tfp->fp_realuid = (uid_t) real_user_id;
  2120. 26908         tfp->fp_effuid =  (uid_t) eff_user_id;
  2121. 26909   }
  2122. 26910   if (fs_call == SETGID) {
  2123. 26911         tfp->fp_effgid =  (gid_t) eff_grp_id;
  2124. 26912         tfp->fp_realgid = (gid_t) real_grp_id;
  2125. 26913   }
  2126. 26914   return(OK);
  2127. 26915 }
  2128. 26918 /*===========================================================================*
  2129. 26919  *                              do_revive                                    *
  2130. 26920  *===========================================================================*/
  2131. 26921 PUBLIC int do_revive()
  2132. 26922 {
  2133. 26923 /* A task, typically TTY, has now gotten the characters that were needed for a
  2134. 26924  * previous read.  The process did not get a reply when it made the call.
  2135. 26925  * Instead it was suspended.  Now we can send the reply to wake it up.  This
  2136. 26926  * business has to be done carefully, since the incoming message is from
  2137. 26927  * a task (to which no reply can be sent), and the reply must go to a process
  2138. 26928  * that blocked earlier.  The reply to the caller is inhibited by setting the
  2139. 26929  * 'dont_reply' flag, and the reply to the blocked process is done explicitly
  2140. 26930  * in revive().
  2141. 26931  */
  2142. 26932
  2143. 26933 #if !ALLOW_USER_SEND
  2144. 26934   if (who >= LOW_USER) return(EPERM);
  2145. 26935 #endif
  2146. 26936
  2147. 26937   revive(m.REP_PROC_NR, m.REP_STATUS);
  2148. 26938   dont_reply = TRUE;            /* don't reply to the TTY task */
  2149. 26939   return(OK);
  2150. 26940 }
  2151. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2152. src/fs/device.c    
  2153. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2154. 27000 /* When a needed block is not in the cache, it must be fetched from the disk.
  2155. 27001  * Special character files also require I/O.  The routines for these are here.
  2156. 27002  *
  2157. 27003  * The entry points in this file are:
  2158. 27004  *   dev_io:     perform a read or write on a block or character device
  2159. 27005  *   dev_opcl:   perform generic device-specific processing for open & close
  2160. 27006  *   tty_open:   perform tty-specific processing for open
  2161. 27007  *   ctty_open:  perform controlling-tty-specific processing for open
  2162. 27008  *   ctty_close: perform controlling-tty-specific processing for close
  2163. 27009  *   do_setsid:  perform the SETSID system call (FS side)
  2164. 27010  *   do_ioctl:   perform the IOCTL system call
  2165. 27011  *   call_task:  procedure that actually calls the kernel tasks
  2166. 27012  *   call_ctty:  procedure that actually calls task for /dev/tty
  2167. 27013  */
  2168. 27014
  2169. 27015 #include "fs.h"
  2170. 27016 #include <fcntl.h>
  2171. 27017 #include <minix/callnr.h>
  2172. 27018 #include <minix/com.h>
  2173. 27019 #include "dev.h"
  2174. 27020 #include "file.h"
  2175. 27021 #include "fproc.h"
  2176. 27022 #include "inode.h"
  2177. 27023 #include "param.h"
  2178. 27024
  2179. 27025 PRIVATE message dev_mess;
  2180. 27026 PRIVATE major, minor, task;
  2181. 27027
  2182. 27028 FORWARD _PROTOTYPE( void find_dev, (Dev_t dev)                          );
  2183. 27029
  2184. 27030 /*===========================================================================*
  2185. 27031  *                              dev_io                                       *
  2186. 27032  *===========================================================================*/
  2187. 27033 PUBLIC int dev_io(op, nonblock, dev, pos, bytes, proc, buff)
  2188. 27034 int op;                         /* DEV_READ, DEV_WRITE, DEV_IOCTL, etc. */
  2189. 27035 int nonblock;                   /* TRUE if nonblocking op */
  2190. 27036 dev_t dev;                      /* major-minor device number */
  2191. 27037 off_t pos;                      /* byte position */
  2192. 27038 int bytes;                      /* how many bytes to transfer */
  2193. 27039 int proc;                       /* in whose address space is buff? */
  2194. 27040 char *buff;                     /* virtual address of the buffer */
  2195. 27041 {
  2196. 27042 /* Read or write from a device.  The parameter 'dev' tells which one. */
  2197. 27043
  2198. 27044   find_dev(dev);                /* load the variables major, minor, and task */
  2199. 27045
  2200. 27046   /* Set up the message passed to task. */
  2201. 27047   dev_mess.m_type   = op;
  2202. 27048   dev_mess.DEVICE   = (dev >> MINOR) & BYTE;
  2203. 27049   dev_mess.POSITION = pos;
  2204. 27050   dev_mess.PROC_NR  = proc;
  2205. 27051   dev_mess.ADDRESS  = buff;
  2206. 27052   dev_mess.COUNT    = bytes;
  2207. 27053   dev_mess.TTY_FLAGS = nonblock; /* temporary kludge */
  2208. 27054
  2209. 27055   /* Call the task. */
  2210. 27056   (*dmap[major].dmap_rw)(task, &dev_mess);
  2211. 27057
  2212. 27058   /* Task has completed.  See if call completed. */
  2213. 27059   if (dev_mess.REP_STATUS == SUSPEND) {
  2214. 27060         if (op == DEV_OPEN) task = XPOPEN;
  2215. 27061         suspend(task);          /* suspend user */
  2216. 27062   }
  2217. 27063
  2218. 27064   return(dev_mess.REP_STATUS);
  2219. 27065 }
  2220. 27068 /*===========================================================================*
  2221. 27069  *                              dev_opcl                                     *
  2222. 27070  *===========================================================================*/
  2223. 27071 PUBLIC void dev_opcl(task_nr, mess_ptr)
  2224. 27072 int task_nr;                    /* which task */
  2225. 27073 message *mess_ptr;              /* message pointer */
  2226. 27074 {
  2227. 27075 /* Called from the dmap struct in table.c on opens & closes of special files.*/
  2228. 27076
  2229. 27077   int op;
  2230. 27078
  2231. 27079   op = mess_ptr->m_type;        /* save DEV_OPEN or DEV_CLOSE for later */
  2232. 27080   mess_ptr->DEVICE = (mess_ptr->DEVICE >> MINOR) & BYTE;
  2233. 27081   mess_ptr->PROC_NR = fp - fproc;
  2234. 27082
  2235. 27083   call_task(task_nr, mess_ptr);
  2236. 27084
  2237. 27085   /* Task has completed.  See if call completed. */
  2238. 27086   if (mess_ptr->REP_STATUS == SUSPEND) {
  2239. 27087         if (op == DEV_OPEN) task_nr = XPOPEN;
  2240. 27088         suspend(task_nr);       /* suspend user */
  2241. 27089   }
  2242. 27090 }
  2243. 27092 /*===========================================================================*
  2244. 27093  *                              tty_open                                     *
  2245. 27094  *===========================================================================*/
  2246. 27095 PUBLIC void tty_open(task_nr, mess_ptr)
  2247. 27096 int task_nr;
  2248. 27097 message *mess_ptr;
  2249. 27098 {
  2250. 27099 /* This procedure is called from the dmap struct in table.c on tty opens. */
  2251. 27100   
  2252. 27101   int r;
  2253. 27102   dev_t dev;
  2254. 27103   int flags, proc;
  2255. 27104   register struct fproc *rfp;
  2256. 27105
  2257. 27106   dev = (dev_t) mess_ptr->DEVICE;
  2258. 27107   flags = mess_ptr->COUNT;
  2259. 27108   proc = fp - fproc;
  2260. 27109
  2261. 27110   /* Add O_NOCTTY to the flags if this process is not a session leader, or
  2262. 27111    * if it already has a controlling tty, or if it is someone elses
  2263. 27112    * controlling tty.
  2264. 27113    */
  2265. 27114   if (!fp->fp_sesldr || fp->fp_tty != 0) {
  2266. 27115         flags |= O_NOCTTY;
  2267. 27116   } else {
  2268. 27117         for (rfp = &fproc[LOW_USER]; rfp < &fproc[NR_PROCS]; rfp++) {
  2269. 27118                 if (rfp->fp_tty == dev) flags |= O_NOCTTY;
  2270. 27119         }
  2271. 27120   }
  2272. 27121
  2273. 27122   r = dev_io(DEV_OPEN, mode, dev, (off_t) 0, flags, proc, NIL_PTR);
  2274. 27123
  2275. 27124   if (r == 1) {
  2276. 27125         fp->fp_tty = dev;
  2277. 27126         r = OK;
  2278. 27127   }
  2279. 27128
  2280. 27129   mess_ptr->REP_STATUS = r;
  2281. 27130 }
  2282. 27133 /*===========================================================================*
  2283. 27134  *                              ctty_open                                    *
  2284. 27135  *===========================================================================*/
  2285. 27136 PUBLIC void ctty_open(task_nr, mess_ptr)
  2286. 27137 int task_nr;
  2287. 27138 message *mess_ptr;
  2288. 27139 {
  2289. 27140 /* This procedure is called from the dmap struct in table.c on opening
  2290. 27141  * /dev/tty, the magic device that translates to the controlling tty.
  2291. 27142  */
  2292. 27143   
  2293. 27144   mess_ptr->REP_STATUS = fp->fp_tty == 0 ? ENXIO : OK;
  2294. 27145 }
  2295. 27148 /*===========================================================================*
  2296. 27149  *                              ctty_close                                   *
  2297. 27150  *===========================================================================*/
  2298. 27151 PUBLIC void ctty_close(task_nr, mess_ptr)
  2299. 27152 int task_nr;
  2300. 27153 message *mess_ptr;
  2301. 27154 {
  2302. 27155 /* Close /dev/tty. */
  2303. 27156
  2304. 27157   mess_ptr->REP_STATUS = OK;
  2305. 27158 }
  2306. 27161 /*===========================================================================*
  2307. 27162  *                              do_setsid                                    *
  2308. 27163  *===========================================================================*/
  2309. 27164 PUBLIC int do_setsid()
  2310. 27165 {
  2311. 27166 /* Perform the FS side of the SETSID call, i.e. get rid of the controlling
  2312. 27167  * terminal of a process, and make the process a session leader.
  2313. 27168  */
  2314. 27169   register struct fproc *rfp;
  2315. 27170
  2316. 27171   /* Only MM may do the SETSID call directly. */
  2317. 27172   if (who != MM_PROC_NR) return(ENOSYS);
  2318. 27173
  2319. 27174   /* Make the process a session leader with no controlling tty. */
  2320. 27175   rfp = &fproc[slot1];
  2321. 27176   rfp->fp_sesldr = TRUE;
  2322. 27177   rfp->fp_tty = 0;
  2323. 27178 }
  2324. 27181 /*===========================================================================*
  2325. 27182  *                              do_ioctl                                     *
  2326. 27183  *===========================================================================*/
  2327. 27184 PUBLIC int do_ioctl()
  2328. 27185 {
  2329. 27186 /* Perform the ioctl(ls_fd, request, argx) system call (uses m2 fmt). */
  2330. 27187
  2331. 27188   struct filp *f;
  2332. 27189   register struct inode *rip;
  2333. 27190   dev_t dev;
  2334. 27191
  2335. 27192   if ( (f = get_filp(ls_fd)) == NIL_FILP) return(err_code);
  2336. 27193   rip = f->filp_ino;            /* get inode pointer */
  2337. 27194   if ( (rip->i_mode & I_TYPE) != I_CHAR_SPECIAL
  2338. 27195         && (rip->i_mode & I_TYPE) != I_BLOCK_SPECIAL) return(ENOTTY);
  2339. 27196   dev = (dev_t) rip->i_zone[0];
  2340. 27197   find_dev(dev);
  2341. 27198
  2342. 27199   dev_mess= m;
  2343. 27200
  2344. 27201   dev_mess.m_type  = DEV_IOCTL;
  2345. 27202   dev_mess.PROC_NR = who;
  2346. 27203   dev_mess.TTY_LINE = minor;    
  2347. 27204
  2348. 27205   /* Call the task. */
  2349. 27206   (*dmap[major].dmap_rw)(task, &dev_mess);
  2350. 27207
  2351. 27208   /* Task has completed.  See if call completed. */
  2352. 27209   if (dev_mess.REP_STATUS == SUSPEND) {
  2353. 27210         if (f->filp_flags & O_NONBLOCK) {
  2354. 27211                 /* Not supposed to block. */
  2355. 27212                 dev_mess.m_type = CANCEL;
  2356. 27213                 dev_mess.PROC_NR = who;
  2357. 27214                 dev_mess.TTY_LINE = minor;
  2358. 27215                 (*dmap[major].dmap_rw)(task, &dev_mess);
  2359. 27216                 if (dev_mess.REP_STATUS == EINTR) dev_mess.REP_STATUS = EAGAIN;
  2360. 27217         } else {
  2361. 27218                 suspend(task);          /* User must be suspended. */
  2362. 27219         }
  2363. 27220   }
  2364. 27221   return(dev_mess.REP_STATUS);
  2365. 27222 }
  2366. 27225 /*===========================================================================*
  2367. 27226  *                              find_dev                                     *
  2368. 27227  *===========================================================================*/
  2369. 27228 PRIVATE void find_dev(dev)
  2370. 27229 dev_t dev;                      /* device */
  2371. 27230 {
  2372. 27231 /* Extract the major and minor device number from the parameter. */
  2373. 27232
  2374. 27233   major = (dev >> MAJOR) & BYTE;        /* major device number */
  2375. 27234   minor = (dev >> MINOR) & BYTE;        /* minor device number */
  2376. 27235   if (major >= max_major) {
  2377. 27236         major = minor = 0;              /* will fail with ENODEV */
  2378. 27237   }
  2379. 27238   task = dmap[major].dmap_task; /* which task services the device */
  2380. 27239 }
  2381. 27242 /*===========================================================================*
  2382. 27243  *                              call_task                                    *
  2383. 27244  *===========================================================================*/
  2384. 27245 PUBLIC void call_task(task_nr, mess_ptr)
  2385. 27246 int task_nr;                    /* which task to call */
  2386. 27247 message *mess_ptr;              /* pointer to message for task */
  2387. 27248 {
  2388. 27249 /* All file system I/O ultimately comes down to I/O on major/minor device
  2389. 27250  * pairs.  These lead to calls on the following routines via the dmap table.
  2390. 27251  */
  2391. 27252
  2392. 27253   int r, proc_nr;
  2393. 27254   message local_m;
  2394. 27255
  2395. 27256   proc_nr = mess_ptr->PROC_NR;
  2396. 27257
  2397. 27258   while ((r = sendrec(task_nr, mess_ptr)) == ELOCKED) {
  2398. 27259         /* sendrec() failed to avoid deadlock. The task 'task_nr' is
  2399. 27260          * trying to send a REVIVE message for an earlier request.
  2400. 27261          * Handle it and go try again.
  2401. 27262          */
  2402. 27263         if ((r = receive(task_nr, &local_m)) != OK) break;
  2403. 27264
  2404. 27265         /* If we're trying to send a cancel message to a task which has just
  2405. 27266          * sent a completion reply, ignore the reply and abort the cancel
  2406. 27267          * request. The caller will do the revive for the process. 
  2407. 27268          */
  2408. 27269         if (mess_ptr->m_type == CANCEL && local_m.REP_PROC_NR == proc_nr)
  2409. 27270                 return;
  2410. 27271
  2411. 27272         /* Otherwise it should be a REVIVE. */
  2412. 27273         if (local_m.m_type != REVIVE) {
  2413. 27274                 printf(
  2414. 27275                 "fs: strange device reply from %d, type = %d, proc = %dn",
  2415. 27276                         local_m.m_source,
  2416. 27277                         local_m.m_type, local_m.REP_PROC_NR);
  2417. 27278                 continue;
  2418. 27279         }
  2419. 27280
  2420. 27281         revive(local_m.REP_PROC_NR, local_m.REP_STATUS);
  2421. 27282   }
  2422. 27283
  2423. 27284   /* The message received may be a reply to this call, or a REVIVE for some
  2424. 27285    * other process.
  2425. 27286    */
  2426. 27287   for (;;) {
  2427. 27288         if (r != OK) panic("call_task: can't send/receive", NO_NUM);
  2428. 27289
  2429. 27290         /* Did the process we did the sendrec() for get a result? */
  2430. 27291         if (mess_ptr->REP_PROC_NR == proc_nr) break;
  2431. 27292
  2432. 27293         /* Otherwise it should be a REVIVE. */
  2433. 27294         if (mess_ptr->m_type != REVIVE) {
  2434. 27295                 printf(
  2435. 27296                 "fs: strange device reply from %d, type = %d, proc = %dn",
  2436. 27297                         mess_ptr->m_source,
  2437. 27298                         mess_ptr->m_type, mess_ptr->REP_PROC_NR);
  2438. 27299                 continue;
  2439. 27300         }
  2440. 27301         revive(mess_ptr->REP_PROC_NR, mess_ptr->REP_STATUS);
  2441. 27302
  2442. 27303         r = receive(task_nr, mess_ptr);
  2443. 27304   }
  2444. 27305 }
  2445. 27308 /*===========================================================================*
  2446. 27309  *                              call_ctty                                            *
  2447. 27310  *===========================================================================*/
  2448. 27311 PUBLIC void call_ctty(task_nr, mess_ptr)
  2449. 27312 int task_nr;                    /* not used - for compatibility with dmap_t */
  2450. 27313 message *mess_ptr;              /* pointer to message for task */
  2451. 27314 {
  2452. 27315 /* This routine is only called for one device, namely /dev/tty.  Its job
  2453. 27316  * is to change the message to use the controlling terminal, instead of the
  2454. 27317  * major/minor pair for /dev/tty itself.
  2455. 27318  */
  2456. 27319
  2457. 27320   int major_device;
  2458. 27321  
  2459. 27322   if (fp->fp_tty == 0) {
  2460. 27323         /* No controlling tty present anymore, return an I/O error. */
  2461. 27324         mess_ptr->REP_STATUS = EIO;
  2462. 27325         return;
  2463. 27326   }
  2464. 27327   major_device = (fp->fp_tty >> MAJOR) & BYTE;
  2465. 27328   task_nr = dmap[major_device].dmap_task;       /* task for controlling tty */
  2466. 27329   mess_ptr->DEVICE = (fp->fp_tty >> MINOR) & BYTE;
  2467. 27330   call_task(task_nr, mess_ptr);
  2468. 27331 }
  2469. 27334 /*===========================================================================*
  2470. 27335  *                              no_dev                                       *
  2471. 27336  *===========================================================================*/
  2472. 27337 PUBLIC void no_dev(task_nr, m_ptr)
  2473. 27338 int task_nr;                    /* not used - for compatibility with dmap_t */
  2474. 27339 message *m_ptr;                 /* message pointer */
  2475. 27340 {
  2476. 27341 /* No device there. */
  2477. 27342
  2478. 27343   m_ptr->REP_STATUS = ENODEV;
  2479. 27344 }
  2480. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2481. src/fs/utility.c    
  2482. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2483. 27400 /* This file contains a few general purpose utility routines.
  2484. 27401  *
  2485. 27402  * The entry points into this file are
  2486. 27403  *   clock_time:  ask the clock task for the real time
  2487. 27404  *   copy:        copy a block of data
  2488. 27405  *   fetch_name:  go get a path name from user space
  2489. 27406  *   no_sys:      reject a system call that FS does not handle
  2490. 27407  *   panic:       something awful has occurred;  MINIX cannot continue
  2491. 27408  *   conv2:       do byte swapping on a 16-bit int
  2492. 27409  *   conv4:       do byte swapping on a 32-bit long
  2493. 27410  */
  2494. 27411
  2495. 27412 #include "fs.h"
  2496. 27413 #include <minix/com.h>
  2497. 27414 #include <minix/boot.h>
  2498. 27415 #include <unistd.h>
  2499. 27416 #include "buf.h"
  2500. 27417 #include "file.h"
  2501. 27418 #include "fproc.h"
  2502. 27419 #include "inode.h"
  2503. 27420 #include "param.h"
  2504. 27421
  2505. 27422 PRIVATE int panicking;          /* inhibits recursive panics during sync */
  2506. 27423 PRIVATE message clock_mess;
  2507. 27424
  2508. 27425 /*===========================================================================*
  2509. 27426  *                              clock_time                                   *
  2510. 27427  *===========================================================================*/
  2511. 27428 PUBLIC time_t clock_time()
  2512. 27429 {
  2513. 27430 /* This routine returns the time in seconds since 1.1.1970.  MINIX is an
  2514. 27431  * astrophysically naive system that assumes the earth rotates at a constant
  2515. 27432  * rate and that such things as leap seconds do not exist.
  2516. 27433  */
  2517. 27434
  2518. 27435   register int k;
  2519. 27436
  2520. 27437   clock_mess.m_type = GET_TIME;
  2521. 27438   if ( (k = sendrec(CLOCK, &clock_mess)) != OK) panic("clock_time err", k);
  2522. 27439
  2523. 27440   return( (time_t) clock_mess.NEW_TIME);
  2524. 27441 }
  2525. 27444 /*===========================================================================*
  2526. 27445  *                              fetch_name                                   *
  2527. 27446  *===========================================================================*/
  2528. 27447 PUBLIC int fetch_name(path, len, flag)
  2529. 27448 char *path;                     /* pointer to the path in user space */
  2530. 27449 int len;                        /* path length, including 0 byte */
  2531. 27450 int flag;                       /* M3 means path may be in message */
  2532. 27451 {
  2533. 27452 /* Go get path and put it in 'user_path'.
  2534. 27453  * If 'flag' = M3 and 'len' <= M3_STRING, the path is present in 'message'.
  2535. 27454  * If it is not, go copy it from user space.
  2536. 27455  */
  2537. 27456
  2538. 27457   register char *rpu, *rpm;
  2539. 27458   int r;
  2540. 27459
  2541. 27460   /* Check name length for validity. */
  2542. 27461   if (len <= 0) {
  2543. 27462         err_code = EINVAL;
  2544. 27463         return(EGENERIC);
  2545. 27464   }
  2546. 27465
  2547. 27466   if (len > PATH_MAX) {
  2548. 27467         err_code = ENAMETOOLONG;
  2549. 27468         return(EGENERIC);
  2550. 27469   }
  2551. 27470
  2552. 27471   if (flag == M3 && len <= M3_STRING) {
  2553. 27472         /* Just copy the path from the message to 'user_path'. */
  2554. 27473         rpu = &user_path[0];
  2555. 27474         rpm = pathname;         /* contained in input message */
  2556. 27475         do { *rpu++ = *rpm++; } while (--len);
  2557. 27476         r = OK;
  2558. 27477   } else {
  2559. 27478         /* String is not contained in the message.  Get it from user space. */
  2560. 27479         r = sys_copy(who, D, (phys_bytes) path,
  2561. 27480                 FS_PROC_NR, D, (phys_bytes) user_path, (phys_bytes) len);
  2562. 27481   }
  2563. 27482   return(r);
  2564. 27483 }
  2565. 27486 /*===========================================================================*
  2566. 27487  *                              no_sys                                       *
  2567. 27488  *===========================================================================*/
  2568. 27489 PUBLIC int no_sys()
  2569. 27490 {
  2570. 27491 /* Somebody has used an illegal system call number */
  2571. 27492
  2572. 27493   return(EINVAL);
  2573. 27494 }
  2574. 27497 /*===========================================================================*
  2575. 27498  *                              panic                                        *
  2576. 27499  *===========================================================================*/
  2577. 27500 PUBLIC void panic(format, num)
  2578. 27501 char *format;                   /* format string */
  2579. 27502 int num;                        /* number to go with format string */
  2580. 27503 {
  2581. 27504 /* Something awful has happened.  Panics are caused when an internal
  2582. 27505  * inconsistency is detected, e.g., a programming error or illegal value of a
  2583. 27506  * defined constant.
  2584. 27507  */
  2585. 27508
  2586. 27509   if (panicking) return;        /* do not panic during a sync */
  2587. 27510   panicking = TRUE;             /* prevent another panic during the sync */
  2588. 27511   printf("File system panic: %s ", format);
  2589. 27512   if (num != NO_NUM) printf("%d",num); 
  2590. 27513   printf("n");
  2591. 27514   (void) do_sync();             /* flush everything to the disk */
  2592. 27515   sys_abort(RBT_PANIC);
  2593. 27516 }
  2594. 27519 /*===========================================================================*
  2595. 27520  *                              conv2                                        *
  2596. 27521  *===========================================================================*/
  2597. 27522 PUBLIC unsigned conv2(norm, w)
  2598. 27523 int norm;                       /* TRUE if no swap, FALSE for byte swap */
  2599. 27524 int w;                          /* promotion of 16-bit word to be swapped */
  2600. 27525 {
  2601. 27526 /* Possibly swap a 16-bit word between 8086 and 68000 byte order. */
  2602. 27527
  2603. 27528   if (norm) return( (unsigned) w & 0xFFFF);
  2604. 27529   return( ((w&BYTE) << 8) | ( (w>>8) & BYTE));
  2605. 27530 }
  2606. 27533 /*===========================================================================*
  2607. 27534  *                              conv4                                        *
  2608. 27535  *===========================================================================*/
  2609. 27536 PUBLIC long conv4(norm, x)
  2610. 27537 int norm;                       /* TRUE if no swap, FALSE for byte swap */
  2611. 27538 long x;                         /* 32-bit long to be byte swapped */
  2612. 27539 {
  2613. 27540 /* Possibly swap a 32-bit long between 8086 and 68000 byte order. */
  2614. 27541
  2615. 27542   unsigned lo, hi;
  2616. 27543   long l;
  2617. 27544   
  2618. 27545   if (norm) return(x);                  /* byte order was already ok */
  2619. 27546   lo = conv2(FALSE, (int) x & 0xFFFF);  /* low-order half, byte swapped */
  2620. 27547   hi = conv2(FALSE, (int) (x>>16) & 0xFFFF);    /* high-order half, swapped */
  2621. 27548   l = ( (long) lo <<16) | hi;
  2622. 27549   return(l);
  2623. 27550 }
  2624. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2625. src/fs/putk.c    
  2626. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2627. 27600 /* FS must occasionally print some message.  It uses the standard library
  2628. 27601  * routine prink().  (The name "printf" is really a macro defined as "printk").
  2629. 27602  * Printing is done by calling the TTY task directly, not going through FS.
  2630. 27603  */
  2631. 27604
  2632. 27605 #include "fs.h"
  2633. 27606 #include <minix/com.h>
  2634. 27607
  2635. 27608 #define BUF_SIZE          100   /* print buffer size */
  2636. 27609
  2637. 27610 PRIVATE int buf_count;          /* # characters in the buffer */
  2638. 27611 PRIVATE char print_buf[BUF_SIZE];       /* output is buffered here */
  2639. 27612 PRIVATE message putch_msg;      /* used for message to TTY task */
  2640. 27613
  2641. 27614 FORWARD _PROTOTYPE( void flush, (void)                                  );
  2642. 27615
  2643. 27616 /*===========================================================================*
  2644. 27617  *                              putk                                         *
  2645. 27618  *===========================================================================*/
  2646. 27619 PUBLIC void putk(c)
  2647. 27620 int c;
  2648. 27621 {
  2649. 27622 /* Accumulate another character.  If 0 or buffer full, print it. */
  2650. 27623
  2651. 27624   if (c == 0 || buf_count == BUF_SIZE) flush();
  2652. 27625   if (c == 'n') putk('r');
  2653. 27626   if (c != 0) print_buf[buf_count++] = c;
  2654. 27627 }
  2655. 27630 /*===========================================================================*
  2656. 27631  *                              flush                                        *
  2657. 27632  *===========================================================================*/
  2658. 27633 PRIVATE void flush()
  2659. 27634 {
  2660. 27635 /* Flush the print buffer by calling TTY task. */
  2661. 27636
  2662. 27637
  2663. 27638   if (buf_count == 0) return;
  2664. 27639   putch_msg.m_type = DEV_WRITE;
  2665. 27640   putch_msg.PROC_NR  = 1;
  2666. 27641   putch_msg.TTY_LINE = 0;
  2667. 27642   putch_msg.ADDRESS  = print_buf;
  2668. 27643   putch_msg.COUNT = buf_count;
  2669. 27644   call_task(TTY, &putch_msg);
  2670. 27645   buf_count = 0;
  2671. 27646 }
  2672. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2673. ./end_of_list    
  2674. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++