让 Claude Code 在你睡觉时持续运行:完整实战指南

Claude Code 可以通过 -p 标志、权限绕过、循环模式和终端持久化的组合,实现数小时甚至整夜的无人值守运行。开发者社区已经形成了一套可靠的操作手册:容器化运行环境、使用 “Ralph Wiggum” 循环模式、安装四个关键 Hook 防止卡死、保持 CLAUDE.md 精简。

一、消除人工干预的三种模式

Claude Code 提供三个级别的自主运行模式:

模式 1:-p(print/pipe)标志

1
claude -p "查找并修复 auth.py 中的 bug" --allowedTools "Read,Edit,Bash"

模式 2:–permission-mode auto

1
claude --permission-mode auto -p "重构认证模块"

模式 3:–dangerously-skip-permissions

1
claude --dangerously-skip-permissions -p "构建这个功能"

二、Ralph Wiggum 循环

最经过实战验证的长时间自主工作模式——一个 bash while 循环持续向 Claude 喂相同的 prompt。

1
2
3
4
while true; do
claude --dangerously-skip-permissions -p "$(cat PROMPT.md)"
sleep 1
done

三、四个关键 Hook

Hook 作用
No-Ask-Human 阻止 AskUserQuestion 工具调用
Context Monitor 监控上下文,自动注入 /compact
Syntax Check 文件编辑后立即语法检查
Decision Warn 标记破坏性命令

四、tmux 持久化

1
2
3
4
tmux new -s claude-work
claude --permission-mode auto
# Ctrl+B D 分离
tmux attach -t claude-work

五、快速启动清单

  1. git add -A && git commit -m "pre-autonomous checkpoint"
  2. npx cc-safe-setup
  3. tmux new -s overnight
  4. 启动循环,去睡觉

China's Leading AI Tools: Transforming the Global Tech Landscape

China’s Leading AI Tools: Transforming the Global Tech Landscape

In recent years, China has emerged as a global powerhouse in the field of artificial intelligence (AI). With significant investments in research and development, a vast pool of talented engineers, and a vibrant startup ecosystem, Chinese companies have developed a range of AI tools that are not only revolutionizing domestic industries but also making waves around the world. In this article, we will explore some of the most remarkable AI tools hailing from China, their features, applications, and the impact they are having on various sectors globally.

Understanding China’s AI Ascendancy

China’s rapid progress in AI is no accident. The government has been actively promoting AI development through strategic initiatives, pouring substantial funds into research institutions and startups. This support, combined with a large population that provides abundant data for training AI models, has created a fertile ground for innovation. Chinese tech giants and innovative startups alike have been quick to capitalize on these advantages, resulting in the creation of some truly game - changing AI tools.

Alibaba Cloud’s Qwen - A Multifaceted AI Powerhouse

Natural Language Processing Prowess

Alibaba Cloud’s Qwen is a leading language model with capabilities that rival the best in the world. It has been trained on an extensive corpus of text, enabling it to understand and generate human language with remarkable fluency. For example, in content creation, Qwen can generate high - quality articles, blog posts, and product descriptions. A marketing team in a global e - commerce company could use Qwen to quickly generate product descriptions in multiple languages, saving countless hours of manual writing.

Industry - Specific Applications

Qwen has been tailored for various industries. In the financial sector, it can analyze market trends, news articles, and financial reports to provide valuable insights for investment decisions. In healthcare, it can assist doctors in diagnosing diseases by analyzing patient symptoms and medical literature. A hospital in a developing country might use Qwen to help its doctors access the latest medical research and make more informed decisions, even if they have limited resources.

Advantages in Multilingual Support

One of Qwen’s stand - out features is its excellent multilingual support. With China’s growing global trade and business connections, Qwen can translate text accurately between multiple languages, breaking down language barriers. A multinational corporation with operations in China and other countries can use Qwen to communicate seamlessly with its international teams, ensuring that information is conveyed clearly and correctly.

ByteDance’s Cloud 雀 - Empowering Visual Creativity

Image and Video Generation

Cloud 雀,developed by ByteDance, is a powerful AI tool in the realm of visual content. It can generate high - resolution images and engaging videos from simple text prompts. For instance, a small advertising agency in Europe could use Cloud 雀 to quickly create eye - catching images for its clients’ social media campaigns. Instead of spending a fortune on professional photographers or graphic designers, they can simply describe the concept they want, and Cloud 雀 will bring it to life.

Video Editing Made Easy

In addition to generation, Cloud 雀 also simplifies video editing. It can automatically edit videos, adding transitions, music, and special effects based on the content. A content creator on YouTube, who is based in South America, can use Cloud 雀 to edit their vlogs more efficiently. They can input their raw footage and some basic instructions, and Cloud 雀 will produce a polished video ready for upload.

Integration with Social Media Platforms

ByteDance’s influence in the social media space means that Cloud 雀 can be easily integrated with popular platforms. This integration allows users to directly share their AI - created visual content on platforms like TikTok (which is owned by ByteDance) and other social media channels. A young influencer in Asia can use Cloud 雀 to create unique content and quickly share it with their followers, enhancing their online presence.

Tencent’s AI - Empowered Healthcare Solutions

Medical Image Diagnosis

Tencent has developed AI tools that are making a significant impact in healthcare, particularly in medical image diagnosis. Their AI algorithms can analyze X - rays, MRIs, and CT scans with high accuracy, helping doctors detect diseases such as cancer and pneumonia at an early stage. In a rural hospital in Africa, where there may be a shortage of experienced radiologists, Tencent’s AI - based diagnostic tool can assist local doctors in interpreting medical images, potentially saving lives.

Patient Monitoring and Prediction

Another aspect of Tencent’s healthcare AI is patient monitoring and prediction. The tool can analyze a patient’s vital signs, medical history, and lifestyle data to predict the likelihood of developing certain diseases or complications. A healthcare provider in North America can use this tool to proactively manage the health of their patients, intervening early to prevent serious health issues.

Telemedicine Support

With the rise of telemedicine, Tencent’s AI tools also play a crucial role. They can facilitate remote consultations by providing real - time translation (using language AI capabilities) during doctor - patient interactions, and by analyzing patient data collected at home through wearable devices. A patient in a remote area of Australia can consult with a specialist in China, with Tencent’s AI ensuring smooth communication and accurate diagnosis support.

DJI’s Intelligent Drone Technologies - AI in the Skies

Autonomous Flight and Obstacle Avoidance

DJI, a world - renowned drone manufacturer based in China, has integrated AI into its drones to enable autonomous flight and advanced obstacle avoidance. Their drones can fly along pre - programmed routes, adjust their flight paths in real - time to avoid obstacles, and even land safely in challenging conditions. A wildlife conservation team in the Amazon rainforest can use DJI’s AI - equipped drones to monitor endangered species without disturbing their habitats. The drones can autonomously navigate through the dense forest, capturing valuable data on the animals’ behavior and population.

Precision Agriculture Applications

In agriculture, DJI’s drones are being used for precision farming. The AI - powered drones can analyze crop health by capturing high - resolution images and using machine learning algorithms to detect signs of disease, nutrient deficiencies, or water stress. A large - scale farmer in the United States can use these drones to optimize their irrigation and fertilization schedules, increasing crop yields while reducing resource waste.

Aerial Photography and Filmmaking

For the creative industry, DJI’s drones offer AI - enhanced features for aerial photography and filmmaking. The drones can track moving subjects, maintain stable camera angles, and capture stunning footage. A film production company in Europe can use DJI drones to add unique aerial perspectives to their movies, enhancing the visual experience for the audience.

The Impact of Chinese AI Tools on Global Industries

Transforming Manufacturing

Chinese AI tools are revolutionizing the manufacturing sector globally. AI - powered robots and automation systems are being used to improve production efficiency, quality control, and supply chain management. For example, Foxconn, a major electronics manufacturer in China, has implemented AI - enabled robots in its factories. These robots can perform complex tasks with high precision, reducing errors and increasing production speed. This model is being replicated by manufacturing companies around the world, as they seek to stay competitive in the global market.

Boosting E - commerce

In the e - commerce industry, Chinese AI tools are enhancing the customer experience. Recommendation engines powered by AI analyze customer browsing and purchase history to provide personalized product recommendations. Platforms like Alibaba’s Taobao use these AI - driven recommendation systems to help customers discover new products they may be interested in. This not only increases customer satisfaction but also boosts sales for merchants. E - commerce companies in other countries are looking to adopt similar AI - based strategies to improve their competitiveness.

Advancing Education

AI tools from China are also making inroads into the education sector. Intelligent tutoring systems can adapt to individual students’ learning styles and paces, providing personalized learning experiences. For example, some Chinese - developed AI - education platforms can analyze students’ performance on practice tests, identify areas of weakness, and provide targeted learning materials. Schools and educational institutions in different parts of the world are exploring the use of these AI - enabled educational tools to improve learning outcomes.

Challenges and Future Outlook

Ethical and Regulatory Concerns

As with any powerful technology, Chinese AI tools face ethical and regulatory challenges. Issues such as data privacy, algorithmic bias, and the potential for job displacement need to be carefully addressed. For example, as AI tools collect and analyze vast amounts of data, ensuring the privacy and security of this data is crucial. Governments around the world are starting to develop regulations to govern the use of AI, and Chinese companies will need to comply with these regulations while continuing to innovate.

Global Competition and Collaboration

The global AI landscape is highly competitive, with companies from various countries vying for market share. Chinese AI companies will need to continue to differentiate themselves through innovation and high - quality products. At the same time, there is also room for collaboration. For example, in the fight against global challenges such as climate change, Chinese and international AI companies could work together to develop solutions. By sharing knowledge and resources, they can accelerate the development of AI - based technologies that benefit the entire world.

Continued Innovation and Expansion

Looking to the future, Chinese AI tools are expected to continue evolving and expanding into new areas. With ongoing research and development, we can anticipate even more advanced natural language processing, computer vision, and machine learning capabilities. Chinese companies may also explore new applications in emerging fields such as quantum computing and edge computing, further pushing the boundaries of what AI can achieve.

Conclusion

China’s leading AI tools are already making a significant impact on the global tech landscape. From language models that enable seamless communication to visual content creation tools that inspire creativity, and from healthcare solutions that save lives to intelligent drones that transform industries, these AI tools are enhancing productivity, improving lives, and driving innovation worldwide. As China continues to invest in AI research and development, and as Chinese companies navigate the challenges of the global market, we can expect even more remarkable AI tools to emerge in the future, further strengthening China’s position as a global AI leader.

FAQs

Are Chinese AI tools only applicable in China?

No, Chinese AI tools are designed to be used globally. Many of them offer multilingual support and are being adopted by companies and individuals in various countries across different industries.

How do Chinese AI tools compare to those from other countries?

Chinese AI tools are highly competitive. They often leverage China’s large data resources and advanced research capabilities. In some areas, such as natural language processing and visual content generation, Chinese AI tools are at the forefront of innovation.

What is the future of Chinese AI tool development?

The future looks bright. With continued government support, investment in R & D, and a talented workforce, Chinese AI tools are expected to expand into new industries, improve existing capabilities, and contribute more to solving global challenges.

Do Chinese AI tools respect data privacy?

Chinese companies are increasingly aware of data privacy issues. They are implementing strict data protection measures and complying with international and domestic regulations to ensure the privacy and security of user data.

Can small businesses afford to use Chinese AI tools?

Many Chinese AI tools offer different pricing models, including options for small businesses. Some tools provide free - to - use basic versions or affordable subscription plans, making them accessible to businesses of all sizes.

5 AI Code Editors to Transform Your Development Workflow in 2025: A Global Guide

5 AI Code Editors to Transform Your Development Workflow in 2025: A Global Guide

In 2025, the landscape of software development has been reshaped by AI-driven innovation—and nowhere is this more evident than in AI code editors. These tools have moved beyond basic code suggestions to become collaborative partners: they analyze your codebase, fix bugs with 90% accuracy, edit multiple files simultaneously, and even automate repetitive tasks. For developers across the globe—whether you’re a solo coder in Tokyo, a startup team in Berlin, or an enterprise engineer in Toronto—AI code editors save hours of work, reduce frustration, and let you focus on creative problem-solving.

This guide breaks down the top 5 AI code editors of 2025, each with unique strengths to fit different workflows, budgets, and technical needs. We’ll explore their key features, real-world use cases, pros and cons, and who they’re best suited for—so you can choose the tool that elevates your coding to the next level.

Why AI Code Editors Matter in 2025: The Global Developer’s Advantage

Before diving into the tools, let’s clarify why AI code editors have become non-negotiable for modern developers:

  • Contextual intelligence: Unlike traditional editors, AI-powered tools understand your code’s structure, dependencies, and purpose—so suggestions aren’t just correct, but relevant to your project.

  • Time savings: Tasks that once took hours (e.g., debugging a complex error, writing boilerplate code, updating documentation) can now be done in minutes.

  • Reduced friction: No more switching between forums, documentation, and terminals—AI editors answer questions, run scripts, and fix issues directly in your workspace.

  • Global collaboration: For distributed teams, AI editors standardize coding styles, auto-generate context for new hires, and bridge language gaps (many support multilingual queries).

In 2025, the best AI code editors don’t just “help” you code—they transform how you approach development. Let’s explore the top options.

  1. Cursor: The Go-To for Quick Edits and Comprehensive AI Assistance

What Is Cursor?

Cursor is a lightweight, fast AI code editor built for developers who prioritize efficiency. It’s designed to handle everything from small bug fixes to building full applications—all with minimal setup. Developed with a focus on “code understanding,” Cursor doesn’t just generate snippets; it analyzes your entire project to provide context-aware solutions.

Key Features (2025 Update)

  • Code-Centric Chat: Chat directly with your source code to ask questions like, “Why is this function throwing an error?” or “Refactor this module to use TypeScript.” The AI references your project files to give precise answers.

  • Multi-File Editing: Edit or create multiple related files at once (e.g., update a React component and its corresponding test file) with a single instruction.

  • Bug Finder: Automatically scan your code for syntax errors, logical bugs, and performance issues—with step-by-step fixes.

  • Universal Autocomplete: Supports autocomplete for 50+ programming languages (Python, JavaScript, Rust, etc.) and file types (Markdown, JSON, YAML).

  • Terminal Integration: Get AI-powered autocomplete for terminal commands (e.g., Git, Docker, AWS CLI) to reduce typos and speed up workflow.

Real-World Use Case

Maria, a frontend developer in Mexico City, uses Cursor to build tutorial projects for her YouTube channel. “When I need to create a sample e-commerce UI, I tell Cursor, ‘Build a React checkout form with validation and Redux integration,’” she says. “It generates the component, test file, and Redux slice—all in 2 minutes. I can focus on explaining the code instead of writing it.”

Pros and Cons

ProsConsBlazing fast (starts in <3 seconds)Full features require a paid subscription ($15/month for individuals)Intuitive interface (no steep learning curve)Limited offline functionality (relies on cloud AI models)Excellent for small-to-medium projectsLess optimized for monorepos with 1000+ filesSupports all major programming languages

Who Should Use Cursor?

  • Solo developers and content creators (tutorials, side projects)

  • Teams needing quick turnaround on small tasks (bug fixes, feature prototypes)

  • Beginners learning to code (AI chat explains concepts in plain language)

  1. Windsurf: Autonomous Task Execution for Iterative Development

What Is Windsurf?

Windsurf is 2025’s breakout AI code editor, designed for developers who want AI to execute tasks independently—not just suggest code. Its “agentic workflow” lets the AI run scripts, check outputs, and iterate on solutions until your request is fully resolved. Think of it as a junior developer who works 24/7 and never gets tired.

Key Features (2025 Update)

Autonomous Agent Mode: Tell Windsurf a goal (e.g., “Train a Random Forest model for credit score prediction”), and it will:

  • Create or edit necessary files (Python scripts, requirements.txt, data preprocessing code)

  • Run tests to validate functionality

  • Fix errors (e.g., missing dependencies, data formatting issues)

  • Document changes (adds comments, updates READMEs)

  • Interactive Iteration: If the first result isn’t perfect, you can refine it with follow-up prompts (“Add cross-validation” or “Optimize for imbalanced data”).

  • Type Hint & Error Prevention: Automatically adds type hints, try-except blocks, and input validation to improve code quality.

  • GitOps Integration: Syncs with Git to commit changes, create branches, and even open pull requests—all from the editor.

Real-World Use Case

Raj, a data scientist in Bangalore, uses Windsurf to build machine learning pipelines. “I used to spend 3 days setting up a model training workflow,” he says. “Now I tell Windsurf, ‘Build a pipeline that loads CSV data, imputes missing values, trains a model, and saves it with versioning.’ It does it in 30 minutes—including testing edge cases I would have missed.”

Pros and Cons

ProsConsAutonomous task execution (no manual step-by-step)Subscription-only ($20/month; no free tier)Excellent for data science and backend projectsSteeper learning curve than CursorAutomatically documents changesUses more system resources (needs 8GB+ RAM)Integrates with Git and cloud platforms (AWS, GCP)

Who Should Use Windsurf?

  • Data scientists and backend developers (complex, multi-step tasks)

  • Teams working on iterative projects (e.g., model tuning, API development)

  • Developers who want to automate repetitive workflows (e.g., setting up Docker containers)

  1. VSCode (with GitHub Copilot): The Free, Ecosystem-Powered Workhorse

What Is VSCode + GitHub Copilot?

In 2025, Microsoft made a game-changing move: GitHub Copilot is now free for all VSCode users (previously a $19/month subscription). VSCode—already the most popular code editor globally—now comes with built-in AI capabilities, making it accessible to developers of all budgets. Copilot integrates seamlessly with VSCode’s ecosystem, including extensions, terminals, and GitHub.

Key Features (2025 Update)

  • Free GitHub Copilot: Generates code, fixes bugs, and explains logic—no subscription required. Supports 100+ languages, from Python to COBOL.

  • Ecosystem Integration: Copilot works across GitHub (pull requests, issues), VSCode extensions (e.g., Docker, Kubernetes), and even the terminal (Copilot CLI for command suggestions).

  • Context-Aware Suggestions: Analyzes your open files, Git history, and project structure to provide relevant code snippets.

  • Multilingual Support: Ask questions or give instructions in 20+ languages (Spanish, Hindi, Japanese) for global teams.

Real-World Use Case

Aisha, a junior developer in Nairobi, uses VSCode + Copilot to learn and contribute to open-source projects. “I’m new to React, so when I’m working on a PR, I ask Copilot, ‘Explain how this hook works,’” she says. “It breaks it down in simple terms, and the free access means I don’t have to choose between learning tools and paying rent.”

Pros and Cons

ProsCons100% free (no hidden costs)Less accurate than paid tools (occasional irrelevant suggestions)Massive ecosystem (10k+ extensions)Limited autonomous task execution (needs more manual guidance)Works offline for basic tasksSlower response times during peak hoursIntegrates with GitHub (pull requests, issues)

Who Should Use VSCode + GitHub Copilot?

  • Beginners and students (free access, learning resources)

  • Teams on a tight budget (no subscription fees)

  • Developers who rely on VSCode extensions (e.g., frontend devs using ESLint, Prettier)

  • Open-source contributors (seamless GitHub integration)

  1. Zed: The Rust-Powered Speed Demon for Performance-Conscious Devs

What Is Zed?

Zed is 2025’s fastest AI code editor—built entirely with Rust (a language known for speed and reliability). It leverages multiple CPU cores and your GPU to deliver real-time AI responses, even for large codebases. Zed is popular among developers who hate waiting: its AI suggestions appear in <100ms, and it can handle monorepos with 10,000+ files without lag.

Key Features (2025 Update)

  • Blazing Fast Performance: Rust’s memory efficiency and GPU acceleration mean Zed runs 2–3x faster than VSCode or Cursor.

  • Flexible AI Integration: Use Zed’s built-in AI, connect to external models (Anthropic Claude 3.5, OpenAI GPT-4o), or run LLMs locally via Ollama (for privacy-sensitive projects).

  • Multi-User Collaboration: Real-time co-editing with AI assistance—great for distributed teams (e.g., a developer in London and a teammate in Sydney working on the same file).

  • Customizable Workspace: Tailor the UI, keybindings, and AI behavior to your workflow (e.g., disable autocomplete for specific files).

Real-World Use Case

Liam, a backend engineer at a fintech startup in Toronto, uses Zed for a monorepo with 5,000+ Python files. “With VSCode, opening the repo took 5 minutes and autocomplete lagged,” he says. “Zed opens in 30 seconds, and AI suggestions pop up instantly—even when I’m editing a file with 1,000 lines of code. It’s a game-changer for productivity.”

Pros and Cons

ProsConsFastest AI response times ( <100ms)AI features are less polished than Cursor/WindsurfHandles large monorepos with easeLimited mobile support (no iPad/Android app)Supports local LLMs (privacy-focused)Free tier has usage limits (100 AI queries/day)Real-time co-editingPaid plan is $12/month

Who Should Use Zed?

  • Developers working on large codebases (monorepos, enterprise projects)

  • Rust enthusiasts (Zed’s codebase is open-source and Rust-focused)

  • Teams needing real-time collaboration (e.g., startup squads)

  • Privacy-conscious developers (local LLM support)

  1. PearAI: The VSCode-Based Tool with Potential (Needs Improvement)

What Is PearAI?

PearAI is an AI code editor built as an extension for VSCode—targeting developers who want to customize their AI setup. It lets you connect to your own AI models (via API or local deployment) instead of relying on the editor’s built-in models. While PearAI has potential, it’s still maturing: its 2025 update fixed some bugs but hasn’t closed the gap with leading tools.

Key Features (2025 Update)

  • Custom AI Integration: Connect to any LLM (e.g., OpenAI GPT-4o, Mistral, Llama 3) via API, or run models locally (e.g., Llama 3 70B on your laptop).

  • Context-Aware Chat: Ask questions about your codebase (e.g., “Where is the user authentication logic?”) and get answers based on open files.

  • Autocomplete & Refactoring: Basic AI-powered suggestions for code completion and refactoring (e.g., converting a function to a class).

  • Team Sharing: Save custom AI configurations (e.g., model API keys, prompt templates) and share them with your team.

Real-World Use Case

Carlos, a DevOps engineer in Madrid, uses PearAI with a local Llama 3 model for sensitive infrastructure code. “I can’t send production Dockerfiles to cloud AI models,” he says. “PearAI lets me run Llama 3 on my machine, so all code stays local. It’s not as fast as Zed, but it solves a critical privacy problem.”

Pros and Cons

ProsConsCustom AI model support (local/cloud)Slow response times (1–2 seconds per suggestion)Integrates with VSCode (familiar interface)Fewer features than competitors (no multi-file editing)Privacy-focused (local LLM option)Complicated setup (needs API key/config for custom models)Free tier available (limited features)Infrequent updates (last major release was 3 months ago)

Who Should Use PearAI?

  • Developers needing custom AI models (e.g., local LLMs, enterprise-specific models)

  • VSCode loyalists who don’t want to switch editors

  • Privacy-focused teams (e.g., healthcare, finance)

  • Developers willing to trade polish for customization

2025 AI Code Editor Comparison: Choose the Right Tool for You

To simplify your decision, here’s a side-by-side comparison of the top 5 tools:

FeatureCursorWindsurfVSCode + CopilotZedPearAIPrice$15/month (free tier: 50 queries/day)$20/month (no free tier)FreeFree (100 queries/day); $12/month (unlimited)Free (basic); $10/month (custom models)SpeedFast ( <500ms)Medium (1–1.5s)Medium (1–2s)Fastest ( <100ms)Slow (1–2s)AI AutonomyLow (needs guidance)High (runs tasks independently)Low (basic suggestions)Medium (some autonomy)Low (basic suggestions)Best ForQuick edits, tutorialsData science, backendBeginners, free usersLarge codebases, speedCustom models, privacyOffline SupportLimitedNoBasicYes (local LLMs)Yes (local LLMs)

Conclusion: Elevate Your Coding with AI in 2025

AI code editors are no longer “nice-to-have”—they’re essential tools for staying competitive in 2025’s fast-paced development landscape. Whether you prioritize speed (Zed), autonomy (Windsurf), cost (VSCode + Copilot), or customization (PearAI), there’s a tool that fits your workflow.

Here’s a final recap to guide your choice:

  • Choose Cursor if you want fast, intuitive AI for small-to-medium projects.

  • Choose Windsurf if you need AI to run complex, multi-step tasks independently.

  • Choose VSCode + Copilot if you’re on a budget or already use VSCode.

  • Choose Zed if you work on large codebases and hate waiting for AI responses.

  • Choose PearAI if you need custom AI models (local or cloud) and don’t mind a less polished experience.

No matter which tool you pick, the goal is the same: let AI handle the repetitive, time-consuming work so you can focus on what matters most—building innovative software that solves real problems. Try one (or more!) today and see how AI transforms your coding workflow.

Qoder: The Agentic Coding Platform Transforming Professional Software Development Globally

Qoder: The Agentic Coding Platform Transforming Professional Software Development Globally

In the fast-paced world of professional software development, teams and individual developers are constantly seeking tools that can streamline workflows, enhance collaboration, and automate complex tasks. Enter Qoder – an innovative agentic coding platform designed to revolutionize how software is built, documented, and maintained. Whether you’re a solo developer tackling a passion project, a team lead managing a cross-functional engineering team, or an open-source maintainer coordinating contributors worldwide, Qoder brings a suite of powerful features to help you think deeper, code smarter, and build better.

What Is Qoder, and Why Does It Matter for Developers?

At its core, Qoder is an agentic coding platform tailored for professional software development. Unlike basic code suggestion tools that offer piecemeal lines of code, Qoder unites three key pillars to deliver end-to-end value: enhanced context engineering, intelligent AI agents, and in-repo documentation. This combination allows the platform to deeply understand your codebase, adapt to your project’s unique needs, and automate tasks that once required hours of manual work.

For developers and teams across the globe, Qoder addresses critical pain points in the software development lifecycle:

  • Disconnected context: Many tools fail to maintain a consistent understanding of a codebase’s structure, dependencies, and coding standards across sessions. Qoder’s persistent memory solves this by preserving project-specific context.

  • Outdated documentation: Keeping docs in sync with code is a constant battle. Qoder’s auto-updated Repo Wiki eliminates this chore, ensuring documentation always reflects the latest codebase changes.

  • Inefficient task delegation: Complex tasks like building a new feature or refactoring legacy code often require manual orchestration. Qoder’s Quest Mode lets you delegate these tasks to AI agents asynchronously, freeing you to focus on high-impact work.

  • Tool fragmentation: Developers waste time switching between Git clients, documentation tools, and AI models. Qoder integrates seamlessly with Git/GitHub, supports top AI models (Claude, GPT, Gemini), and runs on Windows and macOS – all in one unified workspace.

Qoder’s Top Features: Built for Global Development Teams

Qoder’s feature set is designed to solve real-world challenges faced by developers everywhere. Each tool is engineered to work in harmony, creating a cohesive workflow that adapts to your team’s size, project type, and technical stack. Let’s break down the platform’s most impactful capabilities:

1. Agentic Coding Platform: AI Agents That Handle Structured Tasks

Qoder’s intelligent AI agents are more than just code generators – they’re collaborative partners that tackle structured development tasks. Unlike tools that suggest isolated code snippets, these agents can:

  • Refactor entire modules while preserving functionality and adhering to your coding style.

  • Debug complex issues by cross-referencing codebase context and error logs.

  • Implement multi-step features (e.g., adding user authentication, integrating a third-party API) with minimal human oversight.

  • Generate unit tests that cover edge cases, ensuring code reliability.

This is a game-changer for teams in time zones across the globe: a developer in Tokyo can delegate a task to an AI agent at the end of their day, and a colleague in New York can review the completed work first thing in the morning – no manual handoff required.

2. Enhanced Context Engineering: AI That Truly Understands Your Code

The biggest limitation of many AI coding tools is their lack of deep context. Qoder solves this with enhanced context engineering – a system that aggregates and updates information from multiple sources (code files, Git history, documentation, and team guidelines) to build a holistic view of your codebase.

For example, if you ask Qoder to “optimize the checkout flow,” the platform doesn’t just generate generic optimization code. It:

  • Reviews the existing checkout logic, including dependencies on payment gateways and user data models.

  • References your team’s coding standards (stored in Qoder’s Memory) to ensure consistency.

  • Checks the Repo Wiki for documentation on past checkout-related updates.

  • Considers recent Git commits to avoid conflicting with ongoing work.

This level of context ensures AI suggestions are not just correct, but relevant to your project – a critical advantage for global teams working on complex, custom codebases.

3. Quest Mode: Asynchronous Task Delegation for Busy Teams

One of Qoder’s most popular features is Quest Mode – a tool that lets you delegate complex, time-consuming tasks to AI agents and receive complete, ready-to-use results. Unlike real-time AI chat, Quest Mode is asynchronous, meaning you can set a task and come back later to find it done.

How it works:

Define the task (e.g., “Build a user profile API endpoint with input validation and error handling”).

Add context (e.g., “Use our existing Express.js framework, follow the REST API guidelines in the Repo Wiki, and integrate with the user database”).

Submit the “Quest” to Qoder’s AI agents.

Receive a notification when the task is complete – including code, tests, and a summary of changes.

This is ideal for:

  • Solo developers who need to multitask (e.g., delegate API development while designing a UI).

  • Global teams working across time zones (e.g., a London-based developer delegates a task before logging off, and a Sydney-based teammate reviews it the next day).

  • Team leads who want to free up senior developers from repetitive work (e.g., delegating boilerplate code generation to AI).

4. Repo Wiki: Auto-Updated Documentation That Lives With Your Code

Outdated documentation is a universal frustration for developers. Qoder’s Repo Wiki eliminates this problem by automatically generating and updating documentation that lives directly in your repository. Unlike static wikis (e.g., Confluence pages that are forgotten after launch), the Repo Wiki:

  • Updates in real time when you make code changes (e.g., if you add a new function to a utility file, the Wiki automatically adds documentation for that function).

  • Syncs bidirectionally with GitHub Wiki – so if you update the Repo Wiki in Qoder, the changes appear in GitHub, and vice versa.

  • Is accessible to AI agents, chat, and the CLI – ensuring AI suggestions and team decisions are always based on the latest docs.

For example, if a new hire in Toronto joins your team, they don’t need to spend hours reading outdated READMEs or pinging teammates for clarification. They can open the Repo Wiki to find:

  • Auto-generated architecture diagrams of the codebase.

  • Up-to-date API references with example requests/responses.

  • Step-by-step guides for setting up the local development environment.

  • Notes on past bugs and how they were resolved.

This not only speeds up onboarding but also reduces knowledge silos – a key benefit for distributed teams.

5. Live Project Context & Memory: Consistent Guidance Across Sessions

Qoder’s persistent Memory system stores project-specific information (coding standards, team guidelines, tool preferences, and past decisions) so that every AI interaction is consistent – even if you log off and come back weeks later.

For example, if your team decides “we use ESLint with Airbnb rules” or “all database queries must go through the data access layer,” you can save these guidelines to Memory. From that point on:

  • AI agents will automatically follow these rules when generating code.

  • New team members will see these guidelines in the Repo Wiki and AI suggestions.

  • The CLI will flag code that violates these standards during development.

This consistency is invaluable for global teams where members may have different coding backgrounds or join mid-project. It ensures everyone – from a junior developer in Mumbai to a senior engineer in Toronto – is working from the same playbook.

6. Git/GitHub Integration: Seamless Collaboration for Distributed Teams

Qoder integrates seamlessly with Git and GitHub – the most widely used version control tools in the world. This integration ensures your code, documentation, and context stay in sync across your team’s workflow:

  • The Repo Wiki is stored in your Git repository, so it’s version-controlled alongside your code.

  • Changes to the Repo Wiki in Qoder sync automatically to GitHub Wiki, and vice versa.

  • AI agents can reference Git history (e.g., “Who last modified this file?” or “What was the purpose of this commit?”) to make more informed decisions.

  • You can trigger AI tasks (e.g., “Review this pull request”) directly from GitHub.

For distributed teams, this integration eliminates the need to switch between tools – everything you need to code, document, and collaborate is in one place.

7. Multi-Model AI Engine: Flexibility for Every Project

Qoder doesn’t lock you into a single AI model. Its multi-model AI engine supports three of the most powerful models for coding: Claude (Anthropic), GPT (OpenAI), and Gemini (Google). This flexibility lets you choose the model that best fits your project’s needs:

  • Claude: Ideal for long-form tasks (e.g., refactoring a large codebase) thanks to its extended context window.

  • GPT: Great for general coding tasks (e.g., generating boilerplate code, debugging) with its strong understanding of common programming languages.

  • Gemini: Excels at tasks involving multiple languages or emerging technologies (e.g., integrating AI models into your code).

You can even switch models per project – for example, using Claude for a legacy code refactor and GPT for building a new React component. This level of flexibility is rare in coding tools and ensures Qoder adapts to your team’s technical preferences.

8. Cross-Platform Support: Run Qoder Anywhere

Qoder is built for global developers, which means it works on the operating systems you use. The platform offers installers for Windows and macOS, with a consistent user experience across both. Whether you’re a Windows user in Berlin or a macOS user in Tokyo, you’ll have access to all of Qoder’s features without compatibility issues.

Who Uses Qoder? Real-World Use Cases for Global Teams

Qoder’s versatility makes it a fit for nearly every role and project type in software development. Here are the most common use cases, with examples of how global teams are leveraging the platform:

1. Solo Developers: Multitask Without Sacrificing Quality

Solo developers often wear multiple hats – from coding to documentation to testing. Qoder helps them work more efficiently by:

  • Delegating multi-step tasks (e.g., “Build a login system with JWT authentication”) to AI agents via Quest Mode.

  • Auto-generating documentation so they don’t have to stop coding to update READMEs.

  • Providing context-aware suggestions that align with their personal coding style (stored in Memory).

For example, a solo developer in Brazil building an e-commerce app can use Quest Mode to delegate the payment gateway integration while they design the product catalog UI. By the time they finish the UI, the payment code is ready to test – cutting their development time in half.

2. Team Leads & Engineering Managers: Streamline Collaboration and Enforce Standards

Team leads overseeing distributed teams face the challenge of keeping everyone aligned. Qoder solves this by:

  • Using Memory to enforce consistent coding standards (e.g., “All React components must use functional hooks”) across the team.

  • Providing real-time visibility into AI-assisted tasks (e.g., “Which team members have delegated tasks via Quest Mode?”).

  • Simplifying code reviews by ensuring documentation (in Repo Wiki) and code are always in sync.

A team lead in London managing a team of 10 developers across India, Canada, and Australia can use Qoder to:

  • Set global guidelines in Memory (e.g., “We use TypeScript for all new frontend code”).

  • Monitor Quest Mode tasks to ensure no one is stuck on repetitive work.

  • Share the Repo Wiki with stakeholders to keep them updated on progress – no manual status reports needed.

3. New Hires & Onboarding: Ramp Up Fast, No Matter Where You Are

Onboarding new developers to a complex codebase can take weeks – especially for remote hires. Qoder’s Repo Wiki and context-aware AI cut this time down significantly:

  • New hires can use the Repo Wiki to access auto-generated architecture overviews, API references, and setup guides.

  • AI agents can answer questions like “How does the user authentication flow work?” or “Where is the payment logic stored?” in real time.

  • Memory ensures new hires receive suggestions that align with the team’s standards from day one.

A new developer in Singapore joining a U.S.-based team can use Qoder to:

  • Set up their local environment in hours (instead of days) using the Repo Wiki’s step-by-step guide.

  • Ask the AI to explain a complex module without pinging a senior developer in a different time zone.

  • Contribute code within their first week, thanks to context-aware suggestions.

4. Open-Source Maintainers: Keep Contributors Informed

Open-source maintainers rely on clear documentation to attract and retain contributors. Qoder’s Repo Wiki makes this easy by:

  • Auto-updating docs when code changes, so contributors always have accurate information.

  • Syncing with GitHub Wiki, so docs are accessible to anyone visiting the repo.

  • Letting maintainers delegate routine tasks (e.g., “Review this PR for code style”) to AI agents.

A maintainer of a popular open-source library in Germany can use Qoder to:

  • Ensure the README and API docs are always up to date, even as contributors from around the world submit PRs.

  • Use Quest Mode to generate a “contributor’s guide” based on past PR feedback.

  • Reduce the time spent on code reviews by having AI agents flag style issues first.

5. API Developers & Tech Writers: Keep Docs in Sync With Code

Tech writers and API developers spend hours updating documentation to match code changes. Qoder’s Repo Wiki automates this process:

  • When an API endpoint is added or modified, the Repo Wiki automatically updates the API reference (including parameters, response codes, and examples).

  • AI agents can generate draft documentation for new endpoints, which tech writers can refine.

  • Docs sync with GitHub, so external users always have access to the latest API info.

A tech writer in Canada working with an API team in India can use Qoder to:

  • Avoid manually updating API docs every time the team makes a change.

  • Access the Repo Wiki to find context about why an endpoint was modified (e.g., “This change fixes a bug in the payment flow”).

  • Collaborate with the team in real time, even across time zones.

Qoder Pricing: Free Access During Public Preview

For developers and teams looking to try Qoder, the platform offers free access during its public preview – no credit card required. This includes:

  • All currently available features (including Quest Mode, Repo Wiki, and multi-model AI support).

  • A “pro-level experience” during testing, with no restrictions on core functionality.

  • Usage limits to ensure fair access for all users (details are available on the Qoder website).

This free preview is a great opportunity for global teams to test Qoder’s capabilities on real projects, without any financial commitment. As the platform evolves, Qoder plans to introduce paid plans – but for now, anyone can sign up and start using the tool.

Qoder Alternatives: How It Stands Out

While there are other coding tools on the market, Qoder’s focus on agentic workflows, context engineering, and in-repo documentation sets it apart. Here’s how it compares to popular alternatives:

ToolKey FocusHow Qoder DiffersCodeiumReal-time code suggestionsQoder offers asynchronous task delegation (Quest Mode) and auto-updated documentation, while Codeium focuses on inline suggestions.QuestflowAI agent orchestration for workflowsQuestflow is designed for general workflow automation, while Qoder is built specifically for software development (with Git integration, code context, and multi-model AI).CodiumAIAI-powered code quality toolsCodiumAI focuses on testing and quality assurance, while Qoder offers end-to-end workflow support (documentation, task delegation, context management).CoderabbitAI-driven code reviewsCoderabbit specializes in PR reviews, while Qoder integrates code reviews with documentation, context, and task automation.

For developers who need more than just code suggestions – who want a tool that understands their codebase, automates complex tasks, and keeps docs up to date – Qoder is the clear choice.

How to Get Started With Qoder

Getting started with Qoder is simple, regardless of your location or technical stack:

Visit the Qoder website: Go to opentools.ai/tools/qoder to learn more about the platform.

Download the installer: Choose the version for Windows or macOS (both are free during the public preview).

Connect your Git/GitHub repo: Link Qoder to your repository to let the platform build context and generate the Repo Wiki.

Set up your Memory: Add coding standards, team guidelines, or project-specific notes to ensure AI suggestions are consistent.

Start using features: Try Quest Mode for task delegation, explore the Repo Wiki for documentation, or use the AI chat to ask codebase questions.

Qoder’s onboarding process is designed to be intuitive – even for developers new to AI coding tools. If you run into issues, the platform offers support via its website (with troubleshooting guides and a community forum).

Conclusion: Qoder – The Future of Global Software Development

In a world where software teams are increasingly distributed, and development cycles are getting shorter, Qoder provides a much-needed solution: a tool that unites AI, context, and documentation to make coding more efficient, collaborative, and consistent.

Whether you’re a solo developer in a small town or a team lead managing engineers across five continents, Qoder’s features – from Quest Mode to Repo Wiki to multi-model AI – are built to adapt to your needs. And with free access during the public preview, there’s no better time to try it.

Join the growing community of global developers using Qoder to streamline their workflows, reduce manual work, and build better software. Visit opentools.ai/tools/qoder today to get started.

阿里Qoder vs. Cursor vs. Trae:2025年AI编程工具终极对决与深度避坑指南随着AI编程赛道进入 - 掘金

https://opentools.ai/tools/qoder

Top 10 AI Code Editors in 2025 - DEV Community

阿里免费AI-IDE Qoder快速入门

阿里免费AI-IDE Qoder快速入门

开始使用

快速入门

本主题将引导您以个人用户身份使用 Qoder 核心功能的动手项目。最后,您将熟悉它的下一个编辑建议 (NES)、内联聊天和 AI 聊天——人工智能辅助编码的关键工具。

Qoder 个人版目前可供所有用户免费试用。试用期可能会发生变化。有关最新信息,请查看产品更新。

Qoder IDE 用户指南 - 完整使用教程和最佳实践 | 智能编程助手

Qoder IDE - AI-Powered Coding Platform for Real Development

Qoder Reviews, Alternatives, and Pricing updated September 2025

下载并安装 Qoder

https://qoder.com/download 下载安装程序。

双击该文件开始安装。

通过双击 Qoder IDE 图标启动 Qoder。

2

登录

在 Qoder IDE 的右上角,单击用户图标或使用键盘快捷键( (macOS)或 (Windows)),然后选择登录。⌘⇧,Ctrlshift,

在出现的网页上:

  • 点击底部的注册并完成注册过程,或

  • 使用您的 Google 或 GitHub 帐户直接注册。

返回 Qoder IDE。您现在可以自由使用所有功能。

3

打开项目

选择使用本地项目或从 GitHub 克隆示例。

  • 使用本地项目单击打开或使用键盘快捷键:

  • macOS:O⌘

  • 窗户:OCtrl

  • 浏览到项目文件夹,选择一个文件,然后将其打开。

克隆项目

  • 单击克隆存储库。

在顶部的搜索栏中:

  • 输入项目 URL,然后单击从 URL 克隆,或

  • 单击“从 GitHub 克隆”,然后按照提示进行作。

完成克隆项目的步骤。

4

探索功能

  • 触发 NES

NES 通过在您的光标处提供智能、上下文感知的编辑,帮助您开始 AI 辅助编码。

输入部分代码片段或自然语言的代码请求。示例:“初始化列表。

按 (macOS) 或 (Windows)。建议将自动出现。⌥PAltP

按 Tab 键接受建议。

NES 支持多行编辑和无缝自动完成。

  • 发起内联聊天

使用内联聊天直接在代码上下文中获取 AI 帮助。

在 Qoder 代码编辑器中,按 (macOS) 或 (Windows)。将打开“内联聊天”窗口。⌘ICtrlI

键入您的请求,然后按 Enter。示例:“添加用于处理文件更新的方法。

要应用 AI 生成的代码,请按 (macOS) 或 (Windows)。⌘⏎ CtrlEnter

  • 开始 AI 聊天

使用 AI 聊天面板或按 (macOS) 或 (Windows) 在询问或代理模式下执行更广泛的任务。⌘L CtrlL

在右侧的 AI 聊天面板中,输入您的请求。示例:“为此函数创建测试并运行它们。

按 Enter 键。AI 代理将生成包含相关测试用例的测试文件。

单击“根据提示运行”,或按 (macOS) 或 (Windows) 执行测试。⌘⏎CtrlEnter

Get Started

Quick Start

This topic walks you through a hands-on project using Qoder’s core features as an individual user. By the end, you’ll be familiar with its Next Edit Suggestions (NES), Inline Chat, and AI Chat—key tools for AI-assisted coding.

Qoder Individual Edition is currently available as a free trial for all users. The trial duration is subject to change. For the latest information, please check product updates.

1

Download and install Qoder

Download the installer from https://qoder.com/download.

Double-click the file to begin installation.

Launch Qoder by double-clicking the Qoder IDE icon.

2

Sign in

In the upper-right corner of your Qoder IDE, click the user icon or use the keyboard shortcut ( (macOS)or (Windows)), and select Sign in.⌘⇧,Ctrlshift,

On the web page that appears:

  • Click Sign up at the bottom and complete the registration process, or

  • Use your Google or GitHub account to sign up directly.

Return to the Qoder IDE. You can now use all features freely.

3

Open a project

Choose to work with an local project or clone a sample from GitHub.

  • Use a local projectClick Open or use the keyboard shortcut:

  • macOS: O ⌘

  • Windows: O Ctrl

  • Browse to your project folder, select a file, and open it.

Clone a project

  • Click Clone repo.

In the search bar at the top:

  • Enter a project URL and click Clone from URL, or

  • Click Clone from GitHub and follow the prompts.

Complete the steps to clone the project.

4

Explore features

  • Trigger an NES

NES helps you get started with AI-assisted coding by offering intelligent, context-aware edits right at your cursor.

Enter a partial code snippet or a code request in natural language. Example: “Initialize a list.”

Press (macOS) or (Windows). Suggestions will appear automatically.⌥PAltP

Press Tab to accept a suggestion.

NES supports multi-line edits, and seamless autocomplete.

  • Initiate an inline chat

Use Inline Chat to get AI help directly within your code context.

In the Qoder code editor, press (macOS) or (Windows). The Inline Chat window will open.⌘ICtrlI

Type your request and press Enter. Example: “Add a method for handling file updates.”

To apply the AI-generated code, press (macOS) or (Windows).⌘⏎ CtrlEnter

  • Start an AI chat

Use the AI Chat panel or press (macOS) or (Windows) for broader tasks in Ask or Agent mode.⌘L CtrlL

In the AI Chat panel on the right, enter your request. Example: “Create tests for this function and run them.”

Press Enter. The AI agent will generate a test file with relevant test cases.

Click Run as prompted, or press (macOS) or (Windows) to execute the tests.⌘⏎CtrlEnter

getdents系统调用及示例

getdents - 获取目录项

函数介绍

getdents系统调用用于读取目录文件的内容,获取目录中的文件项信息。它返回原始的目录项结构,需要手动解析。这是一个低级别的目录读取函数。

函数原型

1
2
3
4
5
#include <dirent.h>
#include <sys/syscall.h>

int getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count);

功能

从目录文件描述符中读取目录项信息。

参数

  • unsigned int fd: 目录文件描述符(通过opendir或open获得)

  • struct linux_dirent *dirp: 指向存储目录项的缓冲区

  • unsigned int count: 缓冲区大小(字节)

返回值

  • 成功时返回读取的字节数

失败时返回-1,并设置errno:

  • EBADF: 文件描述符无效

  • EFAULT: 缓冲区地址无效

  • EINVAL: 参数无效

  • ENOENT: 目录不存在

相似函数

  • readdir(): 标准C库函数,更易使用

  • opendir(), closedir(): 打开和关闭目录

  • getdents64(): 64位版本,支持大文件

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <linux/types.h>

// 目录项结构体定义
struct linux_dirent {
long d_ino; // inode号
__kernel_off_t d_off; // 到下一个目录项的偏移
unsigned short d_reclen; // 当前目录项长度
char d_name&#91;]; // 文件名(以null结尾)
};

int main() {
int fd;
char buf&#91;4096];
int nread;
char *p;
struct linux_dirent *d;

printf("=== Getdents函数示例 ===\n");

// 示例1: 基本的目录读取操作
printf("\n示例1: 基本的目录读取操作\n");

// 打开当前目录
fd = open(".", O_RDONLY | O_DIRECTORY);
if (fd == -1) {
perror("打开当前目录失败");
exit(EXIT_FAILURE);
}
printf("成功打开当前目录,文件描述符: %d\n", fd);

// 使用getdents读取目录内容
printf("读取目录内容:\n");
while (1) {
nread = syscall(SYS_getdents, fd, buf, sizeof(buf));
if (nread == -1) {
perror("getdents失败");
close(fd);
exit(EXIT_FAILURE);
}

if (nread == 0) // 没有更多的目录项
break;

// 解析目录项
for (p = buf; p < buf + nread;) {
d = (struct linux_dirent *)p;

// 显示目录项信息
printf(" inode: %ld, ", d->d_ino);
printf("长度: %d, ", d->d_reclen);
printf("名称: %s\n", d->d_name);

p += d->d_reclen;
}
}

close(fd);

// 示例2: 创建测试目录和文件进行演示
printf("\n示例2: 创建测试环境进行演示\n");

// 创建测试目录
if (mkdir("test_getdents_dir", 0755) == -1 && errno != EEXIST) {
perror("创建测试目录失败");
} else {
printf("创建测试目录: test_getdents_dir\n");

// 在测试目录中创建一些文件
chdir("test_getdents_dir");

// 创建测试文件
int test_files&#91;] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++) {
char filename&#91;20];
sprintf(filename, "test_file_%d.txt", test_files&#91;i]);
int file_fd = open(filename, O_CREAT | O_WRONLY, 0644);
if (file_fd != -1) {
const char *content = "Test file content";
write(file_fd, content, strlen(content));
close(file_fd);
printf("创建测试文件: %s\n", filename);
}
}

// 创建子目录
if (mkdir("subdir", 0755) == -1 && errno != EEXIST) {
perror("创建子目录失败");
} else {
printf("创建子目录: subdir\n");
}

// 打开测试目录
fd = open(".", O_RDONLY | O_DIRECTORY);
if (fd != -1) {
printf("\n读取测试目录内容:\n");

while (1) {
nread = syscall(SYS_getdents, fd, buf, sizeof(buf));
if (nread == -1) {
perror("getdents失败");
break;
}

if (nread == 0)
break;

// 解析并显示目录项
for (p = buf; p < buf + nread;) {
d = (struct linux_dirent *)p;

// 跳过.和..目录项
if (strcmp(d->d_name, ".") != 0 && strcmp(d->d_name, "..") != 0) {
printf(" 文件名: %-20s", d->d_name);
printf("inode: %ld, ", d->d_ino);
printf("长度: %d\n", d->d_reclen);
}

p += d->d_reclen;
}
}

close(fd);
}

// 返回上级目录并清理
chdir("..");
}

// 示例3: 与readdir的对比
printf("\n示例3: getdents与readdir对比\n");

// 使用getdents读取
fd = open(".", O_RDONLY | O_DIRECTORY);
if (fd != -1) {
printf("使用getdents读取目录:\n");
nread = syscall(SYS_getdents, fd, buf, sizeof(buf));
if (nread > 0) {
int count = 0;
for (p = buf; p < buf + nread && count < 5;) {
d = (struct linux_dirent *)p;
if (strcmp(d->d_name, ".") != 0 && strcmp(d->d_name, "..") != 0) {
printf(" %s\n", d->d_name);
count++;
}
p += d->d_reclen;
}
}
close(fd);
}

// 使用readdir读取(标准方法)
printf("使用readdir读取目录:\n");
DIR *dir = opendir(".");
if (dir != NULL) {
struct dirent *entry;
int count = 0;
while ((entry = readdir(dir)) != NULL && count < 5) {
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
printf(" %s\n", entry->d_name);
count++;
}
}
closedir(dir);
}

printf("getdents提供更多底层控制,但readdir更易使用\n");

// 示例4: 目录项详细信息解析
printf("\n示例4: 目录项详细信息解析\n");

fd = open(".", O_RDONLY | O_DIRECTORY);
if (fd != -1) {
nread = syscall(SYS_getdents, fd, buf, sizeof(buf));
if (nread > 0) {
printf("目录项详细信息:\n");
for (p = buf; p < buf + nread;) {
d = (struct linux_dirent *)p;

// 显示所有目录项(包括.和..)
printf(" 名称: %-20s", d->d_name);
printf("inode: %-10ld", d->d_ino);
printf("偏移: %-8ld", (long)d->d_off);
printf("长度: %d\n", d->d_reclen);

p += d->d_reclen;
}
}
close(fd);
}

// 示例5: 错误处理演示
printf("\n示例5: 错误处理演示\n");

// 尝试对无效文件描述符操作
nread = syscall(SYS_getdents, 999, buf, sizeof(buf));
if (nread == -1) {
printf("对无效文件描述符操作: %s\n", strerror(errno));
}

// 尝试对普通文件操作
int regular_fd = open("regular_file.txt", O_CREAT | O_WRONLY, 0644);
if (regular_fd != -1) {
write(regular_fd, "test", 4);
nread = syscall(SYS_getdents, regular_fd, buf, sizeof(buf));
if (nread == -1) {
printf("对普通文件操作: %s\n", strerror(errno));
}
close(regular_fd);
unlink("regular_file.txt");
}

// 尝试使用无效缓冲区
fd = open(".", O_RDONLY | O_DIRECTORY);
if (fd != -1) {
nread = syscall(SYS_getdents, fd, NULL, sizeof(buf));
if (nread == -1) {
printf("使用无效缓冲区: %s\n", strerror(errno));
}
close(fd);
}

// 示例6: 实际应用场景
printf("\n示例6: 实际应用场景\n");

// 场景1: 快速目录扫描(跳过隐藏文件)
printf("场景1: 快速目录扫描\n");
fd = open(".", O_RDONLY | O_DIRECTORY);
if (fd != -1) {
printf("非隐藏文件列表:\n");
int file_count = 0;
while (1) {
nread = syscall(SYS_getdents, fd, buf, sizeof(buf));
if (nread <= 0) break;

for (p = buf; p < buf + nread;) {
d = (struct linux_dirent *)p;

// 跳过.和..以及隐藏文件(以.开头)
if (strcmp(d->d_name, ".") != 0 &&
strcmp(d->d_name, "..") != 0 &&
d->d_name&#91;0] != '.') {
printf(" %s\n", d->d_name);
file_count++;
}

p += d->d_reclen;
}
}
printf("总共找到 %d 个非隐藏文件\n", file_count);
close(fd);
}

// 场景2: 目录统计信息
printf("场景2: 目录统计信息\n");
fd = open(".", O_RDONLY | O_DIRECTORY);
if (fd != -1) {
int total_files = 0;
int total_dirs = 0;
long long total_size = 0;

while (1) {
nread = syscall(SYS_getdents, fd, buf, sizeof(buf));
if (nread <= 0) break;

for (p = buf; p < buf + nread;) {
d = (struct linux_dirent *)p;

// 跳过.和..
if (strcmp(d->d_name, ".") != 0 && strcmp(d->d_name, "..") != 0) {
// 检查文件类型(需要stat)
struct stat st;
if (stat(d->d_name, &st) == 0) {
if (S_ISDIR(st.st_mode)) {
total_dirs++;
} else {
total_files++;
total_size += st.st_size;
}
}
}

p += d->d_reclen;
}
}

printf("目录统计:\n");
printf(" 文件数: %d\n", total_files);
printf(" 目录数: %d\n", total_dirs);
printf(" 文件总大小: %lld 字节\n", total_size);

close(fd);
}

// 清理测试目录
printf("\n清理测试资源...\n");
if (access("test_getdents_dir", F_OK) == 0) {
// 删除测试目录中的文件
chdir("test_getdents_dir");
for (int i = 1; i <= 5; i++) {
char filename&#91;20];
sprintf(filename, "test_file_%d.txt", i);
unlink(filename);
}
rmdir("subdir");
chdir("..");
rmdir("test_getdents_dir");
printf("删除测试目录完成\n");
}

return 0;
}

https://www.calcguide.tech/2025/09/09/getdents-syscall-demo/

getdents64系统调用及示例

getdents系统调用及示例

getegid系统调用及示例

getegid - 获取当前进程的有效组ID

1. 函数介绍

getegid 是一个 Linux 系统调用,用于获取当前进程的有效组 ID(Effective Group ID)。有效组 ID 决定了进程当前对文件和资源的组级访问权限。

在 Unix/Linux 系统中,每个进程都有多个相关的用户和组 ID:

  • 真实 ID (Real ID):标识运行该进程的实际用户/组

  • 有效 ID (Effective ID):决定当前权限的用户/组 ID

  • 保存的设置 ID (Saved Set ID):用于权限切换的备份 ID

getegid 专门用于获取有效组 ID,这是进程当前用于权限检查的组标识符。

2. 函数原型

1
2
3
4
5
#include <unistd.h>
#include <sys/types.h>

gid_t getegid(void);

3. 功能

返回当前进程的有效组 ID(Effective Group ID)。这是一个只读操作,不会修改任何系统状态。

4. 参数

  • 无参数

5. 返回值

  • 返回当前进程的有效组 ID(gid_t 类型)

  • 不会失败,总是成功返回

6. 相似函数,或关联函数

  • getgid(): 获取真实组 ID(Real Group ID)

  • geteuid(): 获取有效用户 ID(Effective User ID)

  • getuid(): 获取真实用户 ID(Real User ID)

  • setgid(): 设置组 ID

  • setegid(): 设置有效组 ID

  • setregid(): 同时设置真实和有效组 ID

  • setgroups(): 设置补充组列表

  • getgroups(): 获取补充组列表

  • initgroups(): 初始化用户组访问列表

7. 示例代码

示例1:基本使用 - 获取和显示组ID信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <grp.h>
#include <pwd.h>

void print_group_info(const char *label, gid_t gid) {
struct group *grp;

printf("%s: %d", label, gid);

// 尝试获取组名
grp = getgrgid(gid);
if (grp != NULL) {
printf(" (%s)", grp->gr_name);
}
printf("\n");
}

int main() {
gid_t real_gid, effective_gid;

printf("=== 进程组 ID 信息 ===\n");

// 获取真实组 ID
real_gid = getgid();
print_group_info("真实组 ID", real_gid);

// 获取有效组 ID
effective_gid = getegid();
print_group_info("有效组 ID", effective_gid);

// 获取当前用户名
struct passwd *pwd = getpwuid(getuid());
if (pwd != NULL) {
printf("当前用户: %s\n", pwd->pw_name);
}

// 检查是否为 root 组
if (effective_gid == 0) {
printf("注意: 当前进程具有 root 组权限\n");
}

return 0;
}

示例2:权限检查和组切换演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <grp.h>
#include <errno.h>
#include <string.h>

int main() {
gid_t original_egid, current_egid;
int ret;

printf("=== 组 ID 切换演示 ===\n");

// 保存原始有效组 ID
original_egid = getegid();
printf("原始有效组 ID: %d\n", original_egid);

// 尝试切换到不同的组(需要适当权限)
// 这里使用一些常见的系统组进行演示
gid_t test_groups&#91;] = {1000, 1001, 1002}; // 假设的用户组
int num_groups = sizeof(test_groups) / sizeof(test_groups&#91;0]);

for (int i = 0; i < num_groups; i++) {
printf("\n尝试切换到组 %d:\n", test_groups&#91;i]);

// 尝试设置有效组 ID
ret = setegid(test_groups&#91;i]);
if (ret == -1) {
printf(" 切换失败: %s\n", strerror(errno));
switch (errno) {
case EPERM:
printf(" 原因: 权限不足\n");
break;
case EINVAL:
printf(" 原因: 无效的组 ID\n");
break;
default:
break;
}
} else {
current_egid = getegid();
printf(" 切换成功,当前有效组 ID: %d\n", current_egid);

// 切换回原始组 ID
if (setegid(original_egid) == 0) {
printf(" 已切换回原始组 ID: %d\n", getegid());
}
}
}

printf("\n最终有效组 ID: %d\n", getegid());
return 0;
}

示例3:补充组信息获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <grp.h>
#include <pwd.h>

int main() {
gid_t effective_gid;
gid_t *group_list;
int group_count;
long max_groups;

printf("=== 完整组信息展示 ===\n");

// 获取有效组 ID
effective_gid = getegid();
printf("有效组 ID: %d\n", effective_gid);

// 获取组名
struct group *grp = getgrgid(effective_gid);
if (grp != NULL) {
printf("有效组名: %s\n", grp->gr_name);
}

// 获取补充组列表大小
max_groups = sysconf(_SC_NGROUPS_MAX);
if (max_groups == -1) {
max_groups = 64; // 默认值
}

printf("最大支持组数: %ld\n", max_groups);

// 分配组列表内存
group_list = malloc(max_groups * sizeof(gid_t));
if (group_list == NULL) {
perror("内存分配失败");
return 1;
}

// 获取补充组列表
group_count = getgroups(max_groups, group_list);
if (group_count == -1) {
perror("获取补充组列表失败");
free(group_list);
return 1;
}

printf("补充组数量: %d\n", group_count);

if (group_count > 0) {
printf("补充组列表:\n");
for (int i = 0; i < group_count; i++) {
printf(" 组 %d: %d", i + 1, group_list&#91;i]);

// 获取组名
struct group *sup_grp = getgrgid(group_list&#91;i]);
if (sup_grp != NULL) {
printf(" (%s)", sup_grp->gr_name);
}
printf("\n");
}
}

// 检查有效组 ID 是否在补充组列表中
int found = 0;
for (int i = 0; i < group_count; i++) {
if (group_list&#91;i] == effective_gid) {
found = 1;
break;
}
}

printf("\n有效组 ID %s 在补充组列表中\n",
found ? "存在" : "不存在");

free(group_list);
return 0;
}

示例4:权限相关的实际应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <grp.h>
#include <pwd.h>
#include <string.h>

// 检查当前进程是否属于指定组
int is_member_of_group(gid_t target_gid) {
gid_t effective_gid = getegid();

// 首先检查有效组 ID
if (effective_gid == target_gid) {
return 1;
}

// 检查补充组
long max_groups = sysconf(_SC_NGROUPS_MAX);
if (max_groups == -1) max_groups = 64;

gid_t *groups = malloc(max_groups * sizeof(gid_t));
if (groups == NULL) return 0;

int ngroups = getgroups(max_groups, groups);
if (ngroups == -1) {
free(groups);
return 0;
}

for (int i = 0; i < ngroups; i++) {
if (groups&#91;i] == target_gid) {
free(groups);
return 1;
}
}

free(groups);
return 0;
}

// 获取当前用户的主要组信息
void print_user_primary_group() {
uid_t uid = getuid();
struct passwd *pwd = getpwuid(uid);

if (pwd != NULL) {
printf("用户 %s 的主要组: %d", pwd->pw_name, pwd->pw_gid);
struct group *grp = getgrgid(pwd->pw_gid);
if (grp != NULL) {
printf(" (%s)", grp->gr_name);
}
printf("\n");
}
}

int main() {
printf("=== 权限检查应用示例 ===\n");

// 显示基本信息
printf("当前用户 ID: %d\n", getuid());
printf("当前有效组 ID: %d\n", getegid());
print_user_primary_group();

// 检查是否属于 wheel 组(系统管理员组)
struct group *wheel_grp = getgrnam("wheel");
if (wheel_grp != NULL) {
int is_wheel = is_member_of_group(wheel_grp->gr_gid);
printf("是否属于 wheel 组: %s\n", is_wheel ? "是" : "否");
}

// 检查是否属于 sudo 组
struct group *sudo_grp = getgrnam("sudo");
if (sudo_grp != NULL) {
int is_sudo = is_member_of_group(sudo_grp->gr_gid);
printf("是否属于 sudo 组: %s\n", is_sudo ? "是" : "否");
}

// 检查是否具有 root 组权限
int is_root_group = is_member_of_group(0);
printf("是否具有 root 组权限: %s\n", is_root_group ? "是" : "否");

// 根据组权限显示不同信息
if (is_root_group) {
printf("\n提示: 当前进程具有 root 组权限,可以执行特权操作\n");
} else {
printf("\n提示: 当前进程权限受限,某些操作可能需要提升权限\n");
}

return 0;
}

8. 组 ID 类型说明

Unix/Linux 系统中的组 ID 类型:

1
2
3
4
5
6
7
8
9
10
11
12
// 真实组 ID (Real Group ID)
// 标识启动进程的用户的组
gid_t real_gid = getgid();

// 有效组 ID (Effective Group ID)
// 当前用于权限检查的组 ID
gid_t effective_gid = getegid();

// 保存的设置组 ID (Saved Set Group ID)
// 用于权限切换的备份 ID
// 通过 setregid() 或类似函数设置

9. 常见组 ID 值

1
2
3
4
5
6
7
8
9
10
11
// 特殊组 ID
0 // root 组 (超级用户组)
1 // bin 组 (系统二进制文件)
2 // daemon 组 (系统守护进程)
3 // sys 组 (系统文件)
4 // adm 组 (系统日志)
5 // tty 组 (终端设备)
6 // disk 组 (磁盘设备)
10 // wheel 组 (系统管理员,某些发行版)
100+ // 普通用户组

10. 实际应用场景

getegid 在以下场景中非常有用:

场景1:权限检查

1
2
3
4
5
6
7
int check_file_access_permission(const char *filename) {
gid_t effective_gid = getegid();
// 根据有效组 ID 检查文件访问权限
// ...
return 0;
}

场景2:安全审计

1
2
3
4
5
6
7
void audit_process_privileges() {
gid_t egid = getegid();
if (egid == 0) {
syslog(LOG_WARNING, "进程以 root 组权限运行");
}
}

场景3:组权限相关的功能控制

1
2
3
4
int can_perform_admin_task() {
return is_member_of_group(get_admin_group_id());
}

11. 与相关函数的配合使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <unistd.h>
#include <sys/types.h>

// 完整的 ID 管理示例
void demonstrate_id_management() {
printf("真实用户 ID: %d\n", getuid());
printf("有效用户 ID: %d\n", geteuid());
printf("真实组 ID: %d\n", getgid());
printf("有效组 ID: %d\n", getegid());

// 权限切换示例
// seteuid(), setegid() 用于临时权限切换
// setuid(), setgid() 用于永久权限切换
}

总结

getegid 是一个简单但重要的系统调用,用于获取当前进程的有效组 ID。关键要点:

总是成功: 不会失败,总是返回有效组 ID

权限检查: 有效组 ID 决定当前的组级权限

安全相关: 是权限管理和安全检查的基础

配合使用: 通常与 getgroups() 等函数配合使用

实际应用: 广泛用于权限验证、安全审计等场景

在编写需要进行权限检查的程序时,getegid 是必不可少的工具函数,它为程序提供了当前权限状态的重要信息。

getegid系统调用及示例-CSDN博客

https://www.calcguide.tech/2025/09/09/getegid-syscall-demo/

geteuid系统调用及示例

geteuid 函数详解

  1. 函数介绍

geteuid 是 Linux 系统中用于获取进程有效用户 ID(Effective User ID)的系统调用。可以把有效用户 ID 想象成”进程当前正在使用的身份证明”——它决定了进程当前拥有的权限级别。

在 Linux 系统中,每个进程都有两个重要的用户 ID:

  • 真实用户 ID(real UID): 进程实际所属的用户

  • 有效用户 ID(effective UID): 进程当前使用的用户身份(用于权限检查)

这就像是一个人有真实身份和当前扮演的角色。比如一个系统管理员(真实身份)可能暂时切换到普通用户角色(有效身份)来执行某些操作。

geteuid 就是获取进程当前”扮演的角色”的用户 ID。

  1. 函数原型
1
2
3
4
5
#include <unistd.h>
#include <sys/types.h>

uid_t geteuid(void);

  1. 功能

geteuid 函数用于获取调用进程的有效用户 ID(effective user ID)。有效用户 ID 用于权限检查,决定了进程可以访问哪些资源和执行哪些操作。

  1. 参数

geteuid 函数不需要任何参数。

  1. 返回值
  • 成功: 返回调用进程的有效用户 ID(uid_t 类型)

  • 注意: 此函数不会失败,总是成功返回

  1. 相关函数
  • getuid: 获取真实用户 ID(real user ID)

  • getgid: 获取真实组 ID(real group ID)

  • getegid: 获取有效组 ID(effective group ID)

  • setuid: 设置用户 ID

  • seteuid: 设置有效用户 ID

  • setreuid: 同时设置真实和有效用户 ID

  1. 用户 ID 类型说明

Linux 系统中有几种不同的用户 ID:

用户 ID 类型说明真实用户 ID (real UID)进程实际所属的用户,由 getuid 返回有效用户 ID (effective UID)用于权限检查的用户 ID,由 geteuid 返回保存的设置用户 ID (saved set-user-ID)保存的用户 ID,用于权限切换

  1. 示例代码

示例1:基础用法 - 获取进程用户 ID

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>

int main() {
uid_t real_uid, effective_uid;
struct passwd *pwd_info;

printf("=== 进程用户 ID 信息 ===\n\n");

// 获取真实用户 ID
real_uid = getuid();
printf("真实用户 ID (real UID): %d\n", real_uid);

// 获取有效用户 ID
effective_uid = geteuid();
printf("有效用户 ID (effective UID): %d\n", effective_uid);

// 获取用户名信息
pwd_info = getpwuid(real_uid);
if (pwd_info != NULL) {
printf("真实用户名: %s\n", pwd_info->pw_name);
printf("主目录: %s\n", pwd_info->pw_dir);
printf("登录 shell: %s\n", pwd_info->pw_shell);
} else {
printf("无法获取真实用户信息\n");
}

// 获取有效用户信息
pwd_info = getpwuid(effective_uid);
if (pwd_info != NULL) {
printf("有效用户名: %s\n", pwd_info->pw_name);
} else {
printf("无法获取有效用户信息\n");
}

// 判断权限级别
printf("\n权限状态:\n");
if (effective_uid == 0) {
printf("✓ 进程具有 root 权限\n");
} else if (real_uid == 0 && effective_uid != 0) {
printf("⚠ 进程已放弃 root 权限\n");
} else {
printf("✗ 进程为普通用户权限\n");
}

if (real_uid == effective_uid) {
printf("✓ 真实 UID 和有效 UID 相同\n");
} else {
printf("⚠ 真实 UID 和有效 UID 不同\n");
}

return 0;
}

示例2:权限检查和安全验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <string.h>

// 权限检查函数
void check_permissions() {
uid_t real_uid = getuid();
uid_t effective_uid = geteuid();
gid_t real_gid = getgid();
gid_t effective_gid = getegid();

printf("=== 权限检查 ===\n");

// 用户权限检查
printf("用户权限:\n");
printf(" 真实 UID: %d", real_uid);
struct passwd *pwd = getpwuid(real_uid);
if (pwd) printf(" (%s)", pwd->pw_name);
printf("\n");

printf(" 有效 UID: %d", effective_uid);
pwd = getpwuid(effective_uid);
if (pwd) printf(" (%s)", pwd->pw_name);
if (effective_uid == 0) {
printf(" &#91;ROOT 权限!]");
}
printf("\n");

// 组权限检查
printf("组权限:\n");
printf(" 真实 GID: %d\n", real_gid);
printf(" 有效 GID: %d", effective_gid);
if (effective_gid == 0) {
printf(" &#91;ROOT 组权限!]");
}
printf("\n");

// 安全状态分析
printf("\n安全状态分析:\n");
if (effective_uid == 0) {
printf(" ⚠ 危险: 进程以 root 权限运行\n");
printf(" 建议: 在完成特权操作后立即降低权限\n");
} else if (real_uid == 0 && effective_uid != 0) {
printf(" ✓ 良好: 已安全放弃 root 权限\n");
} else {
printf(" ✓ 正常: 以普通用户权限运行\n");
}
}

// 安全操作示例
void secure_operation_example() {
uid_t real_uid = getuid();
uid_t effective_uid = geteuid();

printf("\n=== 安全操作示例 ===\n");

if (effective_uid == 0) {
printf("检测到 root 权限,执行特权操作...\n");

// 模拟特权操作
printf(" 执行系统管理任务...\n");
printf(" 修改系统配置...\n");
printf(" 访问受保护资源...\n");

// 如果真实 UID 不是 root,可以安全地放弃权限
if (real_uid != 0) {
printf(" 准备放弃 root 权限...\n");
// 注意:实际代码中需要使用 setuid() 系列函数
}
} else {
printf("以普通用户权限执行操作...\n");
printf(" 执行用户级任务...\n");
printf(" 访问用户文件...\n");
}
}

int main() {
printf("=== 进程身份和权限管理系统 ===\n\n");

// 显示基本进程信息
printf("进程基本信息:\n");
printf(" 进程 ID: %d\n", getpid());
printf(" 父进程 ID: %d\n", getppid());
printf(" 真实 UID: %d\n", getuid());
printf(" 有效 UID: %d\n", geteuid());
printf(" 真实 GID: %d\n", getgid());
printf(" 有效 GID: %d\n\n", getegid());

// 权限检查
check_permissions();

// 安全操作示例
secure_operation_example();

printf("\n=== 安全建议 ===\n");
printf("1. 遵循最小权限原则\n");
printf("2. 及时放弃不需要的特权\n");
printf("3. 定期检查有效 UID 和真实 UID\n");
printf("4. 避免长时间以 root 权限运行\n");

return 0;
}

示例3:完整的身份验证和权限管理系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <string.h>

// 用户信息结构体
struct user_info {
uid_t uid;
gid_t gid;
char username&#91;256];
char groupname&#91;256];
char homedir&#91;256];
int is_root;
int has_privileges;
};

// 获取用户信息
int get_user_information(struct user_info *info) {
struct passwd *pwd;
struct group *grp;

// 获取 UID 和 GID
info->uid = geteuid();
info->gid = getegid();

// 获取用户信息
pwd = getpwuid(info->uid);
if (pwd) {
strncpy(info->username, pwd->pw_name, sizeof(info->username) - 1);
info->username&#91;sizeof(info->username) - 1] = '\0';
strncpy(info->homedir, pwd->pw_dir, sizeof(info->homedir) - 1);
info->homedir&#91;sizeof(info->homedir) - 1] = '\0';
} else {
snprintf(info->username, sizeof(info->username), "uid_%d", info->uid);
strcpy(info->homedir, "/tmp");
}

// 获取组信息
grp = getgrgid(info->gid);
if (grp) {
strncpy(info->groupname, grp->gr_name, sizeof(info->groupname) - 1);
info->groupname&#91;sizeof(info->groupname) - 1] = '\0';
} else {
snprintf(info->groupname, sizeof(info->groupname), "gid_%d", info->gid);
}

// 设置权限标志
info->is_root = (info->uid == 0);
info->has_privileges = (info->uid == 0 || info->gid == 0);

return 0;
}

// 显示用户信息
void display_user_info(const struct user_info *info) {
printf("=== 当前用户信息 ===\n");
printf("用户名: %s\n", info->username);
printf("用户 ID: %d\n", info->uid);
printf("组名: %s\n", info->groupname);
printf("组 ID: %d\n", info->gid);
printf("主目录: %s\n", info->homedir);
printf("权限状态: %s\n",
info->is_root ? "ROOT 权限" :
info->has_privileges ? "特权用户" : "普通用户");
}

// 权限验证函数
int check_operation_permission(const char *operation) {
struct user_info info;
get_user_information(&info);

printf("权限检查: %s\n", operation);

// 根据操作类型检查权限
if (strcmp(operation, "read_system_files") == 0) {
// 读取系统文件通常需要 root 权限
return info.is_root ? 1 : 0;
} else if (strcmp(operation, "write_user_files") == 0) {
// 写入用户文件通常只需要有效权限
return 1; // 假设总是允许
} else if (strcmp(operation, "network_admin") == 0) {
// 网络管理需要 root 权限
return info.is_root ? 1 : 0;
} else {
// 默认情况下,普通操作允许
return 1;
}
}

// 模拟受保护操作
void perform_protected_operation(const char *operation) {
printf("\n--- 尝试执行操作: %s ---\n", operation);

if (check_operation_permission(operation)) {
printf("✓ 权限检查通过\n");
printf(" 执行操作: %s\n", operation);

// 模拟操作执行
if (strcmp(operation, "read_system_files") == 0) {
printf(" 读取 /etc/shadow...\n");
printf(" 读取系统配置文件...\n");
} else if (strcmp(operation, "network_admin") == 0) {
printf(" 配置网络接口...\n");
printf(" 修改防火墙规则...\n");
}

printf(" 操作完成\n");
} else {
printf("✗ 权限不足,拒绝执行操作\n");
printf(" 需要 ROOT 权限才能执行此操作\n");
}
}

// 显示安全建议
void show_security_advice(const struct user_info *info) {
printf("\n=== 安全建议 ===\n");

if (info->is_root) {
printf("⚠ 警告: 当前以 ROOT 权限运行\n");
printf(" 建议:\n");
printf(" 1. 完成必要操作后立即切换到普通用户\n");
printf(" 2. 避免在 root 权限下运行不必要的程序\n");
printf(" 3. 定期审计 root 权限的使用情况\n");
} else if (info->has_privileges) {
printf("⚠ 注意: 具有特权权限\n");
printf(" 建议:\n");
printf(" 1. 谨慎使用特权功能\n");
printf(" 2. 遵循最小权限原则\n");
} else {
printf("✓ 信息: 以普通用户权限运行\n");
printf(" 建议:\n");
printf(" 1. 如需特权操作,请使用 sudo\n");
printf(" 2. 保持系统和软件更新\n");
}
}

int main() {
struct user_info current_user;

printf("=== 高级身份验证和权限管理系统 ===\n\n");

// 获取并显示用户信息
get_user_information(&current_user);
display_user_info(&current_user);

// 执行各种受保护操作
perform_protected_operation("read_system_files");
perform_protected_operation("write_user_files");
perform_protected_operation("network_admin");

// 显示安全建议
show_security_advice(&current_user);

printf("\n=== 系统信息 ===\n");
printf("进程 ID: %d\n", getpid());
printf("父进程 ID: %d\n", getppid());
printf("真实 UID: %d\n", getuid());
printf("有效 UID: %d\n", geteuid());
printf("真实 GID: %d\n", getgid());
printf("有效 GID: %d\n", getegid());

return 0;
}

编译和运行说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 编译示例程序
gcc -o geteuid_example1 example1.c
gcc -o geteuid_example2 example2.c
gcc -o geteuid_example3 example3.c

# 运行示例
./geteuid_example1
./geteuid_example2
./geteuid_example3

# 以 root 权限运行(需要 sudo)
sudo ./geteuid_example1
sudo ./geteuid_example2
sudo ./geteuid_example3

命令行查看用户信息

1
2
3
4
5
6
7
8
9
10
11
12
13
# 查看当前用户信息
id

# 查看特定用户信息
id username

# 查看当前进程信息
ps -eo pid,ppid,uid,euid,gid,egid,comm

# 查看用户数据库
cat /etc/passwd
cat /etc/group

重要注意事项

不会失败: geteuid 总是成功返回,不需要错误检查

实时性: 返回的是调用时刻的有效用户 ID

权限检查: 有效 UID 用于所有权限检查

安全关键: 在安全敏感程序中要特别注意有效 UID

继承性: 子进程继承父进程的有效 UID

实际应用场景

权限验证: 在执行特权操作前检查有效 UID

安全审计: 记录操作的有效用户身份

访问控制: 根据有效 UID 控制资源访问

特权管理: 管理程序的特权级别切换

日志记录: 在日志中记录有效的用户身份

常见用户 ID 含义

用户 ID用户名说明0root超级用户1daemon系统守护进程用户2bin系统二进制文件用户5sync用于同步操作的用户37www-dataWeb 服务器用户65534nobody无特权用户

与相关函数的配合使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 完整的身份信息获取
uid_t real_uid = getuid(); // 真实用户 ID
uid_t effective_uid = geteuid(); // 有效用户 ID
gid_t real_gid = getgid(); // 真实组 ID
gid_t effective_gid = getegid(); // 有效组 ID

// 权限切换示例
if (geteuid() == 0) {
// 当前有 root 权限,执行特权操作
// ...
// 完成后可以放弃权限
// setuid(getuid()); // 切换到真实 UID
}

安全最佳实践

最小权限原则: 只在必要时获取特权

及时放弃权限: 完成特权操作后立即降低权限

验证身份: 在关键操作前验证有效 UID

避免持久化: 不要长时间保持高权限运行

日志记录: 记录所有特权操作的身份信息

这些示例展示了 geteuid 函数的各种使用方法,从基本的用户 ID 获取到完整的权限管理系统,帮助你全面理解 Linux 系统中的用户权限管理机制。

getgid系统调用及示例-CSDN博客

geteuid系统调用及示例-CSDN博客

getgid系统调用及示例

getgid 函数详解

getgid 是 Linux 系统中获取进程真实组 ID 的系统调用函数,用于确定进程的组权限级别。该函数无参数,总是成功返回调用进程的真实组 ID(gid_t 类型)。组 ID 类似于”部门编号”,决定进程在系统中的组权限。系统还提供相关函数如 getegid(获取有效组 ID)、getuid(获取用户 ID)等。示例代码演示了如何获取组 ID 信息、查询完整用户/组信息以及检查权限状态。真实组 ID 和有效组 ID 通常相同,但在特殊权限操作时可能不同。

  1. 函数介绍

getgid 是 Linux 系统中用于获取进程真实组 ID(Group ID)的系统调用。可以把组 ID 想象成”用户的身份证明”——每个进程都属于一个或多个用户组,组 ID 决定了进程在系统中的组权限级别。

在 Linux 系统中,权限管理不仅基于用户,还基于用户组。就像一个公司员工不仅有个人身份,还属于不同的部门一样,每个用户都属于一个或多个组,而 getgid 就是获取进程所属的”主部门”编号。

  1. 函数原型
1
2
3
4
5
#include <unistd.h>
#include <sys/types.h>

gid_t getgid(void);

  1. 功能

getgid 函数用于获取调用进程的真实组 ID(real group ID)。真实组 ID 是进程启动时从父进程继承的组 ID,通常与有效组 ID(effective group ID)相同,但在某些特殊情况下可能不同。

  1. 参数

getgid 函数不需要任何参数。

  1. 返回值
  • 成功: 返回调用进程的真实组 ID(gid_t 类型)

  • 注意: 此函数不会失败,总是成功返回

  1. 相关函数
  • getegid: 获取有效组 ID(effective group ID)

  • getuid: 获取真实用户 ID(real user ID)

  • geteuid: 获取有效用户 ID(effective user ID)

  • getgroups: 获取进程所属的所有组 ID

  • setgid: 设置组 ID

  • setgroups: 设置进程的附加组 ID 列表

  • initgroups: 初始化用户组访问列表

  1. 组 ID 类型说明

Linux 系统中有几种不同的组 ID:

组 ID 类型说明真实组 ID (real GID)进程实际所属的组,由 getgid 返回有效组 ID (effective GID)用于权限检查的组 ID,由 getegid 返回保存的设置组 ID (saved set-group-ID)保存的组 ID,用于权限切换附加组 ID (supplementary GIDs)进程所属的额外组列表

  1. 示例代码

示例1:基础用法 - 获取进程组 ID

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>

int main() {
gid_t real_gid, effective_gid;
struct group *grp_info;

printf("=== 进程组 ID 信息 ===\n\n");

// 获取真实组 ID
real_gid = getgid();
printf("真实组 ID (real GID): %d\n", real_gid);

// 获取有效组 ID
effective_gid = getegid();
printf("有效组 ID (effective GID): %d\n", effective_gid);

// 获取组名信息
grp_info = getgrgid(real_gid);
if (grp_info != NULL) {
printf("组名: %s\n", grp_info->gr_name);
printf("组密码: %s\n", grp_info->gr_passwd ? grp_info->gr_passwd : "(无)");
printf("组成员: ");
if (grp_info->gr_mem && grp_info->gr_mem&#91;0]) {
for (int i = 0; grp_info->gr_mem&#91;i]; i++) {
printf("%s ", grp_info->gr_mem&#91;i]);
}
} else {
printf("(无成员列表)");
}
printf("\n");
} else {
printf("无法获取组信息\n");
}

// 比较真实组 ID 和有效组 ID
if (real_gid == effective_gid) {
printf("\n真实组 ID 和有效组 ID 相同\n");
} else {
printf("\n真实组 ID 和有效组 ID 不同\n");
}

return 0;
}

示例2:完整的用户和组信息查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>

void print_user_info(uid_t uid) {
struct passwd *pwd_info;

pwd_info = getpwuid(uid);
if (pwd_info != NULL) {
printf(" 用户名: %s\n", pwd_info->pw_name);
printf(" 用户 ID: %d\n", pwd_info->pw_uid);
printf(" 组 ID: %d\n", pwd_info->pw_gid);
printf(" 主目录: %s\n", pwd_info->pw_dir);
printf(" 登录 shell: %s\n", pwd_info->pw_shell);
} else {
printf(" 无法获取用户信息\n");
}
}

void print_group_info(gid_t gid) {
struct group *grp_info;

grp_info = getgrgid(gid);
if (grp_info != NULL) {
printf(" 组名: %s\n", grp_info->gr_name);
printf(" 组 ID: %d\n", grp_info->gr_gid);
printf(" 组成员: ");
if (grp_info->gr_mem && grp_info->gr_mem&#91;0]) {
for (int i = 0; grp_info->gr_mem&#91;i]; i++) {
printf("%s ", grp_info->gr_mem&#91;i]);
}
} else {
printf("(无成员列表)");
}
printf("\n");
} else {
printf(" 无法获取组信息\n");
}
}

int main() {
uid_t real_uid, effective_uid;
gid_t real_gid, effective_gid;

printf("=== 完整的用户和组信息 ===\n\n");

// 获取用户 ID 信息
printf("用户信息:\n");
real_uid = getuid();
effective_uid = geteuid();
printf(" 真实用户 ID: %d\n", real_uid);
printf(" 有效用户 ID: %d\n", effective_uid);
print_user_info(real_uid);

printf("\n");

// 获取组 ID 信息
printf("组信息:\n");
real_gid = getgid();
effective_gid = getegid();
printf(" 真实组 ID: %d\n", real_gid);
printf(" 有效组 ID: %d\n", effective_gid);
print_group_info(real_gid);

// 检查权限状态
printf("\n权限状态分析:\n");
if (real_uid == 0 || effective_uid == 0) {
printf(" ✓ 进程具有 root 权限\n");
} else {
printf(" ✗ 进程为普通用户权限\n");
}

if (real_gid == effective_gid) {
printf(" ✓ 组权限未被修改\n");
} else {
printf(" ⚠ 组权限可能被修改过\n");
}

return 0;
}

示例3:多组支持和权限检查工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <grp.h>
#include <errno.h>

// 获取并显示所有组信息
void show_all_groups() {
gid_t *groups;
int ngroups;
long ngroups_max;

printf("=== 所有组信息 ===\n");

// 获取最大组数
ngroups_max = sysconf(_SC_NGROUPS_MAX);
if (ngroups_max == -1) {
ngroups_max = 1024; // 默认值
}

// 分配内存
groups = malloc(ngroups_max * sizeof(gid_t));
if (groups == NULL) {
perror("malloc");
return;
}

// 获取组列表
ngroups = getgroups(ngroups_max, groups);
if (ngroups == -1) {
perror("getgroups");
free(groups);
return;
}

printf("进程所属组数量: %d\n", ngroups);
printf("组 ID 列表:\n");

for (int i = 0; i < ngroups; i++) {
struct group *grp_info = getgrgid(groups&#91;i]);
printf(" &#91;%d] %d", i + 1, groups&#91;i]);
if (grp_info != NULL) {
printf(" (%s)", grp_info->gr_name);
}
printf("\n");
}

// 显示主组
gid_t primary_gid = getgid();
struct group *primary_grp = getgrgid(primary_gid);
printf("\n主组 (getgid): %d", primary_gid);
if (primary_grp != NULL) {
printf(" (%s)", primary_grp->gr_name);
}
printf("\n");

free(groups);
}

// 检查是否属于特定组
int is_member_of_group(gid_t target_gid) {
gid_t *groups;
int ngroups;
long ngroups_max;
int result = 0;

// 获取最大组数
ngroups_max = sysconf(_SC_NGROUPS_MAX);
if (ngroups_max == -1) {
ngroups_max = 1024;
}

// 分配内存
groups = malloc(ngroups_max * sizeof(gid_t));
if (groups == NULL) {
return -1;
}

// 获取组列表
ngroups = getgroups(ngroups_max, groups);
if (ngroups == -1) {
free(groups);
return -1;
}

// 检查是否包含目标组
for (int i = 0; i < ngroups; i++) {
if (groups&#91;i] == target_gid) {
result = 1;
break;
}
}

// 也要检查主组
if (!result && getgid() == target_gid) {
result = 1;
}

free(groups);
return result;
}

// 特权检查函数
void check_privileges() {
uid_t uid = getuid();
uid_t euid = geteuid();
gid_t gid = getgid();
gid_t egid = getegid();

printf("=== 权限检查 ===\n");

printf("用户权限:\n");
printf(" 真实 UID: %d\n", uid);
printf(" 有效 UID: %d", euid);
if (euid == 0) {
printf(" (root 权限!)\n");
} else {
printf(" (普通用户)\n");
}

printf("组权限:\n");
printf(" 真实 GID: %d\n", gid);
printf(" 有效 GID: %d", egid);
if (egid == 0) {
printf(" (root 组权限!)\n");
} else {
printf(" (普通组)\n");
}

// 检查是否属于 wheel 或 sudo 组(管理员组)
struct group *admin_group;

admin_group = getgrnam("wheel");
if (admin_group && is_member_of_group(admin_group->gr_gid)) {
printf(" ✓ 属于 wheel 组 (管理员组)\n");
}

admin_group = getgrnam("sudo");
if (admin_group && is_member_of_group(admin_group->gr_gid)) {
printf(" ✓ 属于 sudo 组 (管理员组)\n");
}
}

int main() {
printf("=== 进程身份和权限信息工具 ===\n\n");

// 显示基本身份信息
printf("基本身份信息:\n");
printf(" 进程 ID: %d\n", getpid());
printf(" 父进程 ID: %d\n", getppid());
printf(" 真实用户 ID: %d\n", getuid());
printf(" 真实组 ID: %d\n", getgid());
printf(" 有效用户 ID: %d\n", geteuid());
printf(" 有效组 ID: %d\n\n", getegid());

// 权限检查
check_privileges();
printf("\n");

// 显示所有组信息
show_all_groups();

printf("\n=== 使用说明 ===\n");
printf("此工具显示当前进程的完整身份和权限信息。\n");
printf("包括用户 ID、组 ID、所属的所有组等信息。\n");

return 0;
}

编译和运行说明

1
2
3
4
5
6
7
8
9
10
# 编译示例程序
gcc -o getgid_example1 example1.c
gcc -o getgid_example2 example2.c
gcc -o getgid_example3 example3.c

# 运行示例
./getgid_example1
./getgid_example2
./getgid_example3

命令行查看组信息

1
2
3
4
5
6
7
8
9
10
11
12
13
# 查看当前用户信息
id

# 查看特定用户信息
id username

# 查看组信息
groups
cat /etc/group

# 查看当前进程信息
ps -eo pid,ppid,uid,gid,comm

重要注意事项

不会失败: getgid 总是成功返回,不需要错误检查

实时性: 返回的是调用时刻的组 ID

继承性: 子进程继承父进程的组 ID

权限相关: 组 ID 直接影响文件访问权限

安全考虑: 在安全敏感程序中要验证组 ID

实际应用场景

权限检查: 在执行特权操作前检查组权限

日志记录: 记录操作的用户组信息

访问控制: 根据组 ID 控制资源访问

安全审计: 审计程序的执行环境

多用户应用: 根据组 ID 提供不同功能

常见组 ID 含义

组 ID组名说明0root超级用户组1bin系统二进制文件组2daemon系统守护进程组5tty终端设备组10uucpUnix to Unix Copy 组

与相关函数的配合使用

1
2
3
4
5
6
7
8
9
10
11
// 完整的身份信息获取
uid_t uid = getuid(); // 真实用户 ID
gid_t gid = getgid(); // 真实组 ID
uid_t euid = geteuid(); // 有效用户 ID
gid_t egid = getegid(); // 有效组 ID

// 获取所有组
int ngroups = getgroups(0, NULL); // 先获取数量
gid_t *groups = malloc(ngroups * sizeof(gid_t));
getgroups(ngroups, groups); // 再获取组列表

这些示例展示了 getgid 函数的各种使用方法,从基本的组 ID 获取到完整的权限检查工具,帮助你全面理解 Linux 系统中的用户组管理机制。

getgid系统调用及示例-CSDN博客

https://www.calcguide.tech/2025/09/09/geteuid-syscall-demo/

geteuid系统调用及示例-CSDN博客

getgroups系统调用及示例

getgroups - 获取进程的补充组列表

getgroups 是 Linux 系统调用,用于获取当前进程的补充组 ID 列表。该函数需要传入缓冲区大小和数组指针,返回补充组数量或填充的组 ID 数量。主要功能包括:查询进程所属的补充组(除主组外的其他组),支持先获取组数量再分配内存填充,并可与getgid()获取的主组 ID 对比。典型用法是两次调用:第一次获取数量,第二次填充数组。错误处理需注意缓冲区不足(EINVAL)和无效指针(EFAULT)等情况。相关函数包括setgroups()、initgroups()等组管理函数。

1. 函数介绍

getgroups 是一个 Linux 系统调用,用于获取当前进程所属的补充组(supplementary groups)列表。除了进程的主要组 ID(由 getgid() 返回)之外,进程还可以属于多个补充组,这些组决定了进程对文件和资源的额外访问权限。

补充组机制是 Unix/Linux 系统中实现灵活访问控制的重要组成部分,允许用户同时属于多个组以获得相应的权限。

2. 函数原型

1
2
3
4
5
#include <unistd.h>
#include <sys/types.h>

int getgroups(int size, gid_t list&#91;]);

3. 功能

获取当前进程所属的补充组 ID 列表。补充组是除了主要组之外,进程还属于的其他组。

4. 参数

int size: 指定 list 数组的大小(元素个数)

  • 如果为 0:函数返回补充组的数量,不填充 list 数组

  • 如果大于 0:将补充组 ID 填充到 list 数组中

gid_t list[]: 指向存储组 ID 的数组

  • 如果 size 为 0:可以为 NULL

  • 如果 size 大于 0:必须指向有效的数组

5. 返回值

成功时:

  • 如果 size 为 0:返回补充组的数量

  • 如果 size 大于 0:返回实际填充到数组中的组 ID 数量

失败时返回 -1,并设置 errno

6. 常见 errno 错误码

  • EINVAL: size 参数小于补充组的实际数量(缓冲区不足)

  • EFAULT: list 指针指向无效内存地址

  • EPERM: 在某些安全限制下可能返回(较少见)

7. 相似函数,或关联函数

  • setgroups(): 设置进程的补充组列表

  • initgroups(): 根据用户信息初始化补充组列表

  • getgid(): 获取进程的真实组 ID

  • getegid(): 获取进程的有效组 ID

  • getuid(), geteuid(): 获取用户 ID 相关函数

  • setgid(), setegid(): 设置组 ID

  • getgrouplist(): 获取用户的所有组(包括主要组)

  • /etc/group: 系统组信息文件

  • /etc/passwd: 用户主要组信息文件

8. 示例代码

示例1:基本使用 - 获取补充组列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <grp.h>
#include <errno.h>
#include <string.h>

int main() {
int group_count;
gid_t *group_list;
long max_groups;

printf("=== 获取进程补充组列表 ===\n");

// 首先获取补充组数量
group_count = getgroups(0, NULL);
if (group_count == -1) {
perror("获取补充组数量失败");
exit(EXIT_FAILURE);
}

printf("补充组数量: %d\n", group_count);

if (group_count == 0) {
printf("当前进程没有补充组\n");
return 0;
}

// 获取系统支持的最大组数
max_groups = sysconf(_SC_NGROUPS_MAX);
if (max_groups == -1) {
max_groups = 65536; // 设置一个较大的默认值
}

printf("系统最大支持组数: %ld\n", max_groups);

// 确保不会超出系统限制
if (group_count > max_groups) {
printf("警告: 补充组数量超出系统限制\n");
group_count = max_groups;
}

// 分配内存存储组列表
group_list = malloc(group_count * sizeof(gid_t));
if (group_list == NULL) {
perror("内存分配失败");
exit(EXIT_FAILURE);
}

// 获取补充组列表
int result = getgroups(group_count, group_list);
if (result == -1) {
perror("获取补充组列表失败");
free(group_list);
exit(EXIT_FAILURE);
}

printf("成功获取 %d 个补充组:\n", result);
printf("%-8s %-10s %s\n", "序号", "组ID", "组名");
printf("%-8s %-10s %s\n", "----", "----", "----");

// 显示每个组的信息
for (int i = 0; i < result; i++) {
printf("%-8d %-10d ", i + 1, group_list&#91;i]);

// 尝试获取组名
struct group *grp = getgrgid(group_list&#91;i]);
if (grp != NULL) {
printf("%s", grp->gr_name);
} else {
printf("(未知)");
}
printf("\n");
}

// 显示主要组信息进行对比
gid_t primary_gid = getgid();
printf("\n主要组信息:\n");
printf(" 组ID: %d\n", primary_gid);

struct group *primary_grp = getgrgid(primary_gid);
if (primary_grp != NULL) {
printf(" 组名: %s\n", primary_grp->gr_name);
}

// 检查主要组是否在补充组列表中
int found_in_supplementary = 0;
for (int i = 0; i < result; i++) {
if (group_list&#91;i] == primary_gid) {
found_in_supplementary = 1;
break;
}
}

printf("主要组是否在补充组中: %s\n",
found_in_supplementary ? "是" : "否");

free(group_list);
return 0;
}

示例2:错误处理和边界情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <grp.h>
#include <errno.h>
#include <string.h>

void demonstrate_error_handling() {
int result;
gid_t small_buffer&#91;2]; // 故意使用小缓冲区

printf("=== 错误处理演示 ===\n");

// 获取实际补充组数量
int actual_count = getgroups(0, NULL);
if (actual_count == -1) {
perror("获取补充组数量失败");
return;
}

printf("实际补充组数量: %d\n", actual_count);

if (actual_count > 0) {
// 使用过小的缓冲区,应该返回错误
printf("使用过小缓冲区测试 (大小: 2):\n");
result = getgroups(2, small_buffer);

if (result == -1) {
if (errno == EINVAL) {
printf(" 错误处理正确: 缓冲区不足 (EINVAL)\n");
} else {
printf(" 其他错误: %s\n", strerror(errno));
}
} else {
printf(" 意外成功,返回数量: %d\n", result);
}

// 使用 NULL 指针但 size > 0
printf("使用 NULL 指针测试:\n");
result = getgroups(10, NULL);
if (result == -1) {
if (errno == EFAULT) {
printf(" 错误处理正确: 无效指针 (EFAULT)\n");
} else {
printf(" 其他错误: %s\n", strerror(errno));
}
}
}
}

void demonstrate_empty_groups() {
printf("\n=== 空组列表演示 ===\n");

// 获取补充组数量
int count = getgroups(0, NULL);
if (count == -1) {
perror("获取组数量失败");
return;
}

printf("当前进程补充组数量: %d\n", count);

if (count == 0) {
printf("进程没有补充组权限\n");
printf("这可能表示:\n");
printf(" 1. 进程以最小权限运行\n");
printf(" 2. 用户不属于任何补充组\n");
printf(" 3. 在容器或受限环境中运行\n");
}
}

int main() {
demonstrate_error_handling();
demonstrate_empty_groups();
return 0;
}

示例3:完整的组权限分析工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <grp.h>
#include <pwd.h>
#include <string.h>

typedef struct {
gid_t gid;
char group_name&#91;256];
int is_primary;
int is_effective;
int is_supplementary;
} group_info_t;

int compare_gids(const void *a, const void *b) {
gid_t gid_a = ((group_info_t*)a)->gid;
gid_t gid_b = ((group_info_t*)b)->gid;
return (gid_a > gid_b) - (gid_a < gid_b);
}

void analyze_process_groups() {
gid_t primary_gid, effective_gid;
int sup_count;
gid_t *sup_groups = NULL;
group_info_t *all_groups = NULL;
int total_groups = 0;

printf("=== 进程组权限完整分析 ===\n");

// 获取基本信息
primary_gid = getgid();
effective_gid = getegid();

printf("进程基本信息:\n");
printf(" 真实用户 ID: %d\n", getuid());
printf(" 有效用户 ID: %d\n", geteuid());
printf(" 真实组 ID: %d\n", primary_gid);
printf(" 有效组 ID: %d\n", effective_gid);

// 获取用户信息
struct passwd *pwd = getpwuid(getuid());
if (pwd != NULL) {
printf(" 用户名: %s\n", pwd->pw_name);
}

// 获取补充组
sup_count = getgroups(0, NULL);
if (sup_count > 0) {
sup_groups = malloc(sup_count * sizeof(gid_t));
if (sup_groups == NULL) {
perror("内存分配失败");
return;
}

if (getgroups(sup_count, sup_groups) == -1) {
perror("获取补充组失败");
free(sup_groups);
return;
}
}

// 创建完整的组信息列表
total_groups = 2 + sup_count; // primary + effective + supplementary
all_groups = malloc(total_groups * sizeof(group_info_t));
if (all_groups == NULL) {
perror("内存分配失败");
if (sup_groups) free(sup_groups);
return;
}

int index = 0;

// 添加主要组
all_groups&#91;index].gid = primary_gid;
all_groups&#91;index].is_primary = 1;
all_groups&#91;index].is_effective = (primary_gid == effective_gid);
all_groups&#91;index].is_supplementary = 0;
struct group *grp = getgrgid(primary_gid);
if (grp != NULL) {
strncpy(all_groups&#91;index].group_name, grp->gr_name, sizeof(all_groups&#91;index].group_name) - 1);
} else {
snprintf(all_groups&#91;index].group_name, sizeof(all_groups&#91;index].group_name), "group_%d", primary_gid);
}
index++;

// 添加有效组(如果不同于主要组)
if (effective_gid != primary_gid) {
all_groups&#91;index].gid = effective_gid;
all_groups&#91;index].is_primary = 0;
all_groups&#91;index].is_effective = 1;
all_groups&#91;index].is_supplementary = 0;
struct group *grp = getgrgid(effective_gid);
if (grp != NULL) {
strncpy(all_groups&#91;index].group_name, grp->gr_name, sizeof(all_groups&#91;index].group_name) - 1);
} else {
snprintf(all_groups&#91;index].group_name, sizeof(all_groups&#91;index].group_name), "group_%d", effective_gid);
}
index++;
}

// 添加补充组
for (int i = 0; i < sup_count; i++) {
// 检查是否已存在
int exists = 0;
for (int j = 0; j < index; j++) {
if (all_groups&#91;j].gid == sup_groups&#91;i]) {
all_groups&#91;j].is_supplementary = 1;
exists = 1;
break;
}
}

if (!exists) {
all_groups&#91;index].gid = sup_groups&#91;i];
all_groups&#91;index].is_primary = 0;
all_groups&#91;index].is_effective = (sup_groups&#91;i] == effective_gid);
all_groups&#91;index].is_supplementary = 1;
struct group *grp = getgrgid(sup_groups&#91;i]);
if (grp != NULL) {
strncpy(all_groups&#91;index].group_name, grp->gr_name, sizeof(all_groups&#91;index].group_name) - 1);
} else {
snprintf(all_groups&#91;index].group_name, sizeof(all_groups&#91;index].group_name), "group_%d", sup_groups&#91;i]);
}
index++;
}
}

total_groups = index;

// 按组 ID 排序
qsort(all_groups, total_groups, sizeof(group_info_t), compare_gids);

// 显示结果
printf("\n完整的组权限信息:\n");
printf("%-8s %-10s %-12s %-12s %-15s %s\n",
"序号", "组ID", "主要组", "有效组", "补充组", "组名");
printf("%-8s %-10s %-12s %-12s %-15s %s\n",
"----", "----", "----", "----", "----", "----");

for (int i = 0; i < total_groups; i++) {
printf("%-8d %-10d %-12s %-12s %-15s %s\n",
i + 1,
all_groups&#91;i].gid,
all_groups&#91;i].is_primary ? "是" : "否",
all_groups&#91;i].is_effective ? "是" : "否",
all_groups&#91;i].is_supplementary ? "是" : "否",
all_groups&#91;i].group_name);
}

// 统计信息
printf("\n统计信息:\n");
printf(" 总组数: %d\n", total_groups);

int primary_count = 0, effective_count = 0, supplementary_count = 0;
for (int i = 0; i < total_groups; i++) {
if (all_groups&#91;i].is_primary) primary_count++;
if (all_groups&#91;i].is_effective) effective_count++;
if (all_groups&#91;i].is_supplementary) supplementary_count++;
}

printf(" 主要组: %d\n", primary_count);
printf(" 有效组: %d\n", effective_count);
printf(" 补充组: %d\n", supplementary_count);

// 特殊权限检查
printf("\n特殊权限检查:\n");
int has_root_group = 0;
int has_admin_group = 0;

for (int i = 0; i < total_groups; i++) {
if (all_groups&#91;i].gid == 0) {
has_root_group = 1;
}
// 检查常见的管理员组
if (strcmp(all_groups&#91;i].group_name, "wheel") == 0 ||
strcmp(all_groups&#91;i].group_name, "sudo") == 0 ||
strcmp(all_groups&#91;i].group_name, "adm") == 0) {
has_admin_group = 1;
}
}

printf(" Root 组权限: %s\n", has_root_group ? "是" : "否");
printf(" 管理员组权限: %s\n", has_admin_group ? "是" : "否");

// 清理内存
if (sup_groups) free(sup_groups);
if (all_groups) free(all_groups);
}

int main() {
analyze_process_groups();
return 0;
}

示例4:组权限验证和安全检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <grp.h>

// 检查进程是否属于指定组
int is_process_member_of_group(gid_t target_gid) {
// 首先检查主要组和有效组
if (getgid() == target_gid || getegid() == target_gid) {
return 1;
}

// 检查补充组
int sup_count = getgroups(0, NULL);
if (sup_count <= 0) {
return 0;
}

gid_t *sup_groups = malloc(sup_count * sizeof(gid_t));
if (sup_groups == NULL) {
return 0;
}

if (getgroups(sup_count, sup_groups) == -1) {
free(sup_groups);
return 0;
}

for (int i = 0; i < sup_count; i++) {
if (sup_groups&#91;i] == target_gid) {
free(sup_groups);
return 1;
}
}

free(sup_groups);
return 0;
}

// 获取特定组的权限级别
typedef enum {
NO_ACCESS = 0,
SUPPLEMENTARY_ACCESS = 1,
PRIMARY_ACCESS = 2,
EFFECTIVE_ACCESS = 3,
ROOT_ACCESS = 4
} access_level_t;

access_level_t get_group_access_level(gid_t target_gid) {
if (target_gid == 0 && (getgid() == 0 || getegid() == 0)) {
return ROOT_ACCESS;
}

if (getegid() == target_gid) {
return EFFECTIVE_ACCESS;
}

if (getgid() == target_gid) {
return PRIMARY_ACCESS;
}

// 检查补充组
int sup_count = getgroups(0, NULL);
if (sup_count > 0) {
gid_t *sup_groups = malloc(sup_count * sizeof(gid_t));
if (sup_groups != NULL) {
if (getgroups(sup_count, sup_groups) != -1) {
for (int i = 0; i < sup_count; i++) {
if (sup_groups&#91;i] == target_gid) {
free(sup_groups);
return SUPPLEMENTARY_ACCESS;
}
}
}
free(sup_groups);
}
}

return NO_ACCESS;
}

void check_common_groups() {
printf("=== 常见组权限检查 ===\n");

// 检查一些常见的系统组
struct {
const char *name;
gid_t gid;
} common_groups&#91;] = {
{"root", 0},
{"wheel", 0}, // 需要查找实际 GID
{"sudo", 0},
{"adm", 0},
{"disk", 0}
};

// 获取这些组的实际 GID
for (int i = 0; i < sizeof(common_groups)/sizeof(common_groups&#91;0]); i++) {
struct group *grp = getgrnam(common_groups&#91;i].name);
if (grp != NULL) {
common_groups&#91;i].gid = grp->gr_gid;
}
}

printf("%-12s %-8s %-15s %s\n", "组名", "组ID", "访问级别", "成员状态");
printf("%-12s %-8s %-15s %s\n", "----", "----", "----", "----");

for (int i = 0; i < sizeof(common_groups)/sizeof(common_groups&#91;0]); i++) {
if (common_groups&#91;i].gid != 0) {
access_level_t level = get_group_access_level(common_groups&#91;i].gid);
int is_member = is_process_member_of_group(common_groups&#91;i].gid);

const char *level_str;
switch (level) {
case ROOT_ACCESS: level_str = "Root"; break;
case EFFECTIVE_ACCESS: level_str = "Effective"; break;
case PRIMARY_ACCESS: level_str = "Primary"; break;
case SUPPLEMENTARY_ACCESS: level_str = "Supplementary"; break;
default: level_str = "None"; break;
}

printf("%-12s %-8d %-15s %s\n",
common_groups&#91;i].name,
common_groups&#91;i].gid,
level_str,
is_member ? "是" : "否");
}
}
}

int main() {
check_common_groups();
return 0;
}

9. 实际应用场景

getgroups 在以下场景中非常有用:

场景1:权限验证

1
2
3
4
int can_access_resource(gid_t required_group) {
return is_process_member_of_group(required_group);
}

场景2:安全审计

1
2
3
4
5
void audit_process_groups() {
int count = getgroups(0, NULL);
syslog(LOG_INFO, "进程拥有 %d 个补充组", count);
}

场景3:访问控制

1
2
3
4
5
6
7
8
int check_file_group_permission(const char *filename) {
struct stat file_stat;
if (stat(filename, &file_stat) == 0) {
return is_process_member_of_group(file_stat.st_gid);
}
return 0;
}

10. 注意事项

使用 getgroups 时需要注意:

缓冲区大小: 确保缓冲区足够大,避免 EINVAL 错误

内存管理: 正确分配和释放内存

错误处理: 检查返回值和 errno

系统限制: 了解 NGROUPS_MAX 限制

并发安全: 在多线程环境中注意数据一致性

总结

getgroups 是管理进程组权限的重要函数,关键要点:

补充组获取: 获取进程除主要组外的所有组

双重调用: 通常需要先获取数量,再获取实际数据

权限检查: 是权限验证和访问控制的基础

安全相关: 在安全审计和权限管理中广泛使用

系统集成: 与 /etc/group 等系统文件紧密相关

正确使用 getgroups 可以帮助程序准确了解当前的组权限状态,实现更精细的访问控制和安全检查。

getgroups系统调用及示例-CSDN博客

getgid系统调用及示例-CSDN博客

getgid系统调用及示例-CSDN博客