|
|
1.1 root 1: /*
2: * coh.386/sys5.c
3: *
4: * System calls introduced when going from COH 286 to COH 386.
5: *
6: * Revised: Mon Jul 12 12:27:55 1993 CDT
7: */
8: #include <sys/coherent.h>
9: #include <sys/buf.h>
10: #include <sys/errno.h>
11: #include <canon.h>
12: #include <sys/con.h>
13: #include <fcntl.h>
14: #include <sys/fd.h>
15: #include <sys/filsys.h>
16: #include <sys/ino.h>
17: #include <sys/inode.h>
18: #include <sys/io.h>
19: #include <sys/mount.h>
20: #include <sys/stat.h>
21: #include <dirent.h>
22: #include <sys/utsname.h>
23: #include <sys/mount.h>
24: #include <ustat.h>
25: #include <sys/statfs.h>
26: #include <sys/sysi86.h>
27: #include <sys/file.h>
28: #include <ulimit.h>
29:
30:
31: utime(tp)
32: long *tp;
33: {
34: return timer.t_time;
35: }
36:
37: /*
38: * Return an unique number.
39: */
40: usysi86(f, arg1)
41: {
42: register MOUNT *mp;
43: register struct filsys *fsp;
44: extern void (*ndpEmFn)();
45: int fpval;
46: extern short ndpType;
47:
48: switch (f) {
49: case SYI86UNEEK:
50: if ((mp = getment (rootdev, 1)) == NULL)
51: return;
52: fsp = & mp->m_super;
53: fsp->s_fmod = 1;
54: return ++ fsp->s_unique;
55:
56: case SI86FPHW:
57: /*
58: * 2's bit: floating point ndp is present (80287/80387/80486dx)
59: * 1's bit (when 2's bit = 1): 80387/486dx is present
60: */
61:
62: if (! useracc (arg1, sizeof (int), 1)) {
63: SET_U_ERROR (EFAULT, "sysi386:SI86FPHW");
64: return;
65: }
66: if (ndpType <= 1) { /* no ndp */
67: fpval = (ndpEmFn) ? FP_SW : FP_NO;
68: } else
69: fpval = (ndpType > 2) ? FP_387 : FP_287;
70:
71: putuwd (arg1, fpval);
72: return 0;
73:
74: }
75: }
76:
77: ushmsys(func, arg1, arg2, arg3)
78: int func, arg1, arg2, arg3;
79: {
80: switch(func){
81: case 0: return ushmat(arg1, arg2, arg3);
82: case 1: return ushmctl(arg1, arg2, arg3);
83: case 2: return ushmdt(arg1);
84: case 3: return ushmget(arg1, arg2, arg3);
85: default: u.u_error = EINVAL;
86: }
87: }
88:
89: usemsys(func, arg1, arg2, arg3, arg4)
90: int func, arg1, arg2, arg3, arg4;
91: {
92: switch(func){
93: case 0: return usemctl(arg1, arg2, arg3, arg4);
94: case 1: return usemget(arg1, arg2, arg3);
95: case 2: return usemop(arg1, arg2, arg3);
96: default: u.u_error = EINVAL;
97: }
98: }
99:
100: /*
101: * uname and ustat system calls.
102: *
103: * int uname(struct utsname *name)
104: * Before lcall instruction 4(%esp) contains name, 8(%esp) contains
105: * an unspecified value, and 12(%esp) contains the value 0.
106: *
107: * int ustat(int dev, struct ustat *buf)
108: * Before lcall instruction 4(%esp) contains buf (REVERSE order of argument)
109: * 8(%esp) contains dev, and 12(%esp) contains the value 2.
110: */
111:
112: uutssys(arg1, arg2, func)
113: {
114: switch(func) {
115: case 0: return uname(arg1);
116: case 2: return u_ustat(arg2, arg1);
117: default:u.u_error = EINVAL;
118: }
119: }
120:
121: /*
122: * uname - get name of the current operating system.
123: */
124: extern char version[]; /* Defined in main.c */
125: extern char release[]; /* Defined in main.c */
126:
127: uname(name)
128: struct utsname *name;
129: {
130: register char *rcp; /**/
131: register int i; /* Counter, loop index */
132: register INODE *ip; /* /etc/uucpname inode */
133: BUF *bp; /* Read buffer */
134: char namebuf[SYS_NMLN]; /* System name */
135: int fl; /* File length*/
136:
137: /* Check if *name is an available user area */
138: if (! useracc ((char *) name, sizeof (struct utsname), 1)) {
139: u.u_error = EFAULT;
140: return 0;
141: }
142: /* Find the size of the version number */
143: for (rcp = version, i = 0; *rcp != '\0' && i < SYS_NMLN; i++, rcp++)
144: /* DO NOTHING */ ;
145:
146: /* Write version number to user area */
147: if (! kucopy (version, name->version, i))
148: return 0;
149:
150: /* Find the size of the release number */
151: for (rcp = release, i = 0 ; * rcp != '\0' && i < SYS_NMLN ;
152: i ++, rcp ++)
153: /* DO NOTHING */ ;
154:
155: /* Write release number to user area */
156: if (! kucopy (release, name->release, i))
157: return;
158:
159: /* Write "machine" to user area */
160: if (! kucopy ("i386", name->machine, 4))
161: return;
162: /*
163: * We supposed that system name and nodename are in /etc/uucpname
164: * NIGEL: Set the global io segment to IOSYS so that ftoi () will use
165: * the right method of getting at the argument passed to it.
166: */
167:
168: {
169: IO io;
170: struct direct dir;
171:
172: io.io_seg = IOSYS;
173: if (ftoi ("/etc/uucpname", 'r', & io, & dir) != 0)
174: return sys_unknown (name);
175: }
176:
177: ip = u.u_cdiri;
178: if ((fl = ip->i_size) == 0) {
179: idetach (ip);
180: return sys_unknown (name);
181: }
182:
183: if (iaccess (ip, IPR) == 0) {
184: idetach (ip);
185: return;
186: }
187: if ((bp = vread (ip, (daddr_t) 0)) == NULL) {
188: brelease (bp);
189: idetach (ip);
190: return;
191: }
192:
193: /* namebuf should be not more than SYS_NMLN - 1 characters long */
194: fl = fl > SYS_NMLN ? SYS_NMLN : fl;
195: memcpy (namebuf, bp->b_vaddr, fl);
196:
197: brelease (bp);
198: idetach (ip);
199:
200: if (fl == 1 && namebuf [0] == '\n')
201: return sys_unknown (name);
202:
203: for (rcp = namebuf, i = 0 ; i < fl ; rcp ++) {
204: i ++;
205: if (* rcp == '\n') {
206: * rcp = '\0';
207: break;
208: }
209: }
210: namebuf[i - 1] = '\0';
211:
212: /* Write system name to user area */
213: if (! kucopy (namebuf, name->sysname, i))
214: return 0;
215:
216: /* Write system name to user area */
217: if (! kucopy (namebuf, name->nodename, i))
218: return 0;
219: return 0;
220: }
221:
222: /*
223: * sys_unknown - write name unknown to utsname struct
224: */
225: char unknown[] = "UNKNOWN";
226: sys_unknown(name)
227: struct utsname *name;
228: {
229: if (! kucopy (unknown, name->sysname, sizeof (unknown)))
230: return;
231: if (! kucopy (unknown, name->nodename, sizeof (unknown)))
232: return;
233: }
234:
235: /*
236: * u_ustat - get file system statistics. (Name ustat in use for stat s.c.)
237: */
238:
239: u_ustat(dev, buf)
240: dev_t dev;
241: struct ustat *buf;
242: {
243: register MOUNT *mp;
244:
245: /* Check if buf is an available user area. */
246: /* B_READ | B_WRITE is not implemented yet. */
247: if (! useracc ((char *) buf, sizeof (struct ustat), 1)) {
248: u.u_error = EFAULT;
249: return;
250: }
251:
252: /* Take mount filesystem, check if dev is mounted device */
253: for (mp = mountp ; mp != NULL ; mp = mp->m_next)
254: if (mp->m_dev == dev)
255: break;
256:
257: if (mp == NULL) {
258: u.u_error = EINVAL;
259: return;
260: }
261:
262: /* Pickup information from superblock */
263: /* Number of free blocks */
264: if (! kucopy (& mp->m_super.s_tfree, & buf->f_tfree,
265: sizeof (mp->m_super.s_tfree)))
266: return;
267:
268: /* Number of free inodes */
269: if (! kucopy (& mp->m_super.s_tinode, & buf->f_tinode,
270: sizeof (mp->m_super.s_tinode)))
271: return;
272:
273: /* File system name */
274: if (! kucopy (mp->m_super.s_fname, buf->f_fname,
275: sizeof (mp->m_super.s_fname)))
276: return;
277:
278: /* File system pack name */
279: if (! kucopy (mp->m_super.s_fpack, buf->f_fpack,
280: sizeof (mp->m_super.s_fpack)))
281: return;
282: }
283:
284: umsgsys(func, arg1, arg2, arg3, arg4, arg5)
285: {
286: switch (func) {
287: case 0: return umsgget (arg1, arg2);
288: case 1: return umsgctl (arg1, arg2, arg3);
289: case 2: return umsgrcv (arg1, arg2, arg3, arg4, arg5);
290: case 3: return umsgsnd (arg1, arg2, arg3, arg4);
291: default:u.u_error = EINVAL;
292: }
293: }
294:
295: /* Don't tell user process about last remaining 64k of RAM */
296: #define BRK_CUSHION 16
297:
298: uulimit(cmd, newlimit)
299: {
300: int freeClicks;
301:
302: switch (cmd) {
303: case UL_GETFSIZE: /* Get max # of 512-byte blocks per file. */
304: return u.u_bpfmax;
305: break;
306:
307: case UL_SETFSIZE: /* Set max # of 512-byte blocks per file. */
308: /* (only superuser may increase this) */
309: if (newlimit <= u.u_bpfmax || super ()) {
310: u.u_bpfmax = newlimit;
311: return 0;
312: }
313: /* else super() will have set u.u_error to EPERM */
314: break;
315:
316: case UL_GMEMLIM: /* Get max break value. */
317: /* return (current brk value) + (amount of free space) */
318: /* Don't report all free clicks - leave a cushion. */
319: freeClicks = allocno () - BRK_CUSHION;
320: if (freeClicks < 0)
321: freeClicks = 0;
322: return u.u_segl [SIPDATA].sr_base +
323: SELF->p_segp [SIPDATA]->s_size + NBPC * freeClicks;
324:
325: case UL_GDESLIM:
326: /* Return configured number of open files per process. */
327: return NOFILE;
328: break;
329:
330: default:
331: u.u_error = EINVAL;
332: }
333: }
334:
335: /*
336: * Change the size of a file.
337: */
338: uchsize(fd, size)
339: int fd;
340: register long size;
341: {
342: FD *fdp;
343: register INODE *ip;
344:
345: if (size < 0) {
346: u.u_error = EINVAL;
347: return -1;
348: }
349: if ((fdp = fdget (fd))==NULL || (fdp->f_flag & IPW) == 0) {
350: u.u_error = EBADF;
351: return -1;
352: }
353:
354: ip = fdp->f_ip;
355: switch (ip->i_mode & IFMT) {
356: case IFREG:
357: if (size > (long) u.u_bpfmax * BSIZE) {
358: u.u_error = EFBIG;
359: return -1;
360: }
361: if (size == ip->i_size)
362: break;
363: ilock (ip);
364: if (size < ip->i_size)
365: blclear (ip, __DIVIDE_ROUNDUP (ip->i_size, BSIZE));
366: ip->i_size = size;
367: imod (ip);
368: icrt (ip);
369: iunlock (ip);
370: break;
371:
372: case IFPIPE:
373: if (size > PIPSIZE) {
374: u.u_error = EFBIG;
375: return -1;
376: }
377:
378: ilock(ip);
379:
380: if (! ip->i_par && ! ip->i_psr) {
381: u.u_error = EPIPE;
382: sendsig (SIGPIPE, SELF);
383: iunlock (ip);
384: return -1;
385: }
386: ip->i_pwx += (size - ip->i_pnc);
387: if (size > ip->i_pnc) {
388: if (ip->i_pwx >= PIPSIZE)
389: ip->i_pwx -= PIPSIZE;
390: } else if (size < ip->i_pnc) {
391: if (ip->i_pwx < 0)
392: ip->i_pwx += PIPSIZE;
393: }
394:
395: ip->i_pnc = size;
396: imod (ip);
397: icrt (ip);
398:
399: if (size > 0)
400: pwake (ip, 2); /* 2==IFWFW, see pipe.c */
401: if (size < PIPSIZE)
402: pwake (ip, 1); /* 1==IFWFR, see pipe.c */
403: iunlock (ip);
404: break;
405:
406: default:
407: u.u_error = EBADF;
408: return -1;
409: }
410: return 0;
411: }
412:
413: /*
414: * Remove a directory.
415: */
416:
417: urmdir(path)
418: char *path;
419: {
420: register INODE *ip;
421: int iPathLen; /* Size of the string */
422: int isdirempty();
423: extern int strUserAcc();
424: IO io;
425: struct direct dir;
426:
427: /* Check if path points to a valid user buffer.*/
428: if ((iPathLen = strUserAcc (path, 0)) < 0) {
429: u.u_error = EFAULT;
430: return;
431: }
432:
433: io.io_seg = IOUSR;
434: if (ftoi (path, 'r', & io, & dir) != 0)
435: return;
436:
437: ip = u.u_cdiri;
438:
439: /* Check if path is a directory */
440: if ((ip->i_mode & IFMT) != IFDIR) {
441: SET_U_ERROR(ENOTDIR, "rmdir: no such directory");
442: idetach (ip);
443: return;
444: }
445:
446: /* We have to check if directory is empty */
447: if (! isdirempty (ip)) {
448: SET_U_ERROR (EEXIST, "rmdir: directory is not empty");
449: idetach (ip);
450: return;
451: }
452: idetach (ip);
453: removedir (path, iPathLen);
454: return 0;
455: }
456:
457: /*
458: * Remove a directory.
459: * path is a pointer to user area.
460: */
461:
462: removedir(path, iPathLen)
463: char *path; /* Directory name */
464: int iPathLen; /* Path length */
465: {
466: char *buf;
467: char *cpbuf, /* internal file_name buffer */
468: *cppath; /* user file_name buffer */
469:
470: /*
471: * Allocate kernel buffer. We need extra space for '/', '.', '..'
472: * and '\0'
473: */
474:
475: if ((buf = kalloc (iPathLen + 4)) == NULL) {
476: SET_U_ERROR (ENOSPC, "rmdir: out of kernel space");
477: return;
478: }
479: cpbuf = buf;
480: cppath = path;
481:
482: /* Copy path to the kernel buffer. */
483: while ((* cpbuf = getubd (cppath)) != '\0') {
484: cppath ++;
485: cpbuf ++;
486: }
487: * cpbuf++ = '/';
488: * cpbuf++ = '.';
489: * cpbuf = '\0';
490:
491: dunlink (buf);
492: if (u.u_error) {
493: kfree (buf);
494: return;
495: }
496:
497: * cpbuf ++ = '.';
498: * cpbuf = '\0';
499:
500: dunlink (buf);
501: if (u.u_error) {
502: /* We have to link '.' back here. */
503: kfree (buf);
504: return;
505: }
506:
507: buf [iPathLen] = '\0';
508:
509: dunlink (buf);
510: if (u.u_error) {
511: /* We have to link '.' and '..' back here. */
512: kfree (buf);
513: return;
514: }
515: kfree(buf);
516: return;
517: }
518:
519:
520: /*
521: * Unlink the given directory.
522: */
523:
524: dunlink (np)
525: char *np;
526: {
527: register INODE *ip;
528: register dev_t dev;
529: IO io;
530: struct direct dir;
531:
532: io.io_seg = IOSYS;
533: if (file_to_inode (np, 'u', 1, & io, & dir) != 0)
534: return;
535:
536: ip = u.u_pdiri;
537: if (iaccess (ip, IPW) == 0)
538: goto err;
539:
540: dev = ip->i_dev;
541: if (diucheck (dev, u.u_cdirn) == 0)
542: goto err;
543:
544: idirent (0, & io, & dir);
545: idetach (ip);
546:
547: if ((ip = iattach (dev, u.u_cdirn)) == NULL)
548: return;
549:
550: if (ip->i_nlink > 0)
551: -- ip->i_nlink;
552: icrt (ip); /* unlink - ctime */
553:
554: err:
555: idetach (ip);
556: return;
557: }
558:
559: /*
560: * This is a copy of iucheck. The only one difference is that that allows
561: * to remove a directory to a regular user.
562: */
563:
564: diucheck (dev, ino)
565: register dev_t dev;
566: register ino_t ino;
567: {
568: register INODE *ip;
569: INODE inode;
570:
571: for (ip = & inodep [NINODE - 1] ; ip >= inodep ; -- ip) {
572: if (ip->i_ino == ino && ip->i_dev == dev)
573: break;
574: }
575:
576: if (ip < inodep) {
577: ip = & inode;
578: ip->i_dev = dev;
579: ip->i_ino = ino;
580: if (icopydm (ip) == 0)
581: return 0;
582: }
583: return 1;
584: }
585:
586: /*
587: * Check if directory is empty.
588: */
589: int isdirempty (ip)
590: register INODE *ip;
591: {
592: register char *cp;
593: int count;
594: BUF *bp;
595:
596: for (count = 0 ; count < ip->i_size ; count += 512) {
597: if ((bp = vread (ip, count)) == NULL)
598: break;
599:
600: for (cp = (char *) bp->b_vaddr ;
601: cp < (char *) bp->b_vaddr + BSIZE ; cp += 16) {
602:
603: if (cp == '\0' && cp [1] == '\0')
604: continue;
605: if (cp [2] != '.')
606: goto bad;
607: if (cp [3] == '\0')
608: continue;
609: if (cp [3] != '.' || cp [4] != '\0')
610: goto bad;
611: }
612:
613: brelease (bp);
614: }
615: return 1;
616:
617: bad:
618: brelease (bp);
619: return 0;
620: }
621:
622: /*
623: * SysV compatible mkdir() system call.
624: *
625: * Create a directory of the given "path" and "mode", if possible.
626: * Creating the directory is straight forward. Trying to clean
627: * up in case we run out of inodes or freee blocks in the process
628: * is not trivial.
629: * This system call was implemented in very press time.
630: * Vlad 6-04-92
631: */
632:
633: umkdir(path, mode)
634: char *path;
635: int mode;
636: {
637: INODE *dmknod(); /* make directory node */
638: register INODE *pip; /* parent inode pointer */
639: register char *cp_path,
640: *cpb_path,
641: *cp_dot,
642: *cp_dotdot,
643: *cp_parent;
644: char bufpath[512],
645: bufdot[512],
646: bufdotdot[512],
647: bufparent[512];
648: int uid;
649:
650: /* Check if path points to a valid user buffer.*/
651: if (strUserAcc (path, 0) < 0) {
652: u.u_error = EFAULT;
653: return;
654: }
655:
656: /*
657: * Create a local copies of "path" which we can use to build up
658: * the required directory links:
659: * path/. -- bufdot
660: * path/..-- bufdotdot
661: * Verify that the given path is not too long.
662: */
663: cp_path = path;
664: cpb_path = bufpath;
665: cp_dot = bufdot;
666: cp_dotdot = bufdotdot;
667: cp_parent = bufparent;
668:
669: while ((* cpb_path = getubd (cp_path)) != '\0') {
670: * cp_dot ++ = * cp_dotdot ++ = * cp_parent ++ = * cpb_path;
671: ++ cp_path;
672: if (++ cpb_path >= & bufpath [sizeof (bufpath) - 3]) {
673: SET_U_ERROR (ENOENT, "sys5: mkdir: path too long");
674: return;
675: }
676: }
677:
678: while (-- cp_parent >= bufparent) {
679: if (* cp_parent == '/') {
680: * ++ cp_parent = '\0';
681: break;
682: }
683: }
684:
685: if (cp_parent < bufparent) {
686: * ++ cp_parent = '.';
687: * ++ cp_parent = '\0';
688: }
689:
690: * cp_dotdot ++ = * cp_dot++ = '/';
691: * cp_dotdot ++ = * cp_dot++ = '.';
692: * cp_dotdot ++ = '.';
693: * cp_dotdot = * cp_dot = '\0';
694:
695: if ((pip = dmknod (path, mode, IOUSR)) == NULL)
696: return;
697:
698: /*
699: * Now we can switch our id to root. It allows to use existing
700: * functions.
701: */
702:
703: uid = u.u_uid;
704: u.u_uid = 0;
705:
706: do_link (bufpath, bufdot, IOSYS);
707:
708: if (u.u_error) {
709: u.u_error = do_unlink (bufpath, IOSYS);
710:
711: u.u_uid = uid;
712: return;
713: }
714:
715: do_link (bufparent, bufdotdot, IOSYS);
716:
717: if (u.u_error) {
718: u.u_error = do_unlink (bufdot, IOSYS);
719: u.u_error = do_unlink (bufpath, IOSYS);
720: }
721:
722: u.u_uid = uid;
723: return 0;
724: }
725:
726:
727: /*
728: * Create a directory.
729: *
730: * We cannot use original ulink because it makes the directories only
731: * for superuser.
732: */
733:
734: INODE *
735: dmknod (np, mode, space)
736: char *np; /* Direcotory name */
737: int mode;
738: int space;
739: {
740: register INODE *ip, *pip;
741: register int type;
742: IO io;
743: struct direct dir;
744:
745: type = (mode & ~IFMT);
746: type |= S_IFDIR;
747:
748: /* If ftoi returns nonzero, u.u_error has been set. */
749: io.io_seg = space;
750: if (ftoi (np, 'c', & io, & dir) != 0)
751: return NULL;
752:
753: if ((ip = u.u_cdiri) != NULL) {
754: SET_U_ERROR (EEXIST, "dmknod: path already exists");
755: idetach (ip);
756: return NULL;
757: }
758: if ((ip = imake (type, (dev_t) 0, & io, & dir)) != NULL)
759: idetach (ip);
760: pip = u.u_pdiri; /* grab ptr to parent inode */
761: return pip;
762: }
763:
764:
765: /*
766: * Get directory entry in file system independent format.
767: */
768:
769: ugetdents(fd, bp, n)
770: int fd; /* File descriptor to an open directory */
771: char *bp; /* Buffer where entries should be read */
772: unsigned n; /* Number of bytes to be read */
773: {
774: struct direct r_dir;
775: unsigned bytes; /* Number of bytes */
776: struct dirent sd;
777: ino_t inode; /* Inode number */
778: unsigned short ofnm; /* Offset to file name in dirent */
779: char *cw,
780: *cr;
781: int minbuf; /* Minimum possible size of the bp */
782: int i, mod;
783: int entry;
784: char ends[3] = "";
785: int total = 0;
786:
787: cw = bp;
788:
789: ofnm = sizeof (sd.d_ino) + sizeof (sd.d_off) + sizeof (sd.d_reclen);
790:
791: /*
792: * Find minimum possible size of bp. It should be enough to contain
793: * the header of dirent, file name + '\0', and be on a sizeof(long)
794: * boundary.
795: */
796:
797: entry = ofnm + DIRSIZ + 1;
798: mod = entry % sizeof(long);
799: minbuf = entry + (mod ? sizeof(long) - mod : 0);
800:
801: /* Is user buffer available? */
802: if (! useracc (bp, n, 1) || n < minbuf) {
803: u.u_error = EFAULT;
804: return 0;
805: }
806:
807: while(n - (cw - bp) >= minbuf) {
808: /*
809: * Read next entry from the directory.
810: * inode == 0 for rm(ed) entries
811: */
812:
813: do {
814: if ((bytes = dirio (fd, & r_dir,
815: sizeof (struct direct),
816: & sd.d_off)) == 0)
817: return total;
818:
819: inode = r_dir.d_ino;
820: } while (! inode);
821:
822: /* Find the size of file name */
823: for (cr = r_dir.d_name, i = 0 ; * cr != '\0' && i < DIRSIZ ;
824: i ++, cr ++)
825: /* DO NOTHING */ ;
826:
827: /* Copy file name */
828: if (! kucopy (r_dir.d_name, cw + ofnm, i))
829: return 0;
830:
831: /* Write '\0' */
832: putubd (cw + ofnm + i ++, '\0');
833:
834: /* Round up to long boundary */
835: if (mod = (ofnm + i) % sizeof(long))
836: if (! kucopy (ends, cw + ofnm + i, sizeof
837: (long) - mod))
838: return 0;
839:
840: sd.d_ino = r_dir.d_ino;
841: sd.d_reclen = ofnm + i; /* Size of directory entry */
842: if (mod)
843: sd.d_reclen += sizeof (long) - mod;
844:
845: if (! kucopy(& sd, cw, ofnm))
846: return 0;
847:
848: total += sd.d_reclen;
849: cw += sd.d_reclen;
850: }
851: return total;
852: }
853:
854: /*
855: * Read `n' bytes from the directory `fd' using the buffer `bp'.
856: */
857:
858: dirio(fd, bp, n, offset)
859: struct direct *bp;
860: unsigned n;
861: off_t *offset;
862: {
863: register FD *fdp;
864: register INODE *ip;
865: IO io;
866:
867: /* Check file descriptor */
868: if ((fdp = fdget (fd)) == NULL)
869: return 0;
870:
871: if ((fdp->f_flag & IPR) == 0) {
872: u.u_error = EBADF;
873: return 0;
874: }
875:
876: ip = fdp->f_ip;
877: if ((ip->i_mode & IFMT) != IFDIR) {
878: u.u_error = EBADF;
879: return 0;
880: }
881:
882: ilock (ip); /* We do not want file changes during the read */
883:
884: io.io_seg = IOSYS;
885: io.io_seek = fdp->f_seek;
886: io.io.vbase = bp;
887: io.io_ioc = n;
888: io.io_flag = 0;
889:
890: if ((fdp->f_flag & IPNDLY) != 0)
891: io.io_flag |= IONDLY;
892:
893: if ((fdp->f_flag & IPNONBLOCK) != 0)
894: io.io_flag |= IONONBLOCK;
895:
896: iread (ip, & io);
897: iacc (ip); /* read - atime */
898:
899: n -= io.io_ioc;
900: * offset = fdp->f_seek;
901: fdp->f_seek += n;
902:
903: iunlock (ip);
904: return n;
905: }
906:
907: /*
908: * Get file system information by file name.
909: */
910: ustatfs(path, stfs, len, fstyp)
911: char *path; /* File name */
912: struct statfs *stfs; /* Pointer to a user structure */
913: int len; /* Size of the structure */
914: int fstyp; /* File system type */
915: {
916: struct filsys *statmount(); /* Get mp for mounted device */
917: struct filsys *statunmount(); /* Get mp for unmounted device */
918: struct filsys *sb; /* Pointer to superblock */
919: int count = 0; /* Number of copied bytes */
920: short systype = 1; /* System type */
921: long bsize = BSIZE; /* Block size */
922: long frsize = 0; /* Fragment size */
923:
924: /* Check if stfs is an available user area. */
925: if (! useracc ((char *) stfs, len, 1)) {
926: SET_U_ERROR (EFAULT, "ustatfs 0");
927: return;
928: }
929:
930: /* Filesystem type is 1 for 512 bytes blocks. */
931: count += sizeof (systype);
932: if (count > len) {
933: SET_U_ERROR (EFAULT, "ustatfs 1");
934: return;
935: }
936: if (! kucopy (& systype, & stfs->f_fstyp, sizeof (systype)))
937: return;
938:
939: /* Block size */
940: count += sizeof (bsize);
941: if (count > len) {
942: SET_U_ERROR (EFAULT, "ustatfs 2");
943: return;
944: }
945: if (! kucopy (& bsize, & stfs->f_bsize, sizeof (bsize)))
946: return;
947:
948: /* Fragment size. */
949: count += sizeof (int);
950: if (count > len) {
951: SET_U_ERROR (EFAULT, "ustatfs 3");
952: return;
953: }
954: if (! kucopy (& frsize, & stfs->f_frsize, sizeof (frsize)))
955: return;
956:
957: if (! fstyp) {
958: if ((sb = statmount (-1, path)) == NULL)
959: return;
960: devinfo (sb, stfs, len, & count);
961: } else {
962: if ((sb = statunmount (-1, path)) == NULL)
963: return;
964: devinfo (sb, stfs, len, & count);
965: kfree (sb);
966: }
967: return 0;
968: }
969:
970: /*
971: * statmount - get superblock for mounted file system.
972: * fd - file descriptor or -1, path - file name or NULL.
973: */
974: struct filsys *statmount(fd, path)
975: int fd;
976: char *path;
977: {
978: register INODE *ip; /* Structure inode */
979: register FD *fdp;
980: register MOUNT *mp; /* Pointer to device */
981: dev_t device; /* Mounted device */
982:
983: /* Find the device */
984: if (path) { /* Find ip by file name */
985: IO io;
986: struct direct dir;
987:
988: io.io_seg = IOUSR;
989: if (ftoi (path, 'r', & io, & dir)) {
990: /* If ftoi returned nonzero, it also set u.u_error. */
991: return NULL;
992: }
993: ip = u.u_cdiri;
994: device = ip->i_dev;
995: idetach(ip);
996: } else { /* Find ip by file descriptor */
997: if ((fdp = fdget (fd)) == NULL)
998: return NULL;
999: if ((fdp->f_flag & IPR) == 0) {
1000: SET_U_ERROR (EBADF, "statmount 1");
1001: return NULL;
1002: }
1003: ip = fdp->f_ip;
1004: device = ip->i_dev;
1005: }
1006:
1007: /* Take mount filesystem, check if dev is mounted device */
1008: for (mp = mountp; mp != NULL; mp = mp->m_next)
1009: if (mp->m_dev == device)
1010: break;
1011:
1012: if (mp == NULL) {
1013: u.u_error = EINVAL;
1014: return NULL;
1015: }
1016: return & mp->m_super;
1017: }
1018:
1019: /*
1020: * devinfo() write system information to user area
1021: */
1022: devinfo(sb, stfs, len, count)
1023: struct filsys *sb; /* File name */
1024: struct statfs *stfs; /* Pointer to a user structure */
1025: int len; /* Size of the structure */
1026: int *count;
1027: {
1028: long inode;
1029:
1030: /* Total number of blocks */
1031: * count += sizeof (sb->s_fsize);
1032: if (* count > len)
1033: return;
1034:
1035: if (! kucopy (& sb->s_fsize, & stfs->f_blocks, sizeof (sb->s_fsize)))
1036: return;
1037:
1038: /* Count of free blocks */
1039: * count += sizeof (sb->s_tfree);
1040: if (* count > len)
1041: return;
1042: if (! kucopy (& sb->s_tfree, & stfs->f_bfree, sizeof (sb->s_tfree)))
1043: return;
1044:
1045: /* Total number of file inodes */
1046: * count += sizeof (inode);
1047: if (* count > len)
1048: return;
1049:
1050: inode = (long) (sb->s_isize - INODEI) * INOPB;
1051: if (! kucopy (& inode, & stfs->f_files, sizeof (inode)))
1052: return;
1053:
1054: /* Number of free inodes */
1055: * count += sizeof(inode);
1056: if (* count > len)
1057: return;
1058: inode = sb->s_tinode;
1059: if (! kucopy (& inode, & stfs->f_ffree, sizeof (inode)))
1060: return;
1061:
1062: /* Volume name */
1063: * count += sizeof (sb->s_fname);
1064: if (* count > len)
1065: return;
1066: if (! kucopy (sb->s_fname, stfs->f_fname, sizeof (sb->s_fpack)))
1067: return;
1068:
1069: /* Pack name */
1070: * count += sizeof(sb->s_fpack);
1071: if (* count > len)
1072: return;
1073: if (! kucopy (sb->s_fpack, stfs->f_fpack, sizeof (sb->s_fpack)))
1074: return;
1075: }
1076:
1077: /*
1078: * statunmount - get superblock for unmounted file system.
1079: * fd - file descriptor or -1, path - file name or NULL.
1080: */
1081: struct filsys *statunmount(fd, path)
1082: int fd; /* File descriptor */
1083: char *path; /* File name */
1084: {
1085: register INODE *ip;
1086: register MOUNT *mp;
1087: register dev_t rdev;
1088: FD *fdp;
1089: int mode;
1090: BUF *bp;
1091: struct filsys *sb;
1092:
1093: /* Find the device */
1094: if (path) { /* Find ip by file name */
1095: IO io;
1096: struct direct dir;
1097:
1098: if (ftoi (path, 'r', & io, & dir))
1099: return NULL;
1100: ip = u.u_cdiri;
1101: mode = ip->i_mode;
1102: rdev = ip->i_a.i_rdev;
1103: idetach (ip);
1104: } else { /* Find ip by file descriptor */
1105: if ((fdp = fdget(fd)) == NULL)
1106: return NULL;
1107: if ((fdp->f_flag & IPR) == 0) {
1108: u.u_error = EBADF;
1109: return NULL;
1110: }
1111: ip = fdp->f_ip;
1112: ilock (ip);
1113: mode = ip->i_mode;
1114: rdev = ip->i_a.i_rdev;
1115: iunlock (ip);
1116: }
1117:
1118: /* Check for block special device */
1119: if ((mode & IFMT) != IFBLK) {
1120: u.u_error = ENOTBLK;
1121: return NULL;
1122: }
1123:
1124: /* Check if device is mounted device */
1125: for (mp = mountp; mp != NULL; mp = mp->m_next) {
1126: if (mp->m_dev == rdev) {
1127: u.u_error = EBUSY;
1128: return NULL;
1129: }
1130: }
1131:
1132: dopen (rdev, IPR, DFBLK);
1133: if (u.u_error)
1134: return NULL;
1135:
1136: /*
1137: * NIGEL: Modified for new dclose ().
1138: */
1139:
1140: bp = bread (rdev, (daddr_t) SUPERI, BUF_SYNC);
1141: dclose (rdev, IPR, DFBLK);
1142:
1143: if (bp == NULL)
1144: return NULL;
1145:
1146: if ((sb = kalloc (sizeof (struct filsys))) == NULL)
1147: return NULL;
1148:
1149: memcpy (sb, bp->b_vaddr, sizeof (struct filsys));
1150: brelease (bp);
1151:
1152: cansuper (sb); /* canonicalize superblock */
1153: if (tstf (sb) == 0) { /* check for consistency */
1154: kfree (sb);
1155: u.u_error = EINVAL;
1156: return NULL;
1157: }
1158: return sb;
1159: }
1160:
1161: /*
1162: * Get file system information by file descriptor
1163: */
1164: ufstatfs(fildes, stfs, len, fstyp)
1165: int fildes; /* File descriptor */
1166: struct statfs *stfs; /* Pointer to a user structure */
1167: int len; /* Size of the structure */
1168: int fstyp; /* File system type */
1169: {
1170: struct filsys *statmount(); /* Get mp for mounted device */
1171: struct filsys *statunmount(); /* Get mp for unmounted device */
1172: struct filsys *sb; /* Pointer to superblock */
1173: int count = 0; /* Number of copied bytes */
1174: short systype = 1; /* System type */
1175: long bsize = BSIZE; /* Block size */
1176: long frsize = 0; /* Fragment size */
1177:
1178: /* Check if stfs is an available user area. */
1179: if (! useracc ((char *) stfs, len)) {
1180: u.u_error = EFAULT;
1181: return;
1182: }
1183:
1184: /* Filesystem type is 1 for 512 bytes blocks. */
1185: count += sizeof (systype);
1186: if (count > len) {
1187: SET_U_ERROR (EFAULT, "ufstatfs 0");
1188: return;
1189: }
1190: if (! kucopy (& systype, & stfs->f_fstyp, sizeof (systype)))
1191: return;
1192:
1193: /* Block size */
1194: count += sizeof (bsize);
1195: if (count > len) {
1196: SET_U_ERROR (EFAULT, "ufstatfs 1");
1197: return;
1198: }
1199: if (! kucopy (& bsize, & stfs->f_bsize, sizeof (bsize)))
1200: return;
1201:
1202: /* Fragment size. */
1203: count += sizeof (int);
1204: if (count > len) {
1205: SET_U_ERROR (EFAULT, "ufstatfs 2");
1206: return;
1207: }
1208: if (! kucopy (& frsize, & stfs->f_frsize, sizeof (frsize)))
1209: return;
1210:
1211: if (! fstyp) {
1212: if ((sb = statmount (fildes, NULL)) == NULL)
1213: return;
1214: devinfo (sb, stfs, len, & count);
1215: } else {
1216: if ((sb = statunmount (fildes, NULL)) == NULL)
1217: return;
1218: devinfo (sb, stfs, len, & count);
1219: kfree (sb);
1220: }
1221: return 0;
1222: }
1223:
1224: /*
1225: * Check superblock for consistency.
1226: */
1227:
1228: tstf(fp)
1229: register struct filsys *fp;
1230: {
1231: register daddr_t *dp;
1232: register ino_t *ip;
1233: register ino_t maxinode;
1234:
1235: maxinode = (fp->s_isize - INODEI) * INOPB + 1;
1236: if (fp->s_isize >= fp->s_fsize)
1237: return 0;
1238: if (fp->s_tfree < fp->s_nfree ||
1239: fp->s_tfree >= fp->s_fsize - fp->s_isize + 1)
1240: return 0;
1241: if (fp->s_tinode < fp->s_ninode || fp->s_tinode >= maxinode - 1)
1242: return 0;
1243:
1244: for (dp = fp->s_free ; dp < fp->s_free + fp->s_nfree ; dp += 1)
1245: if (* dp < fp->s_isize || * dp >= fp->s_fsize)
1246: return 0;
1247:
1248: for (ip = fp->s_inode ; ip < fp->s_inode + fp->s_ninode ; ip += 1)
1249: if (* ip < 1 || * ip > maxinode)
1250: return 0;
1251: return 1;
1252: }
1253:
1254: /* the following calls are not in the BCS */
1255:
1256: uadmin()
1257: {
1258: u.u_error = EINVAL;
1259: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.