diff --git a/src/nwvolume.c b/src/nwvolume.c index 22aa35b..b97a83f 100644 --- a/src/nwvolume.c +++ b/src/nwvolume.c @@ -888,66 +888,40 @@ int get_volume_user_trustee(int volume, uint32 id, #include #include -/* Return a quotactl() special argument for the filesystem used by path. - * Classic quota code wants the block device. Pseudo filesystems such as - * tmpfs do not have a block device in mnt_fsname; for them use the matching - * mount point. Linux quotactl() accepts this for tmpfs-style quota mounts. - */ +/* Return the device special file that the specified path uses */ const char *find_device_file(const char *path) { - struct stat path_st; - struct stat mnt_st; - struct stat dev_st; + struct stat s; dev_t dev; struct mntent *mntent; FILE *fp; static char mount_device[512]; - static char mount_point[512]; - int best_mount_len = -1; mount_device[0] = '\0'; - mount_point[0] = '\0'; - if (path == (char *) NULL || *path == '\0' || stat(path, &path_st) != 0) + if (path == (char *) NULL || *path == '\0' || stat(path, &s) != 0) return((char *) NULL); - dev = path_st.st_dev; + dev = s.st_dev; if ((fp=setmntent(MOUNTED, "r")) == (FILE *) NULL) return((char *) NULL); - while (!ferror(fp)) { + /* mntent will be a static struct mntent. Copy the device name before + * endmntent(), do not return a pointer into libc's mount table buffer. + */ mntent = getmntent(fp); if (mntent == (struct mntent *) NULL) break; - - if (stat(mntent->mnt_dir, &mnt_st) != 0 || mnt_st.st_dev != dev) - continue; - - /* Remember the deepest matching mount point. */ - if ((int)strlen(mntent->mnt_dir) > best_mount_len) { - best_mount_len = strlen(mntent->mnt_dir); - strmaxcpy(mount_point, mntent->mnt_dir, sizeof(mount_point)-1); - } - - if (stat(mntent->mnt_fsname, &dev_st) == 0) { - if ((S_ISCHR(dev_st.st_mode) || S_ISBLK(dev_st.st_mode)) - && dev_st.st_rdev == dev) { - strmaxcpy(mount_device, mntent->mnt_fsname, sizeof(mount_device)-1); - break; + if (stat(mntent->mnt_fsname, &s) == 0) { + if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode)) { + if (s.st_rdev == dev) { + /* Found it */ + strmaxcpy(mount_device, mntent->mnt_fsname, sizeof(mount_device)-1); + break; + } } } } - endmntent(fp); - - if (mount_device[0]) - return(mount_device); - - if (mount_point[0]) { - XDPRINTF((2,0, "find_device_file: using mount point %s for quota path %s", - mount_point, path)); - return(mount_point); - } - - return((char *) NULL); + return(mount_device[0] ? mount_device : (char *) NULL); } @@ -1013,9 +987,19 @@ int nw_set_vol_restrictions(uint8 volnr, int uid, uint32 quota) res=su_quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device, uid, (caddr_t) &dqblk); if (res != 0) { - XDPRINTF((2,0, "Get quota before set failed device=%s uid=%d errno=%d", - device, uid, errno)); - return(0); /* Quotas are probably not enabled. Keep old compatibility. */ + int err = errno; + if (err == ESRCH) { + /* No quota record exists for this uid yet. That is OK for a set: + * start from an empty dqblk and create the record below. + */ + XDPRINTF((2,0, "No quota record yet device=%s uid=%d, creating one", + device, uid)); + memset(&dqblk, 0, sizeof(dqblk)); + } else { + XDPRINTF((2,0, "Get quota before set failed device=%s uid=%d errno=%d", + device, uid, err)); + return(0); /* Quotas are probably not enabled. Keep old compatibility. */ + } } dqblk.dqb_bhardlimit = quota; dqblk.dqb_bsoftlimit = quota;