L4Re/departure

libext2fs/lib/libsupport/quotaio.c

617:2733e5770ee9
9 months ago Paul Boddie Made the run command wait for completion, introducing the spawn command to run programs in the background. Introduced conveniences for waiting for the last job to be initiated and for piping from the last job, also subscribing to signals from pipe-supplying jobs so that they may be transparently removed from the job list upon completion. Augmented the job listing with the "+" notation familiar from Unix. Prevented new jobs from being started when no job slots are available.
     1 /** quotaio.c     2  *     3  * Generic IO operations on quotafiles     4  * Jan Kara <jack@suse.cz> - sponsored by SuSE CR     5  * Aditya Kali <adityakali@google.com> - Ported to e2fsprogs     6  */     7      8 #include "config.h"     9 #include <stdio.h>    10 #include <errno.h>    11 #include <string.h>    12 #include <unistd.h>    13 #include <stdlib.h>    14 #include <time.h>    15 #include <sys/types.h>    16 #include <sys/stat.h>    17 #include <sys/file.h>    18 #include <assert.h>    19     20 #include "common.h"    21 #include "quotaio.h"    22     23 static const char * const extensions[MAXQUOTAS] = {    24 	[USRQUOTA] = "user",    25 	[GRPQUOTA] = "group",    26 	[PRJQUOTA] = "project",    27 };    28 static const char * const basenames[] = {    29 	"",		/* undefined */    30 	"quota",	/* QFMT_VFS_OLD */    31 	"aquota",	/* QFMT_VFS_V0 */    32 	"",		/* QFMT_OCFS2 */    33 	"aquota"	/* QFMT_VFS_V1 */    34 };    35     36 /* Header in all newer quotafiles */    37 struct disk_dqheader {    38 	__le32 dqh_magic;    39 	__le32 dqh_version;    40 } __attribute__ ((packed));    41     42 /**    43  * Convert type of quota to written representation    44  */    45 const char *quota_type2name(enum quota_type qtype)    46 {    47 	if (qtype >= MAXQUOTAS)    48 		return "unknown";    49 	return extensions[qtype];    50 }    51     52 ext2_ino_t quota_type2inum(enum quota_type qtype,    53                            struct ext2_super_block *sb)    54 {    55 	switch (qtype) {    56 	case USRQUOTA:    57 		return EXT4_USR_QUOTA_INO;    58 	case GRPQUOTA:    59 		return EXT4_GRP_QUOTA_INO;    60 	case PRJQUOTA:    61 		return sb->s_prj_quota_inum;    62 	default:    63 		return 0;    64 	}    65 	return 0;    66 }    67     68 /**    69  * Creates a quota file name for given type and format.    70  */    71 const char *quota_get_qf_name(enum quota_type type, int fmt, char *buf)    72 {    73 	if (!buf)    74 		return NULL;    75 	snprintf(buf, QUOTA_NAME_LEN, "%s.%s",    76 		 basenames[fmt], extensions[type]);    77     78 	return buf;    79 }    80     81 /*    82  * Set grace time if needed    83  */    84 void update_grace_times(struct dquot *q)    85 {    86 	time_t now;    87     88 	time(&now);    89 	if (q->dq_dqb.dqb_bsoftlimit && toqb(q->dq_dqb.dqb_curspace) >    90 			q->dq_dqb.dqb_bsoftlimit) {    91 		if (!q->dq_dqb.dqb_btime)    92 			q->dq_dqb.dqb_btime =    93 				now + q->dq_h->qh_info.dqi_bgrace;    94 	} else {    95 		q->dq_dqb.dqb_btime = 0;    96 	}    97     98 	if (q->dq_dqb.dqb_isoftlimit && q->dq_dqb.dqb_curinodes >    99 			q->dq_dqb.dqb_isoftlimit) {   100 		if (!q->dq_dqb.dqb_itime)   101 				q->dq_dqb.dqb_itime =   102 					now + q->dq_h->qh_info.dqi_igrace;   103 	} else {   104 		q->dq_dqb.dqb_itime = 0;   105 	}   106 }   107    108 errcode_t quota_inode_truncate(ext2_filsys fs, ext2_ino_t ino)   109 {   110 	struct ext2_inode inode;   111 	errcode_t err;   112 	enum quota_type qtype;   113    114 	if ((err = ext2fs_read_inode(fs, ino, &inode)))   115 		return err;   116    117 	for (qtype = 0; qtype < MAXQUOTAS; qtype++)   118 		if (ino == quota_type2inum(qtype, fs->super))   119 			break;   120    121 	if (qtype != MAXQUOTAS) {   122 		inode.i_dtime = fs->now ? fs->now : time(0);   123 		if (!ext2fs_inode_has_valid_blocks2(fs, &inode))   124 			return 0;   125 		err = ext2fs_punch(fs, ino, &inode, NULL, 0, ~0ULL);   126 		if (err)   127 			return err;   128 		fs->flags &= ~EXT2_FLAG_SUPER_ONLY;   129 		memset(&inode, 0, sizeof(struct ext2_inode));   130 	} else {   131 		inode.i_flags &= ~EXT2_IMMUTABLE_FL;   132 	}   133 	err = ext2fs_write_inode(fs, ino, &inode);   134 	return err;   135 }   136    137 /* Functions to read/write quota file. */   138 static unsigned int quota_write_nomount(struct quota_file *qf,   139 					ext2_loff_t offset,   140 					void *buf, unsigned int size)   141 {   142 	ext2_file_t	e2_file = qf->e2_file;   143 	unsigned int	bytes_written = 0;   144 	errcode_t	err;   145    146 	err = ext2fs_file_llseek(e2_file, offset, EXT2_SEEK_SET, NULL);   147 	if (err) {   148 		log_err("ext2fs_file_llseek failed: %ld", err);   149 		return 0;   150 	}   151    152 	err = ext2fs_file_write(e2_file, buf, size, &bytes_written);   153 	if (err) {   154 		log_err("ext2fs_file_write failed: %ld", err);   155 		return 0;   156 	}   157    158 	/* Correct inode.i_size is set in end_io. */   159 	return bytes_written;   160 }   161    162 static unsigned int quota_read_nomount(struct quota_file *qf,   163 				       ext2_loff_t offset,   164 				       void *buf, unsigned int size)   165 {   166 	ext2_file_t	e2_file = qf->e2_file;   167 	unsigned int	bytes_read = 0;   168 	errcode_t	err;   169    170 	err = ext2fs_file_llseek(e2_file, offset, EXT2_SEEK_SET, NULL);   171 	if (err) {   172 		log_err("ext2fs_file_llseek failed: %ld", err);   173 		return 0;   174 	}   175    176 	err = ext2fs_file_read(e2_file, buf, size, &bytes_read);   177 	if (err) {   178 		log_err("ext2fs_file_read failed: %ld", err);   179 		return 0;   180 	}   181    182 	return bytes_read;   183 }   184    185 /*   186  * Detect quota format and initialize quota IO   187  */   188 errcode_t quota_file_open(quota_ctx_t qctx, struct quota_handle *h,   189 			  ext2_ino_t qf_ino, enum quota_type qtype,   190 			  int fmt, int flags)   191 {   192 	ext2_filsys fs = qctx->fs;   193 	ext2_file_t e2_file;   194 	errcode_t err;   195 	int allocated_handle = 0;   196    197 	if (qtype >= MAXQUOTAS)   198 		return EINVAL;   199    200 	if (fmt == -1)   201 		fmt = QFMT_VFS_V1;   202    203 	err = ext2fs_read_bitmaps(fs);   204 	if (err)   205 		return err;   206    207 	if (qf_ino == 0)   208 		qf_ino = *quota_sb_inump(fs->super, qtype);   209    210 	log_debug("Opening quota ino=%u, type=%d", qf_ino, qtype);   211 	err = ext2fs_file_open(fs, qf_ino, flags, &e2_file);   212 	if (err) {   213 		log_err("ext2fs_file_open failed: %s", error_message(err));   214 		return err;   215 	}   216    217 	if (!h) {   218 		if (qctx->quota_file[qtype]) {   219 			h = qctx->quota_file[qtype];   220 			if (((flags & EXT2_FILE_WRITE) == 0) ||   221 			    (h->qh_file_flags & EXT2_FILE_WRITE)) {   222 				ext2fs_file_close(e2_file);   223 				return 0;   224 			}   225 			(void) quota_file_close(qctx, h);   226 		}   227 		err = ext2fs_get_mem(sizeof(struct quota_handle), &h);   228 		if (err) {   229 			log_err("Unable to allocate quota handle");   230 			ext2fs_file_close(e2_file);   231 			return err;   232 		}   233 		allocated_handle = 1;   234 	}   235    236 	h->qh_qf.e2_file = e2_file;   237 	h->qh_qf.fs = fs;   238 	h->qh_qf.ino = qf_ino;   239 	h->e2fs_write = quota_write_nomount;   240 	h->e2fs_read = quota_read_nomount;   241 	h->qh_file_flags = flags;   242 	h->qh_io_flags = 0;   243 	h->qh_type = qtype;   244 	h->qh_fmt = fmt;   245 	memset(&h->qh_info, 0, sizeof(h->qh_info));   246 	h->qh_ops = &quotafile_ops_2;   247    248 	if (h->qh_ops->check_file &&   249 	    (h->qh_ops->check_file(h, qtype, fmt) == 0)) {   250 		log_err("qh_ops->check_file failed");   251 		err = EIO;   252 		goto errout;   253 	}   254    255 	if (h->qh_ops->init_io && (h->qh_ops->init_io(h) < 0)) {   256 		log_err("qh_ops->init_io failed");   257 		err = EIO;   258 		goto errout;   259 	}   260 	if (allocated_handle)   261 		qctx->quota_file[qtype] = h;   262    263 	return 0;   264 errout:   265 	ext2fs_file_close(e2_file);   266 	if (allocated_handle)   267 		ext2fs_free_mem(&h);   268 	return err;   269 }   270    271 static errcode_t quota_inode_init_new(ext2_filsys fs, ext2_ino_t ino)   272 {   273 	struct ext2_inode inode;   274 	errcode_t err = 0;   275    276 	err = ext2fs_read_inode(fs, ino, &inode);   277 	if (err) {   278 		log_err("ex2fs_read_inode failed");   279 		return err;   280 	}   281    282 	if (EXT2_I_SIZE(&inode)) {   283 		err = quota_inode_truncate(fs, ino);   284 		if (err)   285 			return err;   286 	}   287    288 	memset(&inode, 0, sizeof(struct ext2_inode));   289 	ext2fs_iblk_set(fs, &inode, 0);   290 	inode.i_atime = inode.i_mtime =   291 		inode.i_ctime = fs->now ? fs->now : time(0);   292 	inode.i_links_count = 1;   293 	inode.i_mode = LINUX_S_IFREG | 0600;   294 	inode.i_flags |= EXT2_IMMUTABLE_FL;   295 	if (ext2fs_has_feature_extents(fs->super))   296 		inode.i_flags |= EXT4_EXTENTS_FL;   297    298 	err = ext2fs_write_new_inode(fs, ino, &inode);   299 	if (err) {   300 		log_err("ext2fs_write_new_inode failed: %ld", err);   301 		return err;   302 	}   303 	return err;   304 }   305    306 /*   307  * Create new quotafile of specified format on given filesystem   308  */   309 errcode_t quota_file_create(struct quota_handle *h, ext2_filsys fs,   310 			    enum quota_type qtype, int fmt)   311 {   312 	ext2_file_t e2_file;   313 	errcode_t err;   314 	ext2_ino_t qf_inum = 0;   315    316 	if (fmt == -1)   317 		fmt = QFMT_VFS_V1;   318    319 	h->qh_qf.fs = fs;   320 	qf_inum = quota_type2inum(qtype, fs->super);   321 	if (qf_inum == 0 && qtype == PRJQUOTA) {   322 		err = ext2fs_new_inode(fs, EXT2_ROOT_INO, LINUX_S_IFREG | 0600,   323 				       0, &qf_inum);   324 		if (err)   325 			return err;   326 		ext2fs_inode_alloc_stats2(fs, qf_inum, +1, 0);   327 		ext2fs_mark_ib_dirty(fs);   328 	} else if (qf_inum == 0) {   329 		return EXT2_ET_BAD_INODE_NUM;   330 	}   331    332 	err = ext2fs_read_bitmaps(fs);   333 	if (err)   334 		goto out_err;   335    336 	err = quota_inode_init_new(fs, qf_inum);   337 	if (err) {   338 		log_err("init_new_quota_inode failed");   339 		goto out_err;   340 	}   341 	h->qh_qf.ino = qf_inum;   342 	h->qh_file_flags = EXT2_FILE_WRITE | EXT2_FILE_CREATE;   343 	h->e2fs_write = quota_write_nomount;   344 	h->e2fs_read = quota_read_nomount;   345    346 	log_debug("Creating quota ino=%u, type=%d", qf_inum, qtype);   347 	err = ext2fs_file_open(fs, qf_inum, h->qh_file_flags, &e2_file);   348 	if (err) {   349 		log_err("ext2fs_file_open failed: %ld", err);   350 		goto out_err;   351 	}   352 	h->qh_qf.e2_file = e2_file;   353    354 	h->qh_io_flags = 0;   355 	h->qh_type = qtype;   356 	h->qh_fmt = fmt;   357 	memset(&h->qh_info, 0, sizeof(h->qh_info));   358 	h->qh_ops = &quotafile_ops_2;   359    360 	if (h->qh_ops->new_io && (h->qh_ops->new_io(h) < 0)) {   361 		log_err("qh_ops->new_io failed");   362 		err = EIO;   363 		goto out_err1;   364 	}   365    366 	return 0;   367    368 out_err1:   369 	ext2fs_file_close(e2_file);   370 out_err:   371    372 	if (qf_inum)   373 		quota_inode_truncate(fs, qf_inum);   374    375 	return err;   376 }   377    378 /*   379  * Close quotafile and release handle   380  */   381 errcode_t quota_file_close(quota_ctx_t qctx, struct quota_handle *h)   382 {   383 	if (h->qh_io_flags & IOFL_INFODIRTY) {   384 		if (h->qh_ops->write_info && h->qh_ops->write_info(h) < 0)   385 			return EIO;   386 		h->qh_io_flags &= ~IOFL_INFODIRTY;   387 	}   388    389 	if (h->qh_ops->end_io && h->qh_ops->end_io(h) < 0)   390 		return EIO;   391 	if (h->qh_qf.e2_file)   392 		ext2fs_file_close(h->qh_qf.e2_file);   393 	if (qctx->quota_file[h->qh_type] == h)   394 		ext2fs_free_mem(&qctx->quota_file[h->qh_type]);   395 	return 0;   396 }   397    398 /*   399  * Create empty quota structure   400  */   401 struct dquot *get_empty_dquot(void)   402 {   403 	struct dquot *dquot;   404    405 	if (ext2fs_get_memzero(sizeof(struct dquot), &dquot)) {   406 		log_err("Failed to allocate dquot");   407 		return NULL;   408 	}   409    410 	dquot->dq_id = -1;   411 	return dquot;   412 }