LWN:内核代码中该不该有copyright声明?

Btrfs子系统中关于是否需要在代码中添加版权声明的讨论揭示了Linux内核对版权政策的不确定性。Christoph Hellwig强调版权通知的重要性,尤其是在法律层面,而Btrfs维护者David Sterba则倾向于使用SPDX标签代替。这一变化可能导致进一步的内部共识寻求和潜在的项目规范调整。

关注了就能看到更多这么棒的文章哦~

Copyright notices (or the lack thereof) in kernel code

By Jonathan Corbet
October 27, 2022
DeepL assisted translation
https://lwn.net/Articles/912355/

在对自由软件项目进行贡献时要求进行版权转让(copyright assignments),这种做法近年来越来越少了;GNU Binutils 项目可能是这方面倒下的多米诺骨牌中最新的一块。Linux kernel 项目跟其他一些项目不同,它一直允许贡献者保留他们的 copyright,从而形成了一个拥有非常分散的所有权的代码库。在这样的项目中,经常不是很容易看出来谁拥有某段代码的 copyright。一些开发者(或他们所属的公司或组织)坚持要在代码中放置 copyright 声明信息,来记录他们对内核中部分代码的所有权(ownership)。然而,最近在 Btrfs 子系统中进行的一系列讨论表明,目前 Linux kernel 中并没有一个统一的政策来决定什么时候需要这种 notice 信息,也没有说是否是个可以接受的做法。

9 月初,有一个为 Btrfs 文件系统实现 fscrypt 集成的 patch set 包括了一个 patch,其中加入了一行 Facebook 的 copyright notice。Btrfs 维护者 David Sterba 回复要求将 copyright 信息放置在 SPDX tag 中;他引用了 Btrfs wiki 中的一个 page,声称这些 tag 可以完全替代 copyright notice。Christoph Hellwig 不同意这个说法,他指出 SPDX 描述的是 license(许可),而不是 ownership(所有权):

无论从哪个角度来说,它都不能替代 copyright notice,而且我曾经参与过 Copyright enforcement,所以我可以明确地说,至少在某些司法管辖区,Copyright notice 绝对是有必要的。

确实,Hellwig 是针对 VMware 的 GPL 侵权诉讼的发起人,该诉讼由于无法证明相关代码的所有权而被驳回。因此,他很强调代码本身需要放置 copyright notice,这毫不令人意外。Hellwig 也在 9 月份提交了一个自己的 patch,在一个新创建的文件中加入了 copyright notice,Sterba 直接说他也会拒绝这个改动。10 月底,在讨论另一个 patch set 时,Hellwig 最终撤回了这部分改动,他说:

顺便说一下,我反对在没有适当的 copyright notice 的情况下将我的任何代码合并到 btrfs 中,鉴于 btrfs 的维护者拒绝采取适当的、并且法律要求要有的 copyright notice,我也得花一些时间来删除我之前做的重大改动。

鉴于内核代码中不乏 copyright notice(搜索可以看到有将近 79000 行里包含了 "copyright" 一词),我们自然会想知道为什么在 Btrfs 子系统中采用这种政策。Btrfs 的 wiki 页面描述了其中的原因:

copyright notice 不是必须的,而且不鼓励这样做,这里的原因是来自可行性(practical)而不是合法性(legal)。这些文件没有跟踪记录每一位个人贡献者或公司的信息(这些可以在 git 中找到),所以不准确和不完整的信息,对于某个文件中的改动的 copyright 所有人识别方面,给出了一个非常偏颇的、甚至是完全错误的指示。随着时间的推移,代码通常会在较小部分进行大量修改,就慢慢地演变成不再类似于原始代码的东西,尽管可能共享了很多的核心思想和实现逻辑。一个已经不存在的公司在 10 年前的 copyright notice,对开发者来说,明显是完全没有价值的。

该页面还指出,在内核的 Git 历史中可以看到的 Signed-off-by 标签就足以记录代码的 copyright 状态。这个观点可能不是那么牢固,毕竟这些 tag 表明的是相关提交者是将代码贡献给内核的人,但不一定表明了谁是版权所有者(copyright holder)。另一个问题是由 Bradley Kuhn 指出的:如果用 Git 历史记录来作为代码的 copyright notice,那么就有必要将整个 Git 仓库发布出去,才能符合 GPL 的源代码发布的要求。这就使得那些对代码中写版权声明不够方便的抱怨变得有些不那么完全合理了。

在最近的讨论中,Chris Mason 说 "Christoph 的要求完全是符合内核的规范的(well within the norms for the kernel)"。Sterba 回答说他会考虑改变这个策略,但需要 kernel 项目整体来确定一下这方面的策略之后:

我已经要求提供一些类似于 SPDX 流程的建议,或者最佳的参考做法。一些 TAB 能够承认的东西,也许需要向律师咨询。并且需要在 linux project 中达到共识,而不仅仅是少部分人进行争论,因为毫无疑问,人们以前都是在采用不同的方式来做事。

目前还不清楚 Sterba 向谁征求了建议。他有可能会发现,随着时间的推移,Btrfs 子系统对 cpyright notice 的立场在整个 linux kernel 项目中并不是一个广泛接受的共识。Steve Rostedt 的说法可能是更好地描述了 kernel 里的共识:"这个策略很简单。如果有人要求他们的代码有 copyright notice,那么就加上,或者就拒绝他们的代码"。不过,在没有 Linus Torvalds 的决定(decree)的情况下,copyright notice 的问题可能会继续引出一些争议。对于一个大家共享的代码的一部分来声明 copyright,可能总是一个敏感的问题,但这可能是一个开发者非常关心的问题。

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

format,png

/* Copyright (c) 2025-2026 TP-LINK Technologies CO.LTD * All rights reserved * \file primeNumber.c * \brief The source file for primeNumber * \author zuoshicheng <zuoshicheng@tp-link.com> * \version 1.0.0 * \date 2025/07/30 * \history \arg 1.0.0 2025/07/30 zuoshicheng, Create file */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/stat.h> #include <fcntl.h> #define PORT 80 #define WEB_ROOT "./web" // 网站根目录 #define BUFFER_SIZE 8192 // 根据文件扩展名返回MIME类型 const char* get_mime_type(const char *ext) { if (strcmp(ext, "html") == 0) return "text/html"; if (strcmp(ext, "css") == 0) return "text/css"; if (strcmp(ext, "js") == 0) return "application/javascript"; if (strcmp(ext, "jpg") == 0) return "image/jpeg"; if (strcmp(ext, "png") == 0) return "image/png"; return "application/octet-stream"; } // 发送HTTP响应(含文件内容) void send_response(int client_fd, const char *path) { char buffer[BUFFER_SIZE]; FILE *file = fopen(path, "rb"); if (!file) { // 文件不存在时发送404 const char *not_found = "HTTP/1.1 404 Not Found\r\nContent-Type: text/html\r\n\r\n<h1>404 Not Found</h1>"; send(client_fd, not_found, strlen(not_found), 0); return; } // 获取文件扩展名 const char *ext = strrchr(path, '.'); if (ext) ext++; else ext = ""; // 构造HTTP头部 struct stat st; stat(path, &st); snprintf(buffer, BUFFER_SIZE, "HTTP/1.1 200 OK\r\n" "Content-Type: %s\r\n" "Content-Length: %ld\r\n\r\n", get_mime_type(ext), st.st_size ); send(client_fd, buffer, strlen(buffer), 0); // 发送文件内容 size_t bytes_read; while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, file)) > 0) { send(client_fd, buffer, bytes_read, 0); } fclose(file); } // 主服务逻辑 int main() { int server_fd, client_fd; struct sockaddr_in server_addr, client_addr; socklen_t addr_len = sizeof(client_addr); // 创建Socket server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd < 0) { perror("Socket creation failed"); exit(EXIT_FAILURE); } // 绑定端口 server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(PORT); if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr))) { perror("Bind failed"); close(server_fd); exit(EXIT_FAILURE); } // 监听请求 if (listen(server_fd, 10) < 0) { perror("Listen failed"); close(server_fd); exit(EXIT_FAILURE); } printf("Server running on http://localhost:%d\n", PORT); // 主循环:接受请求并处理 while (1) { client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &addr_len); if (client_fd < 0) { perror("Accept error"); continue; } // 读取HTTP请求 char request[BUFFER_SIZE]; recv(client_fd, request, BUFFER_SIZE, 0); // 解析请求路径(简化版) char *method = strtok(request, " "); char *path = strtok(NULL, " "); if (!method || !path) { close(client_fd); continue; } // 映射路径到本地文件 char full_path[256]; if (strcmp(path, "/") == 0) path = "/Index.html"; // 默认首页 snprintf(full_path, sizeof(full_path), "%s%s", WEB_ROOT, path); // 发送响应 send_response(client_fd, full_path); close(client_fd); } close(server_fd); return 0; } 改用多进程方法实现以上代码
最新发布
08-06
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值