|
|
1.1 root 1: /*
2: * system calls introduced by the 386 port
3: *
4: * Copyright (c) Ciaran O'Donnell, Bievres (FRANCE), 1991
5: */
6: #include <sys/coherent.h>
7: #include <sys/buf.h>
8: #include <errno.h>
9: #include <canon.h>
10: #include <sys/con.h>
11: #include <fcntl.h>
12: #include <sys/fd.h>
13: #include <sys/filsys.h>
14: #include <sys/ino.h>
15: #include <sys/inode.h>
16: #include <sys/io.h>
17: #include <sys/mount.h>
18: #include <sys/stat.h>
19: #include <sys/dir.h>
20: #include <sys/dirent.h>
21: #include <sys/utsname.h>
22: #include <sys/mount.h>
23: #include <ustat.h>
24: #include <sys/statfs.h>
25:
26: utime(tp)
27: long *tp;
28: {
29: return timer.t_time;
30: }
31:
32: /*
33: * Return an unique number.
34: */
35: usysi86(f, arg1, arg2, arg3)
36: {
37: register MOUNT *mp;
38: register struct filsys *fsp;
39:
40: switch (f) {
41: case SYI86UNEEK:
42: if ((mp=getment(rootdev, 1)) == NULL)
43: return;
44: fsp = &mp->m_super;
45: fsp->s_fmod = 1;
46: return (++fsp->s_unique);
47: case 40:
48: /*
49: * bit 2: floating point is present (80287/80387)
50: * bit 1: 80387 is present
51: */
52: if (!useracc(arg1, sizeof(int))) {
53: SET_U_ERROR(EFAULT, "sysi386:40");
54: return;
55: }
56: putuwd(arg1, 0);
57: break;
58: }
59: }
60:
61: ushmsys(func, arg1, arg2, arg3)
62: int func, arg1, arg2, arg3;
63: {
64: switch(func){
65:
66: #if 0
67: case 0: return ushmat(arg1, arg2, arg3);
68: case 1: return ushmdt(arg1);
69: #endif
70: case 2: return ushmctl(arg1, arg2, arg3);
71: case 3: return ushmget(arg1, arg2, arg3);
72: default: u.u_error = EINVAL;
73: }
74: }
75:
76: usemsys(func, arg1, arg2, arg3, arg4)
77: int func, arg1, arg2, arg3, arg4;
78: {
79: switch(func){
80: case 0: return usemctl(arg1, arg2, arg3, arg4);
81: case 1: return usemget(arg1, arg2, arg3);
82: case 2: return usemop(arg1, arg2, arg3);
83: default: u.u_error = EINVAL;
84: }
85: }
86:
87: /*
88: * uname and ustat system calls.
89: *
90: * int uname(struct utsname *name)
91: * Before lcall instruction 4(%esp) contains name, 8(%esp) contains
92: * an unspecified value, and 12(%esp) contains the value 0.
93: *
94: * int ustat(int dev, struct ustat *buf)
95: * Before lcall instruction 4(%esp) contains buf (REVERSE order of argument)
96: * 8(%esp) contains dev, and 12(%esp) contains the value 0.
97: */
98:
99: uutssys(arg1, arg2, func)
100: {
101: switch(func) {
102: case 0: return uname(arg1);
103: case 2: return u_ustat(arg2, arg1);
104: default:u.u_error = EINVAL;
105: }
106: }
107:
108: /*
109: * uname - get name of the current operating system.
110: */
111: extern char version[]; /* Defined in main.c */
112: extern char release[]; /* Defined in main.c */
113:
114: uname(name)
115: struct utsname *name;
116: {
117: register char *rcp; /**/
118: register int i; /* Counter, loop index */
119: register INODE *ip; /* /etc/uucpname inode */
120: BUF *bp; /* Read buffer */
121: char namebuf[SYS_NMLN]; /* System name */
122: int fl; /* File length*/
123:
124: /* Check if *name is an available user area */
125: if (!useracc((char *) name, sizeof(struct utsname))) {
126: u.u_error = EFAULT;
127: return(0);
128: }
129: /* Find the size of the version number */
130: for (rcp = version, i = 0; *rcp != '\0' && i < SYS_NMLN; i++, rcp++)
131: ;
132: /* Write version number to user area */
133: if (!kucopy(version, name->version, i))
134: return(0);
135: /* Find the size of the release number */
136: for (rcp = release, i = 0; *rcp != '\0' && i < SYS_NMLN; i++, rcp++)
137: ;
138: /* Write release number to user area */
139: if (!kucopy(release, name->release, i))
140: return;
141: /* Write "machine" to user area */
142: if (!kucopy("i386", name->machine, 4))
143: return;
144: /* We supposed that system name and nodename are in /etc/uucpname */
145: if (ftoi("/etc/uucpname", 'r') != 0)
146: return(sys_unknown(name));
147: ip = u.u_cdiri;
148: if ((fl = ip->i_size) == 0) {
149: idetach(ip);
150: return(sys_unknown(name));
151: }
152: if (iaccess(ip, IPR) == 0) {
153: idetach(ip);
154: return;
155: }
156: if ((bp = vread(ip, (daddr_t) 0)) == NULL) {
157: brelease(bp);
158: idetach(ip);
159: return;
160: }
161: /* namebuf should be not more than SYS_NMLN - 1 characters long */
162: fl = (fl > SYS_NMLN) ? SYS_NMLN : fl;
163: kkcopy(bp->b_vaddr, namebuf, fl);
164: brelease(bp);
165: idetach(ip);
166:
167: if (fl == 1 && namebuf[0] == '\n')
168: return(sys_unknown(name));
169: for (rcp = namebuf, i = 0; i < fl; rcp++) {
170: i++;
171: if (*rcp == '\n') {
172: *rcp = '\0';
173: break;
174: }
175: }
176: namebuf[i - 1] = '\0';
177: /* Write system name to user area */
178: if (!kucopy(namebuf, name->sysname, i))
179: return(0);
180:
181: /* Write system name to user area */
182: if (!kucopy(namebuf, name->nodename, i))
183: return(0);
184: return 0;
185: }
186:
187: /*
188: * sys_unknown - write name unknown to utsname struct
189: */
190: char unknown[] = "UNKNOWN";
191: sys_unknown(name)
192: struct utsname *name;
193: {
194: if (!kucopy(unknown, name->sysname, sizeof(unknown)))
195: return;
196: if (!kucopy(unknown, name->nodename, sizeof(unknown)))
197: return;
198: }
199:
200: /*
201: * u_ustat - get file system statistics. (Name ustat in use for stat s.c.)
202: */
203: u_ustat(dev, buf)
204: dev_t dev;
205: struct ustat *buf;
206: {
207: register MOUNT *mp;
208:
209: /* Check if buf is an available user area. */
210: /* B_READ | B_WRITE is not implemented yet. */
211: if (!useracc((char *) buf, sizeof(struct ustat))) {
212: u.u_error = EFAULT;
213: return;
214: }
215:
216: /* Take mount filesystem, check if dev is mounted device */
217: for (mp = mountp; mp != NULL; mp = mp->m_next)
218: if (mp->m_dev == dev)
219: break;
220: if (mp == NULL) {
221: u.u_error = EINVAL;
222: return;
223: }
224:
225: /* Pickup information from superblock */
226: /* Number of free blocks */
227: if (!kucopy(&(mp->m_super.s_tfree), &(buf->f_tfree),
228: sizeof(mp->m_super.s_tfree)))
229: return;
230: /* Number of free inodes */
231: if (!kucopy(&(mp->m_super.s_tinode), &(buf->f_tinode),
232: sizeof(mp->m_super.s_tinode)))
233: return;
234: /* File system name */
235: if (!kucopy(mp->m_super.s_fname, buf->f_fname,
236: sizeof(mp->m_super.s_fname)))
237: return;
238: /* File system pack name */
239: if (!kucopy(mp->m_super.s_fpack, buf->f_fpack,
240: sizeof(mp->m_super.s_fpack)))
241: return;
242: }
243:
244: umsgsys(func, arg1, arg2, arg3, arg4, arg5)
245: {
246: switch (func) {
247: case 0: return umsgget(arg1, arg2);
248: case 1: return umsgctl(arg1, arg2, arg3);
249: case 2: return umsgrcv(arg1, arg2, arg3, arg4, arg5);
250: case 3: return umsgsnd(arg1, arg2, arg3, arg4);
251: default:u.u_error = EINVAL;
252: }
253: }
254:
255: uulimit()
256: {
257: u.u_error = EINVAL;
258: }
259:
260: /*
261: * Remove a directory.
262: */
263: urmdir(path)
264: char *path;
265: {
266: register INODE *ip;
267: int isdirempty();
268:
269: if (ftoi(path, 'r') != 0)
270: return;
271: ip = u.u_cdiri;
272:
273: /* Check if path is a directory */
274: if ((ip->i_mode & IFMT) != IFDIR) {
275: idetach(ip);
276: SET_U_ERROR(ENOTDIR, "rmdir: no such file or directory");
277: return;
278: }
279: /* We have to check if directory is empty */
280: if (!isdirempty(ip)) {
281: idetach(ip);
282: SET_U_ERROR(EEXIST, "rmdir: directory is not empty");
283: return;
284: }
285: idetach(ip);
286: removedir(path);
287: return (u.u_error);
288: }
289:
290: /*
291: * remove a directory entry.
292: * path is a pointer to user area.
293: */
294: removedir(path)
295: char *path;
296: {
297: char buf[512];
298: char *cpbuf, /* to internal file_name buffer */
299: *cppath; /* to user file_name buffer */
300:
301: /* Write path to a kernel buffer buf */
302: cpbuf = buf;
303: cppath = path;
304:
305: while ((*cpbuf = getubd(cppath)) != '\0') {
306: cppath++;
307: if (++cpbuf >= &buf[sizeof(buf) - 3]) {
308: SET_U_ERROR(ENOENT, "rmdir: path too long");
309: return;
310: }
311: }
312: *cpbuf++ = '/';
313: *cpbuf++ = '.';
314: *cpbuf = '\0';
315: u.u_io.io_seg = IOSYS;
316: dunlink(buf);
317: *cpbuf++ = '.';
318: *cpbuf = '\0';
319: dunlink(buf);
320: u.u_io.io_seg = IOUSR;
321: dunlink(path);
322: return;
323: }
324:
325: /*
326: * Unlink the given directory.
327: */
328: dunlink(np)
329: char *np;
330: {
331: register INODE *ip;
332: register dev_t dev;
333:
334: if (ftoi(np, 'u') != 0)
335: return;
336:
337: ip = u.u_pdiri;
338: if (iaccess(ip, IPW) == 0) {
339: u.u_error = EACCES;
340: goto err;
341: }
342:
343: dev = ip->i_dev;
344: if (diucheck(dev, u.u_cdirn) == 0)
345: goto err;
346: idirent(0);
347: idetach(ip);
348:
349: if ((ip=iattach(dev, u.u_cdirn)) == NULL)
350: return;
351:
352: if (ip->i_nlink > 0)
353: --ip->i_nlink;
354: icrt(ip); /* unlink - ctime */
355:
356: err:
357: idetach(ip);
358: return (0);
359: }
360:
361: /*
362: * This is a copy of iucheck. The only one difference is that that allows
363: * to remove a directory to a regular user.
364: */
365: diucheck(dev, ino)
366: register dev_t dev;
367: register ino_t ino;
368: {
369: register INODE *ip;
370: INODE inode;
371:
372: for (ip=&inodep[NINODE-1]; ip>=inodep; --ip) {
373: if (ip->i_ino==ino && ip->i_dev==dev)
374: break;
375: }
376: if (ip < inodep) {
377: ip = &inode;
378: ip->i_dev = dev;
379: ip->i_ino = ino;
380: if (icopydm(ip) == 0)
381: return (0);
382: }
383: return (1);
384: }
385:
386: /*
387: * Check if directory is empty.
388: */
389: int isdirempty(ip)
390: register INODE *ip;
391: {
392: register char *cp;
393: int count;
394: BUF *bp;
395:
396: for (count = 0; count < ip->i_size; count += 512) {
397: if ((bp = vread(ip, count)) == NULL)
398: break;
399: for (cp = (char *) bp->b_vaddr;
400: cp < (char *) bp->b_vaddr + BSIZE; cp += 16) {
401: if (*cp == '\0' && *(cp + 1) == '\0')
402: continue;
403: if (*(cp + 2) != '.')
404: goto bad;
405: if (*(cp + 3) == '\0')
406: continue;
407: if (*(cp + 3) != '.' || *(cp + 4) != '\0')
408: goto bad;
409: }
410: brelease(bp);
411: }
412: return 1;
413: bad:
414: brelease(bp);
415: return 0;
416: }
417:
418: /*
419: * SysV compatible mkdir() system call.
420: *
421: * Create a directory of the given "path" and "mode", if possible.
422: * Creating the directory is straight forward. Trying to clean
423: * up in case we run out of inodes or freee blocks in the process
424: * is not trivial.
425: * This system call was implemented in very press time.
426: * Vlad 6-04-92
427: */
428: umkdir(path, mode)
429: char *path;
430: int mode;
431: {
432: INODE *dmknod(); /* make directory node */
433: register INODE *pip; /* parent inode pointer */
434: register char *cp_path,
435: *cpb_path,
436: *cp_dot,
437: *cp_dotdot,
438: *cp_parent;
439: char bufpath[512],
440: bufdot[512],
441: bufdotdot[512],
442: bufparent[512];
443: int uid;
444: int error;
445: /*
446: * Create a local copies of "path" which we can use to build up
447: * the required directory links:
448: * path/. -- bufdot
449: * path/..-- bufdotdot
450: * Verify that the given path is not too long.
451: */
452: cp_path = path;
453: cpb_path = bufpath;
454: cp_dot = bufdot;
455: cp_dotdot = bufdotdot;
456: cp_parent = bufparent;
457:
458: while ((*cpb_path = getubd(cp_path)) != '\0') {
459: *cp_dot++ = *cp_dotdot++ = *cp_parent++ = *cpb_path;
460: ++cp_path;
461: if (++cpb_path >= &bufpath[sizeof(bufpath) - 3]) {
462: SET_U_ERROR(ENOENT, "sys5: mkdir: path too long");
463: return;
464: }
465: }
466: while (--cp_parent >= bufparent) {
467: if (*cp_parent == '/') {
468: *++cp_parent = '\0';
469: break;
470: }
471: }
472: if (cp_parent < bufparent) {
473: *++cp_parent = '.';
474: *++cp_parent = '\0';
475: }
476:
477: *cp_dotdot++ = *cp_dot++ = '/';
478: *cp_dotdot++ = *cp_dot++ = '.';
479: *cp_dotdot++ = '.';
480: *cp_dotdot = *cp_dot = '\0';
481:
482: u.u_io.io_seg = IOSYS;
483:
484:
485: u.u_io.io_seg = IOUSR;
486: if ((pip = dmknod(path, mode)) == NULL) {
487: return;
488: }
489: u.u_io.io_seg = IOSYS;
490: /* Now we can switch our id to root. It allows to use existing
491: * functions.
492: */
493: uid = u.u_uid;
494: u.u_uid = 0;
495: ulink(bufpath, bufdot);
496: if (u.u_error) {
497: error = u.u_error;
498: u.u_error = 0;
499: uunlink(bufpath);
500: u.u_error = 0;
501: u.u_io.io_seg = IOUSR;
502: u.u_uid = uid;
503: u.u_error = error;
504: return;
505: }
506: ulink(bufparent, bufdotdot);
507: if (u.u_error) {
508: error = u.u_error;
509: u.u_error = 0;
510: uunlink(bufdot);
511: printf("unlink %s errno is %d\n", bufdot, u.u_error);
512: u.u_error = 0;
513: uunlink(bufpath);
514: printf("unlink %s errno is %d\n", bufpath, u.u_error);
515: u.u_uid = uid;
516: u.u_io.io_seg = IOUSR;
517: u.u_error = error;
518: return;
519: }
520: u.u_io.io_seg = IOUSR;
521: return(0);
522: }
523:
524: /*
525: * Create a directory.
526: * We cannot use original ulink because it makes the directories only for
527: * superuser.
528: */
529: INODE *dmknod(np, mode)
530: char *np; /* Direcotory name */
531: int mode;
532: {
533: register INODE *ip, *pip;
534: register int type;
535:
536: type = (mode & ~IFMT);
537: type |= S_IFDIR;
538:
539: if (ftoi(np, 'c') != 0)
540: return NULL;
541:
542: if ((ip=u.u_cdiri) != NULL) {
543: SET_U_ERROR(EEXIST, "sys5: path already exist")
544: idetach(ip);
545: return NULL;
546: }
547: if ((ip=imake(type, (dev_t) 0)) != NULL)
548: idetach(ip);
549: pip = u.u_pdiri; /* grab ptr to parent inode */
550: return pip;
551: }
552:
553: /*
554: * Get directory entry in file system independent format.
555: */
556: ugetdents(fd, bp, n)
557: int fd; /* File descriptor to an open directory */
558: char *bp; /* Buffer where entries should be read */
559: unsigned n; /* Number of bytes to be read */
560: {
561: struct direct r_dir;
562: unsigned bytes; /* Number of bytes */
563: struct dirent sd;
564: ino_t inode; /* Inode number */
565: unsigned short ofnm; /* Offset to file name in dirent */
566: char *cw,
567: *cr;
568: int minbuf; /* Minimum possible size of the bp */
569: int i, mod;
570: int entry;
571: char ends[3] = "";
572: int total = 0;
573:
574: cw = &bp[0];
575:
576: ofnm = sizeof(sd.d_ino) + sizeof(sd.d_off) + sizeof(sd.d_reclen);
577:
578: /* Find minimum possible size of bp. It should be enough to contain the
579: * header of dirent, file name + '\0', and be on a sizeof(long)
580: * boundary.
581: */
582: entry = ofnm + DIRSIZ + 1;
583: mod = entry % sizeof(long);
584: minbuf = entry + (mod ? sizeof(long) - mod : 0);
585:
586: /* Is user buffer available? */
587: if (!useracc(bp, n) || n < minbuf) {
588: u.u_error = EFAULT;
589: return(0);
590: }
591:
592: while(n - (cw - bp) >= minbuf) {
593: /* Read next entry from the directory.
594: * inode == 0 for rm(ed) entries
595: */
596: do {
597: if ((bytes = dirio(fd, &r_dir, sizeof(struct direct),
598: &sd.d_off)) == 0) {
599: return(total);
600: }
601: inode = r_dir.d_ino;
602: } while (!inode);
603:
604: /* Find the size of file name */
605: for (cr = r_dir.d_name, i = 0; *cr != '\0' && i < DIRSIZ;
606: i++, cr++)
607: ;
608:
609: /* Copy file name */
610: if (!kucopy(r_dir.d_name, cw + ofnm, i))
611: return(0);
612: /* Write '\0' */
613: putubd(cw + ofnm + i++, '\0');
614: /* Round up to long boundary */
615: if (mod = (ofnm + i) % sizeof(long))
616: if (!kucopy(ends, cw + ofnm + i, sizeof(long) - mod))
617: return(0);
618: sd.d_ino = r_dir.d_ino;
619: sd.d_reclen = ofnm + i; /* Size of directory entry */
620: if (mod)
621: sd.d_reclen += sizeof(long) - mod;
622: if (!kucopy(&sd, cw, ofnm))
623: return(0);
624: total += sd.d_reclen;
625: cw += sd.d_reclen;
626: }
627: return(total);
628: }
629:
630: /*
631: * Read `n' bytes from the directory `fd' using the buffer `bp'.
632: */
633: dirio(fd, bp, n, offset)
634: struct direct *bp;
635: unsigned n;
636: off_t *offset;
637: {
638: register FD *fdp;
639: register INODE *ip;
640:
641: /* Check file descriptor */
642: if ((fdp = fdget(fd)) == NULL)
643: return (0);
644: if (((fdp->f_flag & IPR)) == 0) {
645: u.u_error = EBADF;
646: return (0);
647: }
648: ip = fdp->f_ip;
649: if ((ip->i_mode & IFMT) != IFDIR) {
650: u.u_error = EBADF;
651: return(0);
652: }
653:
654: ilock(ip); /* We do not want file changes during the read */
655:
656: u.u_io.io_seek = fdp->f_seek;
657: u.u_io.io.vbase = (vaddr_t) bp;
658: u.u_io.io_ioc = n;
659: u.u_io.io_flag = (fdp->f_flag & IPNDLY) ? IONDLY : 0;
660:
661: iread(ip, &u.u_io);
662: iacc(ip); /* read - atime */
663:
664: n -= u.u_io.io_ioc;
665: *offset = fdp->f_seek;
666: fdp->f_seek += n;
667:
668: iunlock(ip);
669:
670: return (n);
671: }
672:
673: /*
674: * Get file system information by file name.
675: */
676: ustatfs(path, stfs, len, fstyp)
677: char *path; /* File name */
678: struct statfs *stfs; /* Pointer to a user structure */
679: int len; /* Size of the structure */
680: int fstyp; /* File system type */
681: {
682: struct filsys *statmount(); /* Get mp for mounted device */
683: struct filsys *statunmount(); /* Get mp for unmounted device */
684: struct filsys *sb; /* Pointer to superblock */
685: int count = 0; /* Number of copied bytes */
686: short systype = 1; /* System type */
687: long bsize = BSIZE; /* Block size */
688: long frsize = 0; /* Fragment size */
689:
690: /* Check if stfs is an available user area. */
691: if (!useracc((char *) stfs, len)) {
692: u.u_error = EFAULT;
693: return;
694: }
695:
696: /* Filesystem type is 1 for 512 bytes blocks. */
697: count += sizeof(systype);
698: if (count > len)
699: return;
700: if (!kucopy(&(systype), &(stfs->f_fstyp), sizeof(systype)))
701: return;
702:
703: /* Block size */
704: count += sizeof(bsize);
705: if (count > len)
706: return;
707: if (!kucopy(&(bsize), &(stfs->f_bsize), sizeof(bsize)))
708: return;
709:
710: /* Fragment size. */
711: count += sizeof(int);
712: if (count > len)
713: return;
714: if (!kucopy(&(frsize), &(stfs->f_frsize), sizeof(frsize)))
715: return;
716:
717: if (!fstyp) {
718: if ((sb = statmount(-1, path)) == NULL)
719: return;
720: devinfo(sb, stfs, len, &count);
721: } else {
722: if ((sb = statunmount(-1, path)) == NULL)
723: return;
724: devinfo(sb, stfs, len, &count);
725: kfree(sb);
726: }
727: return;
728: }
729:
730: /*
731: * statmount - get superblock for mounted file system.
732: * fd - file descriptor or -1, path - file name or NULL.
733: */
734: struct filsys *statmount(fd, path)
735: int fd;
736: char *path;
737: {
738: register INODE *ip; /* Structure inode */
739: register FD *fdp;
740: register MOUNT *mp; /* Pointer to device */
741: dev_t device; /* Mounted device */
742:
743: /* Find the device */
744: if (path != NULL) { /* Find ip by file name */
745: if (ftoi(path, 'r') != 0)
746: return NULL;
747: ip = u.u_cdiri;
748: device = ip->i_dev;
749: idetach(ip);
750: } else { /* Find ip by file descriptor */
751: if ((fdp = fdget(fd)) == NULL)
752: return NULL;
753: if (((fdp->f_flag & IPR)) == 0) {
754: u.u_error = EBADF;
755: return NULL;
756: }
757: ip = fdp->f_ip;
758: device = ip->i_dev;
759: }
760: /* Take mount filesystem, check if dev is mounted device */
761: for (mp = mountp; mp != NULL; mp = mp->m_next)
762: if (mp->m_dev == device)
763: break;
764: if (mp == NULL) {
765: u.u_error = EINVAL;
766: return NULL;
767: }
768: return &mp->m_super;
769: }
770:
771: /*
772: * devinfo() write system information to user area
773: */
774: devinfo(sb, stfs, len, count)
775: struct filsys *sb; /* File name */
776: struct statfs *stfs; /* Pointer to a user structure */
777: int len; /* Size of the structure */
778: int *count;
779: {
780: long inode;
781:
782: /* Total number of blocks */
783: *count += sizeof(sb->s_fsize);
784: if (*count > len)
785: return;
786: if (!kucopy(&(sb->s_fsize), &(stfs->f_blocks),
787: sizeof(sb->s_fsize)))
788: return;
789:
790: /* Count of free blocks */
791: *count += sizeof(sb->s_tfree);
792: if (*count > len)
793: return;
794: if (!kucopy(&(sb->s_tfree), &(stfs->f_bfree),
795: sizeof(sb->s_tfree)))
796: return;
797:
798: /* Total number of file inodes */
799: *count += sizeof(inode);
800: if (*count > len)
801: return;
802: inode = (long) (sb->s_isize - INODEI) * INOPB;
803: if (!kucopy(&inode, &(stfs->f_files), sizeof(inode)))
804: return;
805:
806: /* Number of free inodes */
807: *count += sizeof(inode);
808: if (*count > len)
809: return;
810: inode = sb->s_tinode;
811: if (!kucopy(&inode, &(stfs->f_ffree), sizeof(inode)))
812: return;
813:
814: /* Volume name */
815: *count += sizeof(sb->s_fname);
816: if (*count > len)
817: return;
818: if (!kucopy(sb->s_fname, stfs->f_fname,
819: sizeof(sb->s_fpack)))
820: return;
821:
822: /* Pack name */
823: *count += sizeof(sb->s_fpack);
824: if (*count > len)
825: return;
826: if (!kucopy(sb->s_fpack, stfs->f_fpack,
827: sizeof(sb->s_fpack)))
828: return;
829: }
830:
831: /*
832: * statunmount - get superblock for unmounted file system.
833: * fd - file descriptor or -1, path - file name or NULL.
834: */
835: struct filsys *statunmount(fd, path)
836: int fd; /* File descriptor */
837: char *path; /* File name */
838: {
839: register INODE *ip;
840: register MOUNT *mp;
841: register dev_t rdev;
842: FD *fdp;
843: int mode;
844: BUF *bp;
845: struct filsys *sb;
846:
847: /* Find the device */
848: if (path != NULL) { /* Find ip by file name */
849: if (ftoi(path, 'r') != 0)
850: return NULL;
851: ip = u.u_cdiri;
852: mode = ip->i_mode;
853: rdev = ip->i_a.i_rdev;
854: idetach(ip);
855: } else { /* Find ip by file descriptor */
856: if ((fdp = fdget(fd)) == NULL)
857: return NULL;
858: if (((fdp->f_flag & IPR)) == 0) {
859: u.u_error = EBADF;
860: return NULL;
861: }
862: ip = fdp->f_ip;
863: ilock(ip);
864: mode = ip->i_mode;
865: rdev = ip->i_a.i_rdev;
866: iunlock(ip);
867: }
868:
869: /* Check for block special device */
870: if ((mode & IFMT) != IFBLK) {
871: u.u_error = ENOTBLK;
872: return NULL;
873: }
874:
875: /* Check if device is mounted device */
876: for (mp = mountp; mp != NULL; mp = mp->m_next) {
877: if (mp->m_dev == rdev) {
878: u.u_error = EBUSY;
879: return NULL;
880: }
881: }
882: dopen(rdev, IPR, DFBLK);
883: if (u.u_error)
884: return NULL;
885:
886: if ((bp = bread(rdev, (daddr_t) SUPERI, 1)) == NULL) {
887: dclose(rdev);
888: return NULL;
889: }
890: dclose(rdev);
891:
892: if ((sb = kalloc(sizeof(struct filsys))) == NULL)
893: return (NULL);
894:
895: kkcopy(bp->b_vaddr, sb, sizeof(struct filsys));
896: brelease(bp);
897: cansuper(sb); /* canonicalize supperblock */
898: if (tstf(sb) == 0) { /* check for consistency */
899: kfree(sb);
900: u.u_error = EINVAL;
901: return(NULL);
902: }
903: return(sb);
904: }
905:
906: /*
907: * Get file system information by file descriptor
908: */
909: ufstatfs(fildes, stfs, len, fstyp)
910: int fildes; /* File descriptor */
911: struct statfs *stfs; /* Pointer to a user structure */
912: int len; /* Size of the structure */
913: int fstyp; /* File system type */
914: {
915: struct filsys *statmount(); /* Get mp for mounted device */
916: struct filsys *statunmount(); /* Get mp for unmounted device */
917: struct filsys *sb; /* Pointer to superblock */
918: int count = 0; /* Number of copied bytes */
919: short systype = 1; /* System type */
920: long bsize = BSIZE; /* Block size */
921: long frsize = 0; /* Fragment size */
922:
923: /* Check if stfs is an available user area. */
924: if (!useracc((char *) stfs, len)) {
925: u.u_error = EFAULT;
926: return;
927: }
928:
929: /* Filesystem type is 1 for 512 bytes blocks. */
930: count += sizeof(systype);
931: if (count > len)
932: return;
933: if (!kucopy(&(systype), &(stfs->f_fstyp), sizeof(systype)))
934: return;
935:
936: /* Block size */
937: count += sizeof(bsize);
938: if (count > len)
939: return;
940: if (!kucopy(&(bsize), &(stfs->f_bsize), sizeof(bsize)))
941: return;
942:
943: /* Fragment size. */
944: count += sizeof(int);
945: if (count > len)
946: return;
947: if (!kucopy(&(frsize), &(stfs->f_frsize), sizeof(frsize)))
948: return;
949:
950: if (!fstyp) {
951: if ((sb = statmount(fildes, NULL)) == NULL)
952: return;
953: devinfo(sb, stfs, len, &count);
954: } else {
955: if ((sb = statunmount(fildes, NULL)) == NULL)
956: return;
957: devinfo(sb, stfs, len, &count);
958: kfree(sb);
959: }
960: return;
961: }
962:
963: /*
964: * Check superblock for consistency.
965: */
966: tstf(fp)
967: register struct filsys *fp;
968: {
969: register daddr_t *dp;
970: register ino_t *ip;
971: register ino_t maxinode;
972:
973: maxinode = (fp->s_isize - INODEI) * INOPB + 1;
974: if (fp->s_isize >= fp->s_fsize)
975: return (0);
976: if (fp->s_tfree < fp->s_nfree
977: || fp->s_tfree >= fp->s_fsize - fp->s_isize + 1)
978: return (0);
979: if (fp->s_tinode < fp->s_ninode
980: || fp->s_tinode >= maxinode-1)
981: return (0);
982: for (dp = &fp->s_free[0]; dp < &fp->s_free[fp->s_nfree]; dp += 1)
983: if (*dp < fp->s_isize || *dp >= fp->s_fsize)
984: return (0);
985: for (ip = &fp->s_inode[0]; ip < &fp->s_inode[fp->s_ninode]; ip += 1)
986: if (*ip < 1 || *ip > maxinode)
987: return (0);
988: return (1);
989: }
990:
991: /* the following calls are not in the BCS */
992:
993: uadmin()
994: {
995: u.u_error = EINVAL;
996: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.