int main(int argc, char **argv) { gfarm_error_t e; int c, use_conn, flags, op = 0; const char *filename, *filename2 = NULL; char *path; struct op_closure closure; struct gfm_connection *conn; gfarm_error_t (*inode_request_op)(struct gfm_connection *, struct gfp_xdr_context *, void *, const char *) = NULL; gfarm_error_t (*name_request_op)(struct gfm_connection *, struct gfp_xdr_context *, void *, const char *, const char *) = NULL; if (argc > 0) program_name = basename(argv[0]); e = gfarm_initialize(&argc, &argv); if (e != GFARM_ERR_NO_ERROR) { fprintf(stderr, "gfarm_initialize: %s\n", gfarm_error_string(e)); return (EXIT_ERR); } while ((c = getopt(argc, argv, "IJNPQRSp")) != -1) { switch (c) { case OP_INODE_OP: case OP_INODE_OP_NF: case OP_NAME_OP: case OP_NAME2_OP: case OP_NAME2_OP_OL: case OP_REALPATH: case OP_SHOW_SVR: if (op != 0) { fprintf(stderr, "%s : too many options", program_name); usage(); } op = c; break; case 'p': /* for OP_NAME_OP */ open_parent = 1; break; default: fprintf(stderr, "%s: unknown option -%c\n", program_name, c); usage(); } } if (optind == 1) usage(); argc -= optind; argv += optind; switch (op) { case OP_NAME2_OP: case OP_NAME2_OP_OL: use_conn = 1; if (argc != 2) usage(); break; case OP_SHOW_SVR: if (argc != 0) usage(); break; default: if (argc != 1) usage(); break; } filename = argv[0]; if (argc > 0) filename2 = argv[1]; memset(&closure, 0, sizeof(closure)); if (use_conn && (e = gfm_client_connection_and_process_acquire_by_path( "/", &conn)) != GFARM_ERR_NO_ERROR) { fprintf(stderr, "%s: %s", program_name, gfarm_error_string(e)); exit(1); } switch (op) { case OP_INODE_OP: if ((e = gfm_inode_op_modifiable(filename, GFARM_FILE_RDONLY, inode_op_request, inode_op_result, inode_op_success, inode_op_cleanup, NULL, &closure)) != GFARM_ERR_NO_ERROR) { fprintf(stderr, "gfm_inode_op : %s\n", gfarm_error_string(e)); break; } assert(closure.request); assert(closure.result); assert(closure.success); assert(closure.cleanup == 0); printf("%ld\n", (long)closure.f1.ino); break; case OP_INODE_OP_NF: if ((e = gfm_inode_op_no_follow_modifiable(filename, GFARM_FILE_RDONLY, inode_op_request, inode_op_result, inode_op_success, inode_op_cleanup, NULL, &closure)) != GFARM_ERR_NO_ERROR) { fprintf(stderr, "gfm_inode_op_no_follow : %s\n", gfarm_error_string(e)); break; } assert(closure.request); assert(closure.result); assert(closure.success); assert(closure.cleanup == 0); printf("%ld\n", (long)closure.f1.ino); break; case OP_NAME_OP: if ((e = gfm_name_op_modifiable(filename, GFARM_ERR_OPERATION_NOT_PERMITTED, name_op_request, name_op_result, name_op_success, NULL, &closure)) != GFARM_ERR_NO_ERROR) { fprintf(stderr, "gfm_name_op : %s\n", gfarm_error_string(e)); break; } assert(closure.request); assert(closure.result); assert(closure.success); assert(closure.cleanup == 0); assert(strlen(closure.f1.name) > 0); assert(closure.f1.ino > 0); printf("%ld %s\n", (long)closure.f1.ino, closure.f1.name); break; case OP_NAME2_OP: case OP_NAME2_OP_OL: if (op == OP_NAME2_OP) { flags = 0; name_request_op = name2_op_request; } else { flags = GFARM_FILE_SYMLINK_NO_FOLLOW | GFARM_FILE_OPEN_LAST_COMPONENT; closure.is_stat_or_open = 1; inode_request_op = name2_op_ol_request; } if ((e = gfm_name2_op_modifiable(filename, filename2, flags, inode_request_op, name_request_op, name2_op_result, name2_op_success, name2_op_cleanup, NULL, &closure)) != GFARM_ERR_NO_ERROR) { fprintf(stderr, "gfm_name2_op : %s\n", gfarm_error_string(e)); break; } assert(closure.request); assert(closure.result); assert(closure.success); assert(closure.cleanup == 0); assert(strlen(closure.f1.name) > 0); assert(closure.f1.ino > 0); printf("%ld %s %ld %s\n", (long)closure.f1.ino, closure.f1.name, (long)closure.f2.ino, closure.f2.name); break; case OP_REALPATH: if ((e = gfs_realpath(filename, &path)) != GFARM_ERR_NO_ERROR) { fprintf(stderr, "gfs_realpath : %s\n", gfarm_error_string(e)); break; } printf("%s\n", path); free(path); break; case OP_SHOW_SVR: printf("%s:%d\n", gfarm_ctxp->metadb_server_name, gfarm_ctxp->metadb_server_port); e = GFARM_ERR_NO_ERROR; break; default: assert(0); } if (e != GFARM_ERR_NO_ERROR) { switch (e) { case GFARM_ERR_PATH_IS_ROOT: return (EXIT_PATH_ROOT); case GFARM_ERR_NO_SUCH_FILE_OR_DIRECTORY: return (EXIT_NO_SUCH_FILE); case GFARM_ERR_CROSS_DEVICE_LINK: return (EXIT_CROSS_DEVICE); case GFARM_ERR_TOO_MANY_LEVELS_OF_SYMBOLIC_LINK: return (EXIT_MANY_LVL_OF_SYMLNK); case GFARM_ERR_OPERATION_NOT_PERMITTED: return (EXIT_OPE_NOT_PERM); default: return (EXIT_ERR); } } if ((e = gfarm_terminate()) != GFARM_ERR_NO_ERROR) { fprintf(stderr, "gfarm_terminate: %s\n", gfarm_error_string(e)); return (EXIT_ERR); } return (EXIT_OK); }
int main(int argc, char *argv[], char *envp[]) { char *e, *gfarm_url, *local_path, **new_env, *cwd_env, *pwd_env; int i, j, status, envc, rank = -1, nodes = -1; pid_t pid; static const char env_node_rank[] = "GFARM_NODE_RANK="; static const char env_node_size[] = "GFARM_NODE_SIZE="; static const char env_flags[] = "GFARM_FLAGS="; static const char env_gfs_pwd[] = "GFS_PWD="; static const char env_pwd[] = "PWD="; char rankbuf[sizeof(env_node_rank) + GFARM_INT64STRLEN]; char nodesbuf[sizeof(env_node_size) + GFARM_INT64STRLEN]; char flagsbuf[sizeof(env_flags) + 3]; char cwdbuf[PATH_MAX * 2], pwdbuf[PATH_MAX * 2]; e = gfarm_initialize(&argc, &argv); if (e != NULL) { errmsg("gfarm_initialize", e); exit(1); } /* * don't use getopt(3) here, because getopt(3) in glibc refers * argv[] passed to main(), instead of argv[] passed to getopt(3). */ for (i = 1; i < argc; i++) { if (argv[i][0] != '-') break; for (j = 1; argv[i][j] != '\0'; j++) { switch (argv[i][j]) { case 'I': if (argv[i][j + 1] != '\0') { rank = strtol(&argv[i][j+1], NULL, 0); j += strlen(&argv[i][j + 1]); } else if (i + 1 < argc) { rank = strtol(argv[++i], NULL, 0); j = strlen(argv[i]) - 1; } else { errmsg("-I", "missing argument"); print_usage(); } break; case 'N': if (argv[i][j + 1] != '\0') { nodes = strtol(&argv[i][j+1], NULL, 0); j += strlen(&argv[i][j + 1]); } else if (i + 1 < argc) { nodes = strtol(argv[++i], NULL, 0); j = strlen(argv[i]) - 1; } else { errmsg("-N", "missing argument"); print_usage(); } break; case 's': rank = 0; nodes = 1; break; case 'h': case '?': print_usage(); default: fprintf(stderr, "%s: invalid option -- %c\n", progname, argv[i][j]); print_usage(); } } } argc -= i; argv += i; if (argc == 0) print_usage(); e = gfs_realpath(argv[0], &gfarm_url); if (e != NULL) { /* XXX check `e' */ local_path = search_path(argv[0]); } else { e = gfarm_url_program_get_local_path(gfarm_url, &local_path); if (e != NULL) { errmsg(gfarm_url, e); exit(1); } } e = modify_ld_library_path(); if (e != NULL) { errmsg("modify_ld_library_path", e); /* continue */ } /* * the followings are only needed for pid==0 case. * but isn't it better to check errors before fork(2)? * * If gfs_pio_get_node_{rank,size}() fails, continue to * execute as a single process (not parallel processes). */ if (rank == -1) { e = gfs_pio_get_node_rank(&rank); if (e != NULL) rank = 0; } if (nodes == -1) { e = gfs_pio_get_node_size(&nodes); if (e != NULL) nodes = 1; } for (envc = 0; envp[envc] != NULL; envc++) ; new_env = malloc(sizeof(*new_env) * (envc + 5 + 1)); memcpy(cwdbuf, GFARM_URL_PREFIX, GFARM_URL_PREFIX_LENGTH); e = gfs_getcwd(cwdbuf + GFARM_URL_PREFIX_LENGTH, sizeof(cwdbuf) - GFARM_URL_PREFIX_LENGTH); if (e != NULL) { errmsg("cannot get current directory", e); exit(1); } if ((cwd_env = malloc(strlen(cwdbuf) + sizeof(env_gfs_pwd))) == NULL) { fprintf(stderr, "%s: no memory for %s%s\n", progname, env_gfs_pwd, cwdbuf); exit(1); } (void)chdir(cwdbuf); /* rely on syscall hook. it is ok if it fails */ getcwd(pwdbuf, sizeof pwdbuf); pwd_env = malloc(strlen(pwdbuf) + sizeof(env_pwd)); if (pwd_env == NULL) { fprintf(stderr, "%s: no memory for %s%s\n", progname, env_pwd, pwdbuf); exit(1); } envc = 0; for (i = 0; (e = envp[i]) != NULL; i++) { if (memcmp(e, env_node_rank, sizeof(env_node_rank) -1 ) != 0 && memcmp(e, env_node_size, sizeof(env_node_size) -1 ) != 0 && memcmp(e, env_flags, sizeof(env_flags) - 1 ) != 0 && memcmp(e, env_gfs_pwd, sizeof(env_gfs_pwd) - 1) != 0 && memcmp(e, env_pwd, sizeof(env_pwd) - 1 ) != 0) new_env[envc++] = e; } sprintf(rankbuf, "%s%d", env_node_rank, rank); new_env[envc++] = rankbuf; sprintf(nodesbuf, "%s%d", env_node_size, nodes); new_env[envc++] = nodesbuf; sprintf(flagsbuf, "%s%s%s%s", env_flags, gf_profile ? "p" : "", gf_on_demand_replication ? "r" : "", gf_hook_default_global ? "g" : ""); new_env[envc++] = flagsbuf; sprintf(cwd_env, "%s%s", env_gfs_pwd, cwdbuf); new_env[envc++] = cwd_env; sprintf(pwd_env, "%s%s", env_pwd, pwdbuf); new_env[envc++] = pwd_env; new_env[envc++] = NULL; if (gf_stdout == NULL && gf_stderr == NULL) { /* what we need is to call exec(2) */ pid = 0; } else { /* * we have to call fork(2) and exec(2), to close * gf_stdout and gf_stderr by calling gfarm_terminate() * after the child program finished. */ pid = fork(); } switch (pid) { case -1: perror(PROGRAM_NAME ": fork"); status = 255; break; case 0: if (gf_stdout == NULL && gf_stderr == NULL) { /* * not to display profile statistics * on gfarm_terminate() */ gfs_profile(gf_profile = 0); e = gfarm_terminate(); if (e != NULL) errmsg("(child) gfarm_terminate", e); } else { /* * otherwise don't call gfarm_terminate(), because: * - it closes gf_stdout and gf_stderr. * - it causes: * "gfarm_terminate: Can't contact LDAP server" * on the parent process. */ } execve(local_path, argv, new_env); if (errno != ENOEXEC) { perror(local_path); } else { /* * argv[-1] must be available, * because there should be "gfexec" at least. */ argv[-1] = BOURNE_SHELL; argv[0] = local_path; execve(BOURNE_SHELL, argv - 1, new_env); } _exit(255); default: if (waitpid(pid, &status, 0) == -1) { perror(PROGRAM_NAME ": waitpid"); status = 255; } else if (WIFSIGNALED(status)) { fprintf(stderr, "%s: signal %d received%s.\n", gfarm_host_get_self_name(), WTERMSIG(status), WCOREDUMP(status) ? " (core dumped)" : ""); status = 255; } else { status = WEXITSTATUS(status); } break; } /* not to display profile statistics on gfarm_terminate() */ gfs_profile(gf_profile = 0); e = gfarm_terminate(); if (e != NULL) { errmsg("gfarm_terminate", e); exit(1); } exit(status); }