inline int xp_id_compare(struct xp_daemon_id *id1, struct xp_daemon_id *id2, int check_related) { if (id1 == NULL || id2 == NULL) return DAZUKO_DIFFERENT; /* if file's are available and they match, * then we say that the id's match * ("file" is only used to unregister daemons and * here we allow other processes to do this) * Note: this is a Linux-only "hack" */ if (id1->file != NULL && id1->file == id2->file) return DAZUKO_SAME; if (id1->pid == id2->pid && id1->current_p == id2->current_p && id1->files == id2->files) return DAZUKO_SAME; if (check_related) { if (check_parent(id1->current_p, id2->current_p) == 0) { return DAZUKO_CHILD; } else if (id1->pid == id2->pid || id1->current_p == id2->current_p || id1->files == id2->files) { return DAZUKO_SUSPICIOUS; } } return DAZUKO_DIFFERENT; }
static struct ib_umem_odp *odp_lookup(struct ib_ucontext *ctx, u64 start, u64 length, struct mlx5_ib_mr *parent) { struct ib_umem_odp *odp; struct rb_node *rb; down_read(&ctx->umem_rwsem); odp = rbt_ib_umem_lookup(&ctx->umem_tree, start, length); if (!odp) goto end; while (1) { if (check_parent(odp, parent)) goto end; rb = rb_next(&odp->interval_tree.rb); if (!rb) goto not_found; odp = rb_entry(rb, struct ib_umem_odp, interval_tree.rb); if (ib_umem_start(odp->umem) > start + length) goto not_found; } not_found: odp = NULL; end: up_read(&ctx->umem_rwsem); return odp; }
static int pre_ss(PRE_ARGS) { if (MDOC_BLOCK != n->type) return(1); return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY)); }
static int pre_sh(PRE_ARGS) { if (MDOC_BLOCK != n->type) return(1); mdoc->regs->regs[(int)REG_nS].set = 0; return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT)); }
static struct ib_umem_odp *odp_next(struct ib_umem_odp *odp) { struct mlx5_ib_mr *mr = odp->private, *parent = mr->parent; struct ib_ucontext *ctx = odp->umem->context; struct rb_node *rb; down_read(&ctx->umem_rwsem); while (1) { rb = rb_next(&odp->interval_tree.rb); if (!rb) goto not_found; odp = rb_entry(rb, struct ib_umem_odp, interval_tree.rb); if (check_parent(odp, parent)) goto end; } not_found: odp = NULL; end: up_read(&ctx->umem_rwsem); return odp; }
static void views_parser_start_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error) { ViewsParserData *parser_data = user_data; GtkWidget *item; g_assert (context != NULL); g_assert (element_name != NULL); g_assert (parser_data != NULL); if (g_strcmp0 (element_name, "views") == 0) { } else if (g_strcmp0 (element_name, "view") == 0) { const gchar *name = NULL; if (!check_parent (context, "views", error)) return; if (!g_markup_collect_attributes (element_name, attribute_names, attribute_values, error, G_MARKUP_COLLECT_STRING, "name", &name, G_MARKUP_COLLECT_INVALID)) return; item = g_object_new (GB_TYPE_SHORTCUTS_VIEW, "view-name", name, "visible", TRUE, NULL); g_queue_push_head (parser_data->stack, g_object_ref_sink (item)); } else if (g_strcmp0 (element_name, "page") == 0) { if (!check_parent (context, "view", error)) return; item = g_object_new (GB_TYPE_SHORTCUTS_PAGE, "visible", TRUE, NULL); g_queue_push_head (parser_data->stack, g_object_ref_sink (item)); } else if (g_strcmp0 (element_name, "column") == 0) { GtkSizeGroup *size_group; if (!check_parent (context, "page", error)) return; size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); g_queue_push_head (parser_data->column_image_size_groups, size_group); size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); g_queue_push_head (parser_data->column_desc_size_groups, size_group); item = g_object_new (GB_TYPE_SHORTCUTS_COLUMN, "visible", TRUE, NULL); g_queue_push_head (parser_data->stack, g_object_ref_sink (item)); } else if (g_strcmp0 (element_name, "group") == 0) { if (!check_parent (context, "column", error)) return; item = g_object_new (GB_TYPE_SHORTCUTS_GROUP, "visible", TRUE, NULL); g_queue_push_head (parser_data->stack, g_object_ref_sink (item)); } else if (g_strcmp0 (element_name, "shortcut") == 0) { GtkSizeGroup *accel_size_group; GtkSizeGroup *desc_size_group; if (!check_parent (context, "group", error)) return; accel_size_group = g_queue_peek_head (parser_data->column_image_size_groups); desc_size_group = g_queue_peek_head (parser_data->column_desc_size_groups); parser_data->search_item = g_object_new (GB_TYPE_SHORTCUTS_SHORTCUT, "visible", TRUE, NULL); item = g_object_new (GB_TYPE_SHORTCUTS_SHORTCUT, "accelerator-size-group", accel_size_group, "title-size-group", desc_size_group, "visible", TRUE, NULL); g_queue_push_head (parser_data->stack, g_object_ref_sink (item)); } else if (g_strcmp0 (element_name, "gesture") == 0) { GtkSizeGroup *accel_size_group; GtkSizeGroup *desc_size_group; if (!check_parent (context, "group", error)) return; accel_size_group = g_queue_peek_head (parser_data->column_image_size_groups); desc_size_group = g_queue_peek_head (parser_data->column_desc_size_groups); parser_data->search_item = g_object_new (GB_TYPE_SHORTCUTS_GESTURE, "visible", TRUE, NULL); item = g_object_new (GB_TYPE_SHORTCUTS_GESTURE, "desc-size-group", desc_size_group, "icon-size-group", accel_size_group, "visible", TRUE, NULL); g_queue_push_head (parser_data->stack, g_object_ref_sink (item)); } else if (g_strcmp0 (element_name, "property") == 0) { const gchar *name = NULL; const gchar *translatable = NULL; item = g_queue_peek_head (parser_data->stack); if (item == NULL) { g_set_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_TAG, "Property called without a parent object"); return; } if (!g_markup_collect_attributes (element_name, attribute_names, attribute_values, error, G_MARKUP_COLLECT_STRING, "name", &name, G_MARKUP_COLLECT_OPTIONAL | G_MARKUP_COLLECT_STRING, "translatable", &translatable, G_MARKUP_COLLECT_INVALID)) return; g_free (parser_data->property_name); parser_data->property_name = g_strdup (name); parser_data->translatable = (g_strcmp0 (translatable, "yes") == 0); } else { const GSList *stack; const gchar *parent_name; const gchar *our_name; gint line; gint col; stack = g_markup_parse_context_get_element_stack (context); our_name = stack->data; parent_name = stack->next ? stack->next->data : ""; g_markup_parse_context_get_position (context, &line, &col); g_set_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_TAG, "%d:%d: Unknown element <%s> found in <%s>.", line, col, our_name, parent_name); } }
/* * Rename a file. * * Locking: * Locks sfs_renamelock. * Calls check_parent, which locks various directories one at a * time. * Locks the target vnodes and their parents in a complex fashion * (described in detail below) which is carefully arranged so * it won't deadlock with rmdir. Or at least I hope so. * Then unlocks everything. * * The rationale for all this is complex. See the comments below. * * Requires up to 7 buffers. */ static int sfs_rename(struct vnode *absdir1, const char *name1, struct vnode *absdir2, const char *name2) { struct sfs_fs *sfs = absdir1->vn_fs->fs_data; struct sfs_vnode *dir1 = absdir1->vn_data; struct sfs_vnode *dir2 = absdir2->vn_data; struct sfs_vnode *obj1=NULL, *obj2=NULL; struct sfs_dinode *dir1_inodeptr, *dir2_inodeptr; struct sfs_dinode *obj1_inodeptr, *obj2_inodeptr; int slot1=-1, slot2=-1; int result, result2; struct sfs_direntry sd; int found_dir1; /* make gcc happy */ obj2_inodeptr = NULL; /* The VFS layer is supposed to enforce this */ KASSERT(absdir1->vn_fs == absdir2->vn_fs); if (!strcmp(name1, ".") || !strcmp(name2, ".") || !strcmp(name1, "..") || !strcmp(name2, "..")) { return EINVAL; } if (strlen(name2)+1 > sizeof(sd.sfd_name)) { return ENAMETOOLONG; } /* * We only allow one rename to occur at a time. This appears * to be necessary to preserve the consistency of the * filesystem: once you do the parent check (that n1 is not an * ancestor of d2/n2) nothing may be allowed to happen that * might invalidate that result until all of the * rearrangements are complete. If other renames are allowed * to proceed, we'd need to lock every descendent of n1 to * make sure that some ancestor of d2/n2 doesn't get inserted * at some point deep down. This is impractical, so we use one * global lock. * * To prevent certain deadlocks while locking the vnodes we * need, the rename lock goes outside all the vnode locks. */ reserve_buffers(SFS_BLOCKSIZE); lock_acquire(sfs->sfs_renamelock); /* * Get the objects we're moving. * * Lock each directory temporarily. We'll check again later to * make sure they haven't disappeared and to find slots. */ lock_acquire(dir1->sv_lock); result = sfs_lookonce(dir1, name1, &obj1, NULL); lock_release(dir1->sv_lock); if (result) { goto out0; } lock_acquire(dir2->sv_lock); result = sfs_lookonce(dir2, name2, &obj2, NULL); lock_release(dir2->sv_lock); if (result && result != ENOENT) { goto out0; } if (result==ENOENT) { /* * sfs_lookonce returns a null vnode with ENOENT in * order to make our life easier. */ KASSERT(obj2==NULL); } /* * Prohibit the case where obj1 is a directory and it's a direct * ancestor in the tree of dir2 (or is the same as dir2). If * that were to be permitted, it'd create a detached chunk of * the directory tree, and we don't like that. * * If we see dir1 while checking up the tree, found_dir1 is * set to true. We use this info to choose the correct ordering * for locking dir1 and dir2. * * To prevent deadlocks, the parent check must be done without * holding locks on any other directories. */ result = check_parent(dir1, obj1, dir2, &found_dir1); if (result) { goto out0; } /* * Now check for cases where some of the four vnodes we have * are the same. * * These cases are, in the order they are handled below: * * dir1 == obj1 Already checked. * dir2 == obj2 Already checked. * dir2 == obj1 Already checked. * dir1 == obj2 Checked below. * dir1 == dir2 Legal. * obj1 == obj2 Legal, special handling. */ /* * A directory should have no entries for itself other than '.'. * Thus, since we explicitly reject '.' above, the names * within the directories should not refer to the directories * themselves. */ KASSERT(dir1 != obj1); KASSERT(dir2 != obj2); /* * The parent check should have caught this case. */ KASSERT(dir2 != obj1); /* * Check for dir1 == obj2. * * This is not necessarily wrong if obj1 is the last entry in * dir1 (this is essentially "mv ./foo/bar ./foo") but our * implementation doesn't tolerate it. Because we need to * unlink g2 before linking g1 in the new place, it will * always fail complaining that g2 (sv1) isn't empty. We could * just charge ahead and let this happen, but we'll get into * trouble with our locks if we do, so detect this as a * special case and return ENOTEMPTY. */ if (obj2==dir1) { result = ENOTEMPTY; goto out0; } /* * Now we can begin acquiring locks for real. * * If we saw dir1 while doing the parent check, it means * dir1 is higher in the tree than dir2. Thus, we should * lock dir1 before dir2. * * If on the other hand we didn't see dir1, either dir2 is * higher in the tree than dir1, in which case we should lock * dir2 first, or dir1 and dir2 are on disjoint branches of * the tree, in which case (because there's a single rename * lock for the whole fs) it doesn't matter what order we lock * in. * * If we lock dir1 first, we don't need to lock obj1 before * dir2, since (due to the parent check) obj1 cannot be an * ancestor of dir2. * * However, if we lock dir2 first, obj2 must be locked before * dir1, in case obj2 is an ancestor of dir1. (In this case we * will find that obj2 is not empty and cannot be removed, but * we must lock it before we can check that.) * * Thus we lock in this order: * * dir1 (if found_dir1) * dir2 * obj2 (if non-NULL) * dir1 (if !found_dir1) * obj1 * * Also, look out for the case where both dirs are the same. * (If this is true, found_dir1 will be set.) */ if (dir1==dir2) { /* This locks "both" dirs */ lock_acquire(dir1->sv_lock); KASSERT(found_dir1); } else { if (found_dir1) { lock_acquire(dir1->sv_lock); } lock_acquire(dir2->sv_lock); } /* * Now lock obj2. * * Note that we must redo the lookup and get a new obj2, as it * may have changed under us. Since we hold the rename lock * for the whole fs, the fs structure cannot have changed, so * we don't need to redo the parent check or any of the checks * for vnode aliasing with dir1 or dir2 above. Note however * that obj1 and obj2 may now be the same even if they weren't * before. */ KASSERT(lock_do_i_hold(dir2->sv_lock)); if (obj2) { VOP_DECREF(&obj2->sv_absvn); obj2 = NULL; } result = sfs_lookonce(dir2, name2, &obj2, &slot2); if (result==0) { KASSERT(obj2 != NULL); lock_acquire(obj2->sv_lock); result = sfs_dinode_load(obj2); if (result) { /* ENOENT would confuse us below; but it can't be */ KASSERT(result != ENOENT); lock_release(obj2->sv_lock); VOP_DECREF(&obj2->sv_absvn); /* continue to check below */ } else { obj2_inodeptr = sfs_dinode_map(obj2); } } else if (result==ENOENT) { /* * sfs_lookonce returns a null vnode and an empty slot * with ENOENT in order to make our life easier. */ KASSERT(obj2==NULL); KASSERT(slot2>=0); } if (!found_dir1) { lock_acquire(dir1->sv_lock); } /* Postpone this check to simplify the error cleanup. */ if (result != 0 && result != ENOENT) { goto out1; } /* * Now reload obj1. */ KASSERT(lock_do_i_hold(dir1->sv_lock)); VOP_DECREF(&obj1->sv_absvn); obj1 = NULL; result = sfs_lookonce(dir1, name1, &obj1, &slot1); if (result) { goto out1; } /* * POSIX mandates that if obj1==obj2, we succeed and nothing * happens. This is somewhat stupid if obj1==obj2 and dir1 != dir2, * but we'll go with POSIX anyway. */ if (obj1==obj2) { result = 0; VOP_DECREF(&obj1->sv_absvn); obj1 = NULL; goto out1; } lock_acquire(obj1->sv_lock); result = sfs_dinode_load(obj1); if (result) { lock_release(obj1->sv_lock); VOP_DECREF(&obj1->sv_absvn); obj1 = NULL; goto out1; } obj1_inodeptr = sfs_dinode_map(obj1); result = sfs_dinode_load(dir2); if (result) { goto out2; } dir2_inodeptr = sfs_dinode_map(dir2); result = sfs_dinode_load(dir1); if (result) { goto out3; } dir1_inodeptr = sfs_dinode_map(dir1); /* * One final piece of paranoia: make sure dir2 hasn't been rmdir'd. * (If dir1 was, the obj1 lookup above would have failed.) */ if (dir2_inodeptr->sfi_linkcount==0) { result = ENOENT; goto out4; } /* * Now we have all the locks we need and we can proceed with * the operation. */ /* At this point we should have valid slots in both dirs. */ KASSERT(slot1>=0); KASSERT(slot2>=0); if (obj2 != NULL) { /* * Target already exists. * Must be the same type (file or directory) as the source, * and if a directory, must be empty. Then unlink it. */ if (obj1_inodeptr->sfi_type == SFS_TYPE_DIR) { if (obj2_inodeptr->sfi_type != SFS_TYPE_DIR) { result = ENOTDIR; goto out4; } result = sfs_dir_checkempty(obj2); if (result) { goto out4; } /* Remove the name */ result = sfs_dir_unlink(dir2, slot2); if (result) { goto out4; } /* Dispose of the directory */ KASSERT(dir2_inodeptr->sfi_linkcount > 1); KASSERT(obj2_inodeptr->sfi_linkcount == 2); dir2_inodeptr->sfi_linkcount--; obj2_inodeptr->sfi_linkcount -= 2; sfs_dinode_mark_dirty(dir2); sfs_dinode_mark_dirty(obj2); /* ignore errors on this */ sfs_itrunc(obj2, 0); } else { KASSERT(obj1->sv_type == SFS_TYPE_FILE); if (obj2->sv_type != SFS_TYPE_FILE) { result = EISDIR; goto out4; } /* Remove the name */ result = sfs_dir_unlink(dir2, slot2); if (result) { goto out4; } /* Dispose of the file */ KASSERT(obj2_inodeptr->sfi_linkcount > 0); obj2_inodeptr->sfi_linkcount--; sfs_dinode_mark_dirty(obj2); } sfs_dinode_unload(obj2); lock_release(obj2->sv_lock); VOP_DECREF(&obj2->sv_absvn); obj2 = NULL; } /* * At this point the target should be nonexistent and we have * a slot in the target directory we can use. Create a link * there. Do it by hand instead of using sfs_dir_link to avoid * duplication of effort. */ KASSERT(obj2==NULL); bzero(&sd, sizeof(sd)); sd.sfd_ino = obj1->sv_ino; strcpy(sd.sfd_name, name2); result = sfs_writedir(dir2, slot2, &sd); if (result) { goto out4; } obj1_inodeptr->sfi_linkcount++; sfs_dinode_mark_dirty(obj1); if (obj1->sv_type == SFS_TYPE_DIR && dir1 != dir2) { /* Directory: reparent it */ result = sfs_readdir(obj1, DOTDOTSLOT, &sd); if (result) { goto recover1; } if (strcmp(sd.sfd_name, "..")) { panic("sfs: %s: rename: moving dir: .. is not " "in slot %d\n", sfs->sfs_sb.sb_volname, DOTDOTSLOT); } if (sd.sfd_ino != dir1->sv_ino) { panic("sfs: %s: rename: moving dir: .. is i%u " "and not i%u\n", sfs->sfs_sb.sb_volname, sd.sfd_ino, dir1->sv_ino); } sd.sfd_ino = dir2->sv_ino; result = sfs_writedir(obj1, DOTDOTSLOT, &sd); if (result) { goto recover1; } dir1_inodeptr->sfi_linkcount--; sfs_dinode_mark_dirty(dir1); dir2_inodeptr->sfi_linkcount++; sfs_dinode_mark_dirty(dir2); } result = sfs_dir_unlink(dir1, slot1); if (result) { goto recover2; } obj1_inodeptr->sfi_linkcount--; sfs_dinode_mark_dirty(obj1); KASSERT(result==0); if (0) { /* Only reached on error */ recover2: if (obj1->sv_type == SFS_TYPE_DIR) { sd.sfd_ino = dir1->sv_ino; result2 = sfs_writedir(obj1, DOTDOTSLOT, &sd); if (result2) { recovermsg(sfs->sfs_sb.sb_volname, result, result2); } dir1_inodeptr->sfi_linkcount++; sfs_dinode_mark_dirty(dir1); dir2_inodeptr->sfi_linkcount--; sfs_dinode_mark_dirty(dir2); } recover1: result2 = sfs_dir_unlink(dir2, slot2); if (result2) { recovermsg(sfs->sfs_sb.sb_volname, result, result2); } obj1_inodeptr->sfi_linkcount--; sfs_dinode_mark_dirty(obj1); } out4: sfs_dinode_unload(dir1); out3: sfs_dinode_unload(dir2); out2: sfs_dinode_unload(obj1); lock_release(obj1->sv_lock); out1: if (obj2) { sfs_dinode_unload(obj2); lock_release(obj2->sv_lock); } lock_release(dir1->sv_lock); if (dir1 != dir2) { lock_release(dir2->sv_lock); } out0: if (obj2 != NULL) { VOP_DECREF(&obj2->sv_absvn); } if (obj1 != NULL) { VOP_DECREF(&obj1->sv_absvn); } unreserve_buffers(SFS_BLOCKSIZE); lock_release(sfs->sfs_renamelock); return result; }
static void sendcmd(const char *cmd, const char *arg1, const char *arg2) { int i, pipefd, ret; char buf[SMALLBUF], enc[SMALLBUF]; /* insanity */ if (!arg1) return; /* build the request */ snprintf(buf, sizeof(buf), "%s \"%s\"", cmd, pconf_encode(arg1, enc, sizeof(enc))); if (arg2) snprintfcat(buf, sizeof(buf), " \"%s\"", pconf_encode(arg2, enc, sizeof(enc))); snprintf(enc, sizeof(enc), "%s\n", buf); /* see if the parent needs to be started (and maybe start it) */ for (i = 0; i < MAX_TRIES; i++) { pipefd = check_parent(cmd, arg2); if (pipefd == PARENT_STARTED) { /* loop back and try to connect now */ usleep(250000); continue; } /* special case for CANCEL when no parent is running */ if (pipefd == PARENT_UNNECESSARY) return; /* we're connected now */ ret = write(pipefd, enc, strlen(enc)); /* if we can't send the whole thing, loop back and try again */ if ((ret < 1) || (ret != (int) strlen(enc))) { upslogx(LOG_ERR, "write failed, trying again"); close(pipefd); continue; } /* ugh - probably should use select here... */ setup_sigalrm(); alarm(2); ret = read(pipefd, buf, sizeof(buf)); alarm(0); signal(SIGALRM, SIG_IGN); close(pipefd); /* same idea: no OK = go try it all again */ if (ret < 2) { upslogx(LOG_ERR, "read confirmation failed, trying again"); continue; } if (!strncmp(buf, "OK", 2)) return; /* success */ upslogx(LOG_ERR, "read confirmation got [%s]", buf); /* try again ... */ } fatalx(EXIT_FAILURE, "Unable to connect to daemon and unable to start daemon"); }
/* * Unlink a file or directory * N.B. After this call fhp needs an fh_put */ int nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, char *fname, int flen) { struct dentry *dentry, *rdentry; struct inode *dirp; int err; /* N.B. We shouldn't need this test ... handled by dentry layer */ err = nfserr_acces; if (!flen || isdotent(fname, flen)) goto out; err = fh_verify(rqstp, fhp, S_IFDIR, MAY_REMOVE); if (err) goto out; dentry = fhp->fh_dentry; dirp = dentry->d_inode; rdentry = lookup_dentry(fname, dget(dentry), 0); err = PTR_ERR(rdentry); if (IS_ERR(rdentry)) goto out_nfserr; if (!rdentry->d_inode) { dput(rdentry); err = nfserr_noent; goto out; } if (type != S_IFDIR) { /* It's UNLINK */ err = fh_lock_parent(fhp, rdentry); if (err) goto out; err = vfs_unlink(dirp, rdentry); DQUOT_DROP(dirp); fh_unlock(fhp); dput(rdentry); } else { /* It's RMDIR */ /* See comments in fs/namei.c:do_rmdir */ rdentry->d_count++; nfsd_double_down(&dirp->i_sem, &rdentry->d_inode->i_sem); if (!fhp->fh_pre_mtime) fhp->fh_pre_mtime = dirp->i_mtime; fhp->fh_locked = 1; err = -ENOENT; if (check_parent(dirp, rdentry)) err = vfs_rmdir(dirp, rdentry); rdentry->d_count--; DQUOT_DROP(dirp); if (!fhp->fh_post_version) fhp->fh_post_version = dirp->i_version; fhp->fh_locked = 0; nfsd_double_up(&dirp->i_sem, &rdentry->d_inode->i_sem); dput(rdentry); } if (err) goto out_nfserr; if (EX_ISSYNC(fhp->fh_export)) write_inode_now(dirp); out: return err; out_nfserr: err = nfserrno(-err); goto out; }
/* * Rename a file * N.B. After this call _both_ ffhp and tfhp need an fh_put */ int nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, struct svc_fh *tfhp, char *tname, int tlen) { struct dentry *fdentry, *tdentry, *odentry, *ndentry; struct inode *fdir, *tdir; int err; err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_REMOVE); if (err) goto out; err = fh_verify(rqstp, tfhp, S_IFDIR, MAY_CREATE); if (err) goto out; fdentry = ffhp->fh_dentry; fdir = fdentry->d_inode; tdentry = tfhp->fh_dentry; tdir = tdentry->d_inode; /* N.B. We shouldn't need this ... dentry layer handles it */ err = nfserr_perm; if (!flen || (fname[0] == '.' && (flen == 1 || (flen == 2 && fname[1] == '.'))) || !tlen || (tname[0] == '.' && (tlen == 1 || (tlen == 2 && tname[1] == '.')))) goto out; odentry = lookup_dentry(fname, dget(fdentry), 0); err = PTR_ERR(odentry); if (IS_ERR(odentry)) goto out_nfserr; err = -ENOENT; if (!odentry->d_inode) goto out_dput_old; ndentry = lookup_dentry(tname, dget(tdentry), 0); err = PTR_ERR(ndentry); if (IS_ERR(ndentry)) goto out_dput_old; /* * Lock the parent directories. */ nfsd_double_down(&tdir->i_sem, &fdir->i_sem); err = -ENOENT; /* GAM3 check for parent changes after locking. */ if (check_parent(fdir, odentry) && check_parent(tdir, ndentry)) { err = vfs_rename(fdir, odentry, tdir, ndentry); if (!err && EX_ISSYNC(tfhp->fh_export)) { write_inode_now(fdir); write_inode_now(tdir); } } else dprintk("nfsd: Caught race in nfsd_rename"); DQUOT_DROP(fdir); DQUOT_DROP(tdir); nfsd_double_up(&tdir->i_sem, &fdir->i_sem); dput(ndentry); out_dput_old: dput(odentry); if (err) goto out_nfserr; out: return err; out_nfserr: err = nfserrno(-err); goto out; }
int main(int argc, char *argv[]) { const char *prog = xbasename(argv[0]); int i, cmd = 0, checking_flag = 0; printf("Network UPS Tools %s %s\n", prog, UPS_VERSION); /* if no configuration file is specified on the command line, use default */ configfile = xmalloc(SMALLBUF); snprintf(configfile, SMALLBUF, "%s/upsmon.conf", confpath()); configfile = xrealloc(configfile, strlen(configfile) + 1); run_as_user = xstrdup(RUN_AS_USER); while ((i = getopt(argc, argv, "+Dhic:f:pu:VK46")) != -1) { switch (i) { case 'c': if (!strncmp(optarg, "fsd", strlen(optarg))) cmd = SIGCMD_FSD; if (!strncmp(optarg, "stop", strlen(optarg))) cmd = SIGCMD_STOP; if (!strncmp(optarg, "reload", strlen(optarg))) cmd = SIGCMD_RELOAD; /* bad command name given */ if (cmd == 0) help(argv[0]); break; case 'D': nut_debug_level++; break; case 'f': free(configfile); configfile = xstrdup(optarg); break; case 'h': help(argv[0]); break; case 'K': checking_flag = 1; break; case 'p': use_pipe = 0; break; case 'u': free(run_as_user); run_as_user = xstrdup(optarg); break; case 'V': /* just show the banner */ exit(EXIT_SUCCESS); case '4': opt_af = AF_INET; break; case '6': opt_af = AF_INET6; break; default: help(argv[0]); break; } } if (cmd) { sendsignal(prog, cmd); exit(EXIT_SUCCESS); } /* otherwise, we are being asked to start. * so check if a previous instance is running by sending signal '0' * (Ie 'kill <pid> 0') */ if (sendsignal(prog, 0) == 0) { printf("Fatal error: A previous upsmon instance is already running!\n"); printf("Either stop the previous instance first, or use the 'reload' command.\n"); exit(EXIT_FAILURE); } argc -= optind; argv += optind; open_syslog(prog); loadconfig(); if (checking_flag) exit(check_pdflag()); if (shutdowncmd == NULL) printf("Warning: no shutdown command defined!\n"); /* we may need to get rid of a flag from a previous shutdown */ if (powerdownflag != NULL) clear_pdflag(); /* FIXME (else): POWERDOWNFLAG is not defined!! * => fallback to a default value */ if (totalpv < minsupplies) { printf("\nFatal error: insufficient power configured!\n\n"); printf("Sum of power values........: %d\n", totalpv); printf("Minimum value (MINSUPPLIES): %d\n", minsupplies); printf("\nEdit your upsmon.conf and change the values.\n"); exit(EXIT_FAILURE); } if (nut_debug_level < 1) { background(); } else { upsdebugx(1, "debug level is '%d'", nut_debug_level); } /* only do the pipe stuff if the user hasn't disabled it */ if (use_pipe) { struct passwd *new_uid = get_user_pwent(run_as_user); /* === root parent and unprivileged child split here === */ start_pipe(); /* write the pid file now, as we will soon lose root */ writepid(prog); become_user(new_uid); } else { upslogx(LOG_INFO, "Warning: running as one big root process by request (upsmon -p)"); writepid(prog); } /* prep our signal handlers */ setup_signals(); /* reopen the log for the child process */ closelog(); open_syslog(prog); while (exit_flag == 0) { utype_t *ups; /* check flags from signal handlers */ if (userfsd) forceshutdown(); if (reload_flag) reload_conf(); for (ups = firstups; ups != NULL; ups = ups->next) pollups(ups); recalc(); /* make sure the parent hasn't died */ if (use_pipe) check_parent(); /* reap children that have exited */ waitpid(-1, NULL, WNOHANG); sleep(sleepval); } upslogx(LOG_INFO, "Signal %d: exiting", exit_flag); upsmon_cleanup(); exit(EXIT_SUCCESS); }