On 12/08/2015 09:11 AM, Dmitry Andreev wrote: > This patch introduces virStorageBackendCreateExec function > that has simple type arguments so it can be used without > 'virStorageXXX' structures. > > --- > src/storage/storage_backend.c | 130 +++++++++++++++++++++++------------------- > 1 file changed, 70 insertions(+), 60 deletions(-) > caveat... only looked at this patch of the series... Mostly because I've recently had the (dis)pleasure of working in this code. There's also a backlog of other changes that I want to look go through first prior to the rest of this series. Still seeing this particular code change just caused my "warning, danger, radar" to go off... > diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c > index 194736b..2e14af9 100644 > --- a/src/storage/storage_backend.c > +++ b/src/storage/storage_backend.c > @@ -675,92 +675,89 @@ virStorageGenerateQcowEncryption(virConnectPtr conn, > return ret; > } > > -static int > -virStorageBackendCreateExecCommand(virStoragePoolObjPtr pool, > - virStorageVolDefPtr vol, > - virCommandPtr cmd) > +static > +int virStorageBackendCreateExec(virCommandPtr cmd, const char* path, > + uid_t uid, gid_t gid, mode_t mode) The coding practices are one argument per line... Generating a comment regarding input arguments might have been nice too. Also, if your goal was to remove the "pool pointer", then why not pass the pool->def->type as well and thus avoid the need to remove/rework the if loop below? > { > struct stat st; > - gid_t gid; > - uid_t uid; > - mode_t mode = (vol->target.perms->mode == (mode_t) -1 ? > - VIR_STORAGE_DEFAULT_VOL_PERM_MODE : > - vol->target.perms->mode); > bool filecreated = false; > int ret = -1; > > - if ((pool->def->type == VIR_STORAGE_POOL_NETFS) > - && (((geteuid() == 0) > - && (vol->target.perms->uid != (uid_t) -1) > - && (vol->target.perms->uid != 0)) > - || ((vol->target.perms->gid != (gid_t) -1) > - && (vol->target.perms->gid != getegid())))) { > - > - virCommandSetUID(cmd, vol->target.perms->uid); > - virCommandSetGID(cmd, vol->target.perms->gid); > - virCommandSetUmask(cmd, S_IRWXUGO ^ mode); > - > - if (virCommandRun(cmd, NULL) == 0) { > - /* command was successfully run, check if the file was created */ > - if (stat(vol->target.path, &st) >= 0) { > - filecreated = true; > - > - /* seems qemu-img disregards umask and open/creates using 0644. > - * If that doesn't match what we expect, then let's try to > - * re-open the file and attempt to force the mode change. > - */ > - if (mode != (st.st_mode & S_IRWXUGO)) { > - int fd = -1; > - int flags = VIR_FILE_OPEN_FORK | VIR_FILE_OPEN_FORCE_MODE; > - > - if ((fd = virFileOpenAs(vol->target.path, O_RDWR, mode, > - vol->target.perms->uid, > - vol->target.perms->gid, > - flags)) >= 0) { > - /* Success - means we're good */ > - VIR_FORCE_CLOSE(fd); > - ret = 0; > - goto cleanup; > - } > - } > - } > + /* check is there a need to set uid/gid */ > + if ((uid == (uid_t) -1 || geteuid() == uid) > + && (gid == (gid_t) -1 || geteuid() == gid)) > + goto retry; Not the label retry really conveys the right meaning. To me it's more of a "skip_netfs_when_running_as_root". It seems there is a slight difference to the original code which checked geteuid() == 0 first, then "uid != 0" (where uid would have been the passed vol->target.perms->uid). So the next question is - have you considered whether this is a non privileged connection? e.g. qemu:///system vs. qemu:///session. The geteuid() may not be 0, but the NETFS check was ensuring that if going through that path, not only was it a NETFS storage pool target, but that we were running as root and the passed uid was set and it wasn't 0. This all because of the NFS root_squash environment. As an aside, generally the order for geteuid/getegid checks is swapped - eg uid == geteuid() and gid == getegid() > + > + /* first try - create with uid/gid/umask > + * Originaly this try was added for NETFS > + * that doesn't support chmod. > + */ Not sure I agree with the comment. NETFS is a "special case" especially when the target NFS Server has root_squash enabled. I would suggest you check the very recent history on this code... I'll claim short term memory lapse (or purge out of unnecessary pages in memory) if you ask too many questions though! It's not that NETFS doesn't support chmod, it's written this way because it's possible that a storage volume being created using kemu-img, qmeu-img, or qcow-create is found on a NFS Server with root_squash enabled. That means when the command runs, it has to run under the specified uid/gid; otherwise, the file gets created with (I think the default of) nfsnobody because NFS takes an incoming root connection and "squashes" it. As for the 'mode' - as I found it in my recent foray into the code... If that's provided, then a 'umask' is done during the command run which "theoretically" would set the right protection bits. However, as I learned qemu-img does it's own thing thus the odd comment. With your/this change every pool type target could try the setting of uid, gid, and mode in this manner as long as they've been provided in the volume.xml. While perhaps technically not different than providing uid, gid, and mode, then creating the file, then changing uid, gid, and mode afterwards. So that's input - I'm not sure doing the reworked/retry logic is necessary and I'd certainly caution against it. You can also look at virFileOpenAs, virFileRemove, and virDirCreate to see other code has the (dis)pleasure of dealing with this NFS root_squash environment. John > + virCommandSetUID(cmd, uid); > + virCommandSetGID(cmd, gid); > + virCommandSetUmask(cmd, S_IRWXUGO ^ mode); > + > + if (virCommandRun(cmd, NULL) < 0) > + goto retry; > + > + if (stat(path, &st) < 0) > + goto retry; > + > + filecreated = true; > + > + /* seems qemu-img disregards umask and open/creates using 0644. > + * If that doesn't match what we expect, then let's try to > + * re-open the file and attempt to force the mode change. > + */ > + if (mode != (st.st_mode & S_IRWXUGO)) { > + int fd = -1; > + int flags = VIR_FILE_OPEN_FORK | VIR_FILE_OPEN_FORCE_MODE; > + > + if ((fd = virFileOpenAs(path, O_RDWR, mode, > + uid, gid, flags)) >= 0) { > + /* Success - means we're good */ > + VIR_FORCE_CLOSE(fd); > + ret = 0; > + virReportSystemError(errno, _("no need to retry %s"), path); > + goto cleanup; > } > } > > + retry: > + /* second try - set uid/gid/umask after creation */ > if (!filecreated) { > - /* don't change uid/gid/mode if we retry */ > virCommandSetUID(cmd, -1); > virCommandSetGID(cmd, -1); > virCommandSetUmask(cmd, 0); > > if (virCommandRun(cmd, NULL) < 0) > goto cleanup; > - if (stat(vol->target.path, &st) < 0) { > + > + if (stat(path, &st) < 0) { > virReportSystemError(errno, > - _("failed to create %s"), vol->target.path); > + _("failed to create %s"), path); > goto cleanup; > } > + > filecreated = true; > } > > - uid = (vol->target.perms->uid != st.st_uid) ? vol->target.perms->uid > - : (uid_t) -1; > - gid = (vol->target.perms->gid != st.st_gid) ? vol->target.perms->gid > - : (gid_t) -1; > + uid = (uid != st.st_uid) ? uid : (uid_t) -1; > + gid = (gid != st.st_gid) ? gid : (gid_t) -1; > + > if (((uid != (uid_t) -1) || (gid != (gid_t) -1)) > - && (chown(vol->target.path, uid, gid) < 0)) { > + && (chown(path, uid, gid) < 0)) { > virReportSystemError(errno, > _("cannot chown %s to (%u, %u)"), > - vol->target.path, (unsigned int) uid, > + path, (unsigned int) uid, > (unsigned int) gid); > goto cleanup; > } > > if (mode != (st.st_mode & S_IRWXUGO) && > - chmod(vol->target.path, mode) < 0) { > + chmod(path, mode) < 0) { > virReportSystemError(errno, > _("cannot set mode of '%s' to %04o"), > - vol->target.path, mode); > + path, mode); > goto cleanup; > } > > @@ -768,11 +765,24 @@ virStorageBackendCreateExecCommand(virStoragePoolObjPtr pool, > > cleanup: > if (ret < 0 && filecreated) > - virFileRemove(vol->target.path, vol->target.perms->uid, > - vol->target.perms->gid); > + virFileRemove(path, uid, gid); > return ret; > } > > +static int > +virStorageBackendCreateExecCommand(virStorageVolDefPtr vol, > + virCommandPtr cmd) > +{ > + mode_t mode = (vol->target.perms->mode == (mode_t) -1 ? > + VIR_STORAGE_DEFAULT_VOL_PERM_MODE : > + vol->target.perms->mode); > + > + return virStorageBackendCreateExec(cmd, vol->target.path, > + vol->target.perms->uid, > + vol->target.perms->gid, > + mode); > +} > + > enum { > QEMU_IMG_BACKING_FORMAT_NONE = 0, > QEMU_IMG_BACKING_FORMAT_FLAG, > @@ -1153,7 +1163,7 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, > if (!cmd) > goto cleanup; > > - ret = virStorageBackendCreateExecCommand(pool, vol, cmd); > + ret = virStorageBackendCreateExecCommand(vol, cmd); > > virCommandFree(cmd); > cleanup: > @@ -1167,7 +1177,7 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, > */ > static int > virStorageBackendCreateQcowCreate(virConnectPtr conn ATTRIBUTE_UNUSED, > - virStoragePoolObjPtr pool, > + virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, > virStorageVolDefPtr vol, > virStorageVolDefPtr inputvol, > unsigned int flags) > @@ -1217,7 +1227,7 @@ virStorageBackendCreateQcowCreate(virConnectPtr conn ATTRIBUTE_UNUSED, > > cmd = virCommandNewArgList("qcow-create", size, vol->target.path, NULL); > > - ret = virStorageBackendCreateExecCommand(pool, vol, cmd); > + ret = virStorageBackendCreateExecCommand(vol, cmd); > virCommandFree(cmd); > VIR_FREE(size); > > -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list