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